Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Bundle/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override JobResult ProcessJob(InventoryJobConfiguration config, SubmitInv

try
{
base.ParseJobProperties();
base.ParseStoreProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory);

Expand Down
2 changes: 1 addition & 1 deletion Bundle/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
try
{
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
base.ParseJobProperties();
base.ParseStoreProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory)
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
v1.10.0
- Modify SSLProfiles entry parameter (F5-SL-REST store type only) to allow adding one-to-many SSL Profile bindings when adding NEW certificates (ignored for renewals/replacements)
- Update dlls with vulnerability alerts
- Handle inventorying certificates with bag attributes

v1.9.0
- Added new SSLProfiles READ ONLY entry parameter that will contain a comma delimited list of SSL Profiles a certificate is bound to on the F5 device.
- Added new SSLProfiles READ ONLY entry parameter that will contain a comma delimited list of SSL Profiles a certificate is bound to on the F5 device. (F5-SL-REST store type only)

v1.8.1
- Documentation changes including highlighting lack of HA support as well as a correction to the proper StorePath value for F5-CA-REST stores.
Expand Down
18 changes: 18 additions & 0 deletions F5Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Diagnostics.CodeAnalysis;
using static Keyfactor.Orchestrators.Common.OrchestratorConstants;
using static Org.BouncyCastle.Math.EC.ECCurve;
using System.Reflection.Metadata;

namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator
{
Expand Down Expand Up @@ -205,6 +206,22 @@
return exists;
}

public void BindCertificate(string alias, string sslProfile)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificate");

try
{
F5Binding binding = new F5Binding { cert = $"{alias}", key = $"{alias}", chain = $"{alias}" };
REST.Patch<F5Binding>($"/mgmt/tm/ltm/profile/client-ssl/{sslProfile}", binding);
}

finally
{
LogHandlerCommon.MethodExit(logger, CertificateStore, "BindCertificate");
}
}

private void AddCertificate(byte[] entryContents, string partition, string name)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "AddCertificate");
Expand Down Expand Up @@ -334,6 +351,7 @@
//PEM(w / headers)-- > L or I
case "L":
case "I":
case "Q":
LogHandlerCommon.Trace(logger, CertificateStore, "Certificate is PEM with headers");
crtBytes = System.Convert.FromBase64String(crt);
certificateEntry = System.Text.ASCIIEncoding.ASCII.GetString(crtBytes);
Expand Down Expand Up @@ -562,7 +580,7 @@
byte[] devicePfx = Convert.FromBase64String(b64Certificate);
string password = PFXPassword;
CertificateCollectionConverter converter = CertificateCollectionConverterFactory.FromDER(devicePfx, password);
string pfxPem = converter.ToPEM(password);

Check warning on line 583 in F5Client.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

'CertificateCollectionConverter.ToPEM(string)' is obsolete: 'The CryptographicObjectFormatter.PEM class should be used for all certificate PEM conversions. '
List<X509Certificate2> clist = converter.ToX509Certificate2List(password);

StringBuilder certPemBuilder = new StringBuilder();
Expand Down
7 changes: 7 additions & 0 deletions F5DataModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ internal class F5BundleInclude
public string[] includeBundle { get; set; }
}

internal class F5Binding
{
public string cert { get; set; }
public string key { get; set; }
public string chain { get; set; }
}

public class F5Transaction
{
public string transid { get; set; }
Expand Down
8 changes: 5 additions & 3 deletions F5Orchestrator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
<PackageReference Include="Keyfactor.Orchestrators.IOrchestratorJobExtensions" Version="0.7.0" />
<PackageReference Include="Keyfactor.PKI" Version="4.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Keyfactor.PKI" Version="5.0.0" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Keyfactor.PKI" Version="8.1.1" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Keyfactor.Logging" Version="1.1.2" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Keyfactor.Logging" Version="1.2.0" Condition="'$(TargetFramework)' == 'net8.0'" />

<None Update="manifest.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
Expand Down
4 changes: 2 additions & 2 deletions InventoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public abstract class InventoryBase : F5JobBase, IInventoryJobExtension

public abstract JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpdate submitInventory);

protected void ParseJobProperties()
protected void ParseStoreProperties()
{
LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "ParseJobProperties");
LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "ParseStoreProperties");
dynamic properties = JsonConvert.DeserializeObject(JobConfig.CertificateStoreDetails.Properties.ToString());

IgnoreSSLWarning = properties.IgnoreSSLWarning == null || string.IsNullOrEmpty(properties.IgnoreSSLWarning.Value) ? false : bool.Parse(properties.IgnoreSSLWarning.Value);
Expand Down
6 changes: 3 additions & 3 deletions ManagementBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public abstract class ManagementBase : F5JobBase, IManagementJobExtension

public abstract JobResult ProcessJob(ManagementJobConfiguration config);

