This is a cloudformation custom resource which is an enhancement of the AWS::CertificateManager::Certificate resource.
It allows creating a certificate in a region different from the stack's region (e.g. us-east-1
for cloudfront),
and allows for creating a certificate for a Route 53 hosted zone in another AWS account.
It also allows for setting the key algorithm.
To use this custom resource, copy the CustomAcmCertificateLambda and CustomAcmCertificateLambdaExecutionRole resources
into your template. You can then create certificate resources of Type: Custom::DNSCertificate
.
This resource is also available as troposphere extension, in the troposphere-dns-certificate package
Remember to add a ServiceToken property to the resource which references the CustomAcmCertificateLambda arn. Certificates may take up to 30 minutes to be issued, but typically takes ~3 minutes. The Certificate resource remains as CREATE_IN_PROGRESS until the certificate is issued.
It should behave similarly to AWS::CertificateManager::Certificate, except for the differences described here.
The additional Region
property can be used to set the region to create the certificate in.
The DomainValidationOption has a additional properties Route53RoleArn
and Route53RoleExternalId
which allow assuming a role before creating DNS validation records.
This lets you create a certificate for a hosted zone in another account.
The additional KeyAlgorithm
property allows setting the key algorithm used to generate the key pair used by the certificate.
Type: Custom::DNSCertificate
Properties:
DomainName: String
DomainValidationOptions:
- DomainValidationOption
SubjectAlternativeNames:
- String
Tags:
- Resource Tag
ValidationMethod: String
Region: String
CertificateTransparencyLoggingPreference: String
KeyAlgorithm: String
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
-
DomainName
Fully qualified domain name (FQDN) to issue the certificate for. Use an asterisk as a wildcard.
- Required: Yes
- Type: String
- Update requires: Replacement
-
DomainValidationOptions
Information for validating domain ownership. A DomainValidationOption should be present for the DomainName and all SubjectAlternativeNames to create validation records. A DomainValidationOption for a parent domain can be used for names that have the same HostedZoneId.
If a DomainValidationOption is not present for a domain, validation records for that domain will not be created. They must be created through other means. The resource will remain in the
CREATE_IN_PROGRESS
state until the records can be validated.- Required: Yes
- Type: List of
DomainValidationOption
- Update requires: Replacement if a HostedZoneId changes
-
SubjectAlternativeNames
FQDNs to include in the Subject Alternative Name of the certificate.
- Required: No
- Type: List of String values
- Update requires: Replacement
-
Tags
Tags for this certificate
- Required: No
- Type: Resource Tag
- Update requires: No interruption
-
ValidationMethod
Method to use to validate domain ownership. This should be
DNS
.- Required: No
- Default:
EMAIL
- Type: String
- Update requires: Replacement
-
Region
The region to create the certificate in.
- Required: No
- Default: The Stack's region
- Type: String
- Update requires: Replacement
-
CertificateTransparencyLoggingPreference
Certificate Transparency Logging Preference. This may be 'ENABLED' or 'DISABLED'.
- Required: No
- Default:
ENABLED
- Type: String
- Update requires: No interruption
-
KeyAlgorithm
The algorithm that will be used to generate the key pair used by the certificate. Currently, this may be
RSA_2048
,EC_prime256v1
, orEC_secp384r1
for new certificates.⚠️ Not all algorithms are supported by all clients, AWS services or regions.- Required: No
- Default:
RSA_2048
- Type: String
- Update requires: Replacement
-
Ref
When the
Ref
function is used on the logical ID of a Certificate resource the certificate ARN is returned.
DomainName: String
HostedZoneId: String
Route53RoleArn: String
Route53RoleExternalId: String
-
DomainName
Fully qualified domain name of the validation request.
- Required: Yes
- Type: String
- Update requires: Replacement
-
HostedZoneId
The Route53 Hosted Zone to create validation records in.
- Required: Yes
- Type: String
- Update requires: Replacement
-
Route53RoleArn
The arn of an IAM Role to assume when creating DNS validation records. This can be used to create the records for a Hosted Zone in another AWS account.
- Required: No
- Type: String
- Update requires: No interruption
-
Route53RoleExternalId
An External ID to use when assuming the Route53RoleArn. This can be set if required by the trust policy of the role. See https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html for details of using ExternalIds.
- Required: No
- Type: String
- Update requires: No interruption
If you are using troposphere you can install this resource as an extension using pip:
$ pip install troposphere_dns_certificate
You can then import the Certificate resource from troposphere_dns_certificate.certificatemanager instead of troposphere.certificatemanager.
cloudformation.py is an example of using troposphere to create a template with a Certificate resource.
If you are not using troposphere, you can simply copy the CustomAcmCertificateLambda and CustomAcmCertificateLambdaExecutionRole resources from the cloudformation.json or cloudformation.yaml files.
The certificate resource looks like:
ExampleCertificate:
Properties:
DomainName: test.example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: test.example.com
HostedZoneId: Z2KZ5YTUFZNC7H
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
As with AWS::CertificateManager::Certificate providing the logical ID of the resource to the Ref function returns the certificate ARN.
For example (in yaml): !Ref 'ExampleCertificate'
Additional names can be added to the certificate using the SubjectAlternativeNames property.
ExampleCertificate:
Properties:
DomainName: example.com
SubjectAlternativeNames:
- additional.example.com
- another.example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: example.com
HostedZoneId: Z2KZ5YTUFZNC7H
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
Names from multiple hosted zones can be used by adding DomainValidationOptions for each of the hosted zones. For example:
ExampleCertificate:
Properties:
DomainName: example.com
SubjectAlternativeNames:
- additional.example.org
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: example.com
HostedZoneId: Z2KZ5YTUFZNC7H
- DomainName: example.org
HostedZoneId: ZEJZ9DIN47IQN
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
Wildcards can be used normally. A certificate for a name and all subdomains for example:
ExampleCertificate:
Properties:
DomainName: example.com
SubjectAlternativeNames:
- *.example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: example.com
HostedZoneId: Z2KZ5YTUFZNC7H
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
This example uses the Region property to create the certificate in us-east-1, for use with cloudfront:
ExampleCertificate:
Properties:
DomainName: example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: example.com
HostedZoneId: Z2KZ5YTUFZNC7H
Region: us-east-1
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
In some cases the account owning the hosted zone might be a different one than the one you are generating the certificate in.
To support this you can specify the domain validation option property Route53RoleArn
with a role-ARN that should be
assumed before creating the records required for certificate validation.
Optionally, you can also specify a Route53RoleExternalId
that will be used when assuming the role specified by Route53RoleArn
.
This would be required if the trust policy of the role requires an external ID.
If a top-level Route53RoleArn property is specified it will be assumed when validating domains that don't contain a Route53RoleArn domain validation option property.
ExampleCertificate:
Properties:
DomainName: test.example.com
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: test.example.com
HostedZoneId: Z2KZ5YTUFZNC7H
Route53RoleArn: arn:aws:iam::TRUSTING-ACCOUNT-ID:role/ACMRecordCreationRole
Route53RoleExternalId: EXTERNAL-ID
Tags:
- Key: Name
Value: Example Certificate
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
Additionally you have to allow the assumption of this role by adding this statement to the CustomAcmCertificateLambdaExecutionRole:
- Action:
- sts:AssumeRole
Resource:
- arn:aws:iam::TRUSTING-ACCOUNT-ID:role/ACMRecordCreationRole
Effect: Allow
If you are using the troposphere extension, this statement is added automatically. The full CustomAcmCertificateLambdaExecutionRole for this example would look like:
CustomAcmCertificateLambdaExecutionRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/service-role/AWSLambdaRole
Policies:
- PolicyDocument:
Statement:
- Action:
- acm:AddTagsToCertificate
- acm:DeleteCertificate
- acm:DescribeCertificate
- acm:RemoveTagsFromCertificate
- acm:UpdateCertificateOptions
Effect: Allow
Resource:
- !Sub 'arn:${AWS::Partition}:acm:*:${AWS::AccountId}:certificate/*'
- Action:
- acm:RequestCertificate
- acm:ListTagsForCertificate
- acm:ListCertificates
Effect: Allow
Resource:
- '*'
- Action:
- route53:ChangeResourceRecordSets
Effect: Allow
Resource:
- arn:aws:route53:::hostedzone/*
- Action:
- sts:AssumeRole
Effect: Allow
Resource:
- arn:aws:iam::TRUSTING-ACCOUNT-ID:role/ACMRecordCreationRole
Version: '2012-10-17'
PolicyName: !Sub '${AWS::StackName}CustomAcmCertificateLambdaExecutionPolicy'
The IAM role in the account with the hosted zone would look something like:
ACMRecordCreationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Principal:
AWS:
- arn:aws:iam::TRUSTED-ACCOUNT-ID:root
Effect: Allow
Condition:
StringEquals:
'sts:ExternalId': EXTERNAL-ID
Version: '2012-10-17'
Policies:
- PolicyName: 'ACMRecordCreation'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- route53:ChangeResourceRecordSets
Resource:
- arn:aws:route53:::hostedzone/Z2KZ5YTUFZNC7H
Effect: Allow
RoleName: ACMRecordCreationRole