AWS Certificate Manager and Terraform Certificate Automation for DNS Validation and Regional Deployment

Introduction

AWS Certificate Manager provides SSL/TLS certificates for securing applications and AWS Certificate Manager provides public certificates for integrated AWS services at no additional cost, and those certificates auto-renew. SSL/TLS certificates are a non-negotiable part of modern web infrastructure. Every public-facing service needs HTTPS, and AWS Certificate Manager provides public certificates for integrated AWS services at no additional cost, and those certificates auto-renew. The catch is that they need to be validated, and that validation process has a few nuances that trip people up when working with Terraform.

In this post, we'll cover requesting ACM certificates, automating DNS validation, handling wildcard certificates, and dealing with the regional constraints that affect CloudFront and other services. Managing AWS Certificate Manager with Terraform. Learn how to provision and manage SSL/TLS certificates using AWS Certificate Manager and Terraform, including validation and integration with other AWS services. This guide demonstrates how to manage certificates using Terraform.

The architecture diagram shows Certificate Management: ACM for public certificates, Private CA for internal certificates, and Route 53 for DNS validation. Public Certificate Usage: Application Load Balancer and CloudFront distributing traffic to various compute services including ECS, EKS, Elastic Beanstalk. Private Certificate Usage: Internal ALB with private certificates for internal services. User Traffic Flow: End users accessing applications through CloudFront and ALB with SSL/TLS encryption.

SSL certificates are generally seen as a requirement to ensure your users’ data is protected, and to demonstrate that you are trustworthy. Indeed some browsers will warn you if you try to access a site without a certificate or if you try to use self-signed certificates. However, traditionally SSL certificates have been an extra expense. Over the last decade or so, there have been several approaches to reduce this cost, from rolling your own with openssl, lets-encrypt, but in 2016, AWS announced the introduction of the AWS Certificate Manager. These certificates are free, and as long as you maintain the DNS setup described in this post, will be automatically renewed annually.

Given that maintaining trust is a function of SSL certificates, verifying that the certificate belongs to the site using it is important. ACM can verify ownership of the domain associated with the certificate either via DNS or via email although the latter is not recommended. To do this, it will look for a specific record in the DNS configuration for the appropriate domain. Using Terraform we can create an ACM certificate using the awsacmcertificate Terraform resource, and then ensure it has been validated with the awsacmcertification_validation resource. However, the complexity of putting the record needed for the validation depends on how we are managing our domain steps.

Prerequisites and Project Foundations

The operational baseline for working with ACM and Terraform requires specific tooling and accounts.

Prerequisites include:

  • AWS CLI configured with appropriate permissions
  • Terraform installed version 1.0.0 or later
  • Domain name registered in Route 53 for DNS validation
  • Basic understanding of SSL/TLS certificates

This article assumes you have the following:

  • An AWS Account
  • Terraform installed
  • A basic understanding of how to configure Terraform to access your AWS account, and how to plan and apply with Terraform.

Project Structure for a modular ACM implementation is:

terraform-acm/ ├── main.tf ├── variables.tf ├── outputs.tf ├── modules/ │ └── acm/ │ ├── main.tf │ ├── variables.tf │ └── outputs.tf └── config/ └── domains.json

The project structure separates configuration from modules and allows reuse of certificate logic across environments. The config directory holds domain definitions that feed into the module variables.

State management is critical for team collaboration and prevents state corruption.

```
provider "aws" {
region = "eu-west-1" # <---- replace with desired deployment region
}

provider "aws" { # This is because we're going to deploy our ACM to us-east-1 so we can later use with CloudFront
alias = "us-east-1"
region = "us-east-1"
}

Terraform {
backend "s3" {
# Replace the values below with your own specific details.
region = "eu-west-1"
bucket = "insertbucketname"
key = "domain-r53-acm.tfstate"
dynamodbtable = "insertdynamodblocktablename_"
encrypt = true
}
}
```

Now that Terraform knows where to store its state, we’ll need to retrieve the details of the hosted zone. The hosted zone will attract a charge of $0.501 per month. At the time this post was published, the cheapest domain was .click at $31 per year, but current pricing can be checked here. Once registered, AWS will automatically create an associated hosted zone in Route53.

Certificate Request Fundamentals

Requesting a Certificate

The basic certificate request is simple. ACM supports two validation methods: DNS and email. DNS validation is strongly preferred because it can be fully automated.

This requests a certificate for a single domain with DNS validation:

resource "aws_acm_certificate" "main" { domain_name = "example.com" validation_method = "DNS" tags = { Environment = "production" ManagedBy = "terraform" } # Create the new certificate before destroying the old one lifecycle { create_before_destroy = true } }

The createbeforedestroy lifecycle rule is important. Without it, Terraform would destroy the existing certificate before creating the new one, causing downtime for any services using it.

For multi-domain and subject alternative name handling, the module pattern expands the resource.

resource "aws_acm_certificate" "main" { domain_name = var.domain_name validation_method = "DNS" subject_alternative_names = var.subject_alternative_names options { certificate_transparency_logging_preference = "ENABLED" } lifecycle { create_before_destroy = true } tags = merge( var.tags, { Name = var.domain_name } ) }

The options block sets certificatetransparencyloggingpreference to ENABLED. The tags merge applies user provided tags plus a Name tag equal to var.domainname.

DNS Validation Automation with Route 53

To complete DNS validation, you need to create specific DNS records that ACM uses to verify domain ownership.

ACM validation requires DNS records in Route 53. DNS validation is strongly preferred because it can be fully automated. The validation process has nuances that trip people up when working with Terraform.

When validation is triggered, Terraform must create the validation record for the certificate. The record reference pattern is shown as record in awsroute53record.cloudfrontcertvalidation : record.fqdn].

