Managing AWS ACM Certificates with Terraform: Validation, Modules, and Production Patterns

AWS Certificate Manager provides SSL/TLS certificates for securing applications and integrates natively with load balancers, CloudFront distributions, and APIs. Terraform enables repeatable provisioning of ACM certificates with automated DNS validation through Route 53, lifecycle management to avoid downtime, and modular patterns for reuse across environments. The catch with ACM is validation and regional placement. Certificates must be validated before use and CloudFront requires certificates in US East N. Virginia. DNS validation is strongly preferred because it can be fully automated by Terraform and Route 53.

Architecture and Certificate Lifecycle

The architecture for certificate management separates public and private concerns.

  • 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 such as ECS, EKS, and 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

ACM provides public certificates for integrated AWS services at no additional cost and those certificates auto-renew. Validation is required before a certificate can be issued and used. DNS validation requires creation of specific DNS records that ACM uses to verify domain ownership. The validation process has nuances that affect Terraform planning and apply order.

Prerequisites for a production setup 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

A common project structure isolates the ACM module for reuse.

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

Native AWS ACM Resource

The basic certificate request is simple with the awsacmcertificate resource.

```hcl
resource "awsacmcertificate" "main" {
domainname = "example.com"
validation
method = "DNS"
tags = {
Environment = "production"
ManagedBy = "terraform"
}

lifecycle {
createbeforedestroy = 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.

A more complete module pattern adds transparency logging, subject alternative names, and tag merging.

```hcl
resource "awsacmcertificate" "main" {
domainname = var.domainname
validationmethod = "DNS"
subject
alternativenames = var.subjectalternativenames
options {
certificate
transparencyloggingpreference = "ENABLED"
}

lifecycle {
createbeforedestroy = true
}

tags = merge(
var.tags,
{
Name = var.domain_name
}
)
}
```

DNS validation with Route 53 automates record creation. Terraform can create the validation records in the same hosted zone used for the domain. Validation records are created by the ACM provider and tied to the certificate resource.

Email validation is supported by ACM but DNS validation is strongly preferred because it can be fully automated.

Terraform Modules for ACM

Modules reduce duplication and encapsulate validation logic. Two widely used module patterns exist.

The terraform-module/acm module creates ACM certificates and validates them using Route53 DNS.

hcl module "acm" { source = "terraform-module/acm/aws" version = "~> 2" domain_name = "example.com" zone_id = "Z0FK2F3K10ACF0" validation_method = "DNS" subject_alternative_names = [ "*.example.com" ] tags = {} }

Module inputs include:

  • allowoverwriterecords: Allow creation of this record in Terraform to overwrite an existing record, if any. Type bool. Default true
  • domain_name: A domain name for which the certificate should be issued. Type string. Default ""
  • subjectalternativenames: A list of domains that should be SANs in the issued certificate. Type list(string). Default []
  • tags: A mapping of tags to assign to the resource. Type map(string). Default {}
  • ttl: The TTL of the record. Type number. Default 60
  • validate_certificate: Whether or not certificate should be validated. Type bool. Default true
  • validation_method: Which method to use for validation. DNS or EMAIL are valid, NONE can be used for certificates that were imported into ACM and then into Terraform. Type string. Default "DNS"
  • zone_id: The ID of the hosted zone to contain this record. Type string. Default ""

Module outputs include:

  • arn: Certificate ARN
  • distinctdomainnames: Distinct domain names

Requirements:

  • terraform >= 0.12
  • aws provider n/a

The terraform-aws-modules/acm/aws module provides a maintained alternative with additional features.

hcl module "acm" { source = "terraform-aws-modules/acm/aws" version = "~> 4.0" domain_name = "my-domain.com" zone_id = "Z2ES7B9AZ6SHAE" validation_method = "DNS" subject_alternative_names = [ "*.my-domain.com", "app.sub.my-domain.com", ] wait_for_validation = true tags = { Name = "my-domain.com" } }

A variation that uses externally managed validation records:

hcl module "acm" { source = "terraform-aws-modules/acm/aws" version = "~> 4.0" domain_name = "weekly.tf" zone_id = "b7d259641bf30b89887c943ffc9d2138" validation_method = "DNS" subject_alternative_names = [ "*.weekly.tf", ] create_route53_records = false validation_record_fqdns = [ "_689571ee9a5f9ec307c512c5d851e25a.weekly.tf", ] tags = { Name = "weekly.tf" } }

Key parameters for the maintained module are summarized below.

Name Description Type Default Required
domain_name Domain name for certificate string no
zone_id Hosted zone ID for validation string no
validation_method DNS or EMAIL string DNS no
subjectalternativenames SAN list list(string) [] no
waitforvalidation Wait for validation completion bool false no
createroute53records Create validation records bool true no

Compliance and Security Controls

Managing certificates with Terraform can be paired with compliance enforcement at plan time.

ACM certificates and validation records for public or private TLS, certificate renewal, and associations used by load balancers, CloudFront distributions, and APIs can be controlled.

Controls enforced are checked at terraform plan time.

Control PCI DSS v4.0
ACM certificates should not use wildcard certificates
ACM RSA certificates should use a key length of at least 2,048 bits
ACM certificates should have transparency logging enabled

● enforced by default
○ not activated by this endpoint

Transparency logging preference can be set to ENABLED in the options block to satisfy audit requirements.

Regional Constraints and Service Integration

SSL/TLS certificates are a non-negotiable part of modern web infrastructure. Every public-facing service needs HTTPS.

ACM 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.

Requesting a certificate for a single domain with DNS validation is the base pattern.

hcl resource "aws_acm_certificate" "main" { domain_name = "example.com" validation_method = "DNS" }

CloudFront supports US East N. Virginia for ACM certificates. Certificates used with CloudFront must be provisioned in us-east-1 regardless of where the origin resides. Application Load Balancers can use certificates in the same region as the load balancer.

Wildcard certificates simplify SAN management but require careful validation. A wildcard *.example.com covers subdomains but not the root domain.

DNS validation with Route 53 requires the hosted zone to be in the same account or accessible via cross-account permissions. The validation record name is generated by ACM and must match exactly.

Migration and Reversibility

Existing usage of terraform-aws-modules can be migrated with minimal changes.

Migration from upstream is supported.

  • Change only the source URL
  • Same arguments
  • Same outputs
  • Controls are checked at terraform plan

Reversibility is provided. No lock-in. Switch back by reverting the source URL with terraform init -upgrade. Terraform state is unchanged, same resource addresses, same provider, no compliance-specific resources. Controls you already applied remain in AWS.

Conclusion

Managing AWS ACM certificates with Terraform combines native resource creation, DNS validation automation, and modular reuse. The native awsacmcertificate resource with createbeforedestroy lifecycle management prevents downtime during renewal. DNS validation via Route 53 enables fully automated issuance. Modules encapsulate validation logic, tag conventions, and transparency logging options for consistent deployments.

Production patterns include separating public and private certificate workflows, enforcing certificate transparency logging, and respecting regional constraints for CloudFront. Compliance controls can be enforced at plan time to prevent wildcard misuse and ensure minimum key lengths. Migration paths exist between module sources with zero state changes and reversibility.

SSL certificates are generally seen as a requirement to ensure users’ data is protected and to demonstrate trustworthiness. Browsers warn when sites lack certificates or use self-signed certificates. Since 2016, AWS Certificate Manager has offered free certificates that auto-renew annually provided DNS validation is maintained. Verifying that the certificate belongs to the site using it remains central to maintaining trust.

Sources

  1. thecloudpanda.com
  2. compliance.tf
  3. github.com/terraform-module/terraform-aws-acm
  4. oneuptime.com
  5. headforthe.cloud
  6. github.com/terraform-aws-modules/terraform-aws-acm

Related Posts