Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ab#64704 #52

Merged
merged 38 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
838151d
ab#64704
Oct 28, 2024
824ff77
ab#64704
Nov 1, 2024
c588053
ab#64704
Nov 1, 2024
bf3d797
ab#64704
Nov 4, 2024
709cae9
ab#64704
Nov 4, 2024
6214633
ab#64704
Nov 4, 2024
ce04d25
ab#64704
Nov 4, 2024
ef7f3a3
ab#64704
Nov 7, 2024
8e6db4a
ab#64704
Nov 7, 2024
cda4696
ab#64704
Nov 7, 2024
2819b47
ab#64704
Nov 7, 2024
d59d1ab
ab#64704
Nov 7, 2024
0d9641e
Update generated docs
Nov 7, 2024
6d2cf61
chore(images): Generate screenshots
m8rmclaren Nov 7, 2024
07717b9
Update generated docs
Nov 7, 2024
3f40029
ab#64704
Nov 7, 2024
7a76f60
ab#64704
Nov 7, 2024
c206e89
ab#64704
Nov 7, 2024
4db70e3
Update generated docs
Nov 7, 2024
d75498f
chore(images): Generate screenshots
m8rmclaren Nov 7, 2024
20b10d0
ab#64704
Nov 11, 2024
f57a5ce
Merge branch 'ab#64704' of https://github.com/Keyfactor/f5-rest-orche…
Nov 11, 2024
d88040c
Update generated docs
Nov 11, 2024
6fb4ef7
Merge branch 'ab#64704' of github.com:Keyfactor/f5-rest-orchestrator …
m8rmclaren Nov 11, 2024
7bb20f0
ab#64704
Nov 11, 2024
d2c6c55
Merge branch 'ab#64704' of https://github.com/Keyfactor/f5-rest-orche…
Nov 11, 2024
01add5a
ab#64704
Nov 11, 2024
c81f2fa
Update generated docs
Nov 11, 2024
d3bf7d4
ab#64704
Nov 11, 2024
08df475
ab#64704
Nov 11, 2024
61257c1
Update generated docs
Nov 11, 2024
3bbf873
Merge branch 'ab#64704' of github.com:Keyfactor/f5-rest-orchestrator …
m8rmclaren Nov 11, 2024
4c3d3da
chore(docs): Regenerate screenshots
m8rmclaren Nov 11, 2024
37d19dc
chore(docs): Regenerate screenshots
m8rmclaren Nov 11, 2024
9fc6616
ab#64704
Nov 12, 2024
7e88994
Merge branch 'ab#64704' of https://github.com/Keyfactor/f5-rest-orche…
Nov 12, 2024
1d59377
ab#64704
leefine02 Nov 25, 2024
c6d62ab
Update generated docs
Nov 25, 2024
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
5 changes: 3 additions & 2 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ on:

jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@v2
uses: keyfactor/actions/.github/workflows/starter.yml@3.1.2
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
scan_token: ${{ secrets.SAST_TOKEN }}
3 changes: 3 additions & 0 deletions Bundle/Discovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ 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, false, new List<PreviousInventoryItem>());

ValidateF5Release(logger, certificateStore, f5);

List<string> partitions = f5.GetPartitions().Select(p => p.name).ToList();

LogHandlerCommon.Trace(logger, certificateStore, $"Found {partitions?.Count} partitions");
Expand Down
7 changes: 6 additions & 1 deletion Bundle/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ 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, UseTokenAuth, config.LastInventory) { F5Version = base.F5Version };
F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory);

ValidateF5Release(logger, JobConfig.CertificateStoreDetails, f5);

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Getting inventory for CA Bundle '{config.CertificateStoreDetails.StorePath}'");
inventory = f5.GetCABundleInventory();

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Submitting {inventory?.Count} inventory entries for CA Bundle '{config.CertificateStoreDetails.StorePath}'");
submitInventory.Invoke(inventory);

if (UseTokenAuth)
f5.RemoveToken();

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, "Job complete");
return new JobResult { Result = OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
}
Expand Down
8 changes: 6 additions & 2 deletions Bundle/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)

F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory)
{
PrimaryNode = base.PrimaryNode,
F5Version = base.F5Version
PrimaryNode = base.PrimaryNode
};

