Skip to main content

AWS ACM module

Imports (and on renewal re-imports) the certificate into AWS Certificate Manager. AWS propagates a same-ARN re-import to every attached resource — CloudFront, ALB/ELB, API Gateway — so no CloudFront/ELB API calls are needed.

Overview

CloudFront, ALB/ELB and API Gateway don't accept a certificate directly — they reference an ACM certificate by ARN. When a certificate is re-imported into the same ARN, AWS automatically pushes the new key material to every resource using that ARN. This single module therefore covers all three services without touching their APIs.

  • Type: awsacm, credential type: aws_aksk (access key ID + secret access key), slot default.
  • Per target: resolve the ACM ARN → acm:ImportCertificate (leaf + private key + intermediate chain) → persist the resulting ARN for the next renewal.
  • Rollback: not supported — a re-import overwrites the ACM certificate in place and AWS has already propagated it.

Region rules

  • CloudFront requires the certificate in us-east-1 — always, regardless of where your origin runs.
  • ALB/ELB and API Gateway use the resource's own region — set region accordingly.
  • CloudFront accepts only ECDSA P-256 or RSA-2048 keys. An RSA-3072/4096 or ECDSA P-384 certificate imports into ACM fine but CloudFront rejects it on association — pick the certificate's key type accordingly.
  • A certificate_arn whose region segment disagrees with the target region is rejected up front (AWS_IMPORT) instead of surfacing as an opaque AWS ResourceNotFound.

Create the AWS credential

In the AWS console:

  1. IAM → Policies → Create policy → JSON — paste the policy below, name it (e.g. CertAutoPilotACM).
  2. IAM → Users → Create user (e.g. certautopilot-acm), no console access. On the permissions step choose Attach policies directly and select the policy.
  3. Open the user → Security credentialsAccess keys → Create access key → use case Application running outside AWS → Create.
  4. Copy the Access key ID and Secret access key — the secret is shown only once.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CertAutoPilotACM",
"Effect": "Allow",
"Action": [
"acm:ImportCertificate",
"acm:DescribeCertificate",
"acm:ListCertificates",
"acm:ListTagsForCertificate",
"acm:AddTagsToCertificate"
],
"Resource": "*"
}
]
}

No CloudFront/ELB/API Gateway permissions are needed. Scope Resource down to specific certificate ARNs in production if you prefer.

Then in CertAutoPilot: Settings → Distribution → CredentialsAdd Credential → type AWS Access Key (AK/SK) (aws_aksk) → paste both values → Save.

Create an ACM target

Settings → Distribution → TargetsNew → module AWS ACM (CloudFront / ALB / API Gateway).

FieldRequiredDescription
regionyesAWS region of the ACM certificate (us-east-1 for CloudFront).
certificate_arnnoRe-import into this existing ACM certificate (adopt a cert already attached to CloudFront/ALB — keeps attachments). Empty → reuse the ARN remembered from a previous run, else create a new certificate.
certificate_namenoName tag applied only when a new certificate is created; ignored on re-import. Empty = auto-generated per certificate as cap-<token>-<domain>. Both the ARN and the Name can be overridden per distribution from the certificate's Distributions → Overrides drawer.

Pick the aws_aksk credential from the previous step.

Idempotent create — no duplicates

Every certificate the module creates is tagged certautopilot:certificate-id=<id>. On a run with no known ARN, the module first searches ACM (paginated ListCertificates, pre-filtered by primary domain, then ListTagsForCertificate) for a certificate carrying that tag and re-imports into it instead of creating a duplicate. This closes the orphan window left by a cancelled or raced first run.

ARN resolution priority: operator-set certificate_arn → ARN remembered from a previous run (remote state) → tag discovery → create new.

First-time CloudFront attachment

The first import creates the ACM certificate but nothing references it yet. Once, in the CloudFront console:

  1. Edit the distribution → Settings.
  2. Add your domain under Alternate domain name (CNAME).
  3. Under Custom SSL certificate, select the ACM certificate the module created (its Name tag = certificate_name).
  4. Save and wait for the distribution to deploy (minutes).

Every subsequent renewal re-imports into the same ARN and CloudFront picks it up automatically — no console visits, no further configuration.

ACM does not renew imported certificates

ACM's managed renewal applies only to certificates ACM itself issued. Imported certificates are never auto-renewed by AWS — CertAutoPilot drives every renewal and re-imports into the same ARN. Ignore the "renewal ineligible" note on imported certs in the ACM console.

Operations

OperationBehavior
ExecuteImport (create) or re-import (in-place update) into ACM; stores the resulting ARN as target remote state.
DryRunWith an ARN: DescribeCertificate and report "update"; without: ListCertificates to prove credentials/region and report "create".
ValidateDescribeCertificate — confirms the ACM cert exists. End-to-end serving checks belong to a tls_fingerprint validation endpoint since CloudFront propagation is asynchronous.
RollbackNot supported (rollback_available stays false).
HealthCheckListCertificates in the target region (10 s timeout) — credential/region reachability.

Error codes

CodeMeaningResolution
AWS_CREDENTIALMissing or malformed aws_aksk credentialProvide a credential JSON with access_key_id and secret_access_key.
AWS_AUTHAWS rejected the credentials or denied the actionCheck the access key and that the IAM policy grants the acm:* actions above.
AWS_CONNECTCould not reach the AWS endpoint (also used for ACM throttling, which is retried as transient)Check outbound network access to acm.<region>.amazonaws.com.
AWS_IMPORTImportCertificate failed — bad chain, key mismatch, or ARN region ≠ target regionChain must be intermediates-only; key must match the certificate; fix the region.

Troubleshooting

Browser says the certificate isn't trusted behind CloudFront

CloudFront serves whatever you imported — including a private-CA certificate that public browsers won't trust. Viewer-facing CloudFront certificates must come from a publicly trusted CA (e.g. your ACME issuer), not from an internal AD CS CA.

CloudFront serves the *.cloudfront.net certificate instead of mine

The Alternate domain name (CNAME) is missing on the distribution, or the custom SSL certificate isn't selected. Complete the first-time attachment steps.

Renewal succeeded but CloudFront still serves the old certificate

Propagation after a re-import takes minutes, not seconds. Wait, or configure a validation endpoint with generous retries against the CloudFront domain to get an explicit signal when the new cert is live.

A duplicate ACM certificate appeared

Should not happen for module-created certs (tag discovery prevents it). It can if the certautopilot:certificate-id tag was manually removed or the IAM policy lacks acm:ListTagsForCertificate/acm:AddTagsToCertificate. Set certificate_arn on the target to pin the correct one, and delete the orphan in the ACM console.

See also