Skip to content

Commit

Permalink
Merge 2f9e221 into a9ff2ea
Browse files Browse the repository at this point in the history
  • Loading branch information
leefine02 authored Sep 25, 2024
2 parents a9ff2ea + 2f9e221 commit 1af7abe
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 74 deletions.
46 changes: 16 additions & 30 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,19 @@
name: Starter Workflow
on: [workflow_dispatch, push, pull_request]
name: Keyfactor Bootstrap Workflow

jobs:
call-create-github-release-workflow:
uses: Keyfactor/actions/.github/workflows/github-release.yml@main

call-assign-from-json-workflow:
uses: Keyfactor/actions/.github/workflows/assign-env-from-json.yml@main

call-dotnet-build-and-release-workflow:
needs: [call-create-github-release-workflow, call-assign-from-json-workflow]
uses: Keyfactor/actions/.github/workflows/dotnet-build-and-release.yml@main
with:
release_version: ${{ needs.call-create-github-release-workflow.outputs.release_version }}
release_url: ${{ needs.call-create-github-release-workflow.outputs.release_url }}
release_dir: ${{ needs.call-assign-from-json-workflow.outputs.release_dir }}
on:
workflow_dispatch:
pull_request:
types: [opened, closed, synchronize, edited, reopened]
push:
create:
branches:
- 'release-*.*'

secrets:
token: ${{ secrets.PRIVATE_PACKAGE_ACCESS }}

call-generate-readme-workflow:
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
uses: Keyfactor/actions/.github/workflows/generate-readme.yml@main
jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@v2
secrets:
token: ${{ secrets.APPROVE_README_PUSH }}

call-update-catalog-workflow:
needs: call-assign-from-json-workflow
if: needs.call-assign-from-json-workflow.outputs.update_catalog == 'True' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: Keyfactor/actions/.github/workflows/update-catalog.yml@main
secrets:
token: ${{ secrets.SDK_SYNC_PAT }}
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
2 changes: 1 addition & 1 deletion Bundle/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private void PerformAddJob(F5Client f5)
if (!JobConfig.Overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); }

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Replace entry '{name}' in '{JobConfig.CertificateStoreDetails.StorePath}'");
f5.ReplaceEntry(partition, name, JobConfig.JobCertificate.Contents);
f5.ReplaceEntry(partition, name, JobConfig.JobCertificate.Contents, null);
}
else
{
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v1.6.0
- Add Store Password (optional) to allow for setting key type to "Password" when adding/replacing a certificate. This will encrypt the private key deployed on the F5 device with the password set as the Store Password.

v1.5.0
- Add new optional custom paramter - UseTokenAuth - to make token auth vs basic auth (default) a selectable option

Expand Down
23 changes: 13 additions & 10 deletions F5Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public F5Client(CertificateStore certificateStore, string serverUserName, string

#region Certificate/PFX Shared

public void AddEntry(string partition, string name, string b64Certificate)
public void AddEntry(string partition, string name, string b64Certificate, string certificatePassword)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "AddEntry");
LogHandlerCommon.Trace(logger, CertificateStore, $"Processing certificate for partition '{partition}' and name '{name}'");
Expand All @@ -94,7 +94,7 @@ public void AddEntry(string partition, string name, string b64Certificate)
if (certificate.HasPrivateKey)
{
LogHandlerCommon.Trace(logger, CertificateStore, $"Certificate for partition '{partition}' and name '{name}' has a private key - performing addition");
AddPfx(entryContents, partition, name, password, null);
AddPfx(entryContents, partition, name, password, null, certificatePassword);
LogHandlerCommon.Trace(logger, CertificateStore, $"PFX addition for partition '{partition}' and name '{name}' completed");
}
else
Expand All @@ -106,7 +106,7 @@ public void AddEntry(string partition, string name, string b64Certificate)
LogHandlerCommon.MethodExit(logger, CertificateStore, "AddEntry");
}

