Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Henderson committed Oct 23, 2023
2 parents cfd89a5 + 2ece1a4 commit a9ff2ea
Show file tree
Hide file tree
Showing 19 changed files with 421 additions and 30 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/keyfactor-merge-store-types.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Keyfactor Merge Cert Store Types
on: [workflow_dispatch]

jobs:
get-manifest-properties:
runs-on: windows-latest
outputs:
update_catalog: ${{ steps.read-json.outputs.update_catalog }}
integration_type: ${{ steps.read-json.outputs.integration_type }}
steps:
- uses: actions/checkout@v3
- name: Store json
id: read-json
shell: pwsh
run: |
$json = Get-Content integration-manifest.json | ConvertFrom-Json
$myvar = $json.update_catalog
echo "update_catalog=$myvar" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
$myvar = $json.integration_type
echo "integration_type=$myvar" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
call-update-store-types-workflow:
needs: get-manifest-properties
if: needs.get-manifest-properties.outputs.integration_type == 'orchestrator' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: Keyfactor/actions/.github/workflows/update-store-types.yml@main
secrets:
token: ${{ secrets.UPDATE_STORE_TYPES }}
2 changes: 1 addition & 1 deletion Bundle/Discovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDis
LogHandlerCommon.Debug(logger, certificateStore, "Getting partitions");
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);

F5Client f5 = new F5Client(certificateStore, ServerUserName, ServerPassword, config.UseSSL, string.Empty, true, new List<PreviousInventoryItem>());
F5Client f5 = new F5Client(certificateStore, ServerUserName, ServerPassword, config.UseSSL, string.Empty, true, false, new List<PreviousInventoryItem>());
List<string> partitions = f5.GetPartitions().Select(p => p.name).ToList();

LogHandlerCommon.Trace(logger, certificateStore, $"Found {partitions?.Count} partitions");
Expand Down
2 changes: 1 addition & 1 deletion Bundle/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
{
base.ParseJobProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, config.LastInventory) { F5Version = base.F5Version };
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory) { F5Version = base.F5Version };

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Getting inventory for CA Bundle '{config.CertificateStoreDetails.StorePath}'");
inventory = f5.GetCABundleInventory();
Expand Down
2 changes: 1 addition & 1 deletion Bundle/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
base.ParseJobProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, config.LastInventory)
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory)
{
PrimaryNode = base.PrimaryNode,
F5Version = base.F5Version
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
v1.4.4
v1.5.0
- Add new optional custom paramter - UseTokenAuth - to make token auth vs basic auth (default) a selectable option

v1.4.5
- Bug Fix: For F5-WS-REST store type, make sure certificate chain is ordered properly when installing to F5 - EE Cert => Issuing CA Cert => One-to-many Intermediate CA Certs => Root CA Cert.
- Bug Fix: Allow PEM formats with # comments at top of file during inventory

v1.4.3
Expand All @@ -22,3 +26,4 @@ v1.1

v1.0
- Initial Version

50 changes: 38 additions & 12 deletions F5Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System.Text.RegularExpressions;

using Newtonsoft.Json;
using System.Collections;

namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator
{
Expand All @@ -44,6 +45,7 @@ internal class F5Client
public string PrimaryNode { get; set; }
public string F5Version { get; set; }
public bool IgnoreSSLWarning { get; set; }
public bool UseTokenAuth { get; set; }
private RESTHandler REST { get; set; }
private F5Transaction Transaction { get; set; }

Expand All @@ -52,23 +54,26 @@ internal class F5Client

#region Constructors

public F5Client(CertificateStore certificateStore, string serverUserName, string serverPassword, bool useSSL, string pfxPassword, bool ignoreSSLWarning, IEnumerable<PreviousInventoryItem> inventory)
public F5Client(CertificateStore certificateStore, string serverUserName, string serverPassword, bool useSSL, string pfxPassword, bool ignoreSSLWarning, bool useTokenAuth, IEnumerable<PreviousInventoryItem> inventory)
{
CertificateStore = certificateStore;
ServerUserName = serverUserName;
ServerPassword = serverPassword;
UseSSL = useSSL;
PFXPassword = pfxPassword;
IgnoreSSLWarning = ignoreSSLWarning;
UseTokenAuth = useTokenAuth;
Inventory = inventory;

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

REST = new RESTHandler(certificateStore.ClientMachine, serverUserName, serverPassword, useSSL, IgnoreSSLWarning);
REST.Token = GetToken(serverUserName, serverPassword);

if (UseTokenAuth)
REST.Token = GetToken(serverUserName, serverPassword);
}

// Constructors
Expand Down Expand Up @@ -246,14 +251,14 @@ private void AddPfx(byte[] entryContents, string partition, string name, string
AddPfx(entryContents, partition, name, password, GetKeyName(ex.message));
else
throw (name.Contains(".crt", StringComparison.OrdinalIgnoreCase) &&
ex.Message.Contains("expected to exist", StringComparison.OrdinalIgnoreCase) ?
new Exception("Certificate and Key name may be different. If so, an F5 hotfix may be required to allow for the automatic renewal of this certificate.", ex) :
ex.Message.Contains("expected to exist", StringComparison.OrdinalIgnoreCase) ?
new Exception("Certificate and Key name may be different. If so, an F5 hotfix may be required to allow for the automatic renewal of this certificate.", ex) :
ex);
}

LogHandlerCommon.MethodExit(logger, CertificateStore, "AddPfx");
}

// Method to parse error message from /pkcs12 API call that can occur when the certificate and key have different names.
// There is an F5 hotfix needed to be installed to produce the specific error message parsed by this method to get the
// separate key name.
Expand Down Expand Up @@ -585,12 +590,9 @@ public void ReplaceWebServerCrt(string b64Certificate)

StringBuilder certPemBuilder = new StringBuilder();



//////// THE LIST MUST BE REVERSED SO THAT THE END-ENTITY CERT IS FIRST /////////
//////// CAN IT BE ASSUMED THE LAST ENTRY IS END-ENTIT? /////////////////////////
clist.Reverse();
/////////////////////////////////////////////////////////////////////////////////
//reordering of certificate chain necessary because of BouncyCastle bug. Being fixed in a later release
if (clist.Count > 1)
clist = ReorderPEMLIst(clist);

LogHandlerCommon.Trace(logger, CertificateStore, "Building certificate PEM");
foreach (X509Certificate2 cert in clist)
Expand Down Expand Up @@ -634,6 +636,30 @@ public void ReplaceWebServerCrt(string b64Certificate)
LogHandlerCommon.MethodExit(logger, CertificateStore, "ReplaceWebServerCrt");
}