ValidateF5Release(logger, JobConfig.CertificateStoreDetails, f5);

switch (config.OperationType)
{
case CertStoreOperationType.Add:
Expand All @@ -69,6 +70,9 @@ public override JobResult ProcessJob(ManagementJobConfiguration config)
throw new Exception($"Management job expecting 'Add' or 'Remove' job - received '{Enum.GetName(typeof(CertStoreOperationType), config.OperationType)}'");
}

if (UseTokenAuth)
f5.RemoveToken();

LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, "Job complete");
return new JobResult { Result = OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId};
}
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
v1.7.0
- Deprecate F5 Version Custom Field for all store types.
- Make Store Password a "PAM eligible" field on the orchestrator
- Remove session token at end of each job
- Convert documentation to use Doctool
- Create separate .net6 and .net8 builds on release

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.

Expand Down
2 changes: 1 addition & 1 deletion DiscoveryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public abstract class DiscoveryBase : F5JobBase, IDiscoveryJobExtension

protected DiscoveryJobConfiguration JobConfig { get; set; }

public string ExtensionName => string.Empty;
public string ExtensionName => "Keyfactor.Extensions.Orchestrator.F5Orchestrator.Discovery";

public abstract JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpdate submitDiscovery);
}
Expand Down
134 changes: 54 additions & 80 deletions F5Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Concurrent;
using System.Drawing.Printing;
using System.Diagnostics.CodeAnalysis;

namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator
{
Expand All @@ -34,6 +37,8 @@ internal class F5Client
private const string INVALID_KEY_SUBSTR = "key(";
private const string INVALID_KEY_BEG_DELIM = @"/";
private const string INVALID_KEY_END_DELIM = ")";
private const int MIN_VERSION_SUPPORTED = 14;
private const string VERSION_DELIMITER = "?ver=";

public CertificateStore CertificateStore { get; set; }
public string ServerUserName { get; set; }
Expand All @@ -43,7 +48,6 @@ internal class F5Client
public string PFXPassword { get; set; }
public IEnumerable<PreviousInventoryItem> Inventory { get; set; }
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; }
Expand Down Expand Up @@ -141,26 +145,23 @@ public void RemoveEntry(string partition, string name)
ArchiveFile($"/config/filestore/files_d/{partition}_d/certificate_key_d/:{partition}:{name}_*", $"{partition}-{name}-{timestamp}.key");
LogHandlerCommon.Trace(logger, CertificateStore, $"Removing certificate and key at '{partition}' and name '{name}'");

string keyName = GetKeyName(name, true);
REST.Delete($"/mgmt/tm/sys/file/ssl-key/~{partition}~{keyName}");
REST.Delete($"/mgmt/tm/sys/file/ssl-key/~{partition}~{name}");
}
LogHandlerCommon.Trace(logger, CertificateStore, $"Archiving certificate at '{partition}' and name '{name}'");
ArchiveFile($"/config/filestore/files_d/{partition}_d/certificate_d/:{partition}:{name}_*", $"{partition}-{name}-{timestamp}.crt");
LogHandlerCommon.Trace(logger, CertificateStore, $"Removing certificate at '{partition}' and name '{name}'");

string crtName = GetCrtName(name, true);
REST.Delete($"/mgmt/tm/sys/file/ssl-cert/~{partition}~{crtName}");
REST.Delete($"/mgmt/tm/sys/file/ssl-cert/~{partition}~{name}");
LogHandlerCommon.MethodExit(logger, CertificateStore, "RemoveEntry");
}

public bool KeyExists(string partition, string name)
public bool KeyExists(string partition, string keyName)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "KeyExists");
bool exists = false;

try
{
string keyName = GetKeyName(name, true);
string query = $"/mgmt/tm/sys/file/ssl-key/~{partition}~{keyName}";
F5Key key = REST.Get<F5Key>(query);
exists = (key != null);
Expand All @@ -178,14 +179,13 @@ public bool KeyExists(string partition, string name)
return exists;
}

public bool CertificateExists(string partition, string name)
public bool CertificateExists(string partition, string crtName)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "CertificateExists");
bool exists = false;

