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. diff --git a/F5Client.cs b/F5Client.cs index dcbcbb0..6ffa261 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 { @@ -42,6 +43,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; } @@ -206,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); } @@ -334,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)) { @@ -371,10 +376,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 +556,33 @@ 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) + { + throw new Exception($"The store path '{CertificateStore.StorePath}' is invalid. Expecting 'Partition\\ProfileType\\ProfileName'"); + } + + if (!Enum.TryParse(pathParts[1], ignoreCase: true, out var profileType) || + !Enum.IsDefined(typeof(ProfileTypeEnum), profileType)) + { + throw new Exception($"Invalid value for profile type: {pathParts[1]}"); + } + + F5ProfileStorePath profileStorePath = new F5ProfileStorePath + { + Partition = pathParts[0], + ProfileType = profileType, + ProfileName = pathParts[2], + }; + + LogHandlerCommon.MethodExit(logger, CertificateStore, "ParseProfileStorePath"); + return profileStorePath; + } + // Infrastructure #endregion @@ -733,6 +775,142 @@ 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(ProfileTypeEnum profileType) + { + return profileType == ProfileTypeEnum.Server ? 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}/~{profileName.Replace($"/","~")}"; + 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 = string.IsNullOrEmpty(inheritedProfile) ? null : $"/{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, 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); + + 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("none", 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..61f03e1 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 @@ -141,6 +146,16 @@ 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 + { + 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 @@ -180,6 +195,19 @@ public class F5Version public string selfLink { get; set; } } + public class F5ProfileStorePath + { + public enum ProfileTypeEnum + { + Client, + Server + } + + public string Partition { get; set; } + public string ProfileName { get; set; } + public ProfileTypeEnum ProfileType { get; set; } + } + public class SyncRequest { public SyncRequest(string deviceGroupName) 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/Discovery.cs b/Profile/Discovery.cs new file mode 100644 index 0000000..3f4e6ac --- /dev/null +++ b/Profile/Discovery.cs @@ -0,0 +1,101 @@ +// 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) + { + if (profile.defaultsFrom.Substring(0,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(profile.defaultsFrom) + ? $"{partition}\\{profile.name}\\{profileType}" + : $"{partition}\\{profile.name}\\{profileType}\\{profile.defaultsFrom}"; + 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..0c3a39c --- /dev/null +++ b/Profile/Management.cs @@ -0,0 +1,199 @@ +// 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 Management : ManagementBase + { + protected string ProfileName { get; set; } + protected F5ProfileStorePath.ProfileTypeEnum ProfileType { get; set; } + protected string ProfileEndpoint { 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); + 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); + 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' 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 }; + } + + 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"); + return null; + } + + private void PerformAddJob(F5Client f5, string partition, string certificatePassword) + { + LogHandlerCommon.MethodEntry(logger, JobConfig.CertificateStoreDetails, "PerformAddJob"); + string name = JobConfig.JobCertificate.Alias; + + string certContents = 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, certificatePassword, certificateExists); + + 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; + } + } +} diff --git a/README.md b/README.md index bb45754..29c6992 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,186 @@ the Keyfactor Command Portal +### F5-PF-REST + +
Click to expand details + +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 + +| Operation | Is Supported | +|--------------|--------------| +| Add | ✅ Checked | +| Remove | 🔲 Unchecked | +| 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 | 🔲 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 | + | 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 | + | ---- | ------------ | ---- | --------------------- | -------- | ----------- | + | 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 | + | 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 | + + 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) + + ###### 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. + + ![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) + + + ###### 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) + + + ###### 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. + + + > [!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 @@ -529,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 | @@ -567,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. @@ -617,8 +806,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. @@ -650,7 +839,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 +942,103 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
+
F5 Profiles REST (F5-PF-REST) + +### 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/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. | + | 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. | + +
+ +#### 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/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.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. | + +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 @@ -872,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. | @@ -904,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. | 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) { diff --git a/docsource/f5-pf-rest.md b/docsource/f5-pf-rest.md new file mode 100644 index 0000000..f1e33bf --- /dev/null +++ b/docsource/f5-pf-rest.md @@ -0,0 +1,8 @@ +## Overview + +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". + + 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-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..4bb0b52 --- /dev/null +++ b/docsource/images/F5-PF-REST-basic-store-type-dialog.svg @@ -0,0 +1,86 @@ + + + + + + + + + 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..bc4ac16 --- /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 + + + Primary Node Online Required + + + + 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-InheritedProfile-dialog.svg b/docsource/images/F5-PF-REST-custom-field-InheritedProfile-dialog.svg new file mode 100644 index 0000000..52bf30c --- /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 + + + Primary Node Online Required + + + + 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-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-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..627e481 --- /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 + + + Primary Node Online Required + + + + 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..2006ecc --- /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 + + + Primary Node Online Required + + + + 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..e8495a4 --- /dev/null +++ b/docsource/images/F5-PF-REST-custom-fields-store-type-dialog.svg @@ -0,0 +1,131 @@ + + + + + + + + + Edit Certificate Store Type + + + + Basic + Advanced + Custom Fields + + Entry Parameters + + + + + + ADD + + EDIT + + DELETE + Total: 10 + + + Display Name + Type + Default Value / Options + + + + + + + + + + + Primary Node Online Required + Bool + + + + + + + Primary Node + String + + + + + + + Primary Node Check Retry Wait Seco... + String + 120 + + + + + + + Primary Node Check Retry Maximum + String + 3 + + + + + + + Ignore SSL Warning + Bool + False + + + + + + + Use Token Authentication + Bool + false + + + + + + + Profile to Inherit + String + + + + + + + Server Username + Secret + + + + + + + Server Password + Secret + + + + + + + Use SSL + Bool + true + \ No newline at end of file diff --git a/integration-manifest.json b/integration-manifest.json index a249136..ff8559e 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -168,10 +168,133 @@ "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)" } ] }, + { + "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": 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 + } + }, + "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", + "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": "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 WS Profiles REST", "ShortName": "F5-WS-REST", @@ -306,91 +429,100 @@ "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." - } - ], + "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": "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", + "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": [] } ] 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" diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh index 965e30b..441be51 100755 --- a/scripts/store_types/bash/curl_create_store_types.sh +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -170,6 +170,133 @@ 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": 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 + } + }, + "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", + "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": "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": [] +}' + echo "Creating store type: F5-WS-REST" curl -s -X POST "https://${KEYFACTOR_HOSTNAME}/${KEYFACTOR_API_PATH}/CertificateStoreTypes" \ -H "Authorization: Bearer ${KEYFACTOR_AUTH_TOKEN}" \ @@ -348,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/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..38471e3 100644 --- a/scripts/store_types/powershell/restmethod_create_store_types.ps1 +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -173,6 +173,133 @@ $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": 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 + } + }, + "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", + "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": "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": [] +} +'@ + +Invoke-RestMethod -Uri "https://$KeyfactorHostname/$KeyfactorApiPath/CertificateStoreTypes" -Method POST -Headers $Headers -Body $Body + Write-Host "Creating store type: F5-WS-REST" $Body = @' { @@ -348,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",