protected void ParseJobProperties()
protected void ParseStoreProperties()
{
if (logger == null)
{
logger = Keyfactor.Logging.LogHandler.GetClassLogger(this.GetType());
}

LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "ParseJobProperties");
LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "ParseStoreProperties");
dynamic properties = JsonConvert.DeserializeObject(JobConfig.CertificateStoreDetails.Properties.ToString());
PrimaryNodeOnlineRequired = false;
PrimaryNode = string.Empty;
Expand Down Expand Up @@ -71,7 +71,7 @@ protected void ParseJobProperties()
int.TryParse(properties.PrimaryNodeCheckRetryWaitSecs.ToString(), out primaryNodeRetryWaitSecs);
PrimaryNodeRetryWaitSecs = primaryNodeRetryWaitSecs;
LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"Primary node retry wait seconds '{PrimaryNodeRetryWaitSecs}'");
LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "ParseJobProperties");
LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "ParseStoreProperties");
}
else
{
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

## Overview

The f5-rest-orchestrator orchestrator extension manages various types of certificates on a F5 Big IP device (version 15 or later). TLS certificates, CA bundles, and the TLS certificate bound to the administrative website can all be managed with this integration within the scope described in the sections below. One important note, this integration DOES NOT manage high availability (HA) failover between primary and secondary nodes. If syncing between primary and secondary nodes is desired, this must either be handled within your F5 Big IP instance itself, or you can set up a Keyfactor Command certificate store for each node (primary and secondary) and manage each separately.
The f5-rest-orchestrator orchestrator extension manages various types of certificates on a F5 Big IP device (version 14 or later). TLS certificates, CA bundles, and the TLS certificate bound to the administrative website can all be managed with this integration within the scope described in the sections below. One important note, this integration DOES NOT manage high availability (HA) failover between primary and secondary nodes. If syncing between primary and secondary nodes is desired, this must either be handled within your F5 Big IP instance itself, or you can set up a Keyfactor Command certificate store for each node (primary and secondary) and manage each separately.

The F5 Universal Orchestrator extension implements 3 Certificate Store Types. Depending on your use case, you may elect to use one, or all of these Certificate Store Types. Descriptions of each are provided below.

Expand All @@ -47,9 +47,9 @@ The F5 Universal Orchestrator extension implements 3 Certificate Store Types. De
This integration is compatible with Keyfactor Universal Orchestrator version 10.1 and later.

## Support
The F5 Universal Orchestrator extension If you have a support issue, please open a support ticket by either contacting your Keyfactor representative or via the Keyfactor Support Portal at https://support.keyfactor.com.
The F5 Universal Orchestrator extension is supported by Keyfactor. If you require support for any issues or have feature request, please open a support ticket by either contacting your Keyfactor representative or 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.
> If you want to contribute bug fixes or additional enhancements, use the **[Pull requests](../../pulls)** tab.

## Requirements & Prerequisites

Expand Down Expand Up @@ -174,7 +174,7 @@ the Keyfactor Command Portal

| Name | Display Name | Description | Type | Default Value | Entry has a private key | Adding an entry | Removing an entry | Reenrolling an entry |
| ---- | ------------ | ---- | ------------- | ----------------------- | ---------------- | ----------------- | ------------------- | ----------- |
| SSLProfiles | SSL Profiles | One to many comma delimited F5 SSL Profile names the certificate is bound to | String | | 🔲 Unchecked | 🔲 Unchecked | 🔲 Unchecked | 🔲 Unchecked |
| SSLProfiles | SSL Profiles | One to many comma delimited F5 SSL Profiles to bind the certificate to (new certificates ONLY) | String | | 🔲 Unchecked | 🔲 Unchecked | 🔲 Unchecked | 🔲 Unchecked |

The Entry Parameters tab should look like this:

Expand Down
2 changes: 1 addition & 1 deletion SSLProfile/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override JobResult ProcessJob(InventoryJobConfiguration config, SubmitInv

try
{
base.ParseJobProperties();
base.ParseStoreProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory);

Expand Down
49 changes: 45 additions & 4 deletions SSLProfile/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Org.BouncyCastle.Security;
using System.Text;
using System.IO;
using Newtonsoft.Json;

namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.SSLProfile
{
Expand Down Expand Up @@ -48,7 +49,8 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
try
{
SetPAMSecrets(config.ServerUsername, config.ServerPassword, config.CertificateStoreDetails.StorePassword, logger);
base.ParseJobProperties();
string sslProfiles = JobConfig.JobProperties.ContainsKey("SSLProfiles") && JobConfig.JobProperties["SSLProfiles"] != null ? JobConfig.JobProperties["SSLProfiles"].ToString() : string.Empty;
base.ParseStoreProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory)
Expand All @@ -62,7 +64,9 @@ 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, StorePassword, RemoveChain);
bool certificateExists = PerformAddJob(f5, StorePassword, RemoveChain);
if (!certificateExists && !string.IsNullOrEmpty(sslProfiles))
BindCertificateToSSLProfiles(f5, config.JobCertificate.Alias, sslProfiles);
break;
case CertStoreOperationType.Remove:
LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'");
Expand All @@ -79,6 +83,11 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, "Job complete");
return new JobResult { Result = OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
}
catch (BindException ex)
{
LogHandlerCommon.Error(logger, config.CertificateStoreDetails, ExceptionHandler.FlattenExceptionMessages(ex, $"Warning performing SSL profile binding: "));
return new JobResult { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = config.JobHistoryId, FailureMessage = ExceptionHandler.FlattenExceptionMessages(ex, "Certificate successfully added, but one or more SSL profiles could not be bound. ") };
}
catch (Exception ex)
{
LogHandlerCommon.Error(logger, config.CertificateStoreDetails, ExceptionHandler.FlattenExceptionMessages(ex, $"Error performing Management {config.OperationType.ToString()}"));
Expand All @@ -90,15 +99,16 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
}
}

