From 2b41931f86cac46e34edc6ae5032150538a71bad Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 16 Jun 2026 22:34:53 +0000 Subject: [PATCH 1/5] Update generated docs --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6a2f36e..23efc3b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- AWSPCA CA Gateway AnyCA Gateway REST Plugin + AWSPCA CAPlugin AnyCA Gateway REST Plugin

@@ -38,10 +38,10 @@ This integration allows for the Synchronization, Enrollment, and Revocation of c ## Compatibility -The AWSPCA CA Gateway AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.4.0 and later. +The AWSPCA CAPlugin AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.4.0 and later. ## Support -The AWSPCA CA Gateway AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. +The AWSPCA CAPlugin AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. 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. @@ -53,7 +53,7 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and 1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). -2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [AWSPCA CA Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/aws-pca-caplugin/releases/latest) from GitHub. +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [AWSPCA CAPlugin AnyCA Gateway REST plugin](https://github.com/Keyfactor/aws-pca-caplugin/releases/latest) from GitHub. 3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: @@ -64,11 +64,11 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the AWSPCA CA Gateway AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + > The directory containing the AWSPCA CAPlugin AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. 4. Restart the AnyCA Gateway REST service. -5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the AWSPCA CA Gateway plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the AWSPCA CAPlugin plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. ## Configuration @@ -100,7 +100,7 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and * **ExternalId** - Optional sts:ExternalId to supply on AssumeRole calls. * **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available. -2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CA Gateway plugin supports the following product IDs: +2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CAPlugin plugin supports the following product IDs: * **EndEntity** * **EndEntityClientAuth** From 57f1c9e7416a19fed4dd1fe768dfcf6551db4cd7 Mon Sep 17 00:00:00 2001 From: Mark Kachkaev Date: Tue, 16 Jun 2026 18:36:03 -0400 Subject: [PATCH 2/5] Fix for the ARN not getting attached to enrollment request. --- .gitignore | 2 + README.md | 26 +++---- aws-pca-caplugin/AWSPCACAPlugin.cs | 98 ++++++++++++------------- aws-pca-caplugin/AWSPCACAPlugin.csproj | 9 +-- aws-pca-caplugin/Client/ACMPCAClient.cs | 28 ++++++- aws-pca-caplugin/Constants.cs | 4 + docsource/configuration.md | 5 -- integration-manifest.json | 3 +- 8 files changed, 96 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 43d9deb..5f58f10 100644 --- a/.gitignore +++ b/.gitignore @@ -361,3 +361,5 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd +/.claude +/issue.txt diff --git a/README.md b/README.md index 6a2f36e..e4a610b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@

- AWSPCA CA Gateway AnyCA Gateway REST Plugin + AWSPCA CAPlugin AnyCA Gateway REST Plugin

Integration Status: pilot -Release -Issues -GitHub Downloads (all assets, all releases) +Release +Issues +GitHub Downloads (all assets, all releases)

