From f9a5be3dfd6374677d4b1b801f516563d5c6d91b Mon Sep 17 00:00:00 2001 From: leefine02 Date: Mon, 3 Aug 2026 09:28:09 -0400 Subject: [PATCH 01/26] ab93116 --- docsource/f5-ca-rest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsource/f5-ca-rest.md b/docsource/f5-ca-rest.md index 1197eb2..e643486 100644 --- a/docsource/f5-ca-rest.md +++ b/docsource/f5-ca-rest.md @@ -1,3 +1,3 @@ ## Overview -The F5-CA-REST certificate store type manages F5 Big IP CA certificate bundles. Only custom CA bundles are supported by this integration. The default bundle "ca-bundle" under the "Common" partition is **not** supported, as F5's REST API endpoints will not return certificates from this bundle. \ No newline at end of file +TThe F5-CA-REST certificate store type manages F5 Big IP CA certificate bundles. Only custom CA bundles are supported by this integration. The default bundle "ca-bundle" under the "Common" partition is **not** supported, as F5's REST API endpoints will not return certificates from this bundle. \ No newline at end of file From 10c8663b047d2998077b4fa018cd5a9bf0095751 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Mon, 3 Aug 2026 09:28:48 -0400 Subject: [PATCH 02/26] ab93116 --- docsource/f5-ca-rest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsource/f5-ca-rest.md b/docsource/f5-ca-rest.md index e643486..1197eb2 100644 --- a/docsource/f5-ca-rest.md +++ b/docsource/f5-ca-rest.md @@ -1,3 +1,3 @@ ## Overview -TThe F5-CA-REST certificate store type manages F5 Big IP CA certificate bundles. Only custom CA bundles are supported by this integration. The default bundle "ca-bundle" under the "Common" partition is **not** supported, as F5's REST API endpoints will not return certificates from this bundle. \ No newline at end of file +The F5-CA-REST certificate store type manages F5 Big IP CA certificate bundles. Only custom CA bundles are supported by this integration. The default bundle "ca-bundle" under the "Common" partition is **not** supported, as F5's REST API endpoints will not return certificates from this bundle. \ No newline at end of file From 199c2b0560bd3785cf16163b0181216397bfc46d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Aug 2026 13:29:28 +0000 Subject: [PATCH 03/26] docs: auto-generate README and documentation [skip ci] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb45754..e590d55 100644 --- a/README.md +++ b/README.md @@ -617,8 +617,8 @@ the Keyfactor Command Portal | Universal Orchestrator Version | Latest .NET version installed on the Universal Orchestrator server | `rollForward` condition in `Orchestrator.runtimeconfig.json` | `f5-rest-orchestrator` .NET version to download | | --------- | ----------- | ----------- | ----------- | | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` | - | Between `11.6.0` and `24.x` | `net8.0` | | `net8.0` | - | `25.0` _and_ newer | `net10.0` | | `net10.0` | + | `11.6` _and_ newer | `net8.0` | | `net8.0` | + | `25.5` _and_ newer | `net10.0` | | `net10.0` | Unzip the archive containing extension assemblies to a known location. From 5f4f1e89a7e5eb5dded56ff9b750a6928e0339f7 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Tue, 4 Aug 2026 14:29:50 -0400 Subject: [PATCH 04/26] ab93116 --- F5Client.cs | 177 +++++++++++++++++++++++++++- F5DataModels.cs | 22 ++++ Profile/Discovery.cs | 97 ++++++++++++++++ Profile/Inventory.cs | 76 ++++++++++++ Profile/Management.cs | 237 ++++++++++++++++++++++++++++++++++++++ integration-manifest.json | 87 ++++++++++++++ manifest.json | 12 ++ 7 files changed, 706 insertions(+), 2 deletions(-) create mode 100644 Profile/Discovery.cs create mode 100644 Profile/Inventory.cs create mode 100644 Profile/Management.cs diff --git a/F5Client.cs b/F5Client.cs index dcbcbb0..9b418bd 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -42,6 +42,7 @@ internal class F5Client private const string INVALID_KEY_END_DELIM = ")"; private const int MIN_VERSION_SUPPORTED = 14; private const string VERSION_DELIMITER = "?ver="; + private const int DEFAULT_PROFILE_PAGE_SIZE = 50; public CertificateStore CertificateStore { get; set; } public string ServerUserName { get; set; } @@ -371,10 +372,20 @@ private X509Certificate2Collection GetCertificateEntry(string path) } public List GetSSLProfiles(int pageSize) + { + return GetSSLProfiles(pageSize, "client-ssl"); + } + + public List GetSSLProfiles(int pageSize, string profileEndpoint) + { + return GetSSLProfiles(pageSize, profileEndpoint, null); + } + + public List GetSSLProfiles(int pageSize, string profileEndpoint, string partition) { LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetSSLProfiles"); - string partition = CertificateStore.StorePath; - string query = $"/mgmt/tm/ltm/profile/client-ssl?$top={pageSize}&$skip=0"; + string partitionFilter = string.IsNullOrEmpty(partition) ? string.Empty : $"&$filter=partition+eq+{partition}"; + string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}?$top={pageSize}&$skip=0{partitionFilter}"; F5PagedSSLProfiles pagedProfiles = REST.Get(query); List profiles = new List(); @@ -541,6 +552,28 @@ public string GetPartitionFromStorePath() return pathParts[0]; } + // Parses a Profile store path in the form 'Partition\ProfileName\ProfileType[\InheritedProfile]' + public F5ProfileStorePath ParseProfileStorePath() + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "ParseProfileStorePath"); + string[] pathParts = CertificateStore.StorePath.Split('\\'); + if (pathParts.Length < 3 || pathParts.Length > 4) + { + throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); + } + + F5ProfileStorePath profileStorePath = new F5ProfileStorePath + { + Partition = pathParts[0], + ProfileName = pathParts[1], + ProfileType = pathParts[2], + InheritedProfile = pathParts.Length == 4 ? pathParts[3] : string.Empty + }; + + LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); + return profileStorePath; + } + // Infrastructure #endregion @@ -733,6 +766,146 @@ public List GetCertificateEntries(int pageSize) // SSL Certificates #endregion + #region SSL Profiles (Client/Server) + + private const string CLIENT_SSL_ENDPOINT = "client-ssl"; + private const string SERVER_SSL_ENDPOINT = "server-ssl"; + + public static string GetProfileEndpoint(string profileType) + { + return profileType.Equals("Server", StringComparison.OrdinalIgnoreCase) ? SERVER_SSL_ENDPOINT : CLIENT_SSL_ENDPOINT; + } + + public bool ProfileExists(string partition, string profileEndpoint, string profileName) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "ProfileExists"); + bool exists = false; + + try + { + string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}"; + F5SSLProfile profile = REST.Get(query); + exists = (profile != null); + } + catch (F5RESTException rex) + { + // A 404 will be returned if the profile is not found + if (rex.code != 404) + { + throw; + } + } + + LogHandlerCommon.MethodExit(logger, CertificateStore, "ProfileExists"); + return exists; + } + + public void CreateProfile(string partition, string profileEndpoint, string profileName, string inheritedProfile) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "CreateProfile"); + + string defaultsFrom = null; + if (!string.IsNullOrEmpty(inheritedProfile) && ProfileExists(partition, profileEndpoint, inheritedProfile)) + { + defaultsFrom = $"/{partition}/{inheritedProfile}"; + } + + F5ProfileCreate profile = new F5ProfileCreate + { + name = profileName, + partition = partition, + defaultsFrom = defaultsFrom + }; + + REST.Post($"/mgmt/tm/ltm/profile/{profileEndpoint}", JsonConvert.SerializeObject(profile)); + + LogHandlerCommon.MethodExit(logger, CertificateStore, "CreateProfile"); + } + + // Returns the certificate name (alias) currently bound to the profile represented by this store, or null if none bound + public string GetBoundCertificateAlias(string partition, string profileEndpoint, string profileName) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetBoundCertificateAlias"); + + string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}"; + F5SSLProfile profile = REST.Get(query); + string alias = null; + if (!string.IsNullOrEmpty(profile?.cert)) + { + string[] certParts = profile.cert.Split('/'); + alias = certParts[certParts.Length - 1]; + } + + LogHandlerCommon.MethodExit(logger, CertificateStore, "GetBoundCertificateAlias"); + return alias; + } + + // Returns the names (partition/profile) of every client-ssl and server-ssl profile bound to the given certificate alias, + // excluding the profile represented by this store definition (partition/excludeProfileName) + public List GetProfilesBoundToCertificate(string partition, string alias, string excludeProfileName) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetProfilesBoundToCertificate"); + + string certName = $"/{partition}/{alias}"; + List boundProfiles = new List(); + + foreach (string profileEndpoint in new[] { CLIENT_SSL_ENDPOINT, SERVER_SSL_ENDPOINT }) + { + List profiles = GetSSLProfiles(DEFAULT_PROFILE_PAGE_SIZE, profileEndpoint); + boundProfiles.AddRange(profiles + .Where(p => p.cert == certName && !(p.name.Equals(excludeProfileName, StringComparison.OrdinalIgnoreCase))) + .Select(p => p.name)); + } + + LogHandlerCommon.MethodExit(logger, CertificateStore, "GetProfilesBoundToCertificate"); + return boundProfiles; + } + + // Reset the profile's cert/key/chain binding back to F5's built-in default, effectively unbinding any custom certificate + public void UnbindCertificate(string partition, string profileEndpoint, string profileName) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "UnbindCertificate"); + + F5Binding binding = new F5Binding { cert = "/Common/default.crt", key = "/Common/default.key", chain = "none" }; + REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); + + LogHandlerCommon.MethodExit(logger, CertificateStore, "UnbindCertificate"); + } + + // Bind a certificate/key (and matching chain) already installed in the given partition to the named profile + public void BindCertificateToProfile(string partition, string profileEndpoint, string profileName, string alias) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificateToProfile"); + + F5Binding binding = new F5Binding { cert = alias, key = alias, chain = alias }; + REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); + + LogHandlerCommon.MethodExit(logger, CertificateStore, "BindCertificateToProfile"); + } + + // Returns the inventory (single certificate) bound to the profile represented by this store definition + public List GetProfileCertificateInventory(string partition, string profileEndpoint, string profileName) + { + LogHandlerCommon.MethodEntry(logger, CertificateStore, "GetProfileCertificateInventory"); + List inventory = new List(); + + string alias = GetBoundCertificateAlias(partition, profileEndpoint, profileName); + if (string.IsNullOrEmpty(alias) || alias.Equals("default.crt", StringComparison.OrdinalIgnoreCase)) + { + LogHandlerCommon.Trace(logger, CertificateStore, $"Profile '{profileName}' in partition '{partition}' has no certificate bound"); + LogHandlerCommon.MethodExit(logger, CertificateStore, "GetProfileCertificateInventory"); + return inventory; + } + + CurrentInventoryItem inventoryItem = GetInventoryItem(partition, alias, true); + LogHandlerCommon.MethodExit(logger, CertificateStore, "GetProfileCertificateInventory"); + inventory.Add(inventoryItem); + return inventory; + } + + // SSL Profiles (Client/Server) + #endregion + #region Auth & Version private string GetToken(string userName, string userPassword) diff --git a/F5DataModels.cs b/F5DataModels.cs index 25887b0..9982437 100644 --- a/F5DataModels.cs +++ b/F5DataModels.cs @@ -82,7 +82,12 @@ internal class F5PagedSSLProfiles : F5PagedResult internal class F5SSLProfile { public string name { get; set; } + public string partition { get; set; } + public string fullPath { get; set; } public string cert { get; set; } + + [Newtonsoft.Json.JsonProperty("defaultsFrom")] + public string defaultsFrom { get; set; } } internal class F5Key @@ -143,6 +148,15 @@ internal class F5Binding public string chain { get; set; } } + internal class F5ProfileCreate + { + public string name { get; set; } + public string partition { get; set; } + + [Newtonsoft.Json.JsonProperty("defaultsFrom", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string defaultsFrom { get; set; } + } + public class F5Transaction { public string transid { get; set; } @@ -180,6 +194,14 @@ public class F5Version public string selfLink { get; set; } } + internal class F5ProfileStorePath + { + public string Partition { get; set; } + public string ProfileName { get; set; } + public string ProfileType { get; set; } + public string InheritedProfile { get; set; } + } + public class SyncRequest { public SyncRequest(string deviceGroupName) diff --git a/Profile/Discovery.cs b/Profile/Discovery.cs new file mode 100644 index 0000000..2565d19 --- /dev/null +++ b/Profile/Discovery.cs @@ -0,0 +1,97 @@ +// Copyright 2023 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using Keyfactor.Logging; +using Keyfactor.Orchestrators.Extensions; +using Keyfactor.Orchestrators.Common.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using Keyfactor.Orchestrators.Extensions.Interfaces; + +namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile +{ + public class Discovery : DiscoveryBase + { + private const int DEFAULT_PROFILE_PAGE_SIZE = 50; + private const string CLIENT_SSL_ENDPOINT = "client-ssl"; + private const string SERVER_SSL_ENDPOINT = "server-ssl"; + + public Discovery(IPAMSecretResolver resolver) + { + _resolver = resolver; + } + + public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpdate sdr) + { + if (logger == null) + { + logger = LogHandler.GetClassLogger(this.GetType()); + } + + CertificateStore certificateStore = new CertificateStore() { ClientMachine = config.ClientMachine }; + LogHandlerCommon.MethodEntry(logger, certificateStore, "ProcessJob"); + + try + { + LogHandlerCommon.Debug(logger, certificateStore, "Getting partitions"); + + SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger); + + F5Client f5 = new F5Client(certificateStore, ServerUserName, ServerPassword, config.UseSSL, string.Empty, true, false, new List()); + + ValidateF5Release(logger, certificateStore, f5); + + List partitions = f5.GetPartitions().Select(p => p.name).ToList(); + + LogHandlerCommon.Trace(logger, certificateStore, $"Found {partitions?.Count} partitions"); + List locations = new List(); + foreach (string partition in partitions) + { + foreach (string profileType in new[] { "Client", "Server" }) + { + string profileEndpoint = profileType.Equals("Server", StringComparison.OrdinalIgnoreCase) ? SERVER_SSL_ENDPOINT : CLIENT_SSL_ENDPOINT; + LogHandlerCommon.Trace(logger, certificateStore, $"Getting {profileType} SSL profiles for partition '{partition}'"); + List profiles = f5.GetSSLProfiles(DEFAULT_PROFILE_PAGE_SIZE, profileEndpoint, partition); + + foreach (F5SSLProfile profile in profiles) + { + string inheritedProfile = string.Empty; + if (!string.IsNullOrEmpty(profile.defaultsFrom)) + { + string[] inheritedParts = profile.defaultsFrom.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + inheritedProfile = inheritedParts[inheritedParts.Length - 1]; + } + + string location = string.IsNullOrEmpty(inheritedProfile) + ? $"{partition}\\{profile.name}\\{profileType}" + : $"{partition}\\{profile.name}\\{profileType}\\{inheritedProfile}"; + locations.Add(location); + } + } + } + + LogHandlerCommon.Debug(logger, certificateStore, $"Submitting {locations.Count} locations"); + sdr.Invoke(locations); + + LogHandlerCommon.Debug(logger, certificateStore, "Job complete"); + return new JobResult { Result = OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId }; + } + catch (Exception ex) + { + LogHandlerCommon.Error(logger, certificateStore, ExceptionHandler.FlattenExceptionMessages(ex, $"Error performing Discovery.")); + return new JobResult { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = ExceptionHandler.FlattenExceptionMessages(ex, "Unable to complete the discovery operation.") }; + } + finally + { + LogHandlerCommon.MethodExit(logger, certificateStore, "ProcessJob"); + } + } + } +} diff --git a/Profile/Inventory.cs b/Profile/Inventory.cs new file mode 100644 index 0000000..995b2aa --- /dev/null +++ b/Profile/Inventory.cs @@ -0,0 +1,76 @@ +// Copyright 2023 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using Keyfactor.Logging; +using Keyfactor.Orchestrators.Extensions; +using Keyfactor.Orchestrators.Common.Enums; +using System; +using System.Collections.Generic; +using Keyfactor.Orchestrators.Extensions.Interfaces; + +namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile +{ + public class Inventory : InventoryBase + { + public Inventory(IPAMSecretResolver resolver) + { + _resolver = resolver; + } + + public override JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpdate submitInventory) + { + if (logger == null) + { + logger = LogHandler.GetClassLogger(this.GetType()); + } + LogHandlerCommon.MethodEntry(logger, config.CertificateStoreDetails, "ProcessJob"); + + // Save the job config for use instead of passing it around + base.JobConfig = config; + + List inventory = new List(); + + try + { + base.ParseStoreProperties(); + + SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger); + F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, null, IgnoreSSLWarning, UseTokenAuth, config.LastInventory); + + ValidateF5Release(logger, JobConfig.CertificateStoreDetails, f5); + + F5ProfileStorePath profileStorePath = f5.ParseProfileStorePath(); + string partition = profileStorePath.Partition; + string profileName = profileStorePath.ProfileName; + string profileEndpoint = F5Client.GetProfileEndpoint(profileStorePath.ProfileType); + + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Getting inventory for profile '{profileName}' in '{config.CertificateStoreDetails.StorePath}'"); + inventory = f5.GetProfileCertificateInventory(partition, profileEndpoint, profileName); + + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Submitting {inventory?.Count} inventory entries for '{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 }; + } + catch (Exception ex) + { + LogHandlerCommon.Error(logger, config.CertificateStoreDetails, ExceptionHandler.FlattenExceptionMessages(ex, $"Error performing Inventory.")); + return new JobResult { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = ExceptionHandler.FlattenExceptionMessages(ex, "Unable to complete the inventory operation.") }; + } + finally + { + LogHandlerCommon.MethodExit(logger, config.CertificateStoreDetails, "ProcessJob"); + } + } + } +} diff --git a/Profile/Management.cs b/Profile/Management.cs new file mode 100644 index 0000000..5e78d57 --- /dev/null +++ b/Profile/Management.cs @@ -0,0 +1,237 @@ +// Copyright 2023 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using Keyfactor.Logging; +using Keyfactor.Orchestrators.Extensions; +using Keyfactor.Orchestrators.Common.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using Keyfactor.Orchestrators.Extensions.Interfaces; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; +using System.IO; + +namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile +{ + public class Management : ManagementBase + { + protected string ProfileName { get; set; } + protected string ProfileType { get; set; } + protected string ProfileEndpoint { get; set; } + protected string InheritedProfile { get; set; } + + public Management(IPAMSecretResolver resolver) + { + _resolver = resolver; + } + + public override JobResult ProcessJob(ManagementJobConfiguration config) + { + if (logger == null) + { + logger = LogHandler.GetClassLogger(this.GetType()); + } + + LogHandlerCommon.MethodEntry(logger, config.CertificateStoreDetails, "ProcessJob"); + + if (config.OperationType != CertStoreOperationType.Add + && config.OperationType != CertStoreOperationType.Remove + && config.OperationType != CertStoreOperationType.Create) + { + throw new Exception($"'{config.CertificateStoreDetails.ClientMachine}-{config.CertificateStoreDetails.StorePath}-' Management job expecting 'Add', 'Remove' or 'Create' job - received '{Enum.GetName(typeof(CertStoreOperationType), config.OperationType)}'"); + } + + // Save the job config for use instead of passing it around + base.JobConfig = config; + + try + { + SetPAMSecrets(config.ServerUsername, config.ServerPassword, config.CertificateStoreDetails.StorePassword, logger); + base.ParseStoreProperties(); + + F5Client f5 = new F5Client(config.CertificateStoreDetails, ServerUserName, ServerPassword, config.UseSSL, config.JobCertificate?.PrivateKeyPassword, IgnoreSSLWarning, UseTokenAuth, config.LastInventory); + + ValidateF5Release(logger, JobConfig.CertificateStoreDetails, f5); + + F5ProfileStorePath profileStorePath = f5.ParseProfileStorePath(); + string partition = profileStorePath.Partition; + ProfileName = profileStorePath.ProfileName; + ProfileType = profileStorePath.ProfileType; + ProfileEndpoint = F5Client.GetProfileEndpoint(ProfileType); + InheritedProfile = profileStorePath.InheritedProfile; + JobResult warningResult = null; + + switch (config.OperationType) + { + case CertStoreOperationType.Create: + LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Create profile '{ProfileName}' in '{config.CertificateStoreDetails.StorePath}'"); + warningResult = PerformCreateJob(f5, partition); + break; + case CertStoreOperationType.Add: + LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Add entry '{config.JobCertificate.Alias}' to '{config.CertificateStoreDetails.StorePath}'"); + PerformAddJob(f5, partition, StorePassword, RemoveChain); + break; + case CertStoreOperationType.Remove: + LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'"); + warningResult = PerformRemovalJob(f5, partition); + break; + default: + // Shouldn't get here, but just in case + throw new Exception($"Management job expecting 'Add', 'Remove' or 'Create' job - received '{Enum.GetName(typeof(CertStoreOperationType), config.OperationType)}'"); + } + + if (UseTokenAuth) + f5.RemoveToken(); + + if (warningResult != null) + { + return warningResult; + } + + LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, "Job complete"); + return new JobResult { Result = OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId }; + } + catch (Exception ex) + { + LogHandlerCommon.Error(logger, config.CertificateStoreDetails, ExceptionHandler.FlattenExceptionMessages(ex, $"Error performing Management {config.OperationType.ToString()}")); + return new JobResult { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = ExceptionHandler.FlattenExceptionMessages(ex, "Unable to complete the management operation.") }; + } + finally + { + LogHandlerCommon.MethodExit(logger, config.CertificateStoreDetails, "ProcessJob"); + } + } + + private JobResult PerformCreateJob(F5Client f5, string partition) + { + LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformCreateJob"); + + if (f5.ProfileExists(partition, ProfileEndpoint, ProfileName)) + { + string message = $"A profile named '{ProfileName}' already exists in partition '{partition}' - no action was taken."; + LogHandlerCommon.Info(logger, JobConfig.CertificateStoreDetails, message); + LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformCreateJob"); + return new JobResult { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = JobConfig.JobHistoryId, FailureMessage = message }; + } + + f5.CreateProfile(partition, ProfileEndpoint, ProfileName, InheritedProfile); + + LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformCreateJob"); + return null; + } + + private void PerformAddJob(F5Client f5, string partition, string certificatePassword, bool removeChain) + { + LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); + string name = JobConfig.JobCertificate.Alias; + + string certContents = !string.IsNullOrEmpty(JobConfig.JobCertificate.PrivateKeyPassword) && removeChain ? RemoveCertificateChainFromPfx() : JobConfig.JobCertificate.Contents; + bool certificateExists = f5.CertificateExists(partition, name); + + if (certificateExists) + { + if (!JobConfig.Overwrite) { throw new Exception($"An entry named '{name}' exists and 'overwrite' was not selected"); } + + List boundElsewhere = f5.GetProfilesBoundToCertificate(partition, name, ProfileName); + if (boundElsewhere.Any()) + { + throw new Exception($"The certificate '{name}' is bound to the following other profile(s) and cannot be replaced: {string.Join(", ", boundElsewhere)}"); + } + + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Replace entry '{name}' in '{JobConfig.CertificateStoreDetails.StorePath}'"); + f5.ReplaceEntry(partition, name, certContents, certificatePassword); + } + else + { + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"The entry '{name}' does not exist in '{JobConfig.CertificateStoreDetails.StorePath}' and will be added"); + f5.AddEntry(partition, name, certContents, certificatePassword); + } + + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Binding '{name}' to profile '{ProfileName}'"); + f5.BindCertificateToProfile(partition, ProfileEndpoint, ProfileName, name); + + LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); + } + + private JobResult PerformRemovalJob(F5Client f5, string partition) + { + LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformRemovalJob"); + string name = JobConfig.JobCertificate.Alias; + JobResult warningResult = null; + + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Unbinding '{name}' from profile '{ProfileName}'"); + f5.UnbindCertificate(partition, ProfileEndpoint, ProfileName); + + if (f5.CertificateExists(partition, name)) + { + List boundElsewhere = f5.GetProfilesBoundToCertificate(partition, name, ProfileName); + if (boundElsewhere.Any()) + { + string message = $"The certificate '{name}' was unbound from profile '{ProfileName}' but was not removed because it is still bound to the following other profile(s): {string.Join(", ", boundElsewhere)}"; + LogHandlerCommon.Warn(logger, JobConfig.CertificateStoreDetails, message); + warningResult = new JobResult { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = JobConfig.JobHistoryId, FailureMessage = message }; + } + else + { + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"The entry '{name}' exists in '{JobConfig.CertificateStoreDetails.StorePath}' and will be removed"); + f5.RemoveEntry(partition, name); + } + } + else + { + LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"The entry '{name}' does not exist in '{JobConfig.CertificateStoreDetails.StorePath}'"); + } + + LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformRemovalJob"); + return warningResult; + } + + private string RemoveCertificateChainFromPfx() + { + string rtnValue = string.Empty; + char[] password = JobConfig.JobCertificate.PrivateKeyPassword.ToCharArray(); + + Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); + Pkcs12Store store = storeBuilder.Build(); + store.Load(new MemoryStream(Convert.FromBase64String(JobConfig.JobCertificate.Contents)), password); + + // Find the key entry (private key and its associated certificate) + string alias = null; + foreach (string currentAlias in store.Aliases) + { + if (store.IsKeyEntry(currentAlias)) + { + alias = currentAlias; + break; + } + } + + if (alias == null) + throw new Exception("No private key entry found in PFX."); + + // Extract the private key and its associated certificate + AsymmetricKeyEntry keyEntry = store.GetKey(alias); + X509CertificateEntry certEntry = store.GetCertificate(alias); + + // Create a new PKCS#12 store with only the main certificate and private key + Pkcs12Store newStore = storeBuilder.Build(); + newStore.SetKeyEntry(alias, keyEntry, new[] { certEntry }); + + // Save the new PFX to a byte array + using (MemoryStream ms = new MemoryStream()) + { + newStore.Save(ms, password, new SecureRandom()); + rtnValue = Convert.ToBase64String(ms.ToArray()); + } + + return rtnValue; + } + } +} diff --git a/integration-manifest.json b/integration-manifest.json index a249136..8902a97 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -172,6 +172,93 @@ } ] }, + { + "Name": "F5 Profiles REST", + "ShortName": "F5-PF-REST", + "Capability": "F5-PF-REST", + "ServerRequired": true, + "BlueprintAllowed": true, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "ClientMachineDescription": "The server name or IP Address for the F5 device.", + "StorePathDescription": "Enter the store path in the form 'Partition\\ProfileName\\ProfileType\\InheritedProfile', delimited by the backslash (\\) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", + "SupportedOperations": { + "Add": true, + "Create": true, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "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\".", + "IsPAMEligible": true + } + }, + "Properties": [ + { + "Name": "RemoveChain", + "DisplayName": "Remove Chain on Add", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": false, + "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." + }, + { + "Name": "IgnoreSSLWarning", + "DisplayName": "Ignore SSL Warning", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": true, + "Description": "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." + }, + { + "Name": "UseTokenAuth", + "DisplayName": "Use Token Authentication", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "false", + "Required": true, + "Description": "Select this if you wish to use F5's token authentication 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." + }, + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login credential for the F5 device. MUST be an Admin account." + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login password for the F5 device." + }, + { + "Name": "ServerUseSsl", + "DisplayName": "Use SSL", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "true", + "Required": true, + "Description": "True if using https to access the F5 device. False if using http." + } + ], + "EntryParameters": [] + }, { "Name": "F5 WS Profiles REST", "ShortName": "F5-WS-REST", diff --git a/manifest.json b/manifest.json index 7aa1a6d..3739b4d 100644 --- a/manifest.json +++ b/manifest.json @@ -25,6 +25,18 @@ "assemblypath": "F5Orchestrator.dll", "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5Orchestrator.SSLProfile.Discovery" }, + "CertStores.F5-PF-REST.Inventory": { + "assemblypath": "F5Orchestrator.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile.Inventory" + }, + "CertStores.F5-PF-REST.Management": { + "assemblypath": "F5Orchestrator.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile.Management" + }, + "CertStores.F5-PF-REST.Discovery": { + "assemblypath": "F5Orchestrator.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile.Discovery" + }, "CertStores.F5-WS-REST.Inventory": { "assemblypath": "F5Orchestrator.dll", "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5Orchestrator.WebServer.Inventory" From a306518f1ad3f2ac883f547ae59a907354014954 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 4 Aug 2026 18:30:27 +0000 Subject: [PATCH 05/26] docs: auto-generate README and documentation [skip ci] --- README.md | 256 +++++++++++++++++- docsource/f5-pf-rest.md | 20 ++ .../F5-PF-REST-advanced-store-type-dialog.svg | 67 +++++ .../F5-PF-REST-basic-store-type-dialog.svg | 87 ++++++ ...T-custom-field-IgnoreSSLWarning-dialog.svg | 54 ++++ ...reSSLWarning-validation-options-dialog.svg | 39 +++ ...F-REST-custom-field-RemoveChain-dialog.svg | 54 ++++ ...-RemoveChain-validation-options-dialog.svg | 39 +++ ...-REST-custom-field-ServerUseSsl-dialog.svg | 54 ++++ ...ServerUseSsl-validation-options-dialog.svg | 39 +++ ...-REST-custom-field-UseTokenAuth-dialog.svg | 54 ++++ ...UseTokenAuth-validation-options-dialog.svg | 39 +++ ...F-REST-custom-fields-store-type-dialog.svg | 98 +++++++ .../bash/curl_create_store_types.sh | 91 +++++++ .../bash/kfutil_create_store_types.sh | 3 + .../powershell/kfutil_create_store_types.ps1 | 3 + .../restmethod_create_store_types.ps1 | 91 +++++++ 17 files changed, 1085 insertions(+), 3 deletions(-) create mode 100644 docsource/f5-pf-rest.md create mode 100644 docsource/images/F5-PF-REST-advanced-store-type-dialog.svg create mode 100644 docsource/images/F5-PF-REST-basic-store-type-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-ServerUseSsl-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg diff --git a/README.md b/README.md index e590d55..1898a04 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,9 @@ 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. +The F5 Universal Orchestrator extension implements 4 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. - [F5 SSL Profiles REST](#F5-SL-REST) +- [F5 Profiles REST](#F5-PF-REST) - [F5 WS Profiles REST](#F5-WS-REST) - [F5 CA Profiles REST](#F5-CA-REST) @@ -58,7 +59,7 @@ An administrator account must be set up in F5 to be used with this orchestrator To use the F5 Universal Orchestrator extension, you **must** create the Certificate Store Types required for your use-case. This only needs to happen _once_ per Keyfactor Command instance. -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. +The F5 Universal Orchestrator extension implements 4 Certificate Store Types. Depending on your use case, you may elect to use one, or all of these Certificate Store Types. ### F5-SL-REST @@ -269,6 +270,157 @@ the Keyfactor Command Portal +### F5-PF-REST + +
Click to expand details + +TODO Overview is a required section + +TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. + +#### F5 Profiles REST Requirements + +TODO Requirements is an optional section. If this section doesn't seem necessary, please delete it. + +#### Supported Operations + +| Operation | Is Supported | +|--------------|--------------| +| Add | ✅ Checked | +| Remove | ✅ Checked | +| Discovery | ✅ Checked | +| Reenrollment | 🔲 Unchecked | +| Create | ✅ Checked | + +#### Store Type Creation + +##### Using kfutil: +`kfutil` is a custom CLI for the Keyfactor Command API and can be used to create certificate store types. +For more information on [kfutil](https://github.com/Keyfactor/kfutil) check out the [docs](https://github.com/Keyfactor/kfutil?tab=readme-ov-file#quickstart) + +
Click to expand F5-PF-REST kfutil details + + ##### Using online definition from GitHub: + This will reach out to GitHub and pull the latest store-type definition + ```shell + # F5 Profiles REST + kfutil store-types create F5-PF-REST + ``` + + ##### Offline creation using integration-manifest file: + If required, it is possible to create store types from the [integration-manifest.json](./integration-manifest.json) included in this repo. + You would first download the [integration-manifest.json](./integration-manifest.json) and then run the following command + in your offline environment. + ```shell + kfutil store-types create --from-file integration-manifest.json + ``` +
+ +#### Manual Creation +Below are instructions on how to create the F5-PF-REST store type manually in +the Keyfactor Command Portal + +
Click to expand manual F5-PF-REST details + + Create a store type called `F5-PF-REST` with the attributes in the tables below: + + ##### Basic Tab + | Attribute | Value | Description | + | --------- | ----- | ----- | + | Name | F5 Profiles REST | Display name for the store type (may be customized) | + | Short Name | F5-PF-REST | Short display name for the store type | + | Capability | F5-PF-REST | Store type name orchestrator will register with. Check the box to allow entry of value | + | Supports Add | ✅ Checked | Indicates that the Store Type supports Management Add | + | Supports Remove | ✅ Checked | Indicates that the Store Type supports Management Remove | + | Supports Discovery | ✅ Checked | Indicates that the Store Type supports Discovery | + | Supports Reenrollment | 🔲 Unchecked | Indicates that the Store Type supports Reenrollment | + | Supports Create | ✅ Checked | Indicates that the Store Type supports store creation | + | Needs Server | ✅ Checked | Determines if a target server name is required when creating store | + | Blueprint Allowed | ✅ Checked | Determines if store type may be included in an Orchestrator blueprint | + | Uses PowerShell | 🔲 Unchecked | Determines if underlying implementation is PowerShell | + | Requires Store Password | ✅ Checked | Enables users to optionally specify a store password when defining a Certificate Store. | + | Supports Entry Password | 🔲 Unchecked | Determines if an individual entry within a store can have a password. | + + The Basic tab should look like this: + + ![F5-PF-REST Basic Tab](docsource/images/F5-PF-REST-basic-store-type-dialog.svg) + + ##### Advanced Tab + | Attribute | Value | Description | + | --------- | ----- | ----- | + | Supports Custom Alias | Required | Determines if an individual entry within a store can have a custom Alias. | + | Private Key Handling | Required | This determines if Keyfactor can send the private key associated with a certificate to the store. | + | PFX Password Style | Default | 'Default' - PFX password is randomly generated, 'Custom' - PFX password may be specified when the enrollment job is created (Requires the Allow Custom Password application setting to be enabled.) | + + The Advanced tab should look like this: + + ![F5-PF-REST Advanced Tab](docsource/images/F5-PF-REST-advanced-store-type-dialog.svg) + + > For Keyfactor **Command versions 24.4 and later**, a Certificate Format dropdown is available with PFX and PEM options. Ensure that **PFX** is selected, as this determines the format of new and renewed certificates sent to the Orchestrator during a Management job. Currently, all Keyfactor-supported Orchestrator extensions support only PFX. + + ##### Custom Fields Tab + Custom fields operate at the certificate store level and are used to control how the orchestrator connects to the remote target server containing the certificate store to be managed. The following custom fields should be added to the store type: + + | Name | Display Name | Description | Type | Default Value/Options | Required | + | ---- | ------------ | ---- | --------------------- | -------- | ----------- | + | RemoveChain | Remove Chain on Add | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | Bool | False | 🔲 Unchecked | + | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | + | UseTokenAuth | Use Token Authentication | Select this if you wish to use F5's token authentication 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. | Bool | false | ✅ Checked | + | ServerUsername | Server Username | Login credential for the F5 device. MUST be an Admin account. | Secret | | 🔲 Unchecked | + | ServerPassword | Server Password | Login password for the F5 device. | Secret | | 🔲 Unchecked | + | ServerUseSsl | Use SSL | True if using https to access the F5 device. False if using http. | Bool | true | ✅ Checked | + + The Custom Fields tab should look like this: + + ![F5-PF-REST Custom Fields Tab](docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg) + + ###### Remove Chain on Add + Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. + + ![F5-PF-REST Custom Field - RemoveChain](docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg) + ![F5-PF-REST Custom Field - RemoveChain](docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg) + + + ###### Ignore SSL Warning + 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. + + ![F5-PF-REST Custom Field - IgnoreSSLWarning](docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg) + ![F5-PF-REST Custom Field - IgnoreSSLWarning](docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-validation-options-dialog.svg) + + + ###### Use Token Authentication + Select this if you wish to use F5's token authentication 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. + + ![F5-PF-REST Custom Field - UseTokenAuth](docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg) + ![F5-PF-REST Custom Field - UseTokenAuth](docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg) + + + ###### Server Username + Login credential for the F5 device. MUST be an Admin account. + + + > [!IMPORTANT] + > This field is created by the `Needs Server` on the Basic tab, do not create this field manually. + + + ###### Server Password + Login password for the F5 device. + + + > [!IMPORTANT] + > This field is created by the `Needs Server` on the Basic tab, do not create this field manually. + + + ###### Use SSL + True if using https to access the F5 device. False if using http. + + ![F5-PF-REST Custom Field - ServerUseSsl](docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg) + ![F5-PF-REST Custom Field - ServerUseSsl](docsource/images/F5-PF-REST-custom-field-ServerUseSsl-validation-options-dialog.svg) + + +
+
+ ### F5-WS-REST
Click to expand details @@ -650,7 +802,7 @@ the Keyfactor Command Portal ## Defining Certificate Stores -The F5 Universal Orchestrator extension implements 3 Certificate Store Types, each of which implements different functionality. Refer to the individual instructions below for each Certificate Store Type that you deemed necessary for your use case from the installation section. +The F5 Universal Orchestrator extension implements 4 Certificate Store Types, each of which implements different functionality. Refer to the individual instructions below for each Certificate Store Type that you deemed necessary for your use case from the installation section.
F5 SSL Profiles REST (F5-SL-REST) @@ -753,6 +905,99 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
+
F5 Profiles REST (F5-PF-REST) + +TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. + +TODO Certificate Store Configuration is an optional section. If this section doesn't seem necessary, please delete it. + +### Store Creation + +#### Manually with the Command UI + +
Click to expand details + +1. **Navigate to the _Certificate Stores_ page in Keyfactor Command.** + + Log into Keyfactor Command, toggle the _Locations_ dropdown, and click _Certificate Stores_. + +2. **Add a Certificate Store.** + + Click the Add button to add a new Certificate Store. Use the table below to populate the **Attributes** in the **Add** form. + + | Attribute | Description | + | --------- | ----------- | + | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | + | Container | Optional container to associate certificate store with. | + | Client Machine | The server name or IP Address for the F5 device. | + | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Password | 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". | + | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | + | IgnoreSSLWarning | 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. | + | UseTokenAuth | Select this if you wish to use F5's token authentication 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. | + | ServerUsername | Login credential for the F5 device. MUST be an Admin account. | + | ServerPassword | Login password for the F5 device. | + | ServerUseSsl | True if using https to access the F5 device. False if using http. | + +
+ +#### Using kfutil CLI + +
Click to expand details + +1. **Generate a CSV template for the F5-PF-REST certificate store** + + ```shell + kfutil stores import generate-template --store-type-name F5-PF-REST --outpath F5-PF-REST.csv + ``` +2. **Populate the generated CSV file** + + Open the CSV file, and reference the table below to populate parameters for each **Attribute**. + + | Attribute | Description | + | --------- | ----------- | + | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | + | Container | Optional container to associate certificate store with. | + | Client Machine | The server name or IP Address for the F5 device. | + | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Password | 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". | + | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | Properties.RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | + | Properties.IgnoreSSLWarning | 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. | + | Properties.UseTokenAuth | Select this if you wish to use F5's token authentication 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. | + | Properties.ServerUsername | Login credential for the F5 device. MUST be an Admin account. | + | Properties.ServerPassword | Login password for the F5 device. | + | Properties.ServerUseSsl | True if using https to access the F5 device. False if using http. | + +3. **Import the CSV file to create the certificate stores** + + ```shell + kfutil stores import csv --store-type-name F5-PF-REST --file F5-PF-REST.csv + ``` + +
+ +#### PAM Provider Eligible Fields +
Attributes eligible for retrieval by a PAM Provider on the Universal Orchestrator + +If a PAM provider was installed _on the Universal Orchestrator_ in the [Installation](#Installation) section, the following parameters can be configured for retrieval _on the Universal Orchestrator_. + + | Attribute | Description | + | --------- | ----------- | + | ServerUsername | Login credential for the F5 device. MUST be an Admin account. | + | ServerPassword | Login password for the F5 device. | + | StorePassword | Password to use when reading/writing to store | + +Please refer to the **Universal Orchestrator (remote)** usage section ([PAM providers on the Keyfactor Integration Catalog](https://keyfactor.github.io/integrations-catalog/content/pam)) for your selected PAM provider for instructions on how to load attributes orchestrator-side. +> Any secret can be rendered by a PAM provider _installed on the Keyfactor Command server_. The above parameters are specific to attributes that can be fetched by an installed PAM provider running on the Universal Orchestrator server itself. + +
+ +> The content in this section can be supplemented by the [official Command documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Certificate%20Stores.htm?Highlight=certificate%20store). + +
+
F5 WS Profiles REST (F5-WS-REST) ### Store Creation @@ -963,6 +1208,11 @@ 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. +### F5 Profiles REST Discovery Job + +TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. +TODO Discovery Job Configuration is an optional section. If this section doesn't seem necessary, please delete it. + ## Syncing To Device Group The "Sync To Device Group" feature, introduced in version 2.0 of this orchestrator extension for the F5-SL-REST store type (ssl certificate management), enables synchronization of the F5 Big-IP node managed by the Keyfactor Command certificate store with a secondary node that is part of the F5 device group specified in the associated "Device Group" certificate store setting. diff --git a/docsource/f5-pf-rest.md b/docsource/f5-pf-rest.md new file mode 100644 index 0000000..7ec5382 --- /dev/null +++ b/docsource/f5-pf-rest.md @@ -0,0 +1,20 @@ +## Overview + +TODO Overview is a required section + +## Requirements + +TODO Requirements is an optional section. If this section doesn't seem necessary, please delete it. + +## Discovery Job Configuration + +TODO Discovery Job Configuration is an optional section. If this section doesn't seem necessary, please delete it. + +## Certificate Store Configuration + +TODO Certificate Store Configuration is an optional section. If this section doesn't seem necessary, please delete it. + +## Global Store Type Section + +TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. + diff --git a/docsource/images/F5-PF-REST-advanced-store-type-dialog.svg b/docsource/images/F5-PF-REST-advanced-store-type-dialog.svg new file mode 100644 index 0000000..123a979 --- /dev/null +++ b/docsource/images/F5-PF-REST-advanced-store-type-dialog.svg @@ -0,0 +1,67 @@ + + + + + + + + + Edit Certificate Store Type + + + + Basic + Advanced + + Custom Fields + Entry Parameters + + + + + Store Path Type + + + + Freeform + + Fixed + + Multiple Choice + + + + + Other Settings + + Supports Custom Alias + + Forbidden + + Optional + + + Required + Private Key Handling + + Forbidden + + Optional + + + Required + PFX Password Style + + + Default + + Custom + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-basic-store-type-dialog.svg b/docsource/images/F5-PF-REST-basic-store-type-dialog.svg new file mode 100644 index 0000000..1e5d0fe --- /dev/null +++ b/docsource/images/F5-PF-REST-basic-store-type-dialog.svg @@ -0,0 +1,87 @@ + + + + + + + + + Edit Certificate Store Type + + + + Basic + + Advanced + Custom Fields + Entry Parameters + + + + + Details + + Name + + F5 Profiles REST + Short Name + + F5-PF-REST + Custom Capability + + + Custom Capability + + + + Supported Job Types + + + + Inventory + + + Add + + + Remove + + + Create + + + Discovery + + ODKG + + + + General Settings + + + + Needs Server + + + Blueprint Allowed + + Uses PowerShell + + + + Password Settings + + + + Requires Store Password + + Supports Entry Password + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg new file mode 100644 index 0000000..2f908bb --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg @@ -0,0 +1,54 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + IgnoreSSLWarning + Display Name + + Ignore SSL Warning + Type + + Bool + + Default Value + + True + + + False + + Not Set + Depends On + + + Remove Chain on Add + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg b/docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg new file mode 100644 index 0000000..81ad566 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg @@ -0,0 +1,54 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + RemoveChain + Display Name + + Remove Chain on Add + Type + + Bool + + Default Value + + True + + + False + + Not Set + Depends On + + + Ignore SSL Warning + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg new file mode 100644 index 0000000..22f8bbd --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + + Optional + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg new file mode 100644 index 0000000..34d538e --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg @@ -0,0 +1,54 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + ServerUseSsl + Display Name + + Use SSL + Type + + Bool + + Default Value + + + True + + False + + Not Set + Depends On + + + Remove Chain on Add + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg new file mode 100644 index 0000000..fe47629 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg @@ -0,0 +1,54 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + UseTokenAuth + Display Name + + Use Token Authentication + Type + + Bool + + Default Value + + True + + + False + + Not Set + Depends On + + + Remove Chain on Add + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg new file mode 100644 index 0000000..a011d96 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -0,0 +1,98 @@ + + + + + + + + + Edit Certificate Store Type + + + + Basic + Advanced + Custom Fields + + Entry Parameters + + + + + + ADD + + EDIT + + DELETE + Total: 6 + + + Display Name + Type + Default Value / Options + + + + + + + + + + + Remove Chain on Add + Bool + False + + + + + + + Ignore SSL Warning + Bool + False + + + + + + + Use Token Authentication + Bool + false + + + + + + + Server Username + Secret + + + + + + + Server Password + Secret + + + + + + + Use SSL + Bool + true + \ No newline at end of file diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index 965e30b..f84bac8 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -170,6 +170,97 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate ] }' +echo "Creating store type: F5-PF-REST" +curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/CertificateStoreTypes" \ + -H "Authorization: Bearer ${KEYFACTOR_AUTH_TOKEN}" \ + -H "Content-Type: application/json" \ + -H "x-keyfactor-requested-with: APIClient" \ + -d '{ + "Name": "F5 Profiles REST", + "ShortName": "F5-PF-REST", + "Capability": "F5-PF-REST", + "ServerRequired": true, + "BlueprintAllowed": true, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "SupportedOperations": { + "Add": true, + "Create": true, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "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\".", + "IsPAMEligible": true + } + }, + "Properties": [ + { + "Name": "RemoveChain", + "DisplayName": "Remove Chain on Add", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": false, + "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." + }, + { + "Name": "IgnoreSSLWarning", + "DisplayName": "Ignore SSL Warning", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": true, + "Description": "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." + }, + { + "Name": "UseTokenAuth", + "DisplayName": "Use Token Authentication", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "false", + "Required": true, + "Description": "Select this if you wish to use F5's token authentication 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." + }, + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login credential for the F5 device. MUST be an Admin account." + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login password for the F5 device." + }, + { + "Name": "ServerUseSsl", + "DisplayName": "Use SSL", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "true", + "Required": true, + "Description": "True if using https to access the F5 device. False if using http." + } + ], + "EntryParameters": [] +}' + echo "Creating store type: F5-WS-REST" curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/CertificateStoreTypes" \ -H "Authorization: Bearer ${KEYFACTOR_AUTH_TOKEN}" \ diff --git a/scripts/store_types/bash/kfutil_create_store_types.sh b/scripts/store_types/bash/kfutil_create_store_types.sh index 9d89cd6..ee7d797 100755 --- a/scripts/store_types/bash/kfutil_create_store_types.sh +++ b/scripts/store_types/bash/kfutil_create_store_types.sh @@ -7,6 +7,9 @@ set -e echo "Creating store type: F5-SL-REST" kfutil store-types create F5-SL-REST +echo "Creating store type: F5-PF-REST" +kfutil store-types create F5-PF-REST + echo "Creating store type: F5-WS-REST" kfutil store-types create F5-WS-REST diff --git a/scripts/store_types/powershell/kfutil_create_store_types.ps1 b/scripts/store_types/powershell/kfutil_create_store_types.ps1 index 06490d7..e8dbe75 100644 --- a/scripts/store_types/powershell/kfutil_create_store_types.ps1 +++ b/scripts/store_types/powershell/kfutil_create_store_types.ps1 @@ -4,6 +4,9 @@ Write-Host "Creating store type: F5-SL-REST" kfutil store-types create F5-SL-REST +Write-Host "Creating store type: F5-PF-REST" +kfutil store-types create F5-PF-REST + Write-Host "Creating store type: F5-WS-REST" kfutil store-types create F5-WS-REST diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 index 0e51ce4..1d64915 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -173,6 +173,97 @@ $Body = @' Invoke-RestMethod -Uri "https://$KeyfactorHostname/$KeyfactorApiPath/CertificateStoreTypes" -Method POST -Headers $Headers -Body $Body +Write-Host "Creating store type: F5-PF-REST" +$Body = @' +{ + "Name": "F5 Profiles REST", + "ShortName": "F5-PF-REST", + "Capability": "F5-PF-REST", + "ServerRequired": true, + "BlueprintAllowed": true, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "SupportedOperations": { + "Add": true, + "Create": true, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "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\".", + "IsPAMEligible": true + } + }, + "Properties": [ + { + "Name": "RemoveChain", + "DisplayName": "Remove Chain on Add", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": false, + "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." + }, + { + "Name": "IgnoreSSLWarning", + "DisplayName": "Ignore SSL Warning", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": true, + "Description": "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." + }, + { + "Name": "UseTokenAuth", + "DisplayName": "Use Token Authentication", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "false", + "Required": true, + "Description": "Select this if you wish to use F5's token authentication 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." + }, + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login credential for the F5 device. MUST be an Admin account." + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login password for the F5 device." + }, + { + "Name": "ServerUseSsl", + "DisplayName": "Use SSL", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "true", + "Required": true, + "Description": "True if using https to access the F5 device. False if using http." + } + ], + "EntryParameters": [] +} +'@ + +Invoke-RestMethod -Uri "https://$KeyfactorHostname/$KeyfactorApiPath/CertificateStoreTypes" -Method POST -Headers $Headers -Body $Body + Write-Host "Creating store type: F5-WS-REST" $Body = @' { From 26008496b0f2084f1e5b3f5224c292bae027b3ae Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 5 Aug 2026 11:02:37 -0400 Subject: [PATCH 06/26] ab93116 --- F5Client.cs | 6 +++--- Profile/Discovery.cs | 4 ++-- integration-manifest.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 9b418bd..217e333 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -552,14 +552,14 @@ public string GetPartitionFromStorePath() return pathParts[0]; } - // Parses a Profile store path in the form 'Partition\ProfileName\ProfileType[\InheritedProfile]' + // Parses a Profile store path in the form 'Partition/ProfileName/ProfileType[/InheritedProfile]' public F5ProfileStorePath ParseProfileStorePath() { LogHandlerCommon.MethodEntry(logger, CertificateStore, "ParseProfileStorePath"); - string[] pathParts = CertificateStore.StorePath.Split('\\'); + string[] pathParts = CertificateStore.StorePath.Split('/'); if (pathParts.Length < 3 || pathParts.Length > 4) { - throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); + throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition/ProfileName/ProfileType' or 'Partition/ProfileName/ProfileType/InheritedProfile'."); } F5ProfileStorePath profileStorePath = new F5ProfileStorePath diff --git a/Profile/Discovery.cs b/Profile/Discovery.cs index 2565d19..e3aa879 100644 --- a/Profile/Discovery.cs +++ b/Profile/Discovery.cs @@ -70,8 +70,8 @@ public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDis } string location = string.IsNullOrEmpty(inheritedProfile) - ? $"{partition}\\{profile.name}\\{profileType}" - : $"{partition}\\{profile.name}\\{profileType}\\{inheritedProfile}"; + ? $"{partition}/{profile.name}/{profileType}" + : $"{partition}/{profile.name}/{profileType}/{inheritedProfile}"; locations.Add(location); } } diff --git a/integration-manifest.json b/integration-manifest.json index 8902a97..7284d7f 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -182,7 +182,7 @@ "PowerShell": false, "PrivateKeyAllowed": "Required", "ClientMachineDescription": "The server name or IP Address for the F5 device.", - "StorePathDescription": "Enter the store path in the form 'Partition\\ProfileName\\ProfileType\\InheritedProfile', delimited by the backslash (\\) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", + "StorePathDescription": "Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", "SupportedOperations": { "Add": true, "Create": true, From 41347de9b20c2d5e2d6fba96cef721a78a8aabf6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:03:17 +0000 Subject: [PATCH 07/26] docs: auto-generate README and documentation [skip ci] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1898a04..f8c0e84 100644 --- a/README.md +++ b/README.md @@ -930,7 +930,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | @@ -960,7 +960,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | Properties.RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | From 9dd4e5a6c4fcbb0cc7223d5d761bd22c8fdbd273 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 5 Aug 2026 11:51:41 -0400 Subject: [PATCH 08/26] ab93116 --- F5Client.cs | 6 +++--- Profile/Discovery.cs | 4 ++-- integration-manifest.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 217e333..9b418bd 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -552,14 +552,14 @@ public string GetPartitionFromStorePath() return pathParts[0]; } - // Parses a Profile store path in the form 'Partition/ProfileName/ProfileType[/InheritedProfile]' + // Parses a Profile store path in the form 'Partition\ProfileName\ProfileType[\InheritedProfile]' public F5ProfileStorePath ParseProfileStorePath() { LogHandlerCommon.MethodEntry(logger, CertificateStore, "ParseProfileStorePath"); - string[] pathParts = CertificateStore.StorePath.Split('/'); + string[] pathParts = CertificateStore.StorePath.Split('\\'); if (pathParts.Length < 3 || pathParts.Length > 4) { - throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition/ProfileName/ProfileType' or 'Partition/ProfileName/ProfileType/InheritedProfile'."); + throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); } F5ProfileStorePath profileStorePath = new F5ProfileStorePath diff --git a/Profile/Discovery.cs b/Profile/Discovery.cs index e3aa879..2565d19 100644 --- a/Profile/Discovery.cs +++ b/Profile/Discovery.cs @@ -70,8 +70,8 @@ public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDis } string location = string.IsNullOrEmpty(inheritedProfile) - ? $"{partition}/{profile.name}/{profileType}" - : $"{partition}/{profile.name}/{profileType}/{inheritedProfile}"; + ? $"{partition}\\{profile.name}\\{profileType}" + : $"{partition}\\{profile.name}\\{profileType}\\{inheritedProfile}"; locations.Add(location); } } diff --git a/integration-manifest.json b/integration-manifest.json index 7284d7f..8902a97 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -182,7 +182,7 @@ "PowerShell": false, "PrivateKeyAllowed": "Required", "ClientMachineDescription": "The server name or IP Address for the F5 device.", - "StorePathDescription": "Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", + "StorePathDescription": "Enter the store path in the form 'Partition\\ProfileName\\ProfileType\\InheritedProfile', delimited by the backslash (\\) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", "SupportedOperations": { "Add": true, "Create": true, From d152b4a87e495b3993a2c1d77a43d045f6e42c8e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:52:35 +0000 Subject: [PATCH 09/26] docs: auto-generate README and documentation [skip ci] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f8c0e84..1898a04 100644 --- a/README.md +++ b/README.md @@ -930,7 +930,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | @@ -960,7 +960,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition/ProfileName/ProfileType/InheritedProfile', delimited by the forward slash (/) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | Properties.RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | From edfad23ad3ce868bd438858d2f3b8ee1c51b4fea Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 5 Aug 2026 12:55:48 -0400 Subject: [PATCH 10/26] Remove RemoveChainOnAdd custom field from F5-PF-REST The Profile store type no longer supports chain removal on add; the custom field and its supporting logic were unused for this store type. --- Profile/Management.cs | 50 +++------------------------------------ integration-manifest.json | 9 ------- 2 files changed, 3 insertions(+), 56 deletions(-) diff --git a/Profile/Management.cs b/Profile/Management.cs index 5e78d57..25ec7d3 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -14,9 +14,6 @@ using System.Collections.Generic; using System.Linq; using Keyfactor.Orchestrators.Extensions.Interfaces; -using Org.BouncyCastle.Pkcs; -using Org.BouncyCastle.Security; -using System.IO; namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile { @@ -76,7 +73,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config) break; case CertStoreOperationType.Add: LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Add entry '{config.JobCertificate.Alias}' to '{config.CertificateStoreDetails.StorePath}'"); - PerformAddJob(f5, partition, StorePassword, RemoveChain); + PerformAddJob(f5, partition, StorePassword); break; case CertStoreOperationType.Remove: LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'"); @@ -127,12 +124,12 @@ private JobResult PerformCreateJob(F5Client f5, string partition) return null; } - private void PerformAddJob(F5Client f5, string partition, string certificatePassword, bool removeChain) + private void PerformAddJob(F5Client f5, string partition, string certificatePassword) { LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); string name = JobConfig.JobCertificate.Alias; - string certContents = !string.IsNullOrEmpty(JobConfig.JobCertificate.PrivateKeyPassword) && removeChain ? RemoveCertificateChainFromPfx() : JobConfig.JobCertificate.Contents; + string certContents = JobConfig.JobCertificate.Contents; bool certificateExists = f5.CertificateExists(partition, name); if (certificateExists) @@ -192,46 +189,5 @@ private JobResult PerformRemovalJob(F5Client f5, string partition) LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformRemovalJob"); return warningResult; } - - private string RemoveCertificateChainFromPfx() - { - string rtnValue = string.Empty; - char[] password = JobConfig.JobCertificate.PrivateKeyPassword.ToCharArray(); - - Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); - Pkcs12Store store = storeBuilder.Build(); - store.Load(new MemoryStream(Convert.FromBase64String(JobConfig.JobCertificate.Contents)), password); - - // Find the key entry (private key and its associated certificate) - string alias = null; - foreach (string currentAlias in store.Aliases) - { - if (store.IsKeyEntry(currentAlias)) - { - alias = currentAlias; - break; - } - } - - if (alias == null) - throw new Exception("No private key entry found in PFX."); - - // Extract the private key and its associated certificate - AsymmetricKeyEntry keyEntry = store.GetKey(alias); - X509CertificateEntry certEntry = store.GetCertificate(alias); - - // Create a new PKCS#12 store with only the main certificate and private key - Pkcs12Store newStore = storeBuilder.Build(); - newStore.SetKeyEntry(alias, keyEntry, new[] { certEntry }); - - // Save the new PFX to a byte array - using (MemoryStream ms = new MemoryStream()) - { - newStore.Save(ms, password, new SecureRandom()); - rtnValue = Convert.ToBase64String(ms.ToArray()); - } - - return rtnValue; - } } } diff --git a/integration-manifest.json b/integration-manifest.json index 8902a97..5889c97 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -200,15 +200,6 @@ } }, "Properties": [ - { - "Name": "RemoveChain", - "DisplayName": "Remove Chain on Add", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "False", - "Required": false, - "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", From ff39d879c8eaad0d3f356da193873acbcfd5ec63 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 16:56:47 +0000 Subject: [PATCH 11/26] docs: auto-generate README and documentation [skip ci] --- README.md | 10 ------ ...T-custom-field-IgnoreSSLWarning-dialog.svg | 2 +- ...-REST-custom-field-ServerUseSsl-dialog.svg | 2 +- ...-REST-custom-field-UseTokenAuth-dialog.svg | 2 +- ...F-REST-custom-fields-store-type-dialog.svg | 35 +++++++------------ .../bash/curl_create_store_types.sh | 9 ----- .../restmethod_create_store_types.ps1 | 9 ----- 7 files changed, 16 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 1898a04..f2e44a5 100644 --- a/README.md +++ b/README.md @@ -363,7 +363,6 @@ the Keyfactor Command Portal | Name | Display Name | Description | Type | Default Value/Options | Required | | ---- | ------------ | ---- | --------------------- | -------- | ----------- | - | RemoveChain | Remove Chain on Add | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | Bool | False | 🔲 Unchecked | | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | | UseTokenAuth | Use Token Authentication | Select this if you wish to use F5's token authentication 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. | Bool | false | ✅ Checked | | ServerUsername | Server Username | Login credential for the F5 device. MUST be an Admin account. | Secret | | 🔲 Unchecked | @@ -374,13 +373,6 @@ the Keyfactor Command Portal ![F5-PF-REST Custom Fields Tab](docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg) - ###### Remove Chain on Add - Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. - - ![F5-PF-REST Custom Field - RemoveChain](docsource/images/F5-PF-REST-custom-field-RemoveChain-dialog.svg) - ![F5-PF-REST Custom Field - RemoveChain](docsource/images/F5-PF-REST-custom-field-RemoveChain-validation-options-dialog.svg) - - ###### Ignore SSL Warning 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. @@ -933,7 +925,6 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | - | RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | | IgnoreSSLWarning | 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. | | UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | ServerUsername | Login credential for the F5 device. MUST be an Admin account. | @@ -963,7 +954,6 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | - | Properties.RemoveChain | Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device. | | Properties.IgnoreSSLWarning | 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. | | Properties.UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | Properties.ServerUsername | Login credential for the F5 device. MUST be an Admin account. | diff --git a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg index 2f908bb..935afe7 100644 --- a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg @@ -44,7 +44,7 @@ Depends On - Remove Chain on Add + Use Token Authentication diff --git a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg index 34d538e..629e39b 100644 --- a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg @@ -44,7 +44,7 @@ Depends On - Remove Chain on Add + Ignore SSL Warning diff --git a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg index fe47629..563662e 100644 --- a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg @@ -44,7 +44,7 @@ Depends On - Remove Chain on Add + Ignore SSL Warning diff --git a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg index a011d96..c9f4d77 100644 --- a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -1,5 +1,5 @@  - + - + Edit Certificate Store Type @@ -24,7 +24,7 @@ Entry Parameters - + @@ -33,7 +33,7 @@ EDIT DELETE - Total: 6 + Total: 5 Display Name @@ -49,7 +49,7 @@ - Remove Chain on Add + Ignore SSL Warning Bool False @@ -58,25 +58,24 @@ - Ignore SSL Warning + Use Token Authentication Bool - False + false - Use Token Authentication - Bool - false + Server Username + Secret - Server Username + Server Password Secret @@ -84,15 +83,7 @@ - Server Password - Secret - - - - - - - Use SSL - Bool - true + Use SSL + Bool + true \ No newline at end of file diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index f84bac8..864e42d 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -201,15 +201,6 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate } }, "Properties": [ - { - "Name": "RemoveChain", - "DisplayName": "Remove Chain on Add", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "False", - "Required": false, - "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 index 1d64915..37fe785 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -201,15 +201,6 @@ $Body = @' } }, "Properties": [ - { - "Name": "RemoveChain", - "DisplayName": "Remove Chain on Add", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "False", - "Required": false, - "Description": "Optional setting. Set this to true if you would like to remove the certificate chain before adding or replacing a certificate on your F5 device." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", From c0833ae6287686d4a3143473c78aef8546f52cb2 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 5 Aug 2026 20:27:50 +0000 Subject: [PATCH 12/26] ab93116 --- F5Client.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 9b418bd..75e28b1 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -567,7 +567,7 @@ public F5ProfileStorePath ParseProfileStorePath() Partition = pathParts[0], ProfileName = pathParts[1], ProfileType = pathParts[2], - InheritedProfile = pathParts.Length == 4 ? pathParts[3] : string.Empty + InheritedProfile = pathParts.Length == 4 ? pathParts[3].Replace($"/","~") : string.Empty }; LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); @@ -783,7 +783,7 @@ public bool ProfileExists(string partition, string profileEndpoint, string profi try { - string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}"; + string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{profileName}"; F5SSLProfile profile = REST.Get(query); exists = (profile != null); } @@ -807,7 +807,7 @@ public void CreateProfile(string partition, string profileEndpoint, string profi string defaultsFrom = null; if (!string.IsNullOrEmpty(inheritedProfile) && ProfileExists(partition, profileEndpoint, inheritedProfile)) { - defaultsFrom = $"/{partition}/{inheritedProfile}"; + defaultsFrom = $"/~{inheritedProfile}"; } F5ProfileCreate profile = new F5ProfileCreate From 865e8833a040f725deda3a4c371b9365fb060052 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Fri, 7 Aug 2026 13:41:00 +0000 Subject: [PATCH 13/26] ab93116 --- F5Client.cs | 37 ++++++++++++++++++++++--------------- F5DataModels.cs | 10 ++++++++-- Profile/Management.cs | 2 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 75e28b1..4798e28 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -7,26 +7,27 @@ // OR CONDITIONS OF ANY KIND, either express or implied. See the License for // thespecific language governing permissions and limitations under the // License. -using Keyfactor.Orchestrators.Extensions; using Keyfactor.Orchestrators.Common.Enums; -using Keyfactor.PKI.X509; +using Keyfactor.Orchestrators.Extensions; using Keyfactor.PKI.PEM; +using Keyfactor.PKI.X509; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Drawing.Printing; using System.Linq; +using System.Reflection.Metadata; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; - -using Newtonsoft.Json; -using System.Collections; -using System.Collections.Concurrent; -using System.Drawing.Printing; -using System.Diagnostics.CodeAnalysis; +using static Keyfactor.Extensions.Orchestrator.F5Orchestrator.F5ProfileStorePath; using static Keyfactor.Orchestrators.Common.OrchestratorConstants; using static Org.BouncyCastle.Math.EC.ECCurve; -using System.Reflection.Metadata; namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator { @@ -562,12 +563,18 @@ public F5ProfileStorePath ParseProfileStorePath() throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); } + if (!Enum.TryParse(pathParts[2], ignoreCase: true, out var profileType) || + !Enum.IsDefined(typeof(ProfileTypeEnum), profileType)) + { + throw new Exception($"Invalid value for profile type: {pathParts[2]}"); + } + F5ProfileStorePath profileStorePath = new F5ProfileStorePath { Partition = pathParts[0], ProfileName = pathParts[1], - ProfileType = pathParts[2], - InheritedProfile = pathParts.Length == 4 ? pathParts[3].Replace($"/","~") : string.Empty + ProfileType = profileType, + InheritedProfile = pathParts.Length == 4 ? pathParts[3] : string.Empty }; LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); @@ -771,9 +778,9 @@ public List GetCertificateEntries(int pageSize) private const string CLIENT_SSL_ENDPOINT = "client-ssl"; private const string SERVER_SSL_ENDPOINT = "server-ssl"; - public static string GetProfileEndpoint(string profileType) + public static string GetProfileEndpoint(ProfileTypeEnum profileType) { - return profileType.Equals("Server", StringComparison.OrdinalIgnoreCase) ? SERVER_SSL_ENDPOINT : CLIENT_SSL_ENDPOINT; + return profileType == ProfileTypeEnum.Server ? SERVER_SSL_ENDPOINT : CLIENT_SSL_ENDPOINT; } public bool ProfileExists(string partition, string profileEndpoint, string profileName) @@ -783,7 +790,7 @@ public bool ProfileExists(string partition, string profileEndpoint, string profi try { - string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{profileName}"; + string query = $"/mgmt/tm/ltm/profile/{profileEndpoint}/~{profileName.Replace($"/","~")}"; F5SSLProfile profile = REST.Get(query); exists = (profile != null); } @@ -807,7 +814,7 @@ public void CreateProfile(string partition, string profileEndpoint, string profi string defaultsFrom = null; if (!string.IsNullOrEmpty(inheritedProfile) && ProfileExists(partition, profileEndpoint, inheritedProfile)) { - defaultsFrom = $"/~{inheritedProfile}"; + defaultsFrom = $"/{inheritedProfile}"; } F5ProfileCreate profile = new F5ProfileCreate diff --git a/F5DataModels.cs b/F5DataModels.cs index 9982437..9ae2eb1 100644 --- a/F5DataModels.cs +++ b/F5DataModels.cs @@ -194,11 +194,17 @@ public class F5Version public string selfLink { get; set; } } - internal class F5ProfileStorePath + public class F5ProfileStorePath { + public enum ProfileTypeEnum + { + Client, + Server + } + public string Partition { get; set; } public string ProfileName { get; set; } - public string ProfileType { get; set; } + public ProfileTypeEnum ProfileType { get; set; } public string InheritedProfile { get; set; } } diff --git a/Profile/Management.cs b/Profile/Management.cs index 25ec7d3..294b899 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -20,7 +20,7 @@ namespace Keyfactor.Extensions.Orchestrator.F5Orchestrator.Profile public class Management : ManagementBase { protected string ProfileName { get; set; } - protected string ProfileType { get; set; } + protected F5ProfileStorePath.ProfileTypeEnum ProfileType { get; set; } protected string ProfileEndpoint { get; set; } protected string InheritedProfile { get; set; } From 934dd624e20f66496bee8d69134891900d8aeefb Mon Sep 17 00:00:00 2001 From: leefine02 Date: Fri, 7 Aug 2026 09:44:10 -0400 Subject: [PATCH 14/26] Validate inherited profile exists before creating F5-PF-REST profile Fail the Create job with a clear error if the specified inherited profile does not exist, instead of silently ignoring it. --- F5Client.cs | 6 +----- Profile/Management.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 4798e28..81401c5 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -811,11 +811,7 @@ public void CreateProfile(string partition, string profileEndpoint, string profi { LogHandlerCommon.MethodEntry(logger, CertificateStore, "CreateProfile"); - string defaultsFrom = null; - if (!string.IsNullOrEmpty(inheritedProfile) && ProfileExists(partition, profileEndpoint, inheritedProfile)) - { - defaultsFrom = $"/{inheritedProfile}"; - } + string defaultsFrom = string.IsNullOrEmpty(inheritedProfile) ? null : $"/{inheritedProfile}"; F5ProfileCreate profile = new F5ProfileCreate { diff --git a/Profile/Management.cs b/Profile/Management.cs index 294b899..9a23155 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -118,6 +118,14 @@ private JobResult PerformCreateJob(F5Client f5, string partition) return new JobResult { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = JobConfig.JobHistoryId, FailureMessage = message }; } + if (!string.IsNullOrEmpty(InheritedProfile) && !f5.ProfileExists(partition, ProfileEndpoint, InheritedProfile)) + { + string message = $"The inherited profile '{InheritedProfile}' does not exist in partition '{partition}' - no action was taken."; + LogHandlerCommon.Error(logger, JobConfig.CertificateStoreDetails, message); + LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformCreateJob"); + return new JobResult { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = JobConfig.JobHistoryId, FailureMessage = message }; + } + f5.CreateProfile(partition, ProfileEndpoint, ProfileName, InheritedProfile); LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformCreateJob"); From 4dae9faba7d5edb4bcca3dfca09b6ba1c2f8230e Mon Sep 17 00:00:00 2001 From: leefine02 Date: Mon, 10 Aug 2026 17:01:14 +0000 Subject: [PATCH 15/26] ab93116 --- F5Client.cs | 8 ++++---- F5DataModels.cs | 1 + Profile/Discovery.cs | 16 ++++++++++------ Profile/Management.cs | 2 +- SSLProfile/Management.cs | 6 +++--- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 81401c5..a3c0841 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -208,13 +208,13 @@ public bool CertificateExists(string partition, string crtName) return exists; } - public void BindCertificate(string alias, string sslProfile) + public void BindCertificate(string alias, string sslProfile, string certificatePassword) { LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificate"); try { - F5Binding binding = new F5Binding { cert = $"{alias}", key = $"{alias}", chain = $"{alias}" }; + F5Binding binding = new F5Binding { cert = $"{alias}", key = $"{alias}", chain = $"{alias}", passphrase = $"{certificatePassword}" }; REST.Patch($"/mgmt/tm/ltm/profile/client-ssl/{sslProfile}", binding); } @@ -876,11 +876,11 @@ public void UnbindCertificate(string partition, string profileEndpoint, string p } // Bind a certificate/key (and matching chain) already installed in the given partition to the named profile - public void BindCertificateToProfile(string partition, string profileEndpoint, string profileName, string alias) + public void BindCertificateToProfile(string partition, string profileEndpoint, string profileName, string alias, string certificatePassword) { LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificateToProfile"); - F5Binding binding = new F5Binding { cert = alias, key = alias, chain = alias }; + F5Binding binding = new F5Binding { cert = alias, key = alias, chain = alias, passphrase = certificatePassword }; REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); LogHandlerCommon.MethodExit(logger, CertificateStore, "BindCertificateToProfile"); diff --git a/F5DataModels.cs b/F5DataModels.cs index 9ae2eb1..024311b 100644 --- a/F5DataModels.cs +++ b/F5DataModels.cs @@ -146,6 +146,7 @@ internal class F5Binding public string cert { get; set; } public string key { get; set; } public string chain { get; set; } + public string passphrase { get; set; } } internal class F5ProfileCreate diff --git a/Profile/Discovery.cs b/Profile/Discovery.cs index 2565d19..3f4e6ac 100644 --- a/Profile/Discovery.cs +++ b/Profile/Discovery.cs @@ -62,16 +62,20 @@ public override JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDis foreach (F5SSLProfile profile in profiles) { - string inheritedProfile = string.Empty; - if (!string.IsNullOrEmpty(profile.defaultsFrom)) + if (profile.defaultsFrom.Substring(0,1) == $"/") { - string[] inheritedParts = profile.defaultsFrom.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - inheritedProfile = inheritedParts[inheritedParts.Length - 1]; + profile.defaultsFrom = profile.defaultsFrom.Substring(1); } + //string inheritedProfile = string.Empty; + //if (!string.IsNullOrEmpty(profile.defaultsFrom)) + //{ + // string[] inheritedParts = profile.defaultsFrom.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + // inheritedProfile = inheritedParts[inheritedParts.Length - 1]; + //} - string location = string.IsNullOrEmpty(inheritedProfile) + string location = string.IsNullOrEmpty(profile.defaultsFrom) ? $"{partition}\\{profile.name}\\{profileType}" - : $"{partition}\\{profile.name}\\{profileType}\\{inheritedProfile}"; + : $"{partition}\\{profile.name}\\{profileType}\\{profile.defaultsFrom}"; locations.Add(location); } } diff --git a/Profile/Management.cs b/Profile/Management.cs index 9a23155..4472b3e 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -160,7 +160,7 @@ private void PerformAddJob(F5Client f5, string partition, string certificatePass } LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Binding '{name}' to profile '{ProfileName}'"); - f5.BindCertificateToProfile(partition, ProfileEndpoint, ProfileName, name); + f5.BindCertificateToProfile(partition, ProfileEndpoint, ProfileName, name, certificatePassword); LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); } diff --git a/SSLProfile/Management.cs b/SSLProfile/Management.cs index 33b5793..78dc7cc 100644 --- a/SSLProfile/Management.cs +++ b/SSLProfile/Management.cs @@ -65,7 +65,7 @@ public override JobResult ProcessJob(ManagementJobConfiguration config) LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Add entry '{config.JobCertificate.Alias}' to '{config.CertificateStoreDetails.StorePath}'"); bool certificateExists = PerformAddJob(f5, StorePassword, RemoveChain); if (!certificateExists && !string.IsNullOrEmpty(sslProfiles)) - BindCertificateToSSLProfiles(f5, config.JobCertificate.Alias, sslProfiles); + BindCertificateToSSLProfiles(f5, config.JobCertificate.Alias, sslProfiles, StorePassword); if (SyncDevice) f5.SyncDevice(SyncDeviceGroup); break; @@ -192,7 +192,7 @@ private string RemoveCertificateChainFromPfx() return rtnValue; } - private void BindCertificateToSSLProfiles(F5Client f5, string alias, string sslProfiles) + private void BindCertificateToSSLProfiles(F5Client f5, string alias, string sslProfiles, string certificatePassword) { bool hasError = false; string errorMessages = string.Empty; @@ -201,7 +201,7 @@ private void BindCertificateToSSLProfiles(F5Client f5, string alias, string sslP { try { - f5.BindCertificate(alias, sslProfile); + f5.BindCertificate(alias, sslProfile, certificatePassword); } catch (Exception ex) { From 5a641ab7ce81e78c3dd9abf0b6d60bef5e35c604 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Tue, 11 Aug 2026 13:35:07 +0000 Subject: [PATCH 16/26] ab93116 --- F5Client.cs | 7 +++++-- Profile/Management.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index a3c0841..80c9906 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -876,12 +876,15 @@ public void UnbindCertificate(string partition, string profileEndpoint, string p } // Bind a certificate/key (and matching chain) already installed in the given partition to the named profile - public void BindCertificateToProfile(string partition, string profileEndpoint, string profileName, string alias, string certificatePassword) + public void BindCertificateToProfile(string partition, string profileEndpoint, string profileName, string alias, string certificatePassword, bool certificateExists) { LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificateToProfile"); F5Binding binding = new F5Binding { cert = alias, key = alias, chain = alias, passphrase = certificatePassword }; - REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); + if (certificateExists) + REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); + else + REST.Post($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", JsonConvert.SerializeObject(binding)); LogHandlerCommon.MethodExit(logger, CertificateStore, "BindCertificateToProfile"); } diff --git a/Profile/Management.cs b/Profile/Management.cs index 4472b3e..c3c2c40 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -160,7 +160,7 @@ private void PerformAddJob(F5Client f5, string partition, string certificatePass } LogHandlerCommon.Debug(logger, JobConfig.CertificateStoreDetails, $"Binding '{name}' to profile '{ProfileName}'"); - f5.BindCertificateToProfile(partition, ProfileEndpoint, ProfileName, name, certificatePassword); + f5.BindCertificateToProfile(partition, ProfileEndpoint, ProfileName, name, certificatePassword, certificateExists); LogHandlerCommon.MethodExit(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); } From e545c08670438d1653fe8ce5d994bc0b1470a4e5 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 12 Aug 2026 18:59:52 +0000 Subject: [PATCH 17/26] ab93116 --- F5Client.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 80c9906..c4986bd 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -336,6 +336,9 @@ private X509Certificate2Collection GetCertificateEntry(string path) utilCmdArgs = $"-c 'cat {path} | base64'" }); + if (crt.Length < 80 || crt.Contains("no such file", StringComparison.OrdinalIgnoreCase)) + return new X509Certificate2Collection(); + byte[] crtBytes; switch (crt.Substring(0, 1)) { @@ -881,10 +884,7 @@ public void BindCertificateToProfile(string partition, string profileEndpoint, s LogHandlerCommon.MethodEntry(logger, CertificateStore, "BindCertificateToProfile"); F5Binding binding = new F5Binding { cert = alias, key = alias, chain = alias, passphrase = certificatePassword }; - if (certificateExists) - REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); - else - REST.Post($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", JsonConvert.SerializeObject(binding)); + REST.Patch($"/mgmt/tm/ltm/profile/{profileEndpoint}/~{partition}~{profileName}", binding); LogHandlerCommon.MethodExit(logger, CertificateStore, "BindCertificateToProfile"); } @@ -896,7 +896,7 @@ public List GetProfileCertificateInventory(string partitio List inventory = new List(); string alias = GetBoundCertificateAlias(partition, profileEndpoint, profileName); - if (string.IsNullOrEmpty(alias) || alias.Equals("default.crt", StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(alias) || alias.Equals("none", StringComparison.OrdinalIgnoreCase)) { LogHandlerCommon.Trace(logger, CertificateStore, $"Profile '{profileName}' in partition '{partition}' has no certificate bound"); LogHandlerCommon.MethodExit(logger, CertificateStore, "GetProfileCertificateInventory"); From 5f06025ea64f618bd87eced16a3a7f8ea14c0a37 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Fri, 21 Aug 2026 13:24:01 +0000 Subject: [PATCH 18/26] ab93116 --- F5Client.cs | 1 - F5DataModels.cs | 1 - ManagementBase.cs | 2 ++ Profile/Management.cs | 2 -- integration-manifest.json | 9 +++++++++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index c4986bd..b695715 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -577,7 +577,6 @@ public F5ProfileStorePath ParseProfileStorePath() Partition = pathParts[0], ProfileName = pathParts[1], ProfileType = profileType, - InheritedProfile = pathParts.Length == 4 ? pathParts[3] : string.Empty }; LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); diff --git a/F5DataModels.cs b/F5DataModels.cs index 024311b..61f03e1 100644 --- a/F5DataModels.cs +++ b/F5DataModels.cs @@ -206,7 +206,6 @@ public enum ProfileTypeEnum public string Partition { get; set; } public string ProfileName { get; set; } public ProfileTypeEnum ProfileType { get; set; } - public string InheritedProfile { get; set; } } public class SyncRequest diff --git a/ManagementBase.cs b/ManagementBase.cs index ffab90d..617b9cf 100644 --- a/ManagementBase.cs +++ b/ManagementBase.cs @@ -31,6 +31,7 @@ public abstract class ManagementBase : F5JobBase, IManagementJobExtension protected bool RemoveChain { get; set; } protected bool SyncDevice { get; set; } protected string SyncDeviceGroup { get; set; } + protected string InheritedProfile { get; set; } public string ExtensionName => "Keyfactor.Extensions.Orchestrator.F5Orchestrator.Management"; @@ -86,6 +87,7 @@ protected void ParseStoreProperties() SyncDevice = properties.SyncDevice == null || string.IsNullOrEmpty(properties.SyncDevice.Value) ? false : bool.Parse(properties.SyncDevice.Value); if (SyncDevice) SyncDeviceGroup = properties.SyncDeviceGroup == null || string.IsNullOrEmpty(properties.SyncDeviceGroup.Value) ? string.Empty : properties.SyncDeviceGroup.Value.ToString(); + InheritedProfile = properties.InheritedProfile == null || string.IsNullOrEmpty(properties.InheritedProfile.Value) ? string.Empty : properties.InheritedProfile.Value.ToString(); LogHandlerCommon.Trace(logger, JobConfig.CertificateStoreDetails, $"Ignore SSL Warnings '{IgnoreSSLWarning.ToString()}'"); } diff --git a/Profile/Management.cs b/Profile/Management.cs index c3c2c40..bd25614 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -22,7 +22,6 @@ public class Management : ManagementBase protected string ProfileName { get; set; } protected F5ProfileStorePath.ProfileTypeEnum ProfileType { get; set; } protected string ProfileEndpoint { get; set; } - protected string InheritedProfile { get; set; } public Management(IPAMSecretResolver resolver) { @@ -62,7 +61,6 @@ public override JobResult ProcessJob(ManagementJobConfiguration config) ProfileName = profileStorePath.ProfileName; ProfileType = profileStorePath.ProfileType; ProfileEndpoint = F5Client.GetProfileEndpoint(ProfileType); - InheritedProfile = profileStorePath.InheritedProfile; JobResult warningResult = null; switch (config.OperationType) diff --git a/integration-manifest.json b/integration-manifest.json index 5889c97..f7025e8 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -218,6 +218,15 @@ "Required": true, "Description": "Select this if you wish to use F5's token authentication 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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used." + }, { "Name": "ServerUsername", "DisplayName": "Server Username", From f272ccfd68986ebc6aa927164cceff0df280f93a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 21 Aug 2026 13:24:41 +0000 Subject: [PATCH 19/26] docs: auto-generate README and documentation [skip ci] --- README.md | 10 ++++ ...T-custom-field-InheritedProfile-dialog.svg | 49 +++++++++++++++++++ ...ritedProfile-validation-options-dialog.svg | 39 +++++++++++++++ ...F-REST-custom-fields-store-type-dialog.svg | 28 +++++++---- .../bash/curl_create_store_types.sh | 9 ++++ .../restmethod_create_store_types.ps1 | 9 ++++ 6 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-InheritedProfile-validation-options-dialog.svg diff --git a/README.md b/README.md index f2e44a5..33ed564 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,7 @@ the Keyfactor Command Portal | ---- | ------------ | ---- | --------------------- | -------- | ----------- | | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | | UseTokenAuth | Use Token Authentication | Select this if you wish to use F5's token authentication 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. | Bool | false | ✅ Checked | + | InheritedProfile | Profile to Inherit | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | String | | 🔲 Unchecked | | ServerUsername | Server Username | Login credential for the F5 device. MUST be an Admin account. | Secret | | 🔲 Unchecked | | ServerPassword | Server Password | Login password for the F5 device. | Secret | | 🔲 Unchecked | | ServerUseSsl | Use SSL | True if using https to access the F5 device. False if using http. | Bool | true | ✅ Checked | @@ -387,6 +388,13 @@ the Keyfactor Command Portal ![F5-PF-REST Custom Field - UseTokenAuth](docsource/images/F5-PF-REST-custom-field-UseTokenAuth-validation-options-dialog.svg) + ###### Profile to Inherit + The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. + + ![F5-PF-REST Custom Field - InheritedProfile](docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg) + ![F5-PF-REST Custom Field - InheritedProfile](docsource/images/F5-PF-REST-custom-field-InheritedProfile-validation-options-dialog.svg) + + ###### Server Username Login credential for the F5 device. MUST be an Admin account. @@ -927,6 +935,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | IgnoreSSLWarning | 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. | | UseTokenAuth | Select this if you wish to use F5's token authentication 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. | + | InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | | ServerUsername | Login credential for the F5 device. MUST be an Admin account. | | ServerPassword | Login password for the F5 device. | | ServerUseSsl | True if using https to access the F5 device. False if using http. | @@ -956,6 +965,7 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | | Properties.IgnoreSSLWarning | 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. | | Properties.UseTokenAuth | Select this if you wish to use F5's token authentication 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. | + | Properties.InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | | Properties.ServerUsername | Login credential for the F5 device. MUST be an Admin account. | | Properties.ServerPassword | Login password for the F5 device. | | Properties.ServerUseSsl | True if using https to access the F5 device. False if using http. | diff --git a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg new file mode 100644 index 0000000..b90f214 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg @@ -0,0 +1,49 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + InheritedProfile + Display Name + + Profile to Inherit + Type + + String + + Default Value + + + Depends On + + + Ignore SSL Warning + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-validation-options-dialog.svg new file mode 100644 index 0000000..22f8bbd --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + + Optional + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg index c9f4d77..c9d0589 100644 --- a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -1,5 +1,5 @@  - + - + Edit Certificate Store Type @@ -24,7 +24,7 @@ Entry Parameters - + @@ -33,7 +33,7 @@ EDIT DELETE - Total: 5 + Total: 6 Display Name @@ -67,15 +67,15 @@ - Server Username - Secret + Profile to Inherit + String - Server Password + Server Username Secret @@ -83,7 +83,15 @@ - Use SSL - Bool - true + Server Password + Secret + + + + + + + Use SSL + Bool + true \ No newline at end of file diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index 864e42d..0f9c181 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -219,6 +219,15 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate "Required": true, "Description": "Select this if you wish to use F5's token authentication 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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used." + }, { "Name": "ServerUsername", "DisplayName": "Server Username", diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 index 37fe785..b8acac7 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -219,6 +219,15 @@ $Body = @' "Required": true, "Description": "Select this if you wish to use F5's token authentication 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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used." + }, { "Name": "ServerUsername", "DisplayName": "Server Username", From 8a8a90148e19cfd8a688153339ed60e3020d5fca Mon Sep 17 00:00:00 2001 From: leefine02 Date: Fri, 21 Aug 2026 13:49:46 +0000 Subject: [PATCH 20/26] ab93116 --- F5Client.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/F5Client.cs b/F5Client.cs index b695715..5b75a14 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -560,7 +560,7 @@ public string GetPartitionFromStorePath() public F5ProfileStorePath ParseProfileStorePath() { LogHandlerCommon.MethodEntry(logger, CertificateStore, "ParseProfileStorePath"); - string[] pathParts = CertificateStore.StorePath.Split('\\'); + string[] pathParts = CertificateStore.StorePath.Split('/'); if (pathParts.Length < 3 || pathParts.Length > 4) { throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); From f2866e24db52112b72adb0cc9d16bd249d1f9165 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 26 Aug 2026 17:52:52 +0000 Subject: [PATCH 21/26] ab93116 --- F5Client.cs | 10 +- docsource/f5-pf-rest.md | 20 +-- integration-manifest.json | 333 +++++++++++++++++++++----------------- 3 files changed, 198 insertions(+), 165 deletions(-) diff --git a/F5Client.cs b/F5Client.cs index 5b75a14..6ffa261 100644 --- a/F5Client.cs +++ b/F5Client.cs @@ -561,22 +561,22 @@ public F5ProfileStorePath ParseProfileStorePath() { LogHandlerCommon.MethodEntry(logger, CertificateStore, "ParseProfileStorePath"); string[] pathParts = CertificateStore.StorePath.Split('/'); - if (pathParts.Length < 3 || pathParts.Length > 4) + if (pathParts.Length != 3) { - throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileName\\ProfileType' or 'Partition\\ProfileName\\ProfileType\\InheritedProfile'."); + throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileType\\ProfileName'"); } - if (!Enum.TryParse(pathParts[2], ignoreCase: true, out var profileType) || + if (!Enum.TryParse(pathParts[1], ignoreCase: true, out var profileType) || !Enum.IsDefined(typeof(ProfileTypeEnum), profileType)) { - throw new Exception($"Invalid value for profile type: {pathParts[2]}"); + throw new Exception($"Invalid value for profile type: {pathParts[1]}"); } F5ProfileStorePath profileStorePath = new F5ProfileStorePath { Partition = pathParts[0], - ProfileName = pathParts[1], ProfileType = profileType, + ProfileName = pathParts[2], }; LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); diff --git a/docsource/f5-pf-rest.md b/docsource/f5-pf-rest.md index 7ec5382..f1e33bf 100644 --- a/docsource/f5-pf-rest.md +++ b/docsource/f5-pf-rest.md @@ -1,20 +1,8 @@ ## Overview -TODO Overview is a required section +The F5-PF-REST certificate store type manages the certificate bound to a single F5 Big IP SSL Profile (client or server only). Adding a certificate to this store will both add the certificate to the F5 Big IP device as well as bind it to +the SSL Profile identified in the Keyfactor Command certificate store configuration. Inventory, Create, and Add (both new certificates and replace/renew) capabilities are supported, but Removal is not, as that would leave an SSL Profile unbound. +The certificate store configuration maps to the SSL Profile being managed by way of the Client Machine (IP address or DNS of the F5 instance being managed) and the Store Path which needs to have the format of "Partition/SSLProfileType/SSLProfileName" where +SSLProfileType **must** be either "Client" or "Server". -## Requirements - -TODO Requirements is an optional section. If this section doesn't seem necessary, please delete it. - -## Discovery Job Configuration - -TODO Discovery Job Configuration is an optional section. If this section doesn't seem necessary, please delete it. - -## Certificate Store Configuration - -TODO Certificate Store Configuration is an optional section. If this section doesn't seem necessary, please delete it. - -## Global Store Type Section - -TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. diff --git a/integration-manifest.json b/integration-manifest.json index f7025e8..0ec1b00 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -172,34 +172,189 @@ } ] }, + { + "Name": "F5 Profiles REST", + "ShortName": "F5-PF-REST", + "Capability": "F5-PF-REST", + "ServerRequired": true, + "BlueprintAllowed": true, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "ClientMachineDescription": "The server name or IP Address for the F5 device.", + "StorePathDescription": "Enter the store path in the form 'Partition/ProfileType/ProfileName'. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\".", + "SupportedOperations": { + "Add": true, + "Create": true, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "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\".", + "IsPAMEligible": true + } + }, + "Properties": [ + { + "Name": "PrimaryNode", + "DisplayName": "Primary Node", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "", + "Required": true, + "Description": "Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive." + }, + { + "Name": "PrimaryNodeCheckRetryWaitSecs", + "DisplayName": "Primary Node Check Retry Wait Seconds", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "120", + "Required": true, + "Description": "Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive." + }, + { + "Name": "PrimaryNodeCheckRetryMax", + "DisplayName": "Primary Node Check Retry Maximum", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "3", + "Required": true, + "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." + }, + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, + { + "Name": "IgnoreSSLWarning", + "DisplayName": "Ignore SSL Warning", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "False", + "Required": true, + "Description": "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." + }, + { + "Name": "UseTokenAuth", + "DisplayName": "Use Token Authentication", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "false", + "Required": true, + "Description": "Select this if you wish to use F5's token authentication 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." + }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used." + }, + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login credential for the F5 device. MUST be an Admin account." + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "IsPAMEligible": true, + "Required": false, + "Description": "Login password for the F5 device." + }, + { + "Name": "ServerUseSsl", + "DisplayName": "Use SSL", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "true", + "Required": true, + "Description": "True if using https to access the F5 device. False if using http." + } + ], + "EntryParameters": [] + }, { - "Name": "F5 Profiles REST", - "ShortName": "F5-PF-REST", - "Capability": "F5-PF-REST", + "Name": "F5 WS Profiles REST", + "ShortName": "F5-WS-REST", + "Capability": "F5-WS-REST", "ServerRequired": true, "BlueprintAllowed": true, - "CustomAliasAllowed": "Required", + "CustomAliasAllowed": "Forbidden", "PowerShell": false, "PrivateKeyAllowed": "Required", "ClientMachineDescription": "The server name or IP Address for the F5 device.", - "StorePathDescription": "Enter the store path in the form 'Partition\\ProfileName\\ProfileType\\InheritedProfile', delimited by the backslash (\\) character. Partition and Profile Name are case sensitive. ProfileType must be either \"Client\" or \"Server\". InheritedProfile is optional; if omitted, F5 default logic will be used.", + "StorePathDescription": "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\",", "SupportedOperations": { "Add": true, - "Create": true, - "Discovery": true, + "Create": false, + "Discovery": false, "Enrollment": false, - "Remove": true + "Remove": false }, "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true, - "StorePassword": { - "Description": "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\".", - "IsPAMEligible": true - } + "StoreRequired": false }, "Properties": [ + { + "Name": "PrimaryNode", + "DisplayName": "Primary Node", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "", + "Required": true, + "Description": "Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive." + }, + { + "Name": "PrimaryNodeCheckRetryWaitSecs", + "DisplayName": "Primary Node Check Retry Wait Seconds", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "120", + "Required": true, + "Description": "Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive." + }, + { + "Name": "PrimaryNodeCheckRetryMax", + "DisplayName": "Primary Node Check Retry Maximum", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "3", + "Required": true, + "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." + }, + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", @@ -216,16 +371,7 @@ "DependsOn": "", "DefaultValue": "false", "Required": true, - "Description": "Select this if you wish to use F5's token authentication 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." - }, - { - "Name": "InheritedProfile", - "DisplayName": "Profile to Inherit", - "Type": "String", - "DependsOn": "", - "DefaultValue": "", - "Required": false, - "Description": "The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used." + "Description": "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." }, { "Name": "ServerUsername", @@ -260,28 +406,29 @@ "EntryParameters": [] }, { - "Name": "F5 WS Profiles REST", - "ShortName": "F5-WS-REST", - "Capability": "F5-WS-REST", + "Name": "F5 CA Profiles REST", + "ShortName": "F5-CA-REST", + "Capability": "F5-CA-REST", "ServerRequired": true, - "BlueprintAllowed": true, - "CustomAliasAllowed": "Forbidden", - "PowerShell": false, - "PrivateKeyAllowed": "Required", "ClientMachineDescription": "The server name or IP Address for the F5 device.", - "StorePathDescription": "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\",", + "StorePathDescription": "Enter the name of the partition followed by the name of the bundle separated by a / (i.e. Common/BundleName). This value is case sensitive, so if the partition name is \"Common/BundleName\", it must be entered as \"Common/BundleName\" and not \"common/bundlename\",", "SupportedOperations": { "Add": true, "Create": false, - "Discovery": false, + "Discovery": true, "Enrollment": false, - "Remove": false + "Remove": true }, "PasswordOptions": { "Style": "Default", "EntrySupported": false, "StoreRequired": false }, + "PrivateKeyAllowed": "Forbidden", + "JobProperties": [], + "PowerShell": false, + "BlueprintAllowed": true, + "CustomAliasAllowed": "Required", "Properties": [ { "Name": "PrimaryNode", @@ -319,6 +466,15 @@ "Required": true, "Description": "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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", @@ -368,117 +524,6 @@ } ], "EntryParameters": [] - }, - { - "Name": "F5 CA Profiles REST", - "ShortName": "F5-CA-REST", - "Capability": "F5-CA-REST", - "ServerRequired": true, - "ClientMachineDescription": "The server name or IP Address for the F5 device.", - "StorePathDescription": "Enter the name of the partition followed by the name of the bundle separated by a / (i.e. Common/BundleName). This value is case sensitive, so if the partition name is \"Common/BundleName\", it must be entered as \"Common/BundleName\" and not \"common/bundlename\",", - "SupportedOperations": { - "Add": true, - "Create": false, - "Discovery": true, - "Enrollment": false, - "Remove": true - }, - "PasswordOptions": { - "Style": "Default", - "EntrySupported": false, - "StoreRequired": false - }, - "PrivateKeyAllowed": "Forbidden", - "JobProperties": [], - "PowerShell": false, - "BlueprintAllowed": true, - "CustomAliasAllowed": "Required", - "Properties": [ - { - "Name": "PrimaryNode", - "DisplayName": "Primary Node", - "Type": "String", - "DependsOn": "PrimaryNodeOnlineRequired", - "DefaultValue": "", - "Required": true, - "Description": "Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive." - }, - { - "Name": "PrimaryNodeCheckRetryWaitSecs", - "DisplayName": "Primary Node Check Retry Wait Seconds", - "Type": "String", - "DependsOn": "PrimaryNodeOnlineRequired", - "DefaultValue": "120", - "Required": true, - "Description": "Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive." - }, - { - "Name": "PrimaryNodeCheckRetryMax", - "DisplayName": "Primary Node Check Retry Maximum", - "Type": "String", - "DependsOn": "PrimaryNodeOnlineRequired", - "DefaultValue": "3", - "Required": true, - "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." - }, - { - "Name": "PrimaryNodeOnlineRequired", - "DisplayName": "Primary Node Online Required", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "", - "Required": true, - "Description": "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." - }, - { - "Name": "IgnoreSSLWarning", - "DisplayName": "Ignore SSL Warning", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "False", - "Required": true, - "Description": "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." - }, - { - "Name": "UseTokenAuth", - "DisplayName": "Use Token Authentication", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "false", - "Required": true, - "Description": "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." - }, - { - "Name": "ServerUsername", - "DisplayName": "Server Username", - "Type": "Secret", - "DependsOn": "", - "DefaultValue": "", - "IsPAMEligible": true, - "Required": false, - "Description": "Login credential for the F5 device. MUST be an Admin account." - }, - { - "Name": "ServerPassword", - "DisplayName": "Server Password", - "Type": "Secret", - "DependsOn": "", - "DefaultValue": "", - "IsPAMEligible": true, - "Required": false, - "Description": "Login password for the F5 device." - }, - { - "Name": "ServerUseSsl", - "DisplayName": "Use SSL", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "true", - "Required": true, - "Description": "True if using https to access the F5 device. False if using http." - } - ], - "EntryParameters": [] } ] } From 58370bb0fbd26e936bc6bdf1ae2bf54b9564902f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 26 Aug 2026 17:53:43 +0000 Subject: [PATCH 22/26] docs: auto-generate README and documentation [skip ci] --- README.md | 74 ++++++++++++++----- ...T-custom-field-InheritedProfile-dialog.svg | 49 ++++++++++++ ...ritedProfile-validation-options-dialog.svg | 39 ++++++++++ ...A-REST-custom-fields-store-type-dialog.svg | 38 ++++++---- ...T-custom-field-IgnoreSSLWarning-dialog.svg | 2 +- ...T-custom-field-InheritedProfile-dialog.svg | 2 +- ...F-REST-custom-field-PrimaryNode-dialog.svg | 50 +++++++++++++ ...-PrimaryNode-validation-options-dialog.svg | 39 ++++++++++ ...-field-PrimaryNodeCheckRetryMax-dialog.svg | 50 +++++++++++++ ...heckRetryMax-validation-options-dialog.svg | 39 ++++++++++ ...d-PrimaryNodeCheckRetryWaitSecs-dialog.svg | 50 +++++++++++++ ...etryWaitSecs-validation-options-dialog.svg | 39 ++++++++++ ...field-PrimaryNodeOnlineRequired-dialog.svg | 54 ++++++++++++++ ...lineRequired-validation-options-dialog.svg | 39 ++++++++++ ...-REST-custom-field-ServerUseSsl-dialog.svg | 2 +- ...-REST-custom-field-UseTokenAuth-dialog.svg | 2 +- ...F-REST-custom-fields-store-type-dialog.svg | 68 ++++++++++++----- .../bash/curl_create_store_types.sh | 45 +++++++++++ .../restmethod_create_store_types.ps1 | 45 +++++++++++ 19 files changed, 672 insertions(+), 54 deletions(-) create mode 100644 docsource/images/F5-CA-REST-custom-field-InheritedProfile-dialog.svg create mode 100644 docsource/images/F5-CA-REST-custom-field-InheritedProfile-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNode-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNode-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-validation-options-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg create mode 100644 docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg diff --git a/README.md b/README.md index 33ed564..40063ec 100644 --- a/README.md +++ b/README.md @@ -274,13 +274,10 @@ the Keyfactor Command Portal
Click to expand details -TODO Overview is a required section - -TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. - -#### F5 Profiles REST Requirements - -TODO Requirements is an optional section. If this section doesn't seem necessary, please delete it. +The F5-PF-REST certificate store type manages the certificate bound to a single F5 Big IP SSL Profile (client or server only). Adding a certificate to this store will both add the certificate to the F5 Big IP device as well as bind it to +the SSL Profile identified in the Keyfactor Command certificate store configuration. Inventory, Create, and Add (both new certificates and replace/renew) capabilities are supported, but Removal is not, as that would leave an SSL Profile unbound. +The certificate store configuration maps to the SSL Profile being managed by way of the Client Machine (IP address or DNS of the F5 instance being managed) and the Store Path which needs to have the format of "Partition/SSLProfileType/SSLProfileName" where +SSLProfileType **must** be either "Client" or "Server". #### Supported Operations @@ -363,6 +360,10 @@ the Keyfactor Command Portal | Name | Display Name | Description | Type | Default Value/Options | Required | | ---- | ------------ | ---- | --------------------- | -------- | ----------- | + | PrimaryNode | Primary Node | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | String | | ✅ Checked | + | PrimaryNodeCheckRetryWaitSecs | Primary Node Check Retry Wait Seconds | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | String | 120 | ✅ Checked | + | PrimaryNodeCheckRetryMax | Primary Node Check Retry Maximum | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | String | 3 | ✅ Checked | + | PrimaryNodeOnlineRequired | Primary Node Online Required | 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. | Bool | | ✅ Checked | | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | | UseTokenAuth | Use Token Authentication | Select this if you wish to use F5's token authentication 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. | Bool | false | ✅ Checked | | InheritedProfile | Profile to Inherit | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | String | | 🔲 Unchecked | @@ -374,6 +375,34 @@ the Keyfactor Command Portal ![F5-PF-REST Custom Fields Tab](docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg) + ###### Primary Node + Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. + + ![F5-PF-REST Custom Field - PrimaryNode](docsource/images/F5-PF-REST-custom-field-PrimaryNode-dialog.svg) + ![F5-PF-REST Custom Field - PrimaryNode](docsource/images/F5-PF-REST-custom-field-PrimaryNode-validation-options-dialog.svg) + + + ###### Primary Node Check Retry Wait Seconds + Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. + + ![F5-PF-REST Custom Field - PrimaryNodeCheckRetryWaitSecs](docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-dialog.svg) + ![F5-PF-REST Custom Field - PrimaryNodeCheckRetryWaitSecs](docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-validation-options-dialog.svg) + + + ###### Primary Node Check Retry Maximum + Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. + + ![F5-PF-REST Custom Field - PrimaryNodeCheckRetryMax](docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-dialog.svg) + ![F5-PF-REST Custom Field - PrimaryNodeCheckRetryMax](docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg) + + + ###### Primary Node Online Required + 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. + + ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg) + ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg) + + ###### Ignore SSL Warning 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. @@ -681,6 +710,7 @@ the Keyfactor Command Portal | PrimaryNodeCheckRetryWaitSecs | Primary Node Check Retry Wait Seconds | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | String | 120 | ✅ Checked | | PrimaryNodeCheckRetryMax | Primary Node Check Retry Maximum | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | String | 3 | ✅ Checked | | PrimaryNodeOnlineRequired | Primary Node Online Required | 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. | Bool | | ✅ Checked | + | InheritedProfile | Profile to Inherit | Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition. | String | | 🔲 Unchecked | | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | | UseTokenAuth | Use Token Authentication | 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. | Bool | false | ✅ Checked | | ServerUsername | Server Username | Login credential for the F5 device. MUST be an Admin account. | Secret | | 🔲 Unchecked | @@ -719,6 +749,13 @@ the Keyfactor Command Portal ![F5-CA-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-CA-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg) + ###### Profile to Inherit + Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition. + + ![F5-CA-REST Custom Field - InheritedProfile](docsource/images/F5-CA-REST-custom-field-InheritedProfile-dialog.svg) + ![F5-CA-REST Custom Field - InheritedProfile](docsource/images/F5-CA-REST-custom-field-InheritedProfile-validation-options-dialog.svg) + + ###### Ignore SSL Warning 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. @@ -907,10 +944,6 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
F5 Profiles REST (F5-PF-REST) -TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. - -TODO Certificate Store Configuration is an optional section. If this section doesn't seem necessary, please delete it. - ### Store Creation #### Manually with the Command UI @@ -930,9 +963,13 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition/ProfileType/ProfileName'. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | PrimaryNode | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | + | PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | + | PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | + | PrimaryNodeOnlineRequired | 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. | | IgnoreSSLWarning | 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. | | UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | @@ -960,9 +997,13 @@ TODO Certificate Store Configuration is an optional section. If this section doe | Category | Select "F5 Profiles REST" or the customized certificate store name from the previous step. | | Container | Optional container to associate certificate store with. | | Client Machine | The server name or IP Address for the F5 device. | - | Store Path | Enter the store path in the form 'Partition\ProfileName\ProfileType\InheritedProfile', delimited by the backslash (\) character. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". InheritedProfile is optional; if omitted, F5 default logic will be used. | + | Store Path | Enter the store path in the form 'Partition/ProfileType/ProfileName'. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | Properties.PrimaryNode | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | + | Properties.PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | + | Properties.PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | + | Properties.PrimaryNodeOnlineRequired | 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. | | Properties.IgnoreSSLWarning | 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. | | Properties.UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | Properties.InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | @@ -1117,6 +1158,7 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov | PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | | PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | | PrimaryNodeOnlineRequired | 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. | + | InheritedProfile | Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition. | | IgnoreSSLWarning | 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. | | UseTokenAuth | 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. | | ServerUsername | Login credential for the F5 device. MUST be an Admin account. | @@ -1149,6 +1191,7 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov | Properties.PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | | Properties.PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | | Properties.PrimaryNodeOnlineRequired | 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. | + | Properties.InheritedProfile | Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition. | | Properties.IgnoreSSLWarning | 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. | | Properties.UseTokenAuth | 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. | | Properties.ServerUsername | Login credential for the F5 device. MUST be an Admin account. | @@ -1208,11 +1251,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. -### F5 Profiles REST Discovery Job - -TODO Global Store Type Section is an optional section. If this section doesn't seem necessary, please delete it. -TODO Discovery Job Configuration is an optional section. If this section doesn't seem necessary, please delete it. - ## Syncing To Device Group The "Sync To Device Group" feature, introduced in version 2.0 of this orchestrator extension for the F5-SL-REST store type (ssl certificate management), enables synchronization of the F5 Big-IP node managed by the Keyfactor Command certificate store with a secondary node that is part of the F5 device group specified in the associated "Device Group" certificate store setting. diff --git a/docsource/images/F5-CA-REST-custom-field-InheritedProfile-dialog.svg b/docsource/images/F5-CA-REST-custom-field-InheritedProfile-dialog.svg new file mode 100644 index 0000000..fd52990 --- /dev/null +++ b/docsource/images/F5-CA-REST-custom-field-InheritedProfile-dialog.svg @@ -0,0 +1,49 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + InheritedProfile + Display Name + + Profile to Inherit + Type + + String + + Default Value + + + Depends On + + + Primary Node + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-CA-REST-custom-field-InheritedProfile-validation-options-dialog.svg b/docsource/images/F5-CA-REST-custom-field-InheritedProfile-validation-options-dialog.svg new file mode 100644 index 0000000..22f8bbd --- /dev/null +++ b/docsource/images/F5-CA-REST-custom-field-InheritedProfile-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + + Optional + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-CA-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-CA-REST-custom-fields-store-type-dialog.svg index e245095..b00eafb 100644 --- a/docsource/images/F5-CA-REST-custom-fields-store-type-dialog.svg +++ b/docsource/images/F5-CA-REST-custom-fields-store-type-dialog.svg @@ -1,5 +1,5 @@  - + - + Edit Certificate Store Type @@ -24,7 +24,7 @@ Entry Parameters - + @@ -33,7 +33,7 @@ EDIT DELETE - Total: 9 + Total: 10 Display Name @@ -83,33 +83,33 @@ - Ignore SSL Warning - Bool - False + Profile to Inherit + String - Use Token Authentication + Ignore SSL Warning Bool - false + False - Server Username - Secret + Use Token Authentication + Bool + false - Server Password + Server Username Secret @@ -117,7 +117,15 @@ - Use SSL - Bool - true + Server Password + Secret + + + + + + + Use SSL + Bool + true \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg index 935afe7..ddba07e 100644 --- a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg @@ -44,7 +44,7 @@ Depends On - Use Token Authentication + Primary Node diff --git a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg index b90f214..fd52990 100644 --- a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg @@ -39,7 +39,7 @@ Depends On - Ignore SSL Warning + Primary Node diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNode-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNode-dialog.svg new file mode 100644 index 0000000..17e8a0f --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNode-dialog.svg @@ -0,0 +1,50 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + PrimaryNode + Display Name + + Primary Node + Type + + String + + Default Value + + + Depends On + + + + Primary Node Online Required + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNode-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNode-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNode-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-dialog.svg new file mode 100644 index 0000000..1827996 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-dialog.svg @@ -0,0 +1,50 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + PrimaryNodeCheckRetryMax + Display Name + + Primary Node Check Retry Maximum + Type + + String + + Default Value + + 3 + Depends On + + + + Primary Node Online Required + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-dialog.svg new file mode 100644 index 0000000..bd941e2 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-dialog.svg @@ -0,0 +1,50 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + PrimaryNodeCheckRetryWaitSecs + Display Name + + Primary Node Check Retry Wait Seconds + Type + + String + + Default Value + + 120 + Depends On + + + + Primary Node Online Required + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryWaitSecs-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg new file mode 100644 index 0000000..503a090 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg @@ -0,0 +1,54 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + + Validation Options + + Name + + PrimaryNodeOnlineRequired + Display Name + + Primary Node Online Required + Type + + Bool + + Default Value + + True + + False + + + Not Set + Depends On + + + Primary Node + + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg new file mode 100644 index 0000000..7993c23 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg @@ -0,0 +1,39 @@ + + + + + + + + + Edit Custom Field + × + + + + Basic Information + Validation Options + + + Creating a certificate store + + Optional + + + Required + + Hidden + + + CANCEL + + SAVE + \ No newline at end of file diff --git a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg index 629e39b..89779b2 100644 --- a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg @@ -44,7 +44,7 @@ Depends On - Ignore SSL Warning + Primary Node diff --git a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg index 563662e..d403b9a 100644 --- a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg @@ -44,7 +44,7 @@ Depends On - Ignore SSL Warning + Primary Node diff --git a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg index c9d0589..4112f44 100644 --- a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -1,5 +1,5 @@  - + - + Edit Certificate Store Type @@ -24,7 +24,7 @@ Entry Parameters - + @@ -33,7 +33,7 @@ EDIT DELETE - Total: 6 + Total: 10 Display Name @@ -49,49 +49,83 @@ - Ignore SSL Warning - Bool - False + Primary Node + String - Use Token Authentication - Bool - false + Primary Node Check Retry Wait Seco... + String + 120 - Profile to Inherit + Primary Node Check Retry Maximum String + 3 - Server Username - Secret + Primary Node Online Required + Bool - Server Password - Secret + Ignore SSL Warning + Bool + False - Use SSL + Use Token Authentication Bool - true + false + + + + + + + Profile to Inherit + String + + + + + + + Server Username + Secret + + + + + + + Server Password + Secret + + + + + + + Use SSL + Bool + true \ No newline at end of file diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index 0f9c181..fc65d02 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -201,6 +201,42 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate } }, "Properties": [ + { + "Name": "PrimaryNode", + "DisplayName": "Primary Node", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "", + "Required": true, + "Description": "Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive." + }, + { + "Name": "PrimaryNodeCheckRetryWaitSecs", + "DisplayName": "Primary Node Check Retry Wait Seconds", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "120", + "Required": true, + "Description": "Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive." + }, + { + "Name": "PrimaryNodeCheckRetryMax", + "DisplayName": "Primary Node Check Retry Maximum", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "3", + "Required": true, + "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." + }, + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", @@ -439,6 +475,15 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate "Required": true, "Description": "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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 index b8acac7..3d5f39c 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -201,6 +201,42 @@ $Body = @' } }, "Properties": [ + { + "Name": "PrimaryNode", + "DisplayName": "Primary Node", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "", + "Required": true, + "Description": "Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive." + }, + { + "Name": "PrimaryNodeCheckRetryWaitSecs", + "DisplayName": "Primary Node Check Retry Wait Seconds", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "120", + "Required": true, + "Description": "Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive." + }, + { + "Name": "PrimaryNodeCheckRetryMax", + "DisplayName": "Primary Node Check Retry Maximum", + "Type": "String", + "DependsOn": "PrimaryNodeOnlineRequired", + "DefaultValue": "3", + "Required": true, + "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." + }, + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", @@ -439,6 +475,15 @@ $Body = @' "Required": true, "Description": "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." }, + { + "Name": "InheritedProfile", + "DisplayName": "Profile to Inherit", + "Type": "String", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "Description": "Optional value representing an existing SSL Profile to inherit settings from during a Management-Create job. Value must be in Partition/SSLProfileName format. Profile must be the same type as the one being added and exist in the same partition or the Common partition." + }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", From c223282274d7e5471137d00efdf321339dc36cf5 Mon Sep 17 00:00:00 2001 From: leefine02 Date: Wed, 26 Aug 2026 18:39:24 +0000 Subject: [PATCH 23/26] ab93116 --- integration-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-manifest.json b/integration-manifest.json index 0ec1b00..e6fb385 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -168,7 +168,7 @@ "DependsOn": "", "DefaultValue": "", "Options": "", - "Description": "One to many comma delimited F5 SSL Profiles to bind the certificate to (new certificates ONLY)" + "Description": "One to many comma delimited F5 SSL Profiles to bind the certificate to (new certificates ONLY)" } ] }, From 3ad3f38e8bdd193da0ccb56379b59f83cf0b721e Mon Sep 17 00:00:00 2001 From: leefine02 Date: Thu, 27 Aug 2026 12:24:52 +0000 Subject: [PATCH 24/26] ab93116 --- Profile/Management.cs | 10 +++++----- integration-manifest.json | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Profile/Management.cs b/Profile/Management.cs index bd25614..0c3a39c 100644 --- a/Profile/Management.cs +++ b/Profile/Management.cs @@ -73,13 +73,13 @@ public override JobResult ProcessJob(ManagementJobConfiguration config) LogHandlerCommon.Debug(logger, config.CertificateStoreDetails, $"Add entry '{config.JobCertificate.Alias}' to '{config.CertificateStoreDetails.StorePath}'"); PerformAddJob(f5, partition, StorePassword); break; - case CertStoreOperationType.Remove: - LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'"); - warningResult = PerformRemovalJob(f5, partition); - break; + //case CertStoreOperationType.Remove: + // LogHandlerCommon.Trace(logger, config.CertificateStoreDetails, $"Remove entry '{config.JobCertificate.Alias}' from '{config.CertificateStoreDetails.StorePath}'"); + // warningResult = PerformRemovalJob(f5, partition); + // break; default: // Shouldn't get here, but just in case - throw new Exception($"Management job expecting 'Add', 'Remove' or 'Create' job - received '{Enum.GetName(typeof(CertStoreOperationType), config.OperationType)}'"); + throw new Exception($"Management job expecting 'Add' or 'Create' job - received '{Enum.GetName(typeof(CertStoreOperationType), config.OperationType)}'"); } if (UseTokenAuth) diff --git a/integration-manifest.json b/integration-manifest.json index e6fb385..ff8559e 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -188,7 +188,7 @@ "Create": true, "Discovery": true, "Enrollment": false, - "Remove": true + "Remove": false }, "PasswordOptions": { "Style": "Default", @@ -200,6 +200,15 @@ } }, "Properties": [ + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "PrimaryNode", "DisplayName": "Primary Node", @@ -227,15 +236,6 @@ "Required": true, "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." }, - { - "Name": "PrimaryNodeOnlineRequired", - "DisplayName": "Primary Node Online Required", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "", - "Required": true, - "Description": "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." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", From acf61279e5078ae9598fd8ade30c004076984f41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Aug 2026 12:25:32 +0000 Subject: [PATCH 25/26] docs: auto-generate README and documentation [skip ci] --- README.md | 24 +++++++++---------- .../F5-PF-REST-basic-store-type-dialog.svg | 3 +-- ...T-custom-field-IgnoreSSLWarning-dialog.svg | 2 +- ...T-custom-field-InheritedProfile-dialog.svg | 2 +- ...-REST-custom-field-ServerUseSsl-dialog.svg | 2 +- ...-REST-custom-field-UseTokenAuth-dialog.svg | 2 +- ...F-REST-custom-fields-store-type-dialog.svg | 16 ++++++------- .../bash/curl_create_store_types.sh | 20 ++++++++-------- .../restmethod_create_store_types.ps1 | 20 ++++++++-------- 9 files changed, 45 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 40063ec..29c6992 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,7 @@ SSLProfileType **must** be either "Client" or "Server". | Operation | Is Supported | |--------------|--------------| | Add | ✅ Checked | -| Remove | ✅ Checked | +| Remove | 🔲 Unchecked | | Discovery | ✅ Checked | | Reenrollment | 🔲 Unchecked | | Create | ✅ Checked | @@ -328,7 +328,7 @@ the Keyfactor Command Portal | Short Name | F5-PF-REST | Short display name for the store type | | Capability | F5-PF-REST | Store type name orchestrator will register with. Check the box to allow entry of value | | Supports Add | ✅ Checked | Indicates that the Store Type supports Management Add | - | Supports Remove | ✅ Checked | Indicates that the Store Type supports Management Remove | + | Supports Remove | 🔲 Unchecked | Indicates that the Store Type supports Management Remove | | Supports Discovery | ✅ Checked | Indicates that the Store Type supports Discovery | | Supports Reenrollment | 🔲 Unchecked | Indicates that the Store Type supports Reenrollment | | Supports Create | ✅ Checked | Indicates that the Store Type supports store creation | @@ -360,10 +360,10 @@ the Keyfactor Command Portal | Name | Display Name | Description | Type | Default Value/Options | Required | | ---- | ------------ | ---- | --------------------- | -------- | ----------- | + | PrimaryNodeOnlineRequired | Primary Node Online Required | 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. | Bool | | ✅ Checked | | PrimaryNode | Primary Node | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | String | | ✅ Checked | | PrimaryNodeCheckRetryWaitSecs | Primary Node Check Retry Wait Seconds | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | String | 120 | ✅ Checked | | PrimaryNodeCheckRetryMax | Primary Node Check Retry Maximum | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | String | 3 | ✅ Checked | - | PrimaryNodeOnlineRequired | Primary Node Online Required | 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. | Bool | | ✅ Checked | | IgnoreSSLWarning | Ignore SSL Warning | 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. | Bool | False | ✅ Checked | | UseTokenAuth | Use Token Authentication | Select this if you wish to use F5's token authentication 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. | Bool | false | ✅ Checked | | InheritedProfile | Profile to Inherit | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | String | | 🔲 Unchecked | @@ -375,6 +375,13 @@ the Keyfactor Command Portal ![F5-PF-REST Custom Fields Tab](docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg) + ###### Primary Node Online Required + 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. + + ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg) + ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg) + + ###### Primary Node Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. @@ -396,13 +403,6 @@ the Keyfactor Command Portal ![F5-PF-REST Custom Field - PrimaryNodeCheckRetryMax](docsource/images/F5-PF-REST-custom-field-PrimaryNodeCheckRetryMax-validation-options-dialog.svg) - ###### Primary Node Online Required - 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. - - ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-dialog.svg) - ![F5-PF-REST Custom Field - PrimaryNodeOnlineRequired](docsource/images/F5-PF-REST-custom-field-PrimaryNodeOnlineRequired-validation-options-dialog.svg) - - ###### Ignore SSL Warning 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. @@ -966,10 +966,10 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov | Store Path | Enter the store path in the form 'Partition/ProfileType/ProfileName'. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | PrimaryNodeOnlineRequired | 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. | | PrimaryNode | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | | PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | | PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | - | PrimaryNodeOnlineRequired | 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. | | IgnoreSSLWarning | 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. | | UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | @@ -1000,10 +1000,10 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov | Store Path | Enter the store path in the form 'Partition/ProfileType/ProfileName'. Partition and Profile Name are case sensitive. ProfileType must be either "Client" or "Server". | | Store Password | 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". | | Orchestrator | Select an approved orchestrator capable of managing `F5-PF-REST` certificates. Specifically, one with the `F5-PF-REST` capability. | + | Properties.PrimaryNodeOnlineRequired | 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. | | Properties.PrimaryNode | Only required (and shown) if Primary Node Online Required is added and selected. Enter the Host Name of the F5 device that acts as the primary node in a highly available F5 implementation. Please note that this value IS case sensitive. | | Properties.PrimaryNodeCheckRetryWaitSecs | Enter the number of seconds to wait between attempts to add/replace/renew a certificate if the node is inactive. | | Properties.PrimaryNodeCheckRetryMax | Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing. | - | Properties.PrimaryNodeOnlineRequired | 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. | | Properties.IgnoreSSLWarning | 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. | | Properties.UseTokenAuth | Select this if you wish to use F5's token authentication 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. | | Properties.InheritedProfile | The optional fully qualified name of the profile you want this profile to inherit settings from in {Partition}/{ProfileName} format. If left blank, the default profile for the profile type will be used. | diff --git a/docsource/images/F5-PF-REST-basic-store-type-dialog.svg b/docsource/images/F5-PF-REST-basic-store-type-dialog.svg index 1e5d0fe..4bb0b52 100644 --- a/docsource/images/F5-PF-REST-basic-store-type-dialog.svg +++ b/docsource/images/F5-PF-REST-basic-store-type-dialog.svg @@ -50,8 +50,7 @@ Add - - + Remove diff --git a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg index ddba07e..bc4ac16 100644 --- a/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-IgnoreSSLWarning-dialog.svg @@ -44,7 +44,7 @@ Depends On - Primary Node + Primary Node Online Required diff --git a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg index fd52990..52bf30c 100644 --- a/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg @@ -39,7 +39,7 @@ Depends On - Primary Node + Primary Node Online Required diff --git a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg index 89779b2..627e481 100644 --- a/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-ServerUseSsl-dialog.svg @@ -44,7 +44,7 @@ Depends On - Primary Node + Primary Node Online Required diff --git a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg index d403b9a..2006ecc 100644 --- a/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-field-UseTokenAuth-dialog.svg @@ -44,7 +44,7 @@ Depends On - Primary Node + Primary Node Online Required diff --git a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg index 4112f44..e8495a4 100644 --- a/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -49,34 +49,34 @@ - Primary Node - String + Primary Node Online Required + Bool - Primary Node Check Retry Wait Seco... + Primary Node String - 120 - Primary Node Check Retry Maximum + Primary Node Check Retry Wait Seco... String - 3 + 120 - Primary Node Online Required - Bool + Primary Node Check Retry Maximum + String + 3 diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index fc65d02..441be51 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -189,7 +189,7 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate "Create": true, "Discovery": true, "Enrollment": false, - "Remove": true + "Remove": false }, "PasswordOptions": { "Style": "Default", @@ -201,6 +201,15 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate } }, "Properties": [ + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "PrimaryNode", "DisplayName": "Primary Node", @@ -228,15 +237,6 @@ curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/Certificate "Required": true, "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." }, - { - "Name": "PrimaryNodeOnlineRequired", - "DisplayName": "Primary Node Online Required", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "", - "Required": true, - "Description": "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." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 index 3d5f39c..38471e3 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -189,7 +189,7 @@ $Body = @' "Create": true, "Discovery": true, "Enrollment": false, - "Remove": true + "Remove": false }, "PasswordOptions": { "Style": "Default", @@ -201,6 +201,15 @@ $Body = @' } }, "Properties": [ + { + "Name": "PrimaryNodeOnlineRequired", + "DisplayName": "Primary Node Online Required", + "Type": "Bool", + "DependsOn": "", + "DefaultValue": "", + "Required": true, + "Description": "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." + }, { "Name": "PrimaryNode", "DisplayName": "Primary Node", @@ -228,15 +237,6 @@ $Body = @' "Required": true, "Description": "Enter the number of times a Management-Add job will attempt to add/replace/renew a certificate if the node is inactive before failing." }, - { - "Name": "PrimaryNodeOnlineRequired", - "DisplayName": "Primary Node Online Required", - "Type": "Bool", - "DependsOn": "", - "DefaultValue": "", - "Required": true, - "Description": "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." - }, { "Name": "IgnoreSSLWarning", "DisplayName": "Ignore SSL Warning", From f5886e08e391b4e8de29180c7dfd01792d6a65ef Mon Sep 17 00:00:00 2001 From: leefine02 Date: Thu, 27 Aug 2026 13:06:55 +0000 Subject: [PATCH 26/26] ab93116 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 144f8eb..0257f3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +v2.1.0 +- Added new store type - F5-PF-REST - to manage the certificate bound to a single F5 Big IP SSL Profile (client or server only). + v2.0.0 - Add option to sync node to device group pre-set up in F5 device for F5-SL-REST store type.