// Put certificate chain in proper order - EE => issuing => intermediate1 => ... => intermediateN => root
private List<X509Certificate2> ReorderPEMLIst(List<X509Certificate2> certList)
{
List<X509Certificate2> rtnList = new List<X509Certificate2>();
X509Certificate2 root = certList.FirstOrDefault(p => p.IssuerName.RawData.SequenceEqual(p.SubjectName.RawData));
if (root == null || string.IsNullOrEmpty(root.SerialNumber))
throw new Exception("Invalid certificate chain. No root CA certificate found.");

rtnList.Add(root);

X509Certificate2 parentCert = root;
for (int i=1; i<certList.Count; i++)
{
X509Certificate2 childCert = certList.FirstOrDefault(p => p.IssuerName.RawData.SequenceEqual(parentCert.SubjectName.RawData) && !p.IssuerName.RawData.SequenceEqual(p.SubjectName.RawData));
if (root == null || string.IsNullOrEmpty(root.SerialNumber))
throw new Exception("Invalid certificate chain. End entity or issuing CA certificate not found.");

rtnList.Insert(0, childCert);
parentCert = childCert;
}

return rtnList;
}

// WebServer
#endregion

Expand Down
2 changes: 2 additions & 0 deletions InventoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public abstract class InventoryBase : F5JobBase, IInventoryJobExtension

protected string F5Version { get; set; }
protected bool IgnoreSSLWarning { get; set; }
protected bool UseTokenAuth { get; set; }

public string ExtensionName => string.Empty;

Expand All @@ -38,6 +39,7 @@ protected void ParseJobProperties()
LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"F5 version '{F5Version}'");

IgnoreSSLWarning = properties.IgnoreSSLWarning == null || string.IsNullOrEmpty(properties.IgnoreSSLWarning.Value) ? false : bool.Parse(properties.IgnoreSSLWarning.Value);
UseTokenAuth = properties.UseTokenAuth == null || string.IsNullOrEmpty(properties.UseTokenAuth.Value) ? false : bool.Parse(properties.UseTokenAuth.Value);
LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"Ignore SSL Warnings '{IgnoreSSLWarning.ToString()}'");
}
}
Expand Down
4 changes: 3 additions & 1 deletion ManagementBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public abstract class ManagementBase : F5JobBase, IManagementJobExtension
protected int _primaryNodeRetryCount = 0;
protected string F5Version { get; set; }
protected bool IgnoreSSLWarning { get; set; }
protected bool UseTokenAuth { get; set; }

public string ExtensionName => string.Empty;

Expand Down Expand Up @@ -82,6 +83,7 @@ protected void ParseJobProperties()
LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"F5 version '{F5Version}'");

IgnoreSSLWarning = properties.IgnoreSSLWarning == null || string.IsNullOrEmpty(properties.IgnoreSSLWarning.Value) ? false : bool.Parse(properties.IgnoreSSLWarning.Value);
UseTokenAuth = properties.UseTokenAuth == null || string.IsNullOrEmpty(properties.UseTokenAuth.Value) ? false : bool.Parse(properties.UseTokenAuth.Value);
LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"Ignore SSL Warnings '{IgnoreSSLWarning.ToString()}'");
}

Expand All @@ -91,7 +93,7 @@ protected void PrimaryNodeActive()

