diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..5a3e2d3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,2 @@
+v1.0
+- Initial Version
\ No newline at end of file
diff --git a/SampleOrchestratorExtension.sln b/F5BigIQ.sln
similarity index 83%
rename from SampleOrchestratorExtension.sln
rename to F5BigIQ.sln
index 27a5c1f..85f5659 100644
--- a/SampleOrchestratorExtension.sln
+++ b/F5BigIQ.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleOrchestratorExtension", "SampleOrchestratorExtension\SampleOrchestratorExtension.csproj", "{ECFD4531-6959-431C-8D5A-8CD62301A82A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F5BigIQ", "F5BigIQ\F5BigIQ.csproj", "{ECFD4531-6959-431C-8D5A-8CD62301A82A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/F5BigIQ/External References/Renci.SshNet.dll b/F5BigIQ/External References/Renci.SshNet.dll
new file mode 100644
index 0000000..d54ea22
Binary files /dev/null and b/F5BigIQ/External References/Renci.SshNet.dll differ
diff --git a/F5BigIQ/External References/SshNet.Security.Cryptography.dll b/F5BigIQ/External References/SshNet.Security.Cryptography.dll
new file mode 100644
index 0000000..2761fd1
Binary files /dev/null and b/F5BigIQ/External References/SshNet.Security.Cryptography.dll differ
diff --git a/F5BigIQ/External References/a.csv b/F5BigIQ/External References/a.csv
new file mode 100644
index 0000000..e098029
--- /dev/null
+++ b/F5BigIQ/External References/a.csv
@@ -0,0 +1,41 @@
+JToken,JToken._annotations,JToken.Type,JToken.HasValues,JToken.Path
+"""id"": ""77b14033-c68f-3682-ad21-de6a66d87d58""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,id
+"""kind"": ""cm:adc-core:working-config:ltm:virtual:adcvirtualstate""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,kind
+"""mask"": ""255.255.255.255""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,mask
+"""name"": ""Test""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,name
+"""nat64"": ""disabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,nat64
+"""state"": ""enabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,state
+"""mirror"": ""disabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,mirror
+"""gtmScore"": 0",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,gtmScore
+"""policies"": []",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,policies
+"""selfLink"": ""https://localhost/mgmt/cm/adc-core/working-config/ltm/virtual/77b14033-c68f-3682-ad21-de6a66d87d58""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,selfLink
+"""partition"": ""Common""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,partition
+"""rateLimit"": ""disabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,rateLimit
+"""generation"": 3",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,generation
+"""ipProtocol"": ""tcp""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,ipProtocol
+"""sourcePort"": ""preserve""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,sourcePort
+"""autoLasthop"": ""default""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,autoLasthop
+"""vlansEnabled"": ""disabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,vlansEnabled
+"""addressStatus"": ""yes""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,addressStatus
+"""rateLimitMode"": ""object""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,rateLimitMode
+"""sourceAddress"": ""0.0.0.0/0""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,sourceAddress
+"""translatePort"": ""enabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,translatePort
+"""connectionLimit"": 0",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,connectionLimit
+"""destinationPort"": ""443""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,destinationPort
+"""deviceReference"": {
+ ""id"": ""4c82397b-ce3f-4047-91b4-2273bf397cfa"",
+ ""kind"": ""shared:resolver:device-groups:restdeviceresolverdevicestate"",
+ ""link"": ""https://localhost/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/4c82397b-ce3f-4047-91b4-2273bf397cfa"",
+ ""name"": ""bigip1"",
+ ""machineId"": ""4c82397b-ce3f-4047-91b4-2273bf397cfa""
+}",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,deviceReference
+"""lastUpdateMicros"": 1708622484831738",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,lastUpdateMicros
+"""translateAddress"": ""enabled""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,translateAddress
+"""destinationAddress"": ""1.1.1.1""",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,destinationAddress
+"""sourceAddressTranslation"": {
+ ""type"": ""none""
+}",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,sourceAddressTranslation
+"""profilesCollectionReference"": {
+ ""link"": ""https://localhost/mgmt/cm/adc-core/working-config/ltm/virtual/77b14033-c68f-3682-ad21-de6a66d87d58/profiles"",
+ ""isSubcollection"": true
+}",Newtonsoft.Json.Linq.JToken+LineInfoAnnotation,Property,True,profilesCollectionReference
diff --git a/F5BigIQ/F5BigIQ.csproj b/F5BigIQ/F5BigIQ.csproj
new file mode 100644
index 0000000..9908713
--- /dev/null
+++ b/F5BigIQ/F5BigIQ.csproj
@@ -0,0 +1,29 @@
+
+
+
+ false
+ net6.0
+ true
+
+
+
+
+
+
+
+
+
+
+
+ External References\Renci.SshNet.dll
+
+
+ External References\SshNet.Security.Cryptography.dll
+
+
+
+
+
+
+
+
diff --git a/F5BigIQ/F5BigIQClient.cs b/F5BigIQ/F5BigIQClient.cs
new file mode 100644
index 0000000..e63f1b4
--- /dev/null
+++ b/F5BigIQ/F5BigIQClient.cs
@@ -0,0 +1,442 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+
+using Microsoft.Extensions.Logging;
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+using RestSharp;
+using RestSharp.Authenticators;
+
+using Renci.SshNet;
+
+using Keyfactor.Logging;
+using Keyfactor.PKI.X509;
+using Keyfactor.Extensions.Orchestrator.F5BigIQ.Models;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ internal class F5BigIQClient
+ {
+ private const string LOCAL_URL_VALUE = @"https://localhost";
+ private const string GET_ENDPOINT = "/mgmt/cm/adc-core/working-config/sys/file/ssl-cert";
+ private const string GET_KEY_ENDPOINT = "/mgmt/cm/adc-core/working-config/sys/file/ssl-key";
+ private const string GET_PROFILE_ENDPOINT = "/mgmt/cm/adc-core/working-config/ltm/profile/client-ssl";
+ private const string GET_VIRTUAL_SERVER_ENDPOINT = "/mgmt/cm/adc-core/working-config/ltm/virtual";
+ private const string POST_ENDPOINT = "/mgmt/cm/adc-core/tasks/certificate-management";
+ private const string POST_DEPLOY_ENDPOINT = "/mgmt/cm/adc-core/tasks/deploy-configuration";
+ private const string UPLOAD_FOLDER = "/var/config/rest/downloads";
+ private const int ITEMS_PER_PAGE = 50;
+ private const string ADD_COMMAND = "ADD_PKCS12";
+ private const string REPLACE_COMMAND = "REPLACE_PKCS12";
+ private const string ALIAS_SUFFIX = ".crt";
+ private const string ALIAS_KEY_SUFFIX = ".key";
+
+ ILogger logger;
+ private string BaseUrl { get; set; }
+ private string UserId { get; set; }
+ private string Password { get; set; }
+ private RestClient Client { get; set; }
+
+ internal F5BigIQClient(string baseUrl, string id, string pswd, string loginProviderName, bool useTokenAuth, bool ignoreSSLWarning)
+ {
+ logger = LogHandler.GetClassLogger();
+ BaseUrl = baseUrl;
+ UserId = id;
+ Password = pswd;
+ Client = GetRestClient(baseUrl, id, pswd, ignoreSSLWarning, false);
+
+ if (useTokenAuth)
+ {
+ string token = GetAccessToken(id, pswd, loginProviderName);
+ Client = GetRestClient(baseUrl, id, pswd, ignoreSSLWarning, true);
+ Client.AddDefaultHeader("X-F5-Auth-Token", token);
+ }
+ }
+
+ internal List GetCertificates()
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ int currentPageIndex = 1;
+
+ List certificates = new List();
+
+ do
+ {
+ string RESOURCE = $"{GET_ENDPOINT}?$top={ITEMS_PER_PAGE.ToString()}&$skip={((currentPageIndex - 1) * ITEMS_PER_PAGE).ToString()}";
+ RestRequest request = new RestRequest(RESOURCE, Method.Get);
+
+ JObject json = SubmitRequest(request);
+ F5Certificate pageOfCerts = JsonConvert.DeserializeObject(json.ToString());
+ if (pageOfCerts.CertificateItems.Count == 0)
+ break;
+
+ certificates.AddRange(pageOfCerts.CertificateItems);
+
+ if (pageOfCerts.TotalPages == pageOfCerts.PageIndex)
+ break;
+
+ currentPageIndex = pageOfCerts.PageIndex + 1;
+ } while (1 == 1);
+ certificates.ForEach(p => p.Alias = p.Alias.Replace(ALIAS_SUFFIX, string.Empty));
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return certificates;
+ }
+
+ internal X509Certificate2Collection GetCertificateByLink(string command)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ string fileLocation = string.Empty;
+ RestRequest request = new RestRequest(command.Replace(LOCAL_URL_VALUE, BaseUrl), Method.Get);
+
+ JObject json = SubmitRequest(request);
+ string certificateLocation = JsonConvert.DeserializeObject(json.ToString()).CertificateLocation;
+ string certChain = System.Text.ASCIIEncoding.ASCII.GetString(DownloadCertificateFile(certificateLocation));
+
+ CertificateCollectionConverter c = CertificateCollectionConverterFactory.FromPEM(certChain);
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return c.ToX509Certificate2Collection();
+ }
+
+ internal void AddReplaceCertificate(string storePath, string alias, string b64Certificate, string password, bool overwriteExisting)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ string aliasWithSuffix = alias + ALIAS_SUFFIX;
+ F5Certificate f5Certificate = GetCertificateByName(aliasWithSuffix);
+
+ if (f5Certificate.TotalCertificates > 1)
+ throw new F5BigIQException($"Two or more certificates already exist with the alias name of {alias}.");
+ if (f5Certificate.TotalCertificates == 1 && !overwriteExisting)
+ throw new F5BigIQException($"Certificate with alias name {alias} already exists but Overwrite is set to FALSE. Please re-schedule this job and select the Overwrite checkbox (set to TRUE) if you wish to replace this certificate.");
+
+ F5Certificate f5Key = f5Certificate.TotalCertificates == 1 ? GetKeyByName(alias + ALIAS_KEY_SUFFIX) : null;
+
+ string uploadFileName = Guid.NewGuid().ToString() + ".p12";
+ byte[] certBytes = Convert.FromBase64String(b64Certificate);
+
+ UploadCertificateFile(certBytes, uploadFileName);
+
+ F5CertificateAddRequest addRequest = new F5CertificateAddRequest()
+ {
+ Alias = aliasWithSuffix,
+ FileLocation = $@"{UPLOAD_FOLDER}/{uploadFileName}",
+ Partition = storePath,
+ Password = password,
+ Command = f5Certificate.TotalCertificates == 1 ? REPLACE_COMMAND : ADD_COMMAND,
+ CertReference = (f5Certificate.TotalCertificates == 1 ? new CertificateReference() { Link = f5Certificate.CertificateItems[0].Link.Replace(LOCAL_URL_VALUE, BaseUrl) } : null),
+ KeyReference = (f5Certificate.TotalCertificates == 1 ? new CertificateReference() { Link = f5Key.CertificateItems[0].Link.Replace(LOCAL_URL_VALUE, BaseUrl) } : null)
+ };
+
+ RestRequest request = new RestRequest(POST_ENDPOINT, Method.Post);
+ request.AddParameter("application/json", JsonConvert.SerializeObject(addRequest), ParameterType.RequestBody);
+
+ SubmitRequest(request);
+ }
+
+ internal void DeleteCertificate(string alias)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ F5Certificate f5Certificate = GetCertificateByName(alias + ALIAS_SUFFIX);
+ if (f5Certificate.TotalCertificates > 1)
+ throw new F5BigIQException($"Two or more certificates already exist with the alias name of {alias}.");
+ if (f5Certificate.TotalCertificates == 0)
+ throw new F5BigIQException($"Alias {alias} not found. Delete unsuccessful.");
+
+ F5Certificate f5Key = GetKeyByName(alias + ALIAS_KEY_SUFFIX);
+ if (f5Key.TotalCertificates > 1)
+ throw new F5BigIQException($"Two or more certificate keys already exist with the alias name of {alias}.");
+ if (f5Key.TotalCertificates == 0)
+ throw new F5BigIQException($"Key for alias {alias} not found. Delete unsuccessful.");
+
+ RestRequest request = new RestRequest(GET_KEY_ENDPOINT + $@"/{f5Key.CertificateItems[0].Id}", Method.Delete);
+ SubmitRequest(request);
+
+ request = new RestRequest(GET_ENDPOINT + $@"/{f5Certificate.CertificateItems[0].Id}", Method.Delete);
+ SubmitRequest(request);
+
+ logger.MethodExit(LogLevel.Debug);
+ }
+
+ internal List GetProfilesNamesByAlias(string alias)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+ List profileNames = new List();
+ string aliasWithSuffix = alias + ALIAS_SUFFIX;
+
+ int currentPageIndex = 1;
+
+ do
+ {
+ string RESOURCE = $"{GET_PROFILE_ENDPOINT}?$top={ITEMS_PER_PAGE.ToString()}&$skip={((currentPageIndex - 1) * ITEMS_PER_PAGE).ToString()}";
+ RestRequest request = new RestRequest(RESOURCE, Method.Get);
+
+ JObject json = SubmitRequest(request);
+ F5Profile pageOfProfiles = JsonConvert.DeserializeObject(json.ToString());
+
+ profileNames.AddRange(pageOfProfiles.ProfileItems.Where(o => o.CertificateKeyChains != null && o.CertificateKeyChains.Any(p => p.CertificateReference.Name == aliasWithSuffix)).Select(q => q.Name).ToList());
+
+ if (pageOfProfiles.TotalPages == pageOfProfiles.PageIndex)
+ break;
+
+ currentPageIndex = pageOfProfiles.PageIndex + 1;
+ } while (1 == 1);
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return profileNames;
+ }
+
+ internal List GetVirtualServerDeploymentsForVirtualServers(List virtualServerNames)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+ List deployments = new List();
+
+ int currentPageIndex = 1;
+
+ do
+ {
+ string RESOURCE = $"{GET_VIRTUAL_SERVER_ENDPOINT}?$top={ITEMS_PER_PAGE.ToString()}&$skip={((currentPageIndex - 1) * ITEMS_PER_PAGE).ToString()}";
+ RestRequest request = new RestRequest(RESOURCE, Method.Get);
+
+ JObject json = SubmitRequest(request);
+ F5VirtualServer pageOfVirtualServers = JsonConvert.DeserializeObject(json.ToString());
+
+ foreach (F5VirtualServerItem virtualServerItem in pageOfVirtualServers.VirtualServerItems)
+ {
+ RestRequest request2 = new RestRequest(virtualServerItem.VirtualServerProfilesCollectionReference.ItemLink.Replace(LOCAL_URL_VALUE, BaseUrl), Method.Get);
+ JObject json2 = SubmitRequest(request2);
+ F5VirtualServerProfile virtualServerProfiles = JsonConvert.DeserializeObject(json2.ToString());
+
+ if (virtualServerProfiles.VirtualServerProfileItems.Any(p => p.VirtualServerProfileClientSSLReference != null && virtualServerNames.Contains(p.VirtualServerProfileClientSSLReference.Name)))
+ {
+ deployments.Add(new F5Deployment()
+ {
+ Name = virtualServerItem.Name + "-" + Guid.NewGuid().ToString(),
+ DeviceReferences = new List() { new F5Reference() { ItemLink = virtualServerItem.VirtualServerDeviceReference.ItemLink } },
+ ObjectsToDeployReferences = new List() { new F5Reference() { ItemLink = virtualServerItem.ItemLink } }
+ });
+ }
+ }
+
+ if (pageOfVirtualServers.TotalPages == pageOfVirtualServers.PageIndex)
+ break;
+
+ currentPageIndex = pageOfVirtualServers.PageIndex + 1;
+ } while (1 == 1);
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return deployments;
+ }
+
+ internal void ScheduleBigIPDeployment(F5Deployment deploymentRequest)
+ {
+ RestRequest request = new RestRequest(POST_DEPLOY_ENDPOINT, Method.Post);
+ request.AddParameter("application/json", JsonConvert.SerializeObject(deploymentRequest), ParameterType.RequestBody);
+
+ SubmitRequest(request);
+ }
+
+ private F5Certificate GetCertificateByName(string name)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ string fileLocation = string.Empty;
+ RestRequest request = new RestRequest($"{GET_ENDPOINT}?$filter=name+eq+'{name}'", Method.Get);
+ JObject json = SubmitRequest(request);
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return JsonConvert.DeserializeObject(json.ToString());
+ }
+
+ private F5Certificate GetKeyByName(string name)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ string fileLocation = string.Empty;
+ RestRequest request = new RestRequest($"{GET_KEY_ENDPOINT}?$filter=name+eq+'{name}'", Method.Get);
+ JObject json = SubmitRequest(request);
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return JsonConvert.DeserializeObject(json.ToString());
+ }
+
+ private byte[] DownloadCertificateFile(string location)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+ logger.LogDebug($"DownloadCertificateFile: {location}");
+
+ byte[] rtnStore = new byte[] { };
+ string serverLocation = BaseUrl.Replace("https://", String.Empty);
+
+ ConnectionInfo connectionInfo = new ConnectionInfo(serverLocation, UserId, new PasswordAuthenticationMethod(UserId, Password));
+ using (ScpClient client = new ScpClient(connectionInfo))
+ {
+ try
+ {
+ logger.LogDebug($"SCP connection attempt from {serverLocation}");
+ client.Connect();
+
+ using (MemoryStream stream = new MemoryStream())
+ {
+ client.Download(location, stream);
+ rtnStore = stream.ToArray();
+ }
+ }
+ catch (Exception ex)
+ {
+ string msg = F5BigIQException.FlattenExceptionMessages(ex, "SCP Download Error: ");
+ logger.LogError(msg);
+ throw new F5BigIQException($"Error attempting SCP file transfer from {BaseUrl} . Please contact your company's system administrator to verify connection and permission settings.", ex);
+ }
+ finally
+ {
+ client.Disconnect();
+ }
+ }
+
+ logger.MethodExit(LogLevel.Debug);
+
+ return rtnStore;
+ }
+
+ private void UploadCertificateFile(byte[] certBytes, string fileName)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ string serverLocation = BaseUrl.Replace("https://", String.Empty);
+
+ ConnectionInfo connectionInfo = new ConnectionInfo(serverLocation, UserId, new List() { new PasswordAuthenticationMethod(UserId, Password) }.ToArray());
+ using (ScpClient client = new ScpClient(connectionInfo))
+ {
+ try
+ {
+ logger.LogDebug($"SCP connection attempt from {serverLocation}");
+ client.Connect();
+
+ using (MemoryStream stream = new MemoryStream(certBytes))
+ {
+ client.Upload(stream, $"{UPLOAD_FOLDER}/{fileName}");
+ }
+ }
+ catch (Exception ex)
+ {
+ string msg = F5BigIQException.FlattenExceptionMessages(ex, "SCP Upload Error: ");
+ logger.LogError(msg);
+ throw new F5BigIQException($"Error attempting SCP file transfer from {BaseUrl} . Please contact your company's system administrator to verify connection and permission settings.", ex);
+ }
+ finally
+ {
+ client.Disconnect();
+ }
+ }
+
+ logger.MethodExit(LogLevel.Debug);
+ }
+
+ private string GetAccessToken(string id, string pswd, string loginProviderName)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ F5LoginRequest loginRequest = new F5LoginRequest() { UserId = id, Password = pswd, LoginProviderName = loginProviderName}; //, ProviderName = "tmos" };
+ RestRequest request = new RestRequest($"/mgmt/shared/authn/login", Method.Post);
+ request.AddParameter("application/json", JsonConvert.SerializeObject(loginRequest), ParameterType.RequestBody);
+
+ JObject json = SubmitRequest(request);
+
+ logger.MethodExit(LogLevel.Debug);
+ return JsonConvert.DeserializeObject(json.ToString()).Token.Token;
+ }
+
+ private JObject SubmitRequest(RestRequest request)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+ logger.LogTrace($"Request Resource: {request.Resource}");
+ logger.LogTrace($"Request Method: {request.Method.ToString()}");
+
+ if (request.Method != Method.Get)
+ {
+ StringBuilder body = new StringBuilder("Request Body: ");
+ foreach (Parameter parameter in request.Parameters)
+ {
+ body.Append($"{parameter.Name}={parameter.Value}");
+ }
+ logger.LogTrace(body.ToString());
+ }
+
+ RestResponse response;
+
+ try
+ {
+ response = Client.ExecuteAsync(request).Result;
+ }
+ catch (Exception ex)
+ {
+ string exceptionMessage = F5BigIQException.FlattenExceptionMessages(ex, $"Error processing {request.Resource}");
+ logger.LogError(exceptionMessage);
+ throw;
+ }
+
+ if (response.StatusCode != System.Net.HttpStatusCode.OK &&
+ response.StatusCode != System.Net.HttpStatusCode.Accepted &&
+ response.StatusCode != System.Net.HttpStatusCode.Created &&
+ response.StatusCode != System.Net.HttpStatusCode.NoContent)
+ {
+ string errorMessage = response.Content + " " + response.ErrorMessage;
+ string exceptionMessage = $"Error processing {request.Resource}: {errorMessage}";
+
+ logger.LogError(exceptionMessage);
+ logger.MethodExit(LogLevel.Debug);
+ if (response.ErrorException != null)
+ throw response.ErrorException;
+ else
+ throw new F5BigIQException(exceptionMessage);
+ }
+
+ JObject json = JObject.Parse(response.Content);
+
+ logger.LogTrace($"API Result: {response.Content}");
+ logger.MethodExit(LogLevel.Debug);
+
+ return json;
+ }
+
+ private RestClient GetRestClient(string baseUrl, string id, string pswd, bool ignoreSSLWarning, bool useTokenAuth)
+ {
+ logger.MethodEntry(LogLevel.Debug);
+
+ RestClientOptions options = new RestClientOptions(baseUrl);
+
+ if (!useTokenAuth)
+ options.Authenticator = new HttpBasicAuthenticator(id, pswd);
+ if (ignoreSSLWarning)
+ options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
+
+ RestClient client = new RestClient(options);
+
+ logger.MethodExit(LogLevel.Debug);
+ return client;
+ }
+ }
+}
diff --git a/F5BigIQ/F5BigIQException.cs b/F5BigIQ/F5BigIQException.cs
new file mode 100644
index 0000000..b672ef9
--- /dev/null
+++ b/F5BigIQ/F5BigIQException.cs
@@ -0,0 +1,29 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ class F5BigIQException : ApplicationException
+ {
+ public F5BigIQException(string message) : base(message)
+ { }
+
+ public F5BigIQException(string message, Exception ex) : base(message, ex)
+ { }
+
+ public static string FlattenExceptionMessages(Exception ex, string message)
+ {
+ message += ex.Message + Environment.NewLine;
+ if (ex.InnerException != null)
+ message = FlattenExceptionMessages(ex.InnerException, message);
+
+ return message;
+ }
+ }
+}
diff --git a/F5BigIQ/F5JobBase.cs b/F5BigIQ/F5JobBase.cs
new file mode 100644
index 0000000..e4c26a6
--- /dev/null
+++ b/F5BigIQ/F5JobBase.cs
@@ -0,0 +1,31 @@
+// Copyright 2024 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.Orchestrators.Extensions.Interfaces;
+using Microsoft.Extensions.Logging;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ public class F5JobBase
+ {
+ public string ExtensionName => "";
+
+ protected string ServerUserName { get; set; }
+
+ protected string ServerPassword { get; set; }
+
+ public IPAMSecretResolver _resolver;
+
+ internal void SetPAMSecrets(string serverUserName, string serverPassword, ILogger logger)
+ {
+ ServerUserName = PAMUtilities.ResolvePAMField(_resolver, logger, "Server User Name", serverUserName);
+ ServerPassword = PAMUtilities.ResolvePAMField(_resolver, logger, "Server Password", serverPassword);
+ }
+ }
+}
diff --git a/F5BigIQ/Inventory.cs b/F5BigIQ/Inventory.cs
new file mode 100644
index 0000000..4e7efe2
--- /dev/null
+++ b/F5BigIQ/Inventory.cs
@@ -0,0 +1,93 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+
+using Keyfactor.Logging;
+using Keyfactor.Orchestrators.Extensions;
+using Keyfactor.Extensions.Orchestrator.F5BigIQ.Models;
+
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Keyfactor.Orchestrators.Extensions.Interfaces;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ public class Inventory : F5JobBase, IInventoryJobExtension
+ {
+ public Inventory(IPAMSecretResolver resolver)
+ {
+ _resolver = resolver;
+ }
+
+ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpdate submitInventory)
+ {
+ ILogger logger = LogHandler.GetClassLogger(this.GetType());
+ logger.LogDebug($"Begin {config.Capability} for job id {config.JobId}...");
+ logger.LogDebug($"Server: {config.CertificateStoreDetails.ClientMachine}");
+ logger.LogDebug($"Store Path: {config.CertificateStoreDetails.StorePath}");
+ logger.LogDebug($"Job Properties:");
+ foreach (KeyValuePair keyValue in config.JobProperties ?? new Dictionary())
+ {
+ logger.LogDebug($" {keyValue.Key}: {keyValue.Value}");
+ }
+
+ dynamic properties = JsonConvert.DeserializeObject(config.CertificateStoreDetails.Properties);
+ SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
+ bool ignoreSSLWarning = properties.IgnoreSSLWarning == null || string.IsNullOrEmpty(properties.IgnoreSSLWarning.Value) ? false : bool.Parse(properties.IgnoreSSLWarning.Value);
+ bool useTokenAuthentication = properties.UseTokenAuth == null || string.IsNullOrEmpty(properties.UseTokenAuth.Value) ? false : bool.Parse(properties.UseTokenAuth.Value);
+ string loginProviderName = properties.LoginProviderName == null || string.IsNullOrEmpty(properties.LoginProviderName.Value) ? "tmos" : properties.LoginProviderName.Value;
+
+ List inventoryItems = new List();
+
+ try
+ {
+ F5BigIQClient f5Client = new F5BigIQClient(config.CertificateStoreDetails.ClientMachine, ServerUserName, ServerPassword, loginProviderName, useTokenAuthentication, ignoreSSLWarning);
+ List certItems = f5Client.GetCertificates();
+ foreach (F5CertificateItem certItem in certItems)
+ {
+ if (certItem.FileReference == null)
+ continue;
+ X509Certificate2Collection certChain = f5Client.GetCertificateByLink(certItem.FileReference.Link);
+ List certContents = new List();
+ bool useChainLevel = certChain.Count > 1;
+ foreach (X509Certificate2 certificate in certChain)
+ {
+ certContents.Add(Convert.ToBase64String(certificate.Export(X509ContentType.Cert)));
+ }
+ inventoryItems.Add(new CurrentInventoryItem()
+ {
+ Alias = certItem.Alias,
+ Certificates = certContents.ToArray(),
+ ItemStatus = Orchestrators.Common.Enums.OrchestratorInventoryItemStatus.Unknown,
+ UseChainLevel = useChainLevel,
+ PrivateKeyEntry = true
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.LogError($"Exception for {config.Capability}: {F5BigIQException.FlattenExceptionMessages(ex, string.Empty)} for job id {config.JobId}");
+ return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = F5BigIQException.FlattenExceptionMessages(ex, $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}:") };
+ }
+
+ try
+ {
+ submitInventory.Invoke(inventoryItems);
+ return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = F5BigIQException.FlattenExceptionMessages(ex, string.Empty);
+ logger.LogError($"Exception returning certificates for {config.Capability}: {errorMessage} for job id {config.JobId}");
+ return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = F5BigIQException.FlattenExceptionMessages(ex, $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}:") };
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/F5BigIQ/Management.cs b/F5BigIQ/Management.cs
new file mode 100644
index 0000000..8e97b28
--- /dev/null
+++ b/F5BigIQ/Management.cs
@@ -0,0 +1,94 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System;
+
+using Keyfactor.Logging;
+using Keyfactor.Orchestrators.Extensions;
+using Keyfactor.Orchestrators.Common.Enums;
+using Keyfactor.Extensions.Orchestrator.F5BigIQ.Models;
+
+using Microsoft.Extensions.Logging;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Keyfactor.Orchestrators.Extensions.Interfaces;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ public class Management : F5JobBase, IManagementJobExtension
+ {
+ //Job Entry Point
+ public Management(IPAMSecretResolver resolver)
+ {
+ _resolver = resolver;
+ }
+ public JobResult ProcessJob(ManagementJobConfiguration config)
+ {
+ ILogger logger = LogHandler.GetClassLogger(this.GetType());
+ logger.LogDebug($"Begin {config.Capability} for job id {config.JobId}...");
+ logger.LogDebug($"Server: {config.CertificateStoreDetails.ClientMachine}");
+ logger.LogDebug($"Store Path: {config.CertificateStoreDetails.StorePath}");
+ logger.LogDebug($"Job Properties:");
+ foreach (KeyValuePair keyValue in config.JobProperties ?? new Dictionary())
+ {
+ logger.LogDebug($" {keyValue.Key}: {keyValue.Value}");
+ }
+
+ dynamic properties = JsonConvert.DeserializeObject(config.CertificateStoreDetails.Properties);
+ SetPAMSecrets(config.ServerUsername, config.ServerPassword, logger);
+ bool deployCertificateOnRenewal = properties.DeployCertificateOnRenewal == null || string.IsNullOrEmpty(properties.DeployCertificateOnRenewal.Value) ? false : bool.Parse(properties.DeployCertificateOnRenewal.Value);
+ bool ignoreSSLWarning = properties.IgnoreSSLWarning == null || string.IsNullOrEmpty(properties.IgnoreSSLWarning.Value) ? false : bool.Parse(properties.IgnoreSSLWarning.Value);
+ bool useTokenAuthentication = properties.UseTokenAuth == null || string.IsNullOrEmpty(properties.UseTokenAuth.Value) ? false : bool.Parse(properties.UseTokenAuth.Value);
+ string loginProviderName = properties.LoginProviderName == null || string.IsNullOrEmpty(properties.LoginProviderName.Value) ? "tmos" : properties.LoginProviderName.Value;
+
+ try
+ {
+ F5BigIQClient f5Client = new F5BigIQClient(config.CertificateStoreDetails.ClientMachine, ServerUserName, ServerPassword, loginProviderName, useTokenAuthentication, ignoreSSLWarning);
+
+ switch (config.OperationType)
+ {
+ case CertStoreOperationType.Add:
+ f5Client.AddReplaceCertificate(config.CertificateStoreDetails.StorePath, config.JobCertificate.Alias,
+ config.JobCertificate.Contents, config.JobCertificate.PrivateKeyPassword, config.Overwrite);
+
+ try
+ {
+ if (config.Overwrite && deployCertificateOnRenewal)
+ {
+ List profileNames = f5Client.GetProfilesNamesByAlias(config.JobCertificate.Alias);
+ if (profileNames.Count > 0)
+ {
+ List f5Deployments = f5Client.GetVirtualServerDeploymentsForVirtualServers(profileNames);
+ foreach (F5Deployment f5Deployment in f5Deployments)
+ f5Client.ScheduleBigIPDeployment(f5Deployment);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ string msg = $"Certificate {config.JobCertificate.Alias} added successfully, but error occurred during attempt to check for linked Big IP deployments or deploying the certificate.";
+ logger.LogError($"Exception for {config.Capability}: {F5BigIQException.FlattenExceptionMessages(ex, msg)} for job id {config.JobId}");
+ return new JobResult() { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = config.JobHistoryId, FailureMessage = F5BigIQException.FlattenExceptionMessages(ex, $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}: {msg} Please see the Keyfactor Orchestrator log for more information.") };
+ }
+ break;
+ case CertStoreOperationType.Remove:
+ f5Client.DeleteCertificate(config.JobCertificate.Alias);
+ break;
+ default:
+ return new JobResult() { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}: Unsupported operation: {config.OperationType.ToString()}" };
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.LogError($"Exception for {config.Capability}: {F5BigIQException.FlattenExceptionMessages(ex, string.Empty)} for job id {config.JobId}");
+ return new JobResult() { Result = OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = F5BigIQException.FlattenExceptionMessages(ex, $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}:") };
+ }
+
+ return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
+ }
+ }
+}
\ No newline at end of file
diff --git a/F5BigIQ/Models/F5Certificate.cs b/F5BigIQ/Models/F5Certificate.cs
new file mode 100644
index 0000000..02246ea
--- /dev/null
+++ b/F5BigIQ/Models/F5Certificate.cs
@@ -0,0 +1,42 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5Certificate
+ {
+ [JsonProperty("pageIndex")]
+ internal int PageIndex { get; set; }
+ [JsonProperty("totalPages")]
+ internal int TotalPages { get; set; }
+ [JsonProperty("totalItems")]
+ internal int TotalCertificates { get; set; }
+ [JsonProperty("items")]
+ internal List CertificateItems { get; set; }
+ }
+
+ internal class F5CertificateItem
+ {
+ [JsonProperty("id")]
+ internal string Id { get; set; }
+ [JsonProperty("name")]
+ internal string Alias { get; set; }
+ [JsonProperty("fileReference")]
+ internal F5CertificateFileReference FileReference { get; set; }
+ [JsonProperty("selfLink")]
+ internal string Link { get; set; }
+ }
+
+ internal class F5CertificateFileReference
+ {
+ [JsonProperty("link")]
+ internal string Link { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5CertificateAddRequest.cs b/F5BigIQ/Models/F5CertificateAddRequest.cs
new file mode 100644
index 0000000..05b5e1d
--- /dev/null
+++ b/F5BigIQ/Models/F5CertificateAddRequest.cs
@@ -0,0 +1,38 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5CertificateAddRequest
+ {
+ [JsonProperty("command")]
+ internal string Command { get; set; }
+ [JsonProperty("pkcs12Passphrase")]
+ internal string Password { get; set; }
+ [JsonProperty("filePath")]
+ internal string FileLocation { get; set; }
+ [JsonProperty("itemName")]
+ internal string Alias { get; set; }
+ [JsonProperty("securityType")]
+ internal string SecurityType { get { return "normal"; } }
+ [JsonProperty("itemPartition")]
+ internal string Partition { get; set; }
+ [JsonProperty("certReference")]
+ internal CertificateReference CertReference { get; set; }
+ [JsonProperty("keyReference")]
+ internal CertificateReference KeyReference { get; set; }
+ }
+
+ internal class CertificateReference
+ {
+ [JsonProperty("link")]
+ internal string Link { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5CertificateLocation.cs b/F5BigIQ/Models/F5CertificateLocation.cs
new file mode 100644
index 0000000..d5cfdac
--- /dev/null
+++ b/F5BigIQ/Models/F5CertificateLocation.cs
@@ -0,0 +1,18 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5CertificateLocation
+ {
+ [JsonProperty("localFilePath")]
+ internal string CertificateLocation { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5Deployment.cs b/F5BigIQ/Models/F5Deployment.cs
new file mode 100644
index 0000000..0290a39
--- /dev/null
+++ b/F5BigIQ/Models/F5Deployment.cs
@@ -0,0 +1,36 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5Deployment
+ {
+ [JsonProperty("skipVerifyConfig")]
+ internal bool SkipVerifyConfig { get { return false; } }
+ [JsonProperty("skipDistribution")]
+ internal bool SkipDistribution { get { return false; } }
+ [JsonProperty("snapshotReference")]
+ internal bool? SnapshotReference { get { return null; } }
+ [JsonProperty("name")]
+ internal string Name { get; set; }
+ [JsonProperty("objectsToDeployReferences")]
+ internal List ObjectsToDeployReferences { get; set; }
+ [JsonProperty("deploySpecifiedObjectsOnly")]
+ internal bool DeploySpecifiedObjectsOnly { get { return false; } }
+ [JsonProperty("deviceReferences")]
+ internal List DeviceReferences { get; set; }
+ }
+
+ internal class F5Reference
+ {
+ [JsonProperty("link")]
+ internal string ItemLink { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5Profile.cs b/F5BigIQ/Models/F5Profile.cs
new file mode 100644
index 0000000..65e2137
--- /dev/null
+++ b/F5BigIQ/Models/F5Profile.cs
@@ -0,0 +1,44 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5Profile
+ {
+ [JsonProperty("pageIndex")]
+ internal int PageIndex { get; set; }
+ [JsonProperty("totalPages")]
+ internal int TotalPages { get; set; }
+ [JsonProperty("totalItems")]
+ internal int TotalProfiles { get; set; }
+ [JsonProperty("items")]
+ internal List ProfileItems { get; set; }
+ }
+
+ internal class F5ProfileItem
+ {
+ [JsonProperty("name")]
+ internal string Name { get; set; }
+ [JsonProperty("certKeyChain")]
+ internal List CertificateKeyChains { get; set; }
+ }
+
+ internal class F5ProfileCertificateKeyChain
+ {
+ [JsonProperty("certReference")]
+ internal F5ProfileCertificateReference CertificateReference { get; set; }
+ }
+
+ internal class F5ProfileCertificateReference
+ {
+ [JsonProperty("name")]
+ internal string Name { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5TokenLogin.cs b/F5BigIQ/Models/F5TokenLogin.cs
new file mode 100644
index 0000000..7afb91f
--- /dev/null
+++ b/F5BigIQ/Models/F5TokenLogin.cs
@@ -0,0 +1,35 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5LoginRequest
+ {
+ [JsonProperty("username")]
+ internal string UserId { get; set; }
+ [JsonProperty("password")]
+ internal string Password { get; set; }
+ [JsonProperty("loginProviderName")]
+ internal string LoginProviderName { get; set; }
+ }
+
+ internal class F5LoginResponse
+ {
+ [JsonProperty("token")]
+ internal F5LoginToken Token { get; set; }
+ }
+
+ internal class F5LoginToken
+ {
+ [JsonProperty("token")]
+ internal string Token { get; set; }
+ }
+
+}
diff --git a/F5BigIQ/Models/F5VirtualServer.cs b/F5BigIQ/Models/F5VirtualServer.cs
new file mode 100644
index 0000000..8a49cbc
--- /dev/null
+++ b/F5BigIQ/Models/F5VirtualServer.cs
@@ -0,0 +1,48 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5VirtualServer
+ {
+ [JsonProperty("pageIndex")]
+ internal int PageIndex { get; set; }
+ [JsonProperty("totalPages")]
+ internal int TotalPages { get; set; }
+ [JsonProperty("totalItems")]
+ internal int TotalVirtualServers { get; set; }
+ [JsonProperty("items")]
+ internal List VirtualServerItems { get; set; }
+ }
+
+ internal class F5VirtualServerItem
+ {
+ [JsonProperty("name")]
+ internal string Name { get; set; }
+ [JsonProperty("selfLink")]
+ internal string ItemLink { get; set; }
+ [JsonProperty("deviceReference")]
+ internal F5VirtualServerDeviceReference VirtualServerDeviceReference { get; set; }
+ [JsonProperty("profilesCollectionReference")]
+ internal F5VirtualServerProfilesCollectionReference VirtualServerProfilesCollectionReference { get; set; }
+ }
+
+ internal class F5VirtualServerDeviceReference
+ {
+ [JsonProperty("link")]
+ internal string ItemLink { get; set; }
+ }
+
+ internal class F5VirtualServerProfilesCollectionReference
+ {
+ [JsonProperty("link")]
+ internal string ItemLink { get; set; }
+ }
+}
diff --git a/F5BigIQ/Models/F5VirtualServerProfile.cs b/F5BigIQ/Models/F5VirtualServerProfile.cs
new file mode 100644
index 0000000..cc32784
--- /dev/null
+++ b/F5BigIQ/Models/F5VirtualServerProfile.cs
@@ -0,0 +1,30 @@
+// Copyright 2024 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 the specific language governing permissions
+// and limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ.Models
+{
+ internal class F5VirtualServerProfile
+ {
+ [JsonProperty("items")]
+ internal List VirtualServerProfileItems { get; set; }
+ }
+
+ internal class F5VirtualServerProfileItem
+ {
+ [JsonProperty("profileClientsslReference")]
+ internal F5VirtualServerProfileClientSSLReference VirtualServerProfileClientSSLReference { get; set; }
+ }
+
+ internal class F5VirtualServerProfileClientSSLReference
+ {
+ [JsonProperty("name")]
+ internal string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/F5BigIQ/PAMUtilities.cs b/F5BigIQ/PAMUtilities.cs
new file mode 100644
index 0000000..e5f95ac
--- /dev/null
+++ b/F5BigIQ/PAMUtilities.cs
@@ -0,0 +1,21 @@
+// Copyright 2021 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 the specific language governing permissions
+// and limitations under the License.
+
+using Keyfactor.Orchestrators.Extensions.Interfaces;
+using Microsoft.Extensions.Logging;
+
+namespace Keyfactor.Extensions.Orchestrator.F5BigIQ
+{
+ internal class PAMUtilities
+ {
+ internal static string ResolvePAMField(IPAMSecretResolver resolver, ILogger logger, string name, string key)
+ {
+ logger.LogDebug($"Attempting to resolve PAM eligible field {name}");
+ return string.IsNullOrEmpty(key) ? key : resolver.Resolve(key);
+ }
+ }
+}
diff --git a/F5BigIQ/manifest.json b/F5BigIQ/manifest.json
new file mode 100644
index 0000000..bf13617
--- /dev/null
+++ b/F5BigIQ/manifest.json
@@ -0,0 +1,14 @@
+{
+ "extensions": {
+ "Keyfactor.Orchestrators.Extensions.IOrchestratorJobExtension": {
+ "CertStores.F5-BigIQ.Inventory": {
+ "assemblypath": "F5BigIQ.dll",
+ "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5BigIQ.Inventory"
+ },
+ "CertStores.F5-BigIQ.Management": {
+ "assemblypath": "F5BigIQ.dll",
+ "TypeFullName": "Keyfactor.Extensions.Orchestrator.F5BigIQ.Management"
+ }
+ }
+ }
+}
diff --git a/README.md b/README.md
index ba0bcce..d9b8d2f 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# Integration Template
+# F5 BigIQ
-This project is meant to be a template to quickly build a basic integration product build. Currently in dev, a work in progress,
+The F5 Big IQ Orchestrator allows for the remote management of F5 Big IQ certificate stores. Inventory and Management functions are supported.
#### Integration status: Prototype - Demonstration quality. Not for use in customer environments.
@@ -13,9 +13,9 @@ The Universal Orchestrator is part of the Keyfactor software distribution and is
The Universal Orchestrator is the successor to the Windows Orchestrator. This Orchestrator Extension plugin only works with the Universal Orchestrator and does not work with the Windows Orchestrator.
-## Support for Integration Template
+## Support for F5 BigIQ
-Integration Template is open source and community supported, meaning that there is no support guaranteed from Keyfactor Support for these tools.
+F5 BigIQ is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com
###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab.
@@ -28,18 +28,18 @@ Integration Template is open source and community supported, meaning that there
## Keyfactor Version Supported
-The minimum version of the Keyfactor Universal Orchestrator Framework needed to run this version of the extension is 10.1
+The minimum version of the Keyfactor Universal Orchestrator Framework needed to run this version of the extension is 10.4
## Platform Specific Notes
The Keyfactor Universal Orchestrator may be installed on either Windows or Linux based platforms. The certificate operations supported by a capability may vary based what platform the capability is installed on. The table below indicates what capabilities are supported based on which platform the encompassing Universal Orchestrator is running.
| Operation | Win | Linux |
|-----|-----|------|
-|Supports Management Add| | |
-|Supports Management Remove| | |
+|Supports Management Add|✓ |✓ |
+|Supports Management Remove|✓ |✓ |
|Supports Create Store| | |
|Supports Discovery| | |
|Supports Renrollment| | |
-|Supports Inventory| | |
+|Supports Inventory|✓ |✓ |
## PAM Integration
@@ -50,9 +50,8 @@ The secrets that this orchestrator extension supports for use with a PAM Provide
|Name|Description|
|----|-----------|
-|ServerUsername|The user id that will be used to authenticate into the server hosting the store|
-|ServerPassword|The password that will be used to authenticate into the server hosting the store|
-|StorePassword|The optional password used to secure the certificate store being managed|
+|ServerUsername|The user id that will be used to authenticate to the F5 Biq API endpoints|
+|ServerPassword|The password that will be used to authenticate to the F5 Biq API endpoints|
It is not necessary to use a PAM Provider for all of the secrets available above. If a PAM Provider should not be used, simply enter in the actual value to be used, as normal.
@@ -99,7 +98,131 @@ This text would be entered in as the value for the __Server Password__, instead
---
+**Please note that this integration will work with the Universal Orchestrator version 10.1 or greater**
-### License
-[Apache](https://apache.org/licenses/LICENSE-2.0)
+## Use Cases
+
+The F5 Big IQ Orchestrator Extension supports the following capabilities for SSL certificates:
+
+- Inventory
+- Management (Add and Remove)
+
+
+## Versioning
+
+The version number of a the F5 Big IQ Orchestrator Extension can be verified by right clicking on the F5BigIQ.dll file, selecting Properties, and then clicking on the Details tab.
+
+
+## F5 Big IQ Prerequisites
+
+When creating a Keyfactor Command Certificate Store, you will be asked to enter server credentials. These credentials will serve two purposes:
+1. They will be used to authenticate to the F5 Big IQ instance when accessing API endpoints. Please make sure these credentials have Admin authority on F5 Big IQ.
+2. When Inventorying and Adding/Replacing certificates it will be necessary for certificate files to be transferred to and from the F5 device. The F5 Big IQ Orchestrator Extension uses SCP (Secure Copy Protocol) to perform these functions. Please make sure your F5 Big IQ device is set up to allow SCP to transfer files *to* /var/config/rest/downloads (a reserved F5 Big IQ folder used for file transfers) and *from* /var/config/rest/fileobject (the certificate file location path) and all subfolders. You may need go into the /etc/ssh/sshd_config file on your F5 Big IQ device and set PasswordAuthentication from “No” to “Yes” for SCP to work. Other configuration tasks may be necessary in your environment to enable this feature.
+
+
+## F5 Big IQ Orchestrator Extension Installation
+
+1. Stop the Keyfactor Universal Orchestrator Service.
+2. In the Keyfactor Orchestrator installation folder (by convention usually C:\Program Files\Keyfactor\Keyfactor Orchestrator), find the "extensions" folder. Underneath that, create a new folder named F5BigIQ or another name of your choosing.
+3. Download the latest version of the F5 BigIQ Orchestrator Extension from [GitHub](https://github.com/Keyfactor/f5-bigiq-rest-orchestrator).
+4. Copy the contents of the download installation zip file into the folder created in step 2.
+5. Start the Keyfactor Universal Orchestrator Service.
+
+
+## F5 Big IQ Orchestrator Extension Configuration
+
+### 1\. In Keyfactor Command, create a new certificate store type by navigating to Settings (the "gear" icon in the top right) => Certificate Store Types, and clicking ADD. Then enter the following information:
+
+**Basic Tab**
+- **Name** – Required. The descriptive display name of the new Certificate Store Type. Suggested => F5 Big IQ
+- **Short Name** – Required. This value ***must be*** F5-BigIQ.
+- **Custom Capability** - Leave unchecked
+- **Supported Job Types** – Select Inventory, Add, and Remove.
+- **General Settings** - Select Needs Server. Select Blueprint Allowed if you plan to use blueprinting. Leave Uses PowerShell unchecked.
+- **Password Settings** - Leave both options unchecked
+
+**Advanced Tab**
+- **Store Path Type** - Select Freeform
+- **Supports Custom Alias** - Required
+- **Private Key Handling** - Required
+- **PFX Password Style** - Default
+
+**Custom Fields Tab**
+
+- **Deploy Certificate to Linked Big IP on Renewal** - optional - This setting determines you wish to deploy renewed certificates (Management-Add jobs with Overwrite selected) to all linked Big IP devices. Linked devices are determined by looking at all of the client-ssl profiles that reference the renewed certificate that have an associated virtual server linked to a Big IP device. An "immediate" deployment is then scheduled within F5 Big IQ for each linked Big IP device.
+ - **Name**=DeployCertificateOnRenewal
+ - **Display Name**=Deploy Certificate to Linked Big IP on Renewal
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Ignore SSL Warning** - optional - If you use a self signed certificate for the F5 Big IQ portal, you will need add this Custom Field and set the value to True on the managed certificate store.
+ - **Name**=IgnoreSSLWarning
+ - **Display Name**=Ignore SSL Warning
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Use Token Authentication** - optional - If you prefer to use F5 Big IQ's Token Authentication to authenticate F5 Big IQ API calls that the integration uses, you will need to add this Custom Field and set the value to True on the managed certificate store. If this exists and is set to True for the store, the store userid/password credentials you set for the certificate store will be used once to receive a token. This token is then used for all remaining API calls for the duration of the job. If this option does not exist or is set to False, the userid/password credentials you set on the certificate store will be used for each API call.
+ - **Name**=LoginProviderName
+ - **Display Name**=Authentication Provider Name
+ - **Type**=String
+ - **Default Value**={client preference}
+ - **Depends on**=""
+ - **Required**=unchecked
+
+- **Use Token Authentication** - optional - If you prefer to use F5 Big IQ's Token Authentication to authenticate F5 Big IQ API calls that the integration uses, you will need to add this Custom Field and set the value to True on the managed certificate store. If this exists and is set to True for the store, the store userid/password credentials you set for the certificate store will be used once to receive a token. This token is then used for all remaining API calls for the duration of the job. If this option does not exist or is set to False, the userid/password credentials you set on the certificate store will be used for each API call.
+ - **Name**=UseTokenAuth
+ - **Display Name**=Use Token Authentication
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Use Token Authentication Provider Name** - optional - If Use Token Authentication is selected, you may optionally add a value for the authentication provider F5 Big IQ will use to retrieve the auth token. If you choose not to add this field or leave it blank on the certificate store (with no default value set), the default of "TMOS" will be used.
+ - **Display Name**=Use Token Authentication Provider Name
+ - **Type**=String
+ - **Default Value**={client preference}
+ - **Depends on**="UseTokenAuth"
+ - **Required**=unchecked
+
+Please note, after saving the store type, going back into this screen will show three additional Custom Fields: Server Username, Server Password, and Use SSL. These are added internally by Keyfactor Command and should not be modified.
+
+**Entry Parameters Tab**
+
+No Entry Parameters should be added.
+
+
+### 2\. Create an F5 Big IQ Certificate Store
+
+Navigate to Certificate Locations =\> Certificate Stores within Keyfactor Command to add the store. Below are the values that should be entered:
+
+- **Category** – Required. Select the Name you entered when creating the Certificate Store Type. Suggested value was F5 Big IQ.
+
+- **Container** – Optional. Select a container if utilized.
+
+- **Client Machine & Credentials** – Required. The full URL of the F5 Big IQ device portal.
+
+- **Store Path** – Required. Enter the name of the partition on the F5 Big IQ device you wish to manage. This value is case sensitive, so if the partition name is "Common", it must be entered as "Common" and not "common".
+
+- **Orchestrator** – Required. Select the orchestrator you wish to use to manage this store
+
+- **Deploy Certificate to Linked Big IP on Renewal** - Optional. Set this to True if you wish to deploy renewed certificates (Management-Add jobs with Overwrite selected) to all linked Big IP devices. Linked devices are determined by looking at all of the client-ssl profiles that reference the renewed certificate that have an associated virtual server linked to a Big IP device. An "immediate" deployment is then scheduled within F5 Big IQ for each linked Big IP device.
+
+- **Ignore SSL Warning** - Optional. Set this to True 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 chose not to add this Custom Field when creating the Certificate Store Type, the default value of False will be assumed. If this value is False (or missing) SSL warnings will cause errors during orchestrator extension jobs.
+
+- **Use Token Authentication** - Optional. Set this to True if you wish to use F5 Big IQ's token authentiation instead of basic authentication for all API requests. If you chose not to add this optional Custom Field when creating the Certificate Store Type, 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.
+
+- **Server Username/Password** - Required. The credentials used to log into the F5 Big IQ device to perform API calls. These values for server login can be either:
+
+ - UserId/Password
+ - PAM provider information used to look up the UserId/Password credentials
+
+ Please make sure these credentials have Admin rights on the F5 Big IQ device and can perform SCP functions as described in the F5 Big IQ Prerequisites section above.
+
+- **Use SSL** - N/A. This value is not referenced in the F5 Big IQ Orchestrator Extension. The value you enter for Client Machine, and specifically whether the protocol entered is http:// or https:// will determine whether a TLS (SSL) connection is utilized.
+
+- **Inventory Schedule** – Set a schedule for running Inventory jobs or "none", if you choose not to schedule Inventory at this time.
diff --git a/SampleOrchestratorExtension/Discovery.cs b/SampleOrchestratorExtension/Discovery.cs
deleted file mode 100644
index 7350632..0000000
--- a/SampleOrchestratorExtension/Discovery.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-using Keyfactor.Logging;
-using Keyfactor.Orchestrators.Extensions;
-
-using Microsoft.Extensions.Logging;
-
-namespace Keyfactor.Extensions.Orchestrator.SampleOrchestratorExtension
-{
- // The Discovery class implementes IAgentJobExtension and is meant to find all certificate stores based on the information passed when creating the job in KF Command
- public class Discovery : IDiscoveryJobExtension
- {
- //Necessary to implement IDiscoveryJobExtension but not used. Leave as empty string.
- public string ExtensionName => "";
-
- //Job Entry Point
- public JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpdate submitDiscovery)
- {
- //METHOD ARGUMENTS...
- //config - contains context information passed from KF Command to this job run:
- //
- // config.ServerUsername, config.ServerPassword - credentials for orchestrated server - use to authenticate to certificate store server.
- // config.ClientMachine - server name or IP address of orchestrated server
- //
- // config.JobProperties["dirs"] - Directories to search
- // config.JobProperties["extensions"] - Extensions to search
- // config.JobProperties["ignoreddirs"] - Directories to ignore
- // config.JobProperties["patterns"] - File name patterns to match
-
-
- //NLog Logging to c:\CMS\Logs\CMS_Agent_Log.txt
- ILogger logger = LogHandler.GetClassLogger(this.GetType());
- logger.LogDebug($"Begin Discovery...");
-
- //Instantiate collection of certificate store locations to pass back
- List locations = new List();
-
- try
- {
- //Code logic to:
- // 1) Connect to the orchestrated server if necessary (config.CertificateStoreDetails.ClientMachine)
- // 2) Custom logic to search for valid certificate stores based on passed in:
- // a) Directories to search
- // b) Extensions
- // c) Directories to ignore
- // d) File name patterns to match
- // 3) Place found and validated store locations (path and file name) in "locations" collection instantiated above
- }
- catch (Exception ex)
- {
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
-
- try
- {
- //Sends store locations back to KF command where they can be approved or rejected
- submitDiscovery.Invoke(locations);
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
- }
- catch (Exception ex)
- {
- // NOTE: if the cause of the submitInventory.Invoke exception is a communication issue between the Orchestrator server and the Command server, the job status returned here
- // may not be reflected in Keyfactor Command.
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
- }
- }
-}
\ No newline at end of file
diff --git a/SampleOrchestratorExtension/Inventory.cs b/SampleOrchestratorExtension/Inventory.cs
deleted file mode 100644
index 22c7252..0000000
--- a/SampleOrchestratorExtension/Inventory.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-using Keyfactor.Logging;
-using Keyfactor.Orchestrators.Extensions;
-
-using Microsoft.Extensions.Logging;
-
-namespace Keyfactor.Extensions.Orchestrator.SampleOrchestratorExtension
-{
- // The Inventory class implementes IAgentJobExtension and is meant to find all of the certificates in a given certificate store on a given server
- // and return those certificates back to Keyfactor for storing in its database. Private keys will NOT be passed back to Keyfactor Command
- public class Inventory : IInventoryJobExtension
- {
- //Necessary to implement IInventoryJobExtension but not used. Leave as empty string.
- public string ExtensionName => "";
-
- //Job Entry Point
- public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpdate submitInventory)
- {
- //METHOD ARGUMENTS...
- //config - contains context information passed from KF Command to this job run:
- //
- // config.Server.Username, config.Server.Password - credentials for orchestrated server - use to authenticate to certificate store server.
- //
- // config.ServerUsername, config.ServerPassword - credentials for orchestrated server - use to authenticate to certificate store server.
- // config.CertificateStoreDetails.ClientMachine - server name or IP address of orchestrated server
- // config.CertificateStoreDetails.StorePath - location path of certificate store on orchestrated server
- // config.CertificateStoreDetails.StorePassword - if the certificate store has a password, it would be passed here
- // config.CertificateStoreDetails.Properties - JSON string containing custom store properties for this specific store type
-
- //NLog Logging to c:\CMS\Logs\CMS_Agent_Log.txt
- ILogger logger = LogHandler.GetClassLogger(this.GetType());
- logger.LogDebug($"Begin Inventory...");
-
- //List is the collection that the interface expects to return from this job. It will contain a collection of certificates found in the store along with other information about those certificates
- List inventoryItems = new List();
-
- try
- {
- //Code logic to:
- // 1) Connect to the orchestrated server (config.CertificateStoreDetails.ClientMachine) containing the certificate store to be inventoried (config.CertificateStoreDetails.StorePath)
- // 2) Custom logic to retrieve certificates from certificate store.
- // 3) Add certificates (no private keys) to the collection below. If multiple certs in a store comprise a chain, the Certificates array will house multiple certs per InventoryItem. If multiple certs
- // in a store comprise separate unrelated certs, there will be one InventoryItem object created per certificate.
-
- //**** Will need to uncomment the block below and code to the extension's specific needs. This builds the collection of certificates and related information that will be passed back to the KF Orchestrator service and then Command.
- //inventoryItems.Add(new AgentCertStoreInventoryItem()
- //{
- // ItemStatus = OrchestratorInventoryItemStatus.Unknown, //There are other statuses, but Command can determine how to handle new vs modified certificates
- // Alias = {valueRepresentingChainIdentifier}
- // PrivateKeyEntry = true|false //You will not pass the private key back, but you can identify if the main certificate of the chain contains a private key in the store
- // UseChainLevel = true|false, //true if Certificates will contain > 1 certificate, main cert => intermediate CA cert => root CA cert. false if Certificates will contain an array of 1 certificate
- // Certificates = //Array of single X509 certificates in Base64 string format (certificates if chain, single cert if not), something like:
- // ****************************
- // foreach(X509Certificate2 certificate in certificates)
- // certList.Add(Convert.ToBase64String(certificate.Export(X509ContentType.Cert)));
- // certList.ToArray();
- // ****************************
- //});
-
- }
- catch (Exception ex)
- {
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
-
- try
- {
- //Sends inventoried certificates back to KF Command
- submitInventory.Invoke(inventoryItems);
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
- }
- catch (Exception ex)
- {
- // NOTE: if the cause of the submitInventory.Invoke exception is a communication issue between the Orchestrator server and the Command server, the job status returned here
- // may not be reflected in Keyfactor Command.
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
- }
- }
-}
\ No newline at end of file
diff --git a/SampleOrchestratorExtension/Management.cs b/SampleOrchestratorExtension/Management.cs
deleted file mode 100644
index a91e14b..0000000
--- a/SampleOrchestratorExtension/Management.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-
-using Keyfactor.Logging;
-using Keyfactor.Orchestrators.Extensions;
-using Keyfactor.Orchestrators.Common.Enums;
-
-using Microsoft.Extensions.Logging;
-
-namespace Keyfactor.Extensions.Orchestrator.SampleOrchestratorExtension
-{
- public class Management : IManagementJobExtension
- {
- //Necessary to implement IManagementJobExtension but not used. Leave as empty string.
- public string ExtensionName => "";
-
- //Job Entry Point
- public JobResult ProcessJob(ManagementJobConfiguration config)
- {
- //METHOD ARGUMENTS...
- //config - contains context information passed from KF Command to this job run:
- //
- // config.Server.Username, config.Server.Password - credentials for orchestrated server - use to authenticate to certificate store server.
- //
- // config.ServerUsername, config.ServerPassword - credentials for orchestrated server - use to authenticate to certificate store server.
- // config.CertificateStoreDetails.ClientMachine - server name or IP address of orchestrated server
- // config.CertificateStoreDetails.StorePath - location path of certificate store on orchestrated server
- // config.CertificateStoreDetails.StorePassword - if the certificate store has a password, it would be passed here
- // config.CertificateStoreDetails.Properties - JSON string containing custom store properties for this specific store type
- //
- // config.JobCertificate.EntryContents - Base64 encoded string representation (PKCS12 if private key is included, DER if not) of the certificate to add for Management-Add jobs.
- // config.JobCertificate.Alias - optional string value of certificate alias (used in java keystores and some other store types)
- // config.OpeerationType - enumeration representing function with job type. Used only with Management jobs where this value determines whether the Management job is a CREATE/ADD/REMOVE job.
- // config.Overwrite - Boolean value telling the Orchestrator Extension whether to overwrite an existing certificate in a store. How you determine whether a certificate is "the same" as the one provided is AnyAgent implementation dependent
- // config.JobCertificate.PrivateKeyPassword - For a Management Add job, if the certificate being added includes the private key (therefore, a pfx is passed in config.JobCertificate.EntryContents), this will be the password for the pfx.
-
-
- //NLog Logging to c:\CMS\Logs\CMS_Agent_Log.txt
- ILogger logger = LogHandler.GetClassLogger(this.GetType());
- logger.LogDebug($"Begin Management...");
-
- try
- {
- //Management jobs, unlike Discovery, Inventory, and Reenrollment jobs can have 3 different purposes:
- switch (config.OperationType)
- {
- case CertStoreOperationType.Add:
- //OperationType == Add - Add a certificate to the certificate store passed in the config object
- //Code logic to:
- // 1) Connect to the orchestrated server (config.CertificateStoreDetails.ClientMachine) containing the certificate store
- // 2) Custom logic to add certificate to certificate store (config.CertificateStoreDetails.StorePath) possibly using alias as an identifier if applicable (config.JobCertificate.Alias). Use alias and overwrite flag (config.Overwrite)
- // to determine if job should overwrite an existing certificate in the store, for example a renewal.
- break;
- case CertStoreOperationType.Remove:
- //OperationType == Remove - Delete a certificate from the certificate store passed in the config object
- //Code logic to:
- // 1) Connect to the orchestrated server (config.CertificateStoreDetails.ClientMachine) containing the certificate store
- // 2) Custom logic to remove the certificate in a certificate store (config.CertificateStoreDetails.StorePath), possibly using alias (config.JobCertificate.Alias) or certificate thumbprint to identify the certificate (implementation dependent)
- break;
- case CertStoreOperationType.Create:
- //OperationType == Create - Create an empty certificate store in the provided location
- //Code logic to:
- // 1) Connect to the orchestrated server (config.CertificateStoreDetails.ClientMachine) where the certificate store (config.CertificateStoreDetails.StorePath) will be located
- // 2) Custom logic to first check if the store already exists and add it if not. If it already exists, implementation dependent as to how to handle - error, warning, success
- break;
- default:
- //Invalid OperationType. Return error. Should never happen though
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = $"Site {config.CertificateStoreDetails.StorePath} on server {config.CertificateStoreDetails.ClientMachine}: Unsupported operation: {config.OperationType.ToString()}" };
- }
- }
- catch (Exception ex)
- {
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
-
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
- }
- }
-}
\ No newline at end of file
diff --git a/SampleOrchestratorExtension/Reenrollment.cs b/SampleOrchestratorExtension/Reenrollment.cs
deleted file mode 100644
index e66903b..0000000
--- a/SampleOrchestratorExtension/Reenrollment.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-using Keyfactor.Logging;
-using Keyfactor.Orchestrators.Extensions;
-
-using Microsoft.Extensions.Logging;
-
-namespace Keyfactor.Extensions.Orchestrator.SampleOrchestratorExtension
-{
- // The Reenrollment class implementes IAgentJobExtension and is meant to:
- // 1) Generate a new public/private keypair locally
- // 2) Generate a CSR from the keypair,
- // 3) Submit the CSR to KF Command to enroll the certificate and retrieve the certificate back
- // 4) Deploy the newly re-enrolled certificate to a certificate store
- public class Reenrollment : IReenrollmentJobExtension
- {
- //Necessary to implement IReenrollmentJobExtension but not used. Leave as empty string.
- public string ExtensionName => "";
-
- //Job Entry Point
- public JobResult ProcessJob(ReenrollmentJobConfiguration config, SubmitReenrollmentCSR submitReenrollment)
- {
- //METHOD ARGUMENTS...
- //config - contains context information passed from KF Command to this job run:
- //
- // config.Server.Username, config.Server.Password - credentials for orchestrated server - use to authenticate to certificate store server.
- //
- // config.ServerUsername, config.ServerPassword - credentials for orchestrated server - use to authenticate to certificate store server.
- // config.CertificateStoreDetails.ClientMachine - server name or IP address of orchestrated server
- // config.CertificateStoreDetails.StorePath - location path of certificate store on orchestrated server
- // config.CertificateStoreDetails.StorePassword - if the certificate store has a password, it would be passed here
- // config.CertificateStoreDetails.Properties - JSON string containing custom store properties for this specific store type
- //
- // config.JobProperties = Dictionary of custom parameters to use in building CSR and placing enrolled certiciate in a the proper certificate store
-
- //NLog Logging to c:\CMS\Logs\CMS_Agent_Log.txt
- ILogger logger = LogHandler.GetClassLogger(this.GetType());
- logger.LogDebug($"Begin Reenrollment...");
-
- try
- {
- //Code logic to:
- // 1) Generate a new public/private keypair locally from any config.JobProperties passed
- // 2) Generate a CSR from the keypair (PKCS10),
- // 3) Submit the CSR to KF Command to enroll the certificate using:
- // string resp = (string)submitEnrollmentRequest.Invoke(Convert.ToBase64String(PKCS10_bytes);
- // X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(resp));
- // 4) Deploy the newly re-enrolled certificate (cert in #3) to a certificate store
- }
- catch (Exception ex)
- {
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Failure, JobHistoryId = config.JobHistoryId, FailureMessage = "Custom message you want to show to show up as the error message in Job History in KF Command" };
- }
-
- //Status: 2=Success, 3=Warning, 4=Error
- return new JobResult() { Result = Keyfactor.Orchestrators.Common.Enums.OrchestratorJobStatusJobResult.Success, JobHistoryId = config.JobHistoryId };
- }
- }
-}
\ No newline at end of file
diff --git a/SampleOrchestratorExtension/SampleOrchestratorExtension.csproj b/SampleOrchestratorExtension/SampleOrchestratorExtension.csproj
deleted file mode 100644
index 9f84aa9..0000000
--- a/SampleOrchestratorExtension/SampleOrchestratorExtension.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- netcoreapp3.1
-
-
-
-
-
-
-
-
diff --git a/integration-manifest.json b/integration-manifest.json
index 56d6c38..39c0381 100644
--- a/integration-manifest.json
+++ b/integration-manifest.json
@@ -1,63 +1,79 @@
{
"$schema": "https://keyfactor.github.io/integration-manifest-schema.json",
"integration_type": "orchestrator",
- "name": "Integration Template",
+ "name": "F5 BigIQ",
"status": "prototype",
- "support_level": "community",
- "description": "This project is meant to be a template to quickly build a basic integration product build. Currently in dev, a work in progress,",
+ "support_level": "kf-supported",
+ "description": "The F5 Big IQ Orchestrator allows for the remote management of F5 Big IQ certificate stores. Inventory and Management functions are supported.",
"link_github": false,
"update_catalog": false,
- "release_dir": "UPDATE-THIS-WITH-PATH-TO-BINARY-BUILD-FOLDER",
+ "release_dir": "F5BigIQ/bin/Release",
"about": {
"orchestrator": {
- "UOFramework": "10.1",
- "keyfactor_platform_version": "9.10",
+ "UOFramework": "10.4",
+ "keyfactor_platform_version": "10.3",
"pam_support": true,
"win": {
"supportsCreateStore": false,
"supportsDiscovery": false,
- "supportsManagementAdd": false,
- "supportsManagementRemove": false,
+ "supportsManagementAdd": true,
+ "supportsManagementRemove": true,
"supportsReenrollment": false,
- "supportsInventory": false
+ "supportsInventory": true
},
"linux": {
"supportsCreateStore": false,
"supportsDiscovery": false,
- "supportsManagementAdd": false,
- "supportsManagementRemove": false,
+ "supportsManagementAdd": true,
+ "supportsManagementRemove": true,
"supportsReenrollment": false,
- "supportsInventory": false
+ "supportsInventory": true
},
"store_types": [
{
- "Name": "MyOrchestratorStoreType",
- "ShortName": "MOST",
- "Capability": "MOST",
+ "Name": "F5 Big IQ",
+ "ShortName": "F5-BigIQ",
+ "Capability": "F5-BigIQ",
"LocalStore": false,
"SupportedOperations": {
- "Add": false,
+ "Add": true,
"Create": false,
- "Discovery": true,
+ "Discovery": false,
"Enrollment": false,
- "Remove": false
+ "Remove": true
},
"Properties": [
{
- "Name": "CustomField1",
- "DisplayName": "CustomField1",
- "Type": "String",
+ "Name": "DeployCertificateOnRenewal",
+ "DisplayName": "Deploy Certificate to Linked Big IP on Renewal",
+ "Type": "Bool",
"DependsOn": "",
- "DefaultValue": "default",
- "Required": true
+ "DefaultValue": "false",
+ "Required": false
},
{
- "Name": "CustomField2",
- "DisplayName": "CustomField2",
- "Type": "String",
+ "Name": "IgnoreSSLWarning",
+ "DisplayName": "Ignore SSL Warning",
+ "Type": "Bool",
+ "DependsOn": "",
+ "DefaultValue": "false",
+ "Required": false
+ },
+ {
+ "Name": "UseTokenAuth",
+ "DisplayName": "Use Token Authentication",
+ "Type": "Bool",
"DependsOn": "",
- "DefaultValue": null,
- "Required": true
+ "DefaultValue": "false",
+ "Required": false
+ },
+ {
+ "Name": "LoginProviderName",
+ "DisplayName": "Authentication Provider Name",
+ "Type": "String",
+ "DependsOn": "UseTokenAuth",
+ "DefaultValue": "",
+ "Required": false
}
],
"EntryParameters": [],
@@ -66,14 +82,12 @@
"StoreRequired": false,
"Style": "Default"
},
- "StorePathType": "",
- "StorePathValue": "",
- "PrivateKeyAllowed": "Forbidden",
+ "PrivateKeyAllowed": "Required",
"JobProperties": [],
"ServerRequired": true,
"PowerShell": false,
"BlueprintAllowed": false,
- "CustomAliasAllowed": "Forbidden"
+ "CustomAliasAllowed": "Required"
}
]
}
diff --git a/readme-src/readme-pam-support.md b/readme-src/readme-pam-support.md
index 3f0d377..c1144e7 100644
--- a/readme-src/readme-pam-support.md
+++ b/readme-src/readme-pam-support.md
@@ -1,6 +1,5 @@
|Name|Description|
|----|-----------|
-|ServerUsername|The user id that will be used to authenticate into the server hosting the store|
-|ServerPassword|The password that will be used to authenticate into the server hosting the store|
-|StorePassword|The optional password used to secure the certificate store being managed|
+|ServerUsername|The user id that will be used to authenticate to the F5 Biq API endpoints|
+|ServerPassword|The password that will be used to authenticate to the F5 Biq API endpoints|
diff --git a/readme_source.md b/readme_source.md
index 3cc7348..6c52d0c 100644
--- a/readme_source.md
+++ b/readme_source.md
@@ -1,3 +1,127 @@
+**Please note that this integration will work with the Universal Orchestrator version 10.1 or greater**
-### License
-[Apache](https://apache.org/licenses/LICENSE-2.0)
+## Use Cases
+
+The F5 Big IQ Orchestrator Extension supports the following capabilities for SSL certificates:
+
+- Inventory
+- Management (Add and Remove)
+
+
+## Versioning
+
+The version number of a the F5 Big IQ Orchestrator Extension can be verified by right clicking on the F5BigIQ.dll file, selecting Properties, and then clicking on the Details tab.
+
+
+## F5 Big IQ Prerequisites
+
+When creating a Keyfactor Command Certificate Store, you will be asked to enter server credentials. These credentials will serve two purposes:
+1. They will be used to authenticate to the F5 Big IQ instance when accessing API endpoints. Please make sure these credentials have Admin authority on F5 Big IQ.
+2. When Inventorying and Adding/Replacing certificates it will be necessary for certificate files to be transferred to and from the F5 device. The F5 Big IQ Orchestrator Extension uses SCP (Secure Copy Protocol) to perform these functions. Please make sure your F5 Big IQ device is set up to allow SCP to transfer files *to* /var/config/rest/downloads (a reserved F5 Big IQ folder used for file transfers) and *from* /var/config/rest/fileobject (the certificate file location path) and all subfolders. You may need go into the /etc/ssh/sshd_config file on your F5 Big IQ device and set PasswordAuthentication from “No” to “Yes” for SCP to work. Other configuration tasks may be necessary in your environment to enable this feature.
+
+
+## F5 Big IQ Orchestrator Extension Installation
+
+1. Stop the Keyfactor Universal Orchestrator Service.
+2. In the Keyfactor Orchestrator installation folder (by convention usually C:\Program Files\Keyfactor\Keyfactor Orchestrator), find the "extensions" folder. Underneath that, create a new folder named F5BigIQ or another name of your choosing.
+3. Download the latest version of the F5 BigIQ Orchestrator Extension from [GitHub](https://github.com/Keyfactor/f5-bigiq-rest-orchestrator).
+4. Copy the contents of the download installation zip file into the folder created in step 2.
+5. Start the Keyfactor Universal Orchestrator Service.
+
+
+## F5 Big IQ Orchestrator Extension Configuration
+
+### 1\. In Keyfactor Command, create a new certificate store type by navigating to Settings (the "gear" icon in the top right) => Certificate Store Types, and clicking ADD. Then enter the following information:
+
+**Basic Tab**
+- **Name** – Required. The descriptive display name of the new Certificate Store Type. Suggested => F5 Big IQ
+- **Short Name** – Required. This value ***must be*** F5-BigIQ.
+- **Custom Capability** - Leave unchecked
+- **Supported Job Types** – Select Inventory, Add, and Remove.
+- **General Settings** - Select Needs Server. Select Blueprint Allowed if you plan to use blueprinting. Leave Uses PowerShell unchecked.
+- **Password Settings** - Leave both options unchecked
+
+**Advanced Tab**
+- **Store Path Type** - Select Freeform
+- **Supports Custom Alias** - Required
+- **Private Key Handling** - Required
+- **PFX Password Style** - Default
+
+**Custom Fields Tab**
+
+- **Deploy Certificate to Linked Big IP on Renewal** - optional - This setting determines you wish to deploy renewed certificates (Management-Add jobs with Overwrite selected) to all linked Big IP devices. Linked devices are determined by looking at all of the client-ssl profiles that reference the renewed certificate that have an associated virtual server linked to a Big IP device. An "immediate" deployment is then scheduled within F5 Big IQ for each linked Big IP device.
+ - **Name**=DeployCertificateOnRenewal
+ - **Display Name**=Deploy Certificate to Linked Big IP on Renewal
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Ignore SSL Warning** - optional - If you use a self signed certificate for the F5 Big IQ portal, you will need add this Custom Field and set the value to True on the managed certificate store.
+ - **Name**=IgnoreSSLWarning
+ - **Display Name**=Ignore SSL Warning
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Use Token Authentication** - optional - If you prefer to use F5 Big IQ's Token Authentication to authenticate F5 Big IQ API calls that the integration uses, you will need to add this Custom Field and set the value to True on the managed certificate store. If this exists and is set to True for the store, the store userid/password credentials you set for the certificate store will be used once to receive a token. This token is then used for all remaining API calls for the duration of the job. If this option does not exist or is set to False, the userid/password credentials you set on the certificate store will be used for each API call.
+ - **Name**=LoginProviderName
+ - **Display Name**=Authentication Provider Name
+ - **Type**=String
+ - **Default Value**={client preference}
+ - **Depends on**=""
+ - **Required**=unchecked
+
+- **Use Token Authentication** - optional - If you prefer to use F5 Big IQ's Token Authentication to authenticate F5 Big IQ API calls that the integration uses, you will need to add this Custom Field and set the value to True on the managed certificate store. If this exists and is set to True for the store, the store userid/password credentials you set for the certificate store will be used once to receive a token. This token is then used for all remaining API calls for the duration of the job. If this option does not exist or is set to False, the userid/password credentials you set on the certificate store will be used for each API call.
+ - **Name**=UseTokenAuth
+ - **Display Name**=Use Token Authentication
+ - **Type**=Bool
+ - **Default Value**={client preference}
+ - **Depends on**=unchecked
+ - **Required**=unchecked
+
+- **Use Token Authentication Provider Name** - optional - If Use Token Authentication is selected, you may optionally add a value for the authentication provider F5 Big IQ will use to retrieve the auth token. If you choose not to add this field or leave it blank on the certificate store (with no default value set), the default of "TMOS" will be used.
+ - **Display Name**=Use Token Authentication Provider Name
+ - **Type**=String
+ - **Default Value**={client preference}
+ - **Depends on**="UseTokenAuth"
+ - **Required**=unchecked
+
+Please note, after saving the store type, going back into this screen will show three additional Custom Fields: Server Username, Server Password, and Use SSL. These are added internally by Keyfactor Command and should not be modified.
+
+**Entry Parameters Tab**
+
+No Entry Parameters should be added.
+
+
+### 2\. Create an F5 Big IQ Certificate Store
+
+Navigate to Certificate Locations =\> Certificate Stores within Keyfactor Command to add the store. Below are the values that should be entered:
+
+- **Category** – Required. Select the Name you entered when creating the Certificate Store Type. Suggested value was F5 Big IQ.
+
+- **Container** – Optional. Select a container if utilized.
+
+- **Client Machine & Credentials** – Required. The full URL of the F5 Big IQ device portal.
+
+- **Store Path** – Required. Enter the name of the partition on the F5 Big IQ device you wish to manage. This value is case sensitive, so if the partition name is "Common", it must be entered as "Common" and not "common".
+
+- **Orchestrator** – Required. Select the orchestrator you wish to use to manage this store
+
+- **Deploy Certificate to Linked Big IP on Renewal** - Optional. Set this to True if you wish to deploy renewed certificates (Management-Add jobs with Overwrite selected) to all linked Big IP devices. Linked devices are determined by looking at all of the client-ssl profiles that reference the renewed certificate that have an associated virtual server linked to a Big IP device. An "immediate" deployment is then scheduled within F5 Big IQ for each linked Big IP device.
+
+- **Ignore SSL Warning** - Optional. Set this to True 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 chose not to add this Custom Field when creating the Certificate Store Type, the default value of False will be assumed. If this value is False (or missing) SSL warnings will cause errors during orchestrator extension jobs.
+
+- **Use Token Authentication** - Optional. Set this to True if you wish to use F5 Big IQ's token authentiation instead of basic authentication for all API requests. If you chose not to add this optional Custom Field when creating the Certificate Store Type, 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.
+
+- **Server Username/Password** - Required. The credentials used to log into the F5 Big IQ device to perform API calls. These values for server login can be either:
+
+ - UserId/Password
+ - PAM provider information used to look up the UserId/Password credentials
+
+ Please make sure these credentials have Admin rights on the F5 Big IQ device and can perform SCP functions as described in the F5 Big IQ Prerequisites section above.
+
+- **Use SSL** - N/A. This value is not referenced in the F5 Big IQ Orchestrator Extension. The value you enter for Client Machine, and specifically whether the protocol entered is http:// or https:// will determine whether a TLS (SSL) connection is utilized.
+
+- **Inventory Schedule** – Set a schedule for running Inventory jobs or "none", if you choose not to schedule Inventory at this time.
\ No newline at end of file