For using this certificate with CloudFront, see our post on creating CloudFront distributions with Terraform.

The validation workflow connects the awsacmcertificate resource with a Route 53 record resource and the awsacmcertificate_validation resource. The validation resource depends on the DNS record being present so ACM can confirm domain ownership.

Regional Constraints and Provider Configuration

Regional constraints affect CloudFront and other services. ACM certificates used with CloudFront must be created in us-east-1 regardless of where the rest of the infrastructure lives.

The dual provider pattern is used to support this requirement.

```
provider "aws" {
region = "eu-west-1"
}

provider "aws" {
alias = "us-east-1"
region = "us-east-1"
}
```

This allows Terraform to create certificates in eu-west-1 for regional services like Application Load Balancer, and to create certificates in us-east-1 for CloudFront usage.

The architecture shows Public Certificate Usage with Application Load Balancer and CloudFront distributing traffic to various compute services. Private Certificate Usage with Internal ALB with private certificates for internal services.

Certificate Usage and Integration

Once validated, reference the certificate ARN in your resources:

resource "aws_lb_listener" "https" { load_balancer_arn = aws_lb.main.arn port = 443 protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06" certificate_arn = aws_acm_certificate_validation.main.certificate_arn default_action { type = "forward" target_group_arn = aws_lb_target_group.app.arn } }

Notice we reference awsacmcertificatevalidation.main.certificatearn instead of awsacmcertificate.main.arn.

Referencing the validation resource ARN ensures Terraform only attaches the certificate after ACM has confirmed successful validation. Using the raw certificate ARN can lead to attachment of a pending certificate which results in listener errors.

The architecture overview shows User Traffic Flow: End users accessing applications through CloudFront and ALB with SSL/TLS encryption. Certificate Management includes ACM for public certificates, Private CA for internal certificates, and Route 53 for DNS validation.

Configuration Reference Tables

Table 1: ACM Certificate Resource Parameters

| Parameter | Example Value | Impact |
| domainname | example.com | Sets the primary domain for the certificate |
| validation
method | DNS | Enables automated DNS validation via Route 53 |
| subjectalternativenames | [] | Allows SAN coverage for additional domains |
| options.certificatetransparencyloggingpreference | ENABLED | Enables CT log submission for transparency |
| lifecycle.create
before_destroy | true | Prevents downtime during certificate rotation |

Table 2: Provider and Backend Configuration

| Item | Value | Purpose |
| provider aws region | eu-west-1 | Default region for regional resources |
| provider aws alias | us-east-1 | Required region for CloudFront certificates |
| backend s3 bucket | insertbucketname | Remote state storage |
| backend s3 key | domain-r53-acm.tfstate | State file path |
| backend dynamodbtable | _insertdynamodblocktablename | State locking |
| backend encrypt | true | Server side encryption for state |

Table 3: Validation Methods Comparison

| Method | Automation | Recommendation |
| DNS | Fully automated | Strongly preferred |
| Email | Manual | Not recommended |

Operational Considerations

The catch is that they need to be validated, and that validation process has a few nuances that trip people up when working with Terraform. In this post, we'll cover requesting ACM certificates, automating DNS validation, handling wildcard certificates, and dealing with the regional constraints that affect CloudFront and other services.

These certificates are free, and as long as you maintain the DNS setup described in this post, will be automatically renewed annually. Given that maintaining trust is a function of SSL certificates, verifying that the certificate belongs to the site using it is important.

At the time this post was published, the cheapest domain was .click at $31 per year, but current pricing can be checked here. Once registered, AWS will automatically create an associated hosted zone in Route53. This hosted zone will attract a charge of $0.501 per month.

The createbeforedestroy lifecycle rule is important. Without it, Terraform would destroy the existing certificate before creating the new one, causing downtime for any services using it.

Conclusion

The integration of AWS Certificate Manager with Terraform reduces operational overhead for SSL/TLS management and enforces consistent validation and renewal policies across environments. DNS validation via Route 53 provides the automation foundation that makes Terraform workflows reliable. The dual provider pattern addresses the regional constraint imposed by CloudFront, which requires certificates in us-east-1 while regional load balancers can use certificates in their local region.

Project structuring with modules for ACM isolates certificate logic and allows reuse. Lifecycle controls such as createbeforedestroy prevent service interruption during rotation. Referencing the validation resource ARN rather than the raw certificate ARN guarantees that dependent listeners and distributions only attach fully validated certificates.

State management in S3 with DynamoDB locking ensures safe collaboration. The cost model remains favorable because ACM public certificates carry no issuance or renewal fees, with only the underlying Route 53 hosted zone incurring a monthly charge and domain registration costs applying externally.

Maintaining the DNS setup required for ACM validation ensures automatic annual renewal continues without manual intervention. The combination of automated DNS validation, Terraform lifecycle management, and regional awareness provides a durable pattern for securing public-facing AWS services with HTTPS.

Sources

  1. Managing AWS Certificate Manager (ACM) with Terraform
  2. Manage AWS ACM Certificates with Terraform
  3. Managing ACM with Terraform

Related Posts