private void PerformAddJob(F5Client f5, string certificatePassword, bool removeChain)
private bool PerformAddJob(F5Client f5, string certificatePassword, bool removeChain)
{
LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformAddJob");
string name = JobConfig.JobCertificate.Alias;
string partition = f5.GetPartitionFromStorePath();

string certContents = !string.IsNullOrEmpty(JobConfig.JobCertificate.PrivateKeyPassword) && removeChain ? RemoveCertificateChainFromPfx() : JobConfig.JobCertificate.Contents;
bool certificateExists = f5.CertificateExists(partition, name);

if (f5.CertificateExists(partition, name))
if (certificateExists)
{
if (!JobConfig.Overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); }

Expand All @@ -111,6 +121,8 @@ private void PerformAddJob(F5Client f5, string certificatePassword, bool removeC
f5.AddEntry(partition, name, certContents, certificatePassword);
}
LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformAddJob");

return certificateExists;
}

private void PerformRemovalJob(F5Client f5)
Expand Down Expand Up @@ -171,5 +183,34 @@ private string RemoveCertificateChainFromPfx()

return rtnValue;
}

private void BindCertificateToSSLProfiles(F5Client f5, string alias, string sslProfiles)
{
bool hasError = false;
string errorMessages = string.Empty;

foreach (string sslProfile in sslProfiles.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
try
{
f5.BindCertificate(alias, sslProfile);
}
catch (Exception ex)
{
hasError = true;
errorMessages += ExceptionHandler.FlattenExceptionMessages(ex, $"Error binding {sslProfile}: ");
}
}

if (hasError)
{
throw new BindException(errorMessages);
}
}

public class BindException : Exception
{
public BindException(string message) : base(message) { }
}
}
}
2 changes: 1 addition & 1 deletion WebServer/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override JobResult ProcessJob(InventoryJobConfiguration config, SubmitInv
try
{
LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, "Processing job parameters");
base.ParseJobProperties();
base.ParseStoreProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory);
Expand Down
2 changes: 1 addition & 1 deletion WebServer/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
try
{
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
base.ParseJobProperties();
base.ParseStoreProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(JobConfig.CertificateStoreDetails, ServerUserName, ServerPassword, JobConfig.UseSSL, JobConfig.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, JobConfig.LastInventory)
Expand Down
2 changes: 1 addition & 1 deletion docsource/content.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Overview

The f5-rest-orchestrator orchestrator extension manages various types of certificates on a F5 Big IP device (version 15 or later). TLS certificates, CA bundles, and the TLS certificate bound to the administrative website can all be managed with this integration within the scope described in the sections below. One important note, this integration DOES NOT manage high availability (HA) failover between primary and secondary nodes. If syncing between primary and secondary nodes is desired, this must either be handled within your F5 Big IP instance itself, or you can set up a Keyfactor Command certificate store for each node (primary and secondary) and manage each separately.
The f5-rest-orchestrator orchestrator extension manages various types of certificates on a F5 Big IP device (version 14 or later). TLS certificates, CA bundles, and the TLS certificate bound to the administrative website can all be managed with this integration within the scope described in the sections below. One important note, this integration DOES NOT manage high availability (HA) failover between primary and secondary nodes. If syncing between primary and secondary nodes is desired, this must either be handled within your F5 Big IP instance itself, or you can set up a Keyfactor Command certificate store for each node (primary and secondary) and manage each separately.

## Requirements

Expand Down
Binary file modified docsource/images/F5-SL-REST-advanced-store-type-dialog.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 docsource/images/F5-SL-REST-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
"DependsOn": "",
"DefaultValue": "",
"Options": "",
"Description": "One to many comma delimited F5 SSL Profile names the certificate is bound to"
"Description": "One to many comma delimited F5 SSL Profiles to bind the certificate to (new certificates ONLY)"
}
]
},
Expand Down
Loading