AWS Certificate Manager
AWS Certificate Manager
External Secrets Operator integrates with AWS Certificate Manager (ACM) to support:
- Exporting certificates from ACM into Kubernetes via
ExternalSecret. - Importing TLS certificates into ACM via
PushSecret(e.g., certificates issued by cert-manager).
Both public and private ACM certificates can be exported, provided the export option was enabled when the certificate was requested. See Exportable Certificates below for details.
SecretStore
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: aws-certificate-manager
spec:
provider:
aws:
service: CertificateManager
region: us-east-1
auth:
secretRef:
accessKeyIDSecretRef:
name: awssm-secret
key: access-key
secretAccessKeySecretRef:
name: awssm-secret
key: secret-access-key
NOTE: In case of a ClusterSecretStore, be sure to provide namespace in accessKeyIDSecretRef and secretAccessKeySecretRef with the namespaces where the secrets reside.
IAM Policy
The required IAM permissions depend on whether you use ExternalSecret (export), PushSecret (import), or both.
Export only (ExternalSecret)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:DescribeCertificate",
"acm:ExportCertificate",
"acm:GetCertificate"
],
"Resource": "*"
}
]
}
Import only (PushSecret)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:GetCertificate",
"acm:ImportCertificate",
"acm:DeleteCertificate",
"acm:AddTagsToCertificate",
"acm:ListTagsForCertificate",
"acm:RemoveTagsFromCertificate",
"tag:GetResources"
],
"Resource": "*"
}
]
}
The tag:GetResources permission (Resource Groups Tagging API) is used to locate certificates by their ESO management tags with server-side filtering. tag:GetResources does not support resource-level ARNs and must be granted on "Resource": "*".
Both export and import
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:GetCertificate",
"acm:ImportCertificate",
"acm:DeleteCertificate",
"acm:DescribeCertificate",
"acm:ExportCertificate",
"acm:AddTagsToCertificate",
"acm:ListTagsForCertificate",
"acm:RemoveTagsFromCertificate",
"tag:GetResources"
],
"Resource": "*"
}
]
}
You can scope the acm:* actions to specific certificate ARNs or use conditions to restrict access to certain regions or accounts. tag:GetResources must remain on "Resource": "*".
ExternalSecret
Exportable Certificates
Both public and private ACM certificates can be exported, but the certificate must have been requested with the export option enabled. This option cannot be changed after the certificate is created — if it was not enabled at request time, the certificate is not exportable.
Requesting a public certificate with the export option enabled is a paid feature — AWS charges a fee upon issuance and again on each renewal. Separately, the ExportCertificate API is free for the first 10,000 calls per month per account; exceeding this threshold incurs additional per-call charges. See the ACM pricing page for current details.
Export Caching
To minimize calls to the paid ExportCertificate API, the provider caches exported PEM bundles in memory, keyed by certificate ARN. On each access the provider calls the free GetCertificate and compares the certificate's fingerprint against the cached entry, which prevents serving stale data; ExportCertificate is only called on the first access, when the fingerprint changes (certificate renewal), or when the cached entry has been evicted. The cache is bounded to 128 entries with a 24-hour TTL per entry (LRU eviction above that). It is held on the long-lived AWS provider instance and survives across reconciles, but is in-memory only and is reset when the operator pod restarts or when the underlying SecretStore is updated.
Usage
Use remoteRef.key to specify the certificate ARN. The provider returns the certificate, chain, and decrypted private key as a single PEM bundle. Use template functions such as filterPEM and filterCertChain to extract individual components:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: acm-exported-cert
spec:
refreshInterval: 1h0m0s
secretStoreRef:
kind: SecretStore
name: aws-certificate-manager
target:
template:
type: kubernetes.io/tls
engineVersion: v2
data:
tls.crt: '{{ .cert | filterPEM "CERTIFICATE" }}'
tls.key: '{{ .cert | filterPEM "PRIVATE KEY" }}'
data:
- secretKey: cert
remoteRef:
key: arn:aws:acm:us-east-1:123456789012:certificate/abcd-1234
You can also extract just the leaf or intermediate certificates using filterCertChain:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: acm-exported-cert-chain
spec:
refreshInterval: 1h0m0s
secretStoreRef:
kind: SecretStore
name: aws-certificate-manager
target:
template:
type: kubernetes.io/tls
engineVersion: v2
data:
ca.crt: '{{ .cert | filterPEM "CERTIFICATE" | filterCertChain "intermediate" }}'
tls.crt: '{{ .cert | filterPEM "CERTIFICATE" | filterCertChain "leaf" }}'
tls.key: '{{ .cert | filterPEM "PRIVATE KEY" }}'
data:
- secretKey: cert
remoteRef:
key: arn:aws:acm:us-east-1:123456789012:certificate/abcd-1234
PushSecret
The ACM provider expects the source Kubernetes secret to be a standard kubernetes.io/tls secret containing:
tls.crt— PEM-encoded leaf certificate, optionally followed by intermediate CA certificates.tls.key— PEM-encoded private key.
The spec.data entry must not set secretKey — the provider always reads the full secret in whole-secret mode because ACM's ImportCertificate API requires both the certificate and private key in a single call.
The remoteKey field is used as a tag value (external-secrets-remote-key) to identify and track the imported certificate in ACM.
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: acm-certificate
spec:
deletionPolicy: Delete
refreshInterval: 1h0m0s
secretStoreRefs:
- name: aws-certificate-manager
kind: SecretStore
selector:
secret:
name: my-tls-cert
data:
- match:
remoteRef:
remoteKey: my-app-certificate
Certificate Chain Handling
The provider automatically splits the tls.crt PEM bundle:
- The first PEM block is treated as the leaf certificate and passed as the
Certificatefield. - Any subsequent PEM blocks are passed as-is in the
CertificateChainfield.
This matches the output format of cert-manager, which places the leaf certificate first, followed by intermediates.
Custom Tags (Metadata)
You can apply custom AWS resource tags to the imported certificate using PushSecret metadata:
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: acm-certificate-with-tags
spec:
deletionPolicy: Delete
refreshInterval: 1h0m0s
secretStoreRefs:
- name: aws-certificate-manager
kind: SecretStore
selector:
secret:
name: my-tls-cert
data:
- match:
remoteRef:
remoteKey: my-app-certificate
metadata:
apiVersion: kubernetes.external-secrets.io/v1alpha1
kind: PushSecretMetadata
spec:
tags:
environment: production
team: platform
The tags managed-by and external-secrets-remote-key are reserved for ESO internal tracking and cannot be overridden via metadata.
Usage with cert-manager
A common pattern is to use cert-manager to provision TLS certificates and then push them to ACM via PushSecret. cert-manager stores issued certificates as kubernetes.io/tls secrets, which is exactly the format expected by the ACM provider.
1. Create a Certificate resource:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-app-cert
spec:
secretName: my-tls-cert
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- myapp.example.com
2. Create a PushSecret to import the certificate into ACM:
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: acm-my-app-cert
spec:
deletionPolicy: Delete
refreshInterval: 1h0m0s
secretStoreRefs:
- name: aws-certificate-manager
kind: SecretStore
selector:
secret:
name: my-tls-cert
data:
- match:
remoteRef:
remoteKey: my-app-certificate
When cert-manager renews the certificate, the PushSecret controller will detect the change and re-import the updated certificate into ACM using the same ARN (identified by the external-secrets-remote-key tag). This keeps the ACM certificate in sync without creating duplicates.
If the PushSecret is deleted and deletionPolicy is set to Delete, the imported certificate will be removed from ACM (provided it is not in use).