try
{
string crtName = GetCrtName(name, true);
string query = $"/mgmt/tm/sys/file/ssl-cert/~{partition}~{crtName}";
F5SSLProfile certificate = REST.Get<F5SSLProfile>(query);
exists = (certificate != null);
Expand Down Expand Up @@ -406,12 +406,12 @@ private void SetItemStatus(CurrentInventoryItem agentInventoryItem)
LogHandlerCommon.MethodExit(logger, CertificateStore, "SetItemStatus");
}

private CurrentInventoryItem GetInventoryItem(string partition, string name, bool hasPrivateKey)
private CurrentInventoryItem GetInventoryItem(string partition, string crtName, bool hasPrivateKey)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetInventoryItem");

// Get the pfx/certificate contents from the filesystem (using a wildcard as the files have slightly randomized name suffixes)
X509Certificate2Collection certificateCollection = GetCertificateEntry($"/config/filestore/files_d/{partition}_d/certificate_d/:{partition}:{name}_*");
X509Certificate2Collection certificateCollection = GetCertificateEntry($"/config/filestore/files_d/{partition}_d/certificate_d/:{partition}:{crtName}_*");
List<string> certContents = new List<string>();
bool useChainLevel = certificateCollection.Count > 1;
foreach (X509Certificate2 certificate in certificateCollection)
Expand All @@ -420,7 +420,6 @@ private CurrentInventoryItem GetInventoryItem(string partition, string name, boo
//LogHandlerCommon.Debug(logger, CertificateStore, $"ALIAS: {name}: {Convert.ToBase64String(certificate.Export(X509ContentType.Cert))}");
}

string crtName = GetCrtName(name, false);
CurrentInventoryItem inventoryItem = new CurrentInventoryItem
{
ItemStatus = OrchestratorInventoryItemStatus.Unknown,
Expand All @@ -434,61 +433,6 @@ private CurrentInventoryItem GetInventoryItem(string partition, string name, boo
return inventoryItem;
}

private string GetCrtName(string name, bool addExtension)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetCrtName");
string crtName = name;

switch (F5Version.ToLowerInvariant())
{
case "v12":
throw new Exception($"F5 Version 12 is not supported by the REST-based orchestrator. The legacy SOAP-based orchestrator should be used.");
case "v13":
if (addExtension)
{
// The .crt extension must be added
if (!crtName.EndsWith(".crt", StringComparison.OrdinalIgnoreCase)) { crtName = $"{crtName}.crt"; }
}
else
{
// The .crt extension must be removed
if (crtName.EndsWith(".crt", StringComparison.OrdinalIgnoreCase)) { crtName = crtName.Substring(0, crtName.Length - 4); }
}
break;
};

LogHandlerCommon.MethodExit(logger, CertificateStore, "GetCrtName");
return crtName;
}

private string GetKeyName(string name, bool addExtension)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetKeyName");
string keyName = name;

// No longer checking past version 14 for future-proofing
switch (F5Version.ToLowerInvariant())
{
case "v12":
throw new Exception($"F5 Version 12 is not supported by the REST-based orchestrator. The legacy SOAP-based orchestrator should be used.");
case "v13":
if (addExtension)
{
// The .key extension must be added
if (!keyName.EndsWith(".key", StringComparison.OrdinalIgnoreCase)) { keyName = $"{keyName}.key"; }
}
else
{
// The .key extension must be removed
if (keyName.EndsWith(".key", StringComparison.OrdinalIgnoreCase)) { keyName = keyName.Substring(0, keyName.Length - 4); }
}
break;
};

LogHandlerCommon.MethodExit(logger, CertificateStore, "GetKeyName");
return keyName;
}

// Certificate PFX Shared
#endregion

Expand Down Expand Up @@ -728,7 +672,7 @@ public List<CurrentInventoryItem> GetSSLProfiles(int pageSize)
// SSL Profiles
#endregion

#region Auth
#region Auth & Version

private string GetToken(string userName, string userPassword)
{
Expand All @@ -739,6 +683,39 @@ private string GetToken(string userName, string userPassword)

return loginResponse.token.token;
}