if (PrimaryNodeOnlineRequired)
{
F5Client f5 = new F5Client(JobConfig.CertificateStoreDetails, ServerUserName, ServerPassword, JobConfig.UseSSL, JobConfig.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, JobConfig.LastInventory)
F5Client f5 = new F5Client(JobConfig.CertificateStoreDetails, ServerUserName, ServerPassword, JobConfig.UseSSL, JobConfig.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, JobConfig.LastInventory)
{ PrimaryNode = this.PrimaryNode };
if (!f5.PrimaryNodeActive())
{
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@ 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.

###### 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.



---


Expand Down Expand Up @@ -171,7 +168,7 @@ The version number of a the F5 Orchestrator can be verified by right clicking on



The Custom Fields tab contains 6 custom store parameters. The set up is consistent across store types, and should look as follows:
The Custom Fields tab contains 10 custom store parameters (3 of which, Server Username, Server Password, and Use SSL were set up on the Basic tab and are not actually custom parameters you need or want to modify on this tab). The set up is consistent across store types, and should look as follows:

![](images/image3.png)<br>
![](images/image6.png)<br>
Expand All @@ -180,6 +177,7 @@ The Custom Fields tab contains 6 custom store parameters. The set up is consist
![](images/image4.png)<br>
![](images/image5.png)<br>
![](images/image15.png)<br>
![](images/image16.png)<br>

If any or all of the 3 certificate store types were already set up on installation of Keyfactor, you may only need to add Primary Node Online Required and Ignore SSL Warning. These parameters, however, are optional and only necessary if needed to be set to true. Please see the descriptions below in "2a. Create a F5 Certificate Store wihin Keyfactor Command.

Expand Down Expand Up @@ -216,6 +214,8 @@ If you choose to manually create a F5 store In Keyfactor Command rather than run

- **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

- **Inventory Schedule** – Set a schedule for running Inventory jobs or none, if you choose not to schedule Inventory at this time.
Expand Down
10 changes: 8 additions & 2 deletions RESTHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,14 @@ public void UploadFile(string filename, byte[] fileBytes)
webClient.Headers.Add("ServerHost", $"{GetProtocol()}{Host}/mgmt/shared/file-transfer/uploads/{filename}");
webClient.Headers.Add("Content-Type", "application/octet-stream");
webClient.Headers.Add("Content-Range", $"0-{fileBytes.Length - 1}/{fileBytes.Length}");
webClient.Headers.Add("X-F5-Auth-Token", Token);
//webClient.Headers.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.ASCII.GetBytes($"{User}:{Password}"))}");
if (Token == null)
{
webClient.Headers.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.ASCII.GetBytes($"{User}:{Password}"))}");
}
else
{
webClient.Headers.Add("X-F5-Auth-Token", Token);
}

webClient.UploadData($"{GetProtocol()}{Host}/mgmt/shared/file-transfer/uploads/{filename}", fileBytes);
}
Expand Down
2 changes: 1 addition & 1 deletion SSLProfile/Discovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDis

SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);

F5Client f5 = new F5Client(certificateStore, ServerUserName, ServerPassword, config.UseSSL, string.Empty, true, new List<PreviousInventoryItem>());
F5Client f5 = new F5Client(certificateStore, ServerUserName, ServerPassword, config.UseSSL, string.Empty, true, false, new List<PreviousInventoryItem>());
List<string> locations = f5.GetPartitions().Select(p => p.name).ToList();

LogHandlerCommon.Debug(logger, certificateStore, $"Submitting {locations?.Count} partitions");
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
{
base.ParseJobProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, config.LastInventory) { F5Version = base.F5Version };
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory) { F5Version = base.F5Version };

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Getting inventory from '{config.CertificateStoreDetails.StorePath}'");
inventory = f5.GetSSLProfiles(20);
Expand Down
2 changes: 1 addition & 1 deletion SSLProfile/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
base.ParseJobProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, config.LastInventory)
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory)
{
PrimaryNode = base.PrimaryNode,
F5Version = base.F5Version
Expand Down
2 changes: 1 addition & 1 deletion WebServer/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public override JobResult ProcessJob(InventoryJobConfiguration config, SubmitInv
base.ParseJobProperties();
SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, config.LastInventory);
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory);

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, "Getting the F5 web server device inventory");
inventory = f5.GetWebServerInventory();
Expand Down
2 changes: 1 addition & 1 deletion WebServer/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
base.ParseJobProperties();
base.PrimaryNodeActive();

F5Client f5 = new F5Client(JobConfig.CertificateStoreDetails, ServerUserName, ServerPassword, JobConfig.UseSSL, JobConfig.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, JobConfig.LastInventory)
F5Client f5 = new F5Client(JobConfig.CertificateStoreDetails, ServerUserName, ServerPassword, JobConfig.UseSSL, JobConfig.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, JobConfig.LastInventory)
{
PrimaryNode = base.PrimaryNode
};
Expand Down
Binary file added images/image16.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/image3.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 a9ff2ea

Please sign in to comment.