https://github.com/dflook/cloudformation-dns-certificate
Cloudformation DNS Validated Certificate Resource
https://github.com/dflook/cloudformation-dns-certificate
aws-acm aws-cloudformation aws-route53 certificate cloudformation route53 troposphere
Last synced: about 2 months ago
JSON representation
Cloudformation DNS Validated Certificate Resource
- Host: GitHub
- URL: https://github.com/dflook/cloudformation-dns-certificate
- Owner: dflook
- License: mit
- Created: 2018-05-26T10:02:18.000Z (almost 7 years ago)
- Default Branch: main
- Last Pushed: 2024-09-04T08:40:47.000Z (8 months ago)
- Last Synced: 2025-02-25T03:04:30.958Z (2 months ago)
- Topics: aws-acm, aws-cloudformation, aws-route53, certificate, cloudformation, route53, troposphere
- Language: Python
- Homepage:
- Size: 196 KB
- Stars: 48
- Watchers: 8
- Forks: 13
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Cloudformation DNS Validated Certificate Resource
This is a cloudformation custom resource which is an enhancement of the [AWS::CertificateManager::Certificate](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html) 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.## Usage
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](https://pypi.org/project/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.### Differences from AWS::CertificateManager::Certificate
It should behave similarly to [AWS::CertificateManager::Certificate](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html),
except for the differences described here.The additional `Region` property can be used to set the region to create the certificate in.
The [DomainValidationOption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-certificatemanager-certificate-domainvalidationoption.html) 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.
### Certificate Resource
#### Syntax
```yaml
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'
```#### Properties
* `DomainName`
Fully qualified domain name (FQDN) to issue the certificate for. Use an asterisk as a wildcard.
- Required: Yes
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-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](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-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](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement)* `Tags`
Tags for this certificate
- Required: No
- Type: [Resource Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html)
- Update requires: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)* `ValidationMethod`
Method to use to validate domain ownership. This should be `DNS`.
- Required: No
- Default: `EMAIL`
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement)* `Region`
The region to create the certificate in.
- Required: No
- Default: The Stack's region
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement)* `CertificateTransparencyLoggingPreference`
Certificate Transparency Logging Preference. This may be 'ENABLED' or 'DISABLED'.
- Required: No
- Default: `ENABLED`
- Type: String
- Update requires: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)* `KeyAlgorithm`
The algorithm that will be used to generate the key pair used by the certificate.
Currently, this may be `RSA_2048`, `EC_prime256v1`, or `EC_secp384r1` for new certificates.:warning: Not all algorithms are supported by all clients, AWS services or regions.
- Required: No
- Default: `RSA_2048`
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement)#### Return value
* Ref
When the [`Ref`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html)
function is used on the logical ID of a Certificate resource the certificate ARN is returned.### DomainValidationOption
#### Syntax
```yaml
DomainName: String
HostedZoneId: String
Route53RoleArn: String
Route53RoleExternalId: String
```#### Properties
* `DomainName`
Fully qualified domain name of the validation request.
- Required: Yes
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-replacement)
* `HostedZoneId`The Route53 Hosted Zone to create validation records in.
- Required: Yes
- Type: String
- Update requires: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-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](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)* `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](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)## Troposphere
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.## Examples
The certificate resource looks like:
```yaml
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'`
### SubjectAlternativeNames
Additional names can be added to the certificate using the SubjectAlternativeNames property.
```yaml
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
```### Multiple Hosted Zones
Names from multiple hosted zones can be used by adding DomainValidationOptions for each of the hosted zones.
For example:```yaml
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
Wildcards can be used normally. A certificate for a name and all subdomains for example:
```yaml
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
```### Specifying a region
This example uses the Region property to create the certificate in us-east-1, for use with cloudfront:
```yaml
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
```### Assuming a role for Route 53 record creation
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.```yaml
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:
```yaml
- 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:```yaml
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:
```yaml
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
```