internal void RemoveToken()
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "RemoveToken");
REST.Delete($"/mgmt/shared/authz/tokens/{REST.Token}");
LogHandlerCommon.MethodExit(logger, CertificateStore, "RemoveToken");
}

internal void ValidateF5Version()
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "IsVersionSupported");

string query = $"/mgmt/tm/sys/version";
F5Version f5Version = REST.Get<F5Version>(query);
LogHandlerCommon.Debug(logger, CertificateStore, $"Version supported self link: {f5Version.selfLink}");
if (!f5Version.selfLink.Contains(VERSION_DELIMITER))
return;

string selfLink = f5Version.selfLink;
string strVersion = selfLink.Substring(selfLink.IndexOf(VERSION_DELIMITER, StringComparison.CurrentCultureIgnoreCase) + VERSION_DELIMITER.Length, 2);
int version;
if (!int.TryParse(strVersion, out version))
return;

LogHandlerCommon.MethodExit(logger, CertificateStore, "IsVersionSupported");

if (version < MIN_VERSION_SUPPORTED)
{
string errMesage = $"F5 version {version.ToString()} not supported by this version of the F5 Orchestrator Extension. This orchestrator extension only supports verion {MIN_VERSION_SUPPORTED.ToString()} and later.";
logger.LogError(errMesage);
throw new Exception(errMesage);
}
}
#endregion

#region Bundles
Expand Down Expand Up @@ -822,8 +799,7 @@ public bool EntryExistsInBundle(string alias)
List<string> bundleIncludes = new List<string>(GetCABundleIncludes());
string partition = GetPartitionFromStorePath();

string crtName = GetCrtName(alias, true);
exists = bundleIncludes.Any<string>(i => i.Equals($"/{partition}/{crtName}", StringComparison.OrdinalIgnoreCase));
exists = bundleIncludes.Any<string>(i => i.Equals($"/{partition}/{alias}", StringComparison.OrdinalIgnoreCase));

LogHandlerCommon.MethodExit(logger, CertificateStore, "EntryExistsInBundle");
return exists;
Expand Down Expand Up @@ -855,26 +831,25 @@ private string[] GetCABundleIncludes()
return includeBundle;
}

public void AddBundleEntry(string bundle, string partition, string name, string b64Certificate, string alias, bool overwrite)
public void AddBundleEntry(string bundle, string partition, string crtName, string b64Certificate, string alias, bool overwrite)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "AddBundleEntry");

// Add the entry to inventory
if (!CertificateExists(partition, name))
if (!CertificateExists(partition, crtName))
{
LogHandlerCommon.Debug(logger, CertificateStore, $"Add entry '{name}' in '{CertificateStore.StorePath}'");
AddEntry(partition, name, b64Certificate, null);
LogHandlerCommon.Debug(logger, CertificateStore, $"Add entry '{crtName}' in '{CertificateStore.StorePath}'");
AddEntry(partition, crtName, b64Certificate, null);
}
else
{
if (!overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); }
if (!overwrite) { throw new Exception($"An entry named '{crtName}' exists and 'overwrite' was not selected"); }

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

// Add the entry to the bundle
string crtName = GetCrtName(name, true);
string crt = $"/{partition}/{crtName}";
List<string> bundleIncludes = new List<string>(GetCABundleIncludes());
if (!bundleIncludes.Contains(crt))
Expand All @@ -886,11 +861,10 @@ public void AddBundleEntry(string bundle, string partition, string name, string
LogHandlerCommon.MethodExit(logger, CertificateStore, "AddBundleEntry");
}

public void RemoveBundleEntry(string bundle, string partition, string name)
public void RemoveBundleEntry(string bundle, string partition, string crtName)
{
LogHandlerCommon.MethodEntry(logger, CertificateStore, "RemoveBundleEntry");

string crtName = GetCrtName(name, true);
string crtEntry = $"/{partition}/{crtName}";

LogHandlerCommon.Trace(logger, CertificateStore, $"Preparing to remove bundle entry '{crtEntry}'");
Expand Down
5 changes: 5 additions & 0 deletions F5DataModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ public class F5LoginToken
public string token { get; set; }
}

public class F5Version
{
public string selfLink { get; set; }
}

// F5 data models
#endregion
}
Loading
Loading