@@ -38,10 +38,10 @@ This integration allows for the Synchronization, Enrollment, and Revocation of c ## Compatibility -The AWSPCA CA Gateway AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.4.0 and later. +The AWSPCA CAPlugin AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.4.0 and later. ## Support -The AWSPCA CA Gateway AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. +The AWSPCA CAPlugin AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. 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. @@ -53,7 +53,7 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and 1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). -2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [AWSPCA CA Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/aws-pca-caplugin/releases/latest) from GitHub. +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [AWSPCA CAPlugin AnyCA Gateway REST plugin](https://github.com/Keyfactor/aws-pca-caplugin-dev/releases/latest) from GitHub. 3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: @@ -64,11 +64,11 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the AWSPCA CA Gateway AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + > The directory containing the AWSPCA CAPlugin AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. 4. Restart the AnyCA Gateway REST service. -5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the AWSPCA CA Gateway plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the AWSPCA CAPlugin plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. ## Configuration @@ -100,11 +100,12 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and * **ExternalId** - Optional sts:ExternalId to supply on AssumeRole calls. * **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available. -2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CA Gateway plugin supports the following product IDs: +2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CAPlugin plugin supports the following product IDs: * **EndEntity** * **EndEntityClientAuth** * **EndEntityServerAuth** + * **CodeSigning** 3. Follow the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Keyfactor.htm) to add each defined Certificate Authority to Keyfactor Command and import the newly defined Certificate Templates. @@ -119,11 +120,6 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and The CAPlugin currently supports **one** authentication method: **AWS Access Key ID + Secret Access Key**. **OAuth** and **Default SDK authentication** will be enabled in later updates. There is functionality present via the **Keyfactor AWS Authentication** library, but these alternate methods are currently ***untested***. -### Known Issues - -At present, a fresh install of Keyfactor Command 24.4 used in conjuction with Keyfactor Gateway REST 25.4.0.0 is confirmed as working. A fresh install of Command 25.3 used with REST 25.4.0.0 is also confirmed as working. -Latest version of Command 25.4 may run into issues, investigation into compatibility issues is ongoing. - ### What you need ready Before configuring the CAPlugin, have the following prepared: diff --git a/aws-pca-caplugin/AWSPCACAPlugin.cs b/aws-pca-caplugin/AWSPCACAPlugin.cs index 2201fc9..6a70311 100644 --- a/aws-pca-caplugin/AWSPCACAPlugin.cs +++ b/aws-pca-caplugin/AWSPCACAPlugin.cs @@ -415,60 +415,60 @@ public async Task Enroll( switch (enrollmentType) { case EnrollmentType.New: - { - return await IssueAndFetchAsync( - csr, - productInfo.ProductID, - days, - signingAlgorithm, - "Certificate Issued") - .ConfigureAwait(false); - } + { + return await IssueAndFetchAsync( + csr, + productInfo.ProductID, + days, + signingAlgorithm, + "Certificate Issued") + .ConfigureAwait(false); + } case EnrollmentType.RenewOrReissue: - { - if (productInfo.ProductParameters == null || - !TryGetProductParam(productInfo.ProductParameters, "PriorCertSN", out var priorSn) || - string.IsNullOrWhiteSpace(priorSn)) - return new EnrollmentResult - { - Status = (int)EndEntityStatus.FAILED, - StatusMessage = - "Renew/Reissue requires ProductParameters['PriorCertSN'] (hex serial number)." - }; - - string priorRequestId; - try - { - priorRequestId = await _certificateDataReader - .GetRequestIDBySerialNumber(priorSn) - .ConfigureAwait(false); - } - catch (Exception ex) + { + if (productInfo.ProductParameters == null || + !TryGetProductParam(productInfo.ProductParameters, "PriorCertSN", out var priorSn) || + string.IsNullOrWhiteSpace(priorSn)) + return new EnrollmentResult { - return new EnrollmentResult - { - Status = (int)EndEntityStatus.FAILED, - StatusMessage = $"Could not resolve PriorCertSN to request id: {ex.Message}" - }; - } - - var expiration = _certificateDataReader.GetExpirationDateByRequestId(priorRequestId); - var isRenewal = expiration.HasValue && expiration.Value.ToUniversalTime() <= DateTime.UtcNow; + Status = (int)EndEntityStatus.FAILED, + StatusMessage = + "Renew/Reissue requires ProductParameters['PriorCertSN'] (hex serial number)." + }; - var msg = isRenewal ? "Certificate Renewed" : "Certificate Reissued"; - var token = BuildIdempotencyToken(isRenewal ? "renew" : "reissue", priorRequestId, csr); - - // Still "IssueCertificate" under the hood; PCA doesn't have first-class renew/reissue. - return await IssueAndFetchAsync( - csr, - productInfo.ProductID, - days, - msg, - // Optional: stable-ish idempotency (helps avoid duplicates if caller retries quickly) - token) + string priorRequestId; + try + { + priorRequestId = await _certificateDataReader + .GetRequestIDBySerialNumber(priorSn) .ConfigureAwait(false); } + catch (Exception ex) + { + return new EnrollmentResult + { + Status = (int)EndEntityStatus.FAILED, + StatusMessage = $"Could not resolve PriorCertSN to request id: {ex.Message}" + }; + } + + var expiration = _certificateDataReader.GetExpirationDateByRequestId(priorRequestId); + var isRenewal = expiration.HasValue && expiration.Value.ToUniversalTime() <= DateTime.UtcNow; + + var msg = isRenewal ? "Certificate Renewed" : "Certificate Reissued"; + var token = BuildIdempotencyToken(isRenewal ? "renew" : "reissue", priorRequestId, csr); + + // Still "IssueCertificate" under the hood; PCA doesn't have first-class renew/reissue. + return await IssueAndFetchAsync( + csr, + productInfo.ProductID, + days, + msg, + // Optional: stable-ish idempotency (helps avoid duplicates if caller retries quickly) + token) + .ConfigureAwait(false); + } default: return new EnrollmentResult @@ -685,7 +685,7 @@ public Dictionary GetCAConnectorAnnotations() DefaultValue = "", Type = "String" }, - [Constants.Enabled] = new() + [Constants.Enabled] = new () { Comments = "Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available.", Hidden = false, diff --git a/aws-pca-caplugin/AWSPCACAPlugin.csproj b/aws-pca-caplugin/AWSPCACAPlugin.csproj index ae30f76..4abdbb7 100644 --- a/aws-pca-caplugin/AWSPCACAPlugin.csproj +++ b/aws-pca-caplugin/AWSPCACAPlugin.csproj @@ -13,14 +13,13 @@ - + - - + + @@ -35,7 +34,7 @@ - + diff --git a/aws-pca-caplugin/Client/ACMPCAClient.cs b/aws-pca-caplugin/Client/ACMPCAClient.cs index 008ddb6..455ee19 100644 --- a/aws-pca-caplugin/Client/ACMPCAClient.cs +++ b/aws-pca-caplugin/Client/ACMPCAClient.cs @@ -39,6 +39,7 @@ public sealed class AwsPcaClient : IAwsPcaClient private const string ENHANCED_KEY_USAGE_OID = "2.5.29.37"; private const string SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1"; private const string CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2"; + private const string CODE_SIGNING_OID = "1.3.6.1.5.5.7.3.3"; private readonly SemaphoreSlim _caInfoLock = new(1, 1); private readonly AWSCredentials AwsCredentials; @@ -60,7 +61,6 @@ public AwsPcaClient(IAnyCAPluginConfigProvider configProvider) throw new ArgumentNullException(nameof(configProvider), "Config provider and CAConnectionData are required."); - var enabled = bool.Parse(GetRequiredString(configProvider, "Enabled")); if (!enabled) { @@ -145,12 +145,29 @@ public async Task SubmitIssueCertificateAsync( if (signingAlgoRes.Error != null) return new IssueCertificateResponse { RegistrationError = signingAlgoRes.Error }; + // Map the requested ProductId to its AWS PCA template ARN. Without this, + // PCA falls back to EndEntityCertificate/V1 and every cert gets the default + // Server+Client Auth EKU combination regardless of the selected product. + if (string.IsNullOrWhiteSpace(request.ProductId) || + !Constants.TemplateARNs.TryGetValue(request.ProductId, out var templateArn)) + return new IssueCertificateResponse + { + RegistrationError = new RegistrationError + { + Description = string.IsNullOrWhiteSpace(request.ProductId) + ? "ProductId is required to resolve the AWS PCA template ARN." + : $"Unsupported ProductId '{request.ProductId}'. Supported: {string.Join(", ", Constants.TemplateARNs.Keys)}", + ErrorCode = "InvalidRequest" + } + }; + var signingAlgorithm = signingAlgoRes.Value!; var issueReq = new Amazon.ACMPCA.Model.IssueCertificateRequest { CertificateAuthorityArn = CaArn, Csr = new MemoryStream(Encoding.ASCII.GetBytes(csrBytes)), SigningAlgorithm = signingAlgorithm, + TemplateArn = templateArn, IdempotencyToken = request.IdempotencyToken ?? Guid.NewGuid().ToString("N"), Validity = new Validity { @@ -554,14 +571,14 @@ private static string Wrap64(string b64) ///