public void ReplaceEntry(string partition, string name, string b64Certificate)
public void ReplaceEntry(string partition, string name, string b64Certificate, string certificatePassword)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "ReplaceEntry");
LogHandlerCommon.Trace(logger, CertificateStore, $"Processing certificate for partition '{partition}' and name '{name}'");
Expand All @@ -118,7 +118,7 @@ public void ReplaceEntry(string partition, string name, string b64Certificate)
if (certificate.HasPrivateKey)
{
LogHandlerCommon.Trace(logger, CertificateStore, $"Certificate for partition '{partition}' and name '{name}' has a private key - performing replacement");
ReplacePfx(entryContents, partition, name, password);
ReplacePfx(entryContents, partition, name, password, certificatePassword);
LogHandlerCommon.Trace(logger, CertificateStore, $"PFX replacement for partition '{partition}' and name '{name}' completed");
}
else
Expand Down Expand Up @@ -220,7 +220,7 @@ private void AddCertificate(byte[] entryContents, string partition, string name)
LogHandlerCommon.MethodExit(logger, CertificateStore, "AddCertificate");
}

private void AddPfx(byte[] entryContents, string partition, string name, string password, string keyName)
private void AddPfx(byte[] entryContents, string partition, string name, string password, string keyName, string certificatePassword)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "AddPfx");
LogHandlerCommon.Trace(logger, CertificateStore, $"Uploading PFX to {partition}-{name}.p12");
Expand All @@ -238,6 +238,8 @@ private void AddPfx(byte[] entryContents, string partition, string name, string
name = $"{name}",
localfile = $"/var/config/rest/downloads/{partition}-{name}.p12{keyNameParam}",
passphrase = password,
keyPassphrase = String.IsNullOrEmpty(certificatePassword) ? string.Empty : certificatePassword,
keySecurityType = String.IsNullOrEmpty(certificatePassword) ? "normal" : "password",
partition = partition
}, "pkcs12");
}
Expand All @@ -248,7 +250,7 @@ private void AddPfx(byte[] entryContents, string partition, string name, string
// again with that key name appended onto the localfile parameter. An F5 hotfix is necessary to produce
// this message and use the updated /pkcs12 API that accepts the separate key name.
if (string.IsNullOrEmpty(keyName) && ex.message.Contains(INVALID_KEY_MSG_ID))
AddPfx(entryContents, partition, name, password, GetKeyName(ex.message));
AddPfx(entryContents, partition, name, password, GetKeyName(ex.message), certificatePassword);
else
throw (name.Contains(".crt", StringComparison.OrdinalIgnoreCase) &&
ex.Message.Contains("expected to exist", StringComparison.OrdinalIgnoreCase) ?
Expand Down Expand Up @@ -287,7 +289,7 @@ private void ReplaceCertificate(byte[] entryContents, string partition, string n
LogHandlerCommon.MethodExit(logger, CertificateStore, "ReplaceCertificate");
}

private void ReplacePfx(byte[] entryContents, string partition, string name, string password)
private void ReplacePfx(byte[] entryContents, string partition, string name, string password, string certificatePassword)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "ReplacePfx");
string timestamp = DateTime.Now.ToString("MM-dd-yy:H:mm:ss");
Expand All @@ -297,7 +299,7 @@ private void ReplacePfx(byte[] entryContents, string partition, string name, str
ArchiveFile($"/config/filestore/files_d/{partition}_d/certificate_d/:{partition}:{name}_*", $"{partition}-{name}-{timestamp}.crt");

LogHandlerCommon.Trace(logger, CertificateStore, $"Adding PFX to partition '{partition}' and name '{name}'");
AddPfx(entryContents, partition, name, password, null);
AddPfx(entryContents, partition, name, password, null, certificatePassword);
LogHandlerCommon.MethodExit(logger, CertificateStore, "ReplacePfx");
}

Expand Down Expand Up @@ -703,6 +705,7 @@ public List<CurrentInventoryItem> GetSSLProfiles(int pageSize)
{
try
{
LogHandlerCommon.Trace(logger, CertificateStore, $"Processing alias {profiles[i].name}");
// Exclude 'ca-bundle.crt' as that can only be managed by F5
if (profiles[i].name.Equals("ca-bundle.crt", StringComparison.OrdinalIgnoreCase)
|| profiles[i].name.Equals("f5-ca-bundle.crt", StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -860,14 +863,14 @@ public void AddBundleEntry(string bundle, string partition, string name, string
if (!CertificateExists(partition, name))
{
LogHandlerCommon.Debug(logger, CertificateStore, $"Add entry '{name}' in '{CertificateStore.StorePath}'");
AddEntry(partition, name, b64Certificate);
AddEntry(partition, name, b64Certificate, null);
}
else
{
if (!overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); }

LogHandlerCommon.Debug(logger, CertificateStore, $"Replace entry '{name}' in '{CertificateStore.StorePath}'");
ReplaceEntry(partition, name, b64Certificate);
ReplaceEntry(partition, name, b64Certificate, null);
}

// Add the entry to the bundle
Expand Down
2 changes: 2 additions & 0 deletions F5DataModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ internal class F5InstallCommand
public string localfile { get; set; }

public string passphrase { get; set; }
public string keyPassphrase { get; set; }
public string keySecurityType { get; set; }
public string partition { get; set; }
}

Expand Down
38 changes: 22 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

# F5

The F5 Orchestrator allows for the remote management of F5 Stores. Discovery, Inventory, and Management functions are supported.

#### Integration status: Production - Ready for use in production environments.


## About the Keyfactor Universal Orchestrator Extension

This repository contains a Universal Orchestrator Extension which is a plugin to the Keyfactor Universal Orchestrator. Within the Keyfactor Platform, Orchestrators are used to manage “certificate stores” &mdash; collections of certificates and roots of trust that are found within and used by various applications.
Expand All @@ -13,23 +13,22 @@ The Universal Orchestrator is part of the Keyfactor software distribution and is

The Universal Orchestrator is the successor to the Windows Orchestrator. This Orchestrator Extension plugin only works with the Universal Orchestrator and does not work with the Windows Orchestrator.


## Support for F5

F5 is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative.
F5 is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com

###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab.


---


---



## Keyfactor Version Supported

The minimum version of the Keyfactor Universal Orchestrator Framework needed to run this version of the extension is 10.1

## Platform Specific Notes

The Keyfactor Universal Orchestrator may be installed on either Windows or Linux based platforms. The certificate operations supported by a capability may vary based what platform the capability is installed on. The table below indicates what capabilities are supported based on which platform the encompassing Universal Orchestrator is running.
Expand All @@ -39,7 +38,7 @@ The Keyfactor Universal Orchestrator may be installed on either Windows or Linux
|Supports Management Remove|&check; |&check; |
|Supports Create Store| | |
|Supports Discovery|&check; |&check; |
|Supports Renrollment| | |
|Supports Reenrollment| | |
|Supports Inventory|&check; |&check; |


Expand Down Expand Up @@ -192,31 +191,35 @@ If you choose to manually create a F5 store In Keyfactor Command rather than run

- **Container** – Optional. Select a container if utilized.

- **Client Machine & Credentials** – Required. The server name or IP Address and login credentials for the F5 device. The credentials for server login can be any of:

- UserId/Password

- PAM provider information to pass the UserId/Password or UserId/SSH private key credentials

When entering the credentials, UseSSL ***must*** be selected.
- **Client Machine** – Required. The server name or IP Address for the F5 device.

- **Store Path** – Required. Enter the name of the partition on the F5 device you wish to manage. This value is case sensitive, so if the partition name is "Common", it must be entered as "Common" and not "common".

- **Orchestrator** – Required. Select the orchestrator you wish to use to manage this store

- **Primary Node Online Required** – Optional. Select this if you wish to stop the orchestrator from adding, replacing or renewing certificates on nodes that are inactive. If this is not selected, adding, replacing and renewing certificates on inactive nodes will be allowed. If you choose not to add this custom field, the default value of False will be assumed.

- **Primary Node** - Only required (and shown) if Primary Node Online Required is added and selected. Enter the fully qualified domain name of the F5 device that acts as the primary node in a highly available F5 implementation. If you're using a single F5 device, this will typically be the same value you entered in the Client Machine field.

- **Primary Node Check Retry Maximum** - Only required (and shown) if Primary Node Online Required is added and selected. Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing.

- **Primary Node Check Retry Wait Seconds** - Only required (and shown) if Primary Node Online Required is added and selected. Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive.

- **Primary Node Check Retry Maximum** - Only required (and shown) if Primary Node Online Required is added and selected. Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing.

- **Version of F5** - Required. Select v13, v14, or v15 to match the version for the F5 device being managed

- **Server Username/Server Password** - Required. The credentials for server login can be any of:

- UserId/Password

- PAM provider information to pass the UserId/Password or UserId/SSH private key credentials

- **Use SSL** - Required. True if using https to access the F5 device. False if using http.

- **Ignore SSL Warning** - Optional. Select this if you wish to ignore SSL warnings from F5 that occur during API calls when the site does not have a trusted certificate with the proper SAN bound to it. If you choose not to add this custom field, the default value of False will be assumed and SSL warnings will cause errors during orchestrator extension jobs.

- **Use Token Authentication** - Optional. Select this if you wish to use F5's token authentiation instead of basic authentication for all API requests. If you choose not to add this custom field, the default value of False will be assumed and basic authentication will be used for all API requests for all jobs. Setting this value to True will enable an initial basic authenticated request to acquire an authentication token, which will then be used for all subsequent API requests.

- **Orchestrator** Required. Select the orchestrator you wish to use to manage this store
- **Store Password** - Required for F5-SL-REST only. Check "No Password" if you wish the private key of any added certificate to be set to Key Security Type "Normal". Enter a value (either a password or pointer to an installed PAM provider key for the password) to be used to encrypt the private key of any added certificate for Key Security Type of "Password".

- **Inventory Schedule** – Set a schedule for running Inventory jobs or none, if you choose not to schedule Inventory at this time.

Expand Down Expand Up @@ -246,3 +249,6 @@ First, in Keyfactor Command navigate to Certificate Locations =\> Certificate St

Once the Discovery job has completed, a list of F5 certificate store locations should show in the Certificate Stores Discovery tab in Keyfactor Command. Right click on a store and select Approve to bring up a dialog that will ask for the remaining necessary certificate store parameters described in Step 2a. Complete those and click Save, and the Certificate Store should now show up in the list of stores in the Certificate Stores tab.

When creating cert store type manually, that store property names and entry parameter names are case sensitive


8 changes: 4 additions & 4 deletions SSLProfile/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
{
case CertStoreOperationType.Add:
LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Add entry '{config.JobCertificate.Alias}' to '{config.CertificateStoreDetails.StorePath}'");
PerformAddJob(f5);
PerformAddJob(f5, config.CertificateStoreDetails.StorePassword);
break;
case CertStoreOperationType.Remove:
LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'");
Expand All @@ -81,7 +81,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
}
}

private void PerformAddJob(F5Client f5)
private void PerformAddJob(F5Client f5, string certificatePassword)
{
LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformAddJob");
string name = JobConfig.JobCertificate.Alias;
Expand All @@ -92,12 +92,12 @@ private void PerformAddJob(F5Client f5)
if (!JobConfig.Overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); }

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Replace entry '{name}' in '{JobConfig.CertificateStoreDetails.StorePath}'");
f5.ReplaceEntry(partition, name, JobConfig.JobCertificate.Contents);
f5.ReplaceEntry(partition, name, JobConfig.JobCertificate.Contents, null);
}
else
{
LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"The entry '{name}' does not exist in '{JobConfig.CertificateStoreDetails.StorePath}' and will be added");
f5.AddEntry(partition, name, JobConfig.JobCertificate.Contents);
f5.AddEntry(partition, name, JobConfig.JobCertificate.Contents, certificatePassword);
}
LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformAddJob");
}
Expand Down
Binary file modified images/image11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/image13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1af7abe

Please sign in to comment.