/// Infers one of the supported template type keys: - /// EndEntity, EndEntityClientAuth, EndEntityServerAuth. + /// EndEntity, EndEntityClientAuth, EndEntityServerAuth, CodeSigning. /// Returns "Unknown" if certificate parsing/inspection fails. /// public static string InferTemplateTypeKey(X509Certificate2 cert) { try { - bool server = false, client = false; + bool server = false, client = false, codeSigning = false; // Find EKU extension (do not rely on indexer throwing) var eku = cert.Extensions @@ -574,8 +591,11 @@ public static string InferTemplateTypeKey(X509Certificate2 cert) server = true; else if (string.Equals(usage.Value, CLIENT_AUTH_OID, StringComparison.Ordinal)) client = true; + else if (string.Equals(usage.Value, CODE_SIGNING_OID, StringComparison.Ordinal)) + codeSigning = true; // Map to your known keys + if (codeSigning && !server && !client) return "CodeSigning"; if (server && !client) return "EndEntityServerAuth"; if (client && !server) return "EndEntityClientAuth"; @@ -761,4 +781,4 @@ private static class ConfigKeys public const string Region = "Region"; public const string S3Bucket = "S3Bucket"; } -} +} \ No newline at end of file diff --git a/aws-pca-caplugin/Constants.cs b/aws-pca-caplugin/Constants.cs index 69b76f3..b0f0ac0 100644 --- a/aws-pca-caplugin/Constants.cs +++ b/aws-pca-caplugin/Constants.cs @@ -22,6 +22,10 @@ public static class Constants { "EndEntityServerAuth", "arn:aws:acm-pca:::template/EndEntityServerAuthCertificate/V1" + }, + { + "CodeSigning", + "arn:aws:acm-pca:::template/CodeSigningCertificate/V1" } }; diff --git a/docsource/configuration.md b/docsource/configuration.md index f15dd50..30fee0d 100644 --- a/docsource/configuration.md +++ b/docsource/configuration.md @@ -13,11 +13,6 @@ Download the **PCA root certificate** from AWS and have it ready to import into The CAPlugin currently supports **one** authentication method: **AWS Access Key ID + Secret Access Key**. **OAuth** and **Default SDK authentication** will be enabled in later updates. There is functionality present via the **Keyfactor AWS Authentication** library, but these alternate methods are currently ***untested***. -### Known Issues - -At present, a fresh install of Keyfactor Command 24.4 used in conjuction with Keyfactor Gateway REST 25.4.0.0 is confirmed as working. A fresh install of Command 25.3 used with REST 25.4.0.0 is also confirmed as working. -Latest version of Command 25.4 may run into issues, investigation into compatibility issues is ongoing. - ### What you need ready Before configuring the CAPlugin, have the following prepared: diff --git a/integration-manifest.json b/integration-manifest.json index 515032c..ee8c3d8 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -95,7 +95,8 @@ "product_ids": [ "EndEntity", "EndEntityClientAuth", - "EndEntityServerAuth" + "EndEntityServerAuth", + "CodeSigning" ] } } From f105f72bfede80e808a04de78d1af60d76021f12 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Wed, 17 Jun 2026 18:41:53 +0000 Subject: [PATCH 3/5] Update generated docs --- README.md | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8f5bbb --- /dev/null +++ b/README.md @@ -0,0 +1,355 @@ +

+ AWSPCA CAPlugin AnyCA Gateway REST Plugin +

+ +

+ +Integration Status: pilot +Release +Issues +GitHub Downloads (all assets, all releases) +

+ +

+ + + Support + + · + + Requirements + + · + + Installation + + · + + License + + · + + Related Integrations + +

+ + +This integration allows for the Synchronization, Enrollment, and Revocation of certificates from the AWS ACM PCA. This is the AnyGateway REST version. + +## Compatibility + +The AWSPCA CAPlugin AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.4.0 and later. + +## Support +The AWSPCA CAPlugin AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. 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. + +## Requirements + +This integration is tested and confirmed as working for Anygateway REST 24.4 and above. Notice: Keyfactor Anygateway REST 24.4 requires the use of .Net 8. + +## Installation + +1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). + +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [AWSPCA CAPlugin AnyCA Gateway REST plugin](https://github.com/Keyfactor/aws-pca-caplugin/releases/latest) from GitHub. + +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + + + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions + ``` + + > The directory containing the AWSPCA CAPlugin AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + +4. Restart the AnyCA Gateway REST service. + +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the AWSPCA CAPlugin plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. + +## Configuration + +1. Follow the [official AnyCA Gateway REST documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) to define a new Certificate Authority, and use the notes below to configure the **Gateway Registration** and **CA Connection** tabs: + + * **Gateway Registration** + + Download the **PCA root certificate** from AWS and have it ready to import into the Gateway **in `.pem` format**. + + * **CA Connection** + + Populate using the configuration fields collected in the [requirements](#requirements) section. + + * **RoleArn** - Destination Role ARN to use for AWS auth. Supports the [profile] prefix when using Default SDK auth, e.g. [myprofile]arn:aws:iam::123456789012:role/MyRole. + * **Region** - AWS Region (single region only, e.g. us-east-1). + * **CAArn** - AWS ACM PCA Certificate Authority ARN. Example: arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + * **S3Bucket** - S3 bucket name used for PCA audit reports (inventory). The AWS identity in the Role context must have read/write permissions to this bucket. + * **UseDefaultSdkAuth** - Use AWS SDK default credential inference (supports EC2 instance role, environment variables, shared credentials, etc.). If RoleArn is prefixed with [profile], that profile is prioritized. + * **DefaultSdkAssumeRole** - If UseDefaultSdkAuth is true, setting this to true will perform AssumeRole into RoleArn using the inferred SDK credentials. + * **UseOAuth** - Use OAuth OIDC authentication to obtain a token, then AssumeRole into RoleArn. + * **OAuthScope** - OAuth scope to request. + * **OAuthGrantType** - OAuth grant type to request (commonly client_credentials). + * **OAuthUrl** - OAuth token endpoint URL. + * **OAuthClientId** - OAuth client id (secret). + * **OAuthClientSecret** - OAuth client secret (secret). + * **UseIAM** - Use IAM user access key/secret to AssumeRole into RoleArn. + * **IAMUserAccessKey** - IAM user access key (secret). + * **IAMUserAccessSecret** - IAM user access secret (secret). + * **ExternalId** - Optional sts:ExternalId to supply on AssumeRole calls. + * **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available. + +2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CAPlugin plugin supports the following product IDs: + + * **EndEntity** + * **EndEntityClientAuth** + * **EndEntityServerAuth** + * **CodeSigning** + +3. Follow the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Keyfactor.htm) to add each defined Certificate Authority to Keyfactor Command and import the newly defined Certificate Templates. + +4. In Keyfactor Command (v12.3+), for each imported Certificate Template, follow the [official documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm) to define enrollment fields for each of the following parameters: + + * **LifetimeDays** - OPTIONAL: The number of days of validity to use when requesting certs. If not provided, default is 365 + * **SigningAlgorithm** - Required: AWS ACM PCA certificate signature algorithm to use when issuing certificates. Value is an AWS PCA SigningAlgorithm enum name (case-insensitive), e.g. SHA256WITHRSA, SHA384WITHRSA, SHA256WITHECDSA. If omitted, the plugin selects a default compatible with the CA key algorithm. + + +## Authentication (Access Key + Secret) + +The CAPlugin currently supports **one** authentication method: **AWS Access Key ID + Secret Access Key**. +**OAuth** and **Default SDK authentication** will be enabled in later updates. There is functionality present via the **Keyfactor AWS Authentication** library, but these alternate methods are currently ***untested***. + +### What you need ready + +Before configuring the CAPlugin, have the following prepared: + +#### 1) IAMUserAccessKey and IAMUserAccessSecret +- **Access Key ID** (example format: `AKIAIOSFODNN7EXAMPLE`) +- **Secret Access Key** (example format: `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`) + +#### 2) A target IAM Role the Gateway will run as (recommended) +Example: +- `arn:aws:iam::123456789012:role/Keyfactor-AnyGateway-AcmPcaRole` + +**Role expectations:** +- The role must have permissions for: + - **ACM PCA operations** (Issue/Get/Revoke/Describe + CA certificate chain retrieval) + - **Audit report creation & status polling** (Create/Describe audit reports) + - **S3 bucket access** to read/write audit report objects + +#### 3) Permissions on the assumed role +The assumed role must have permissions for the AWS services the Gateway needs. This typically includes: +- `acm-pca:*` actions required for enrollment + revocation workflows +- Audit report actions (`acm-pca:CreateCertificateAuthorityAuditReport`, `acm-pca:DescribeCertificateAuthorityAuditReport`) +- S3 bucket and object access for the audit report destination bucket + +**See the example IAM policies below in this README section** + +#### 4) Region +Know the **AWS region** the connector should use (for service endpoints), e.g.: +- `us-east-1` + +> Region must match the region of your **ACM Private CA**. + +#### 5) CA ARN +Have the **Certificate Authority ARN** for the PCA you want to integrate with. + +Example format: +- `arn:aws:acm-pca:::certificate-authority/` + +Example: +- `arn:aws:acm-pca:us-east-2:123456789012:certificate-authority/11111111-2222-3333-4444-555555555555` + +#### 6) S3 Bucket +Choose an S3 bucket to store / retrieve ACM PCA audit reports. + +You should have: +- **Bucket name** (example: `keyfactor-acmpca-audit-reports`, not the full bucket ARN!) + + +> The role needs `s3:ListBucket` / `s3:GetBucketLocation` at the bucket ARN, and `s3:GetObject` / `s3:PutObject` on the object ARN pattern. + +#### 7) PCA Root Cert +Download the **PCA root certificate** from AWS and have it ready to import into the Gateway **in `.pem` format**. + +### Enabling all this in the Gateway Configuration Portal + +#### 1) Register the Gateway CA and upload the Root CA certificate +1. Navigate to **Gateway Registration**. +2. Upload the **Root CA Certificate** you downloaded earlier (PEM). + +#### 2) Configure the CA connection settings +1. Navigate to **CAConnection**. +2. Populate: + - `RoleArn` (example: `arn:aws:iam::123456789012:role/Keyfactor-AnyGateway-AcmPcaRole`) + - `Region` (example: `us-east-2`) + - `CAArn` (example: `arn:aws:acm-pca:us-east-2:123456789012:certificate-authority/11111111-2222-3333-4444-555555555555`) + - `S3Bucket` (example: `keyfactor-acmpca-audit-reports`) + - `IAMUserAccessKey` (example: `AKIA...`) + - `IAMUserAccessSecret` (example: `wJalrXU...`) + +3. Set these auth toggles: + - `UseDefaultSdkAuth` = `false` + - `UseOAuth` = `false` + - `UseIAM` = `true` + +--- + +### Example IAM policies for the assumed role + +The following examples are intended as **copy/adapt templates**. + +#### Example 1: Minimal PCA issuance/retrieval/revocation + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PrivateCABasicOps", + "Effect": "Allow", + "Action": [ + "acm-pca:IssueCertificate", + "acm-pca:GetCertificate", + "acm-pca:RevokeCertificate", + "acm-pca:DescribeCertificateAuthority", + "acm-pca:GetCertificateAuthorityCertificate" + ], + "Resource": "arn:aws:acm-pca:::certificate-authority/" + } + ] +} +``` + +#### Example 2: PCA issuance + audit reports + S3 audit bucket access + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PrivateCAIssueAndFetch", + "Effect": "Allow", + "Action": [ + "acm-pca:IssueCertificate", + "acm-pca:GetCertificate", + "acm-pca:DescribeCertificateAuthority", + "acm-pca:GetCertificateAuthorityCertificate" + ], + "Resource": [ + "arn:aws:acm-pca:::certificate-authority/" + ] + }, + { + "Sid": "PrivateCAAuditReportOps", + "Effect": "Allow", + "Action": [ + "acm-pca:CreateCertificateAuthorityAuditReport", + "acm-pca:DescribeCertificateAuthorityAuditReport" + ], + "Resource": "*" + }, + { + "Sid": "AuditReportBucketAccessForCaller", + "Effect": "Allow", + "Action": [ + "s3:GetBucketLocation", + "s3:ListBucket" + ], + "Resource": "arn:aws:s3:::" + }, + { + "Sid": "AuditReportObjectAccessForCaller", + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], + "Resource": "arn:aws:s3:::/*" + } + ] +} +``` +--- + +### Example policy for bucket +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowACMPCAWriteAuditReports", + "Effect": "Allow", + "Principal": { + "Service": "acm-pca.amazonaws.com" + }, + "Action": "s3:PutObject", + "Resource": "arn:aws:s3:::/*", + "Condition": { + "StringEquals": { + "aws:SourceAccount": "" + }, + "ArnLike": { + "aws:SourceArn": "arn:aws:acm-pca:::certificate-authority/" + } + } + } + ] +} +``` + +--- + +## Signing algorithm selection (ACM PCA) + +The connector supports an optional **template / product parameter** named `SigningAlgorithm` that controls the **certificate signature algorithm** +passed to AWS ACM PCA `IssueCertificate`. + +- If **not set**, the plugin will **auto-select** a compatible default based on the CA `KeyAlgorithm` returned by + `DescribeCertificateAuthority`. +- If **set**, the plugin validates the value and **rejects incompatible combinations** before calling AWS. + +### Where to configure + +Set `SigningAlgorithm` on the **AnyGateway template** (product parameters), alongside `LifetimeDays`. + +### Valid `SigningAlgorithm` values (AWS PCA) + +- RSA family: `SHA256WITHRSA`, `SHA384WITHRSA`, `SHA512WITHRSA` +- ECDSA family: `SHA256WITHECDSA`, `SHA384WITHECDSA`, `SHA512WITHECDSA` +- SM2: `SM3WITHSM2` +- ML-DSA (post-quantum): `ML_DSA_44`, `ML_DSA_65`, `ML_DSA_87` + +### Allowed CA key algorithm <-> signing algorithm combinations + +The CA key algorithm is the PCA CA **KeyAlgorithm** (not the subject key in the CSR). The signing algorithm must match the CA key family. + +| CA KeyAlgorithm | Allowed SigningAlgorithm values | +|---|---| +| `RSA_2048`, `RSA_3072`, `RSA_4096` | `SHA256WITHRSA`, `SHA384WITHRSA`, `SHA512WITHRSA` | +| `EC_prime256v1`, `EC_secp384r1`, `EC_secp521r1` | `SHA256WITHECDSA`, `SHA384WITHECDSA`, `SHA512WITHECDSA` | +| `SM2` | `SM3WITHSM2` | +| `ML_DSA_44` | `ML_DSA_44` | +| `ML_DSA_65` | `ML_DSA_65` | +| `ML_DSA_87` | `ML_DSA_87` | + +### Auto-selection defaults + +When `SigningAlgorithm` is omitted, the plugin selects: + +- RSA CAs -> `SHA256WITHRSA` +- EC P-256 -> `SHA256WITHECDSA` +- EC P-384 -> `SHA384WITHECDSA` +- EC P-521 -> `SHA512WITHECDSA` +- SM2 -> `SM3WITHSM2` +- ML-DSA -> exact-match (`ML_DSA_44/65/87`) + + +## License + +Apache License 2.0, see [LICENSE](LICENSE). + +## Related Integrations + +See all [Keyfactor Any CA Gateways (REST)](https://github.com/orgs/Keyfactor/repositories?q=anycagateway). \ No newline at end of file From 284f1fe63888ffb2c4e46488a493dc862f7b4afe Mon Sep 17 00:00:00 2001 From: Mark Kachkaev Date: Wed, 17 Jun 2026 14:44:57 -0400 Subject: [PATCH 4/5] Build change to inclu de auth fix --- aws-pca-caplugin/AWSPCACAPlugin.csproj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aws-pca-caplugin/AWSPCACAPlugin.csproj b/aws-pca-caplugin/AWSPCACAPlugin.csproj index 4abdbb7..4ae9771 100644 --- a/aws-pca-caplugin/AWSPCACAPlugin.csproj +++ b/aws-pca-caplugin/AWSPCACAPlugin.csproj @@ -3,7 +3,7 @@ true - net8.0 + net8.0;net10.0 Keyfactor.Extensions.CAPlugin.AWS true enable @@ -32,10 +32,9 @@ - - + From 4fb1efc8fe037c945064613acd446c5434f232cc Mon Sep 17 00:00:00 2001 From: Mark Kachkaev Date: Wed, 17 Jun 2026 15:00:06 -0400 Subject: [PATCH 5/5] Build package fixes --- aws-pca-caplugin/AWSPCACAPlugin.csproj | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/aws-pca-caplugin/AWSPCACAPlugin.csproj b/aws-pca-caplugin/AWSPCACAPlugin.csproj index 4ae9771..a53434c 100644 --- a/aws-pca-caplugin/AWSPCACAPlugin.csproj +++ b/aws-pca-caplugin/AWSPCACAPlugin.csproj @@ -17,11 +17,7 @@ - - - - - + @@ -30,12 +26,17 @@ + - - + + + + + - + + \ No newline at end of file