Terraform AWS ACM Certificate Management with DNS Validation and Lifecycle Controls

Modern public facing services require HTTPS with valid SSL TLS certificates. AWS Certificate Manager provides public certificates for integrated AWS services at no additional cost and those certificates auto renew. The validation process has nuances that affect Terraform workflows. Requesting ACM certificates, automating DNS validation, handling wildcard certificates, and dealing with regional constraints that affect CloudFront and other services require precise Terraform configuration.

What awsacmcertificate Provides

The awsacmcertificate resource creates and manages an ACM certificate in AWS. The data source awsacmcertificate provides details about a specific ACM Certificate. A minimal configuration to get started is shown in the reference material. The data source is used to read existing certificate attributes for use in dependent resources without creating a new certificate.

A typical data source block is:

hcl data "aws_acm_certificate" "example" { }

The data source requires arguments that are referenced in the Terraform Registry documentation. Using the data source allows modules to import an existing certificate ARN and avoid recreation.

Core Resource Configuration

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.

A minimal request for a single domain with DNS validation:

hcl resource "aws_acm_certificate" "main" { domain_name = "example.com" validation_method = "DNS" tags = { Environment = "production" ManagedBy = "terraform" } lifecycle { create_before_destroy = true } }

A module based configuration expands the options:

hcl 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 allows certificatetransparencylogging_preference to be set to ENABLED. Subject alternative names allow multiple domains to be covered by a single certificate.

Argument Purpose
domain_name Primary domain for the certificate
validation_method DNS or EMAIL
subjectalternativenames Additional SAN entries
options Certificate transparency logging preference
lifecycle createbeforedestroy control

Validation Methods and DNS Automation

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.

To complete DNS validation, you need to create specific DNS records that ACM uses to verify domain ownership. With Route 53 the validation records are created automatically from the domainvalidationoptions attribute of the certificate resource.

A complete DNS validation flow:

```hcl
resource "awsacmcertificate" "sitecert" {
provider = aws.us-east-1
domain
name = var.domainname
validation
method = "DNS"
lifecycle {
createbeforedestroy = true
}
}

resource "awsroute53record" "sitecertdns" {
allowoverwrite = true
name = tolist(aws
acmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordname
records = [tolist(awsacmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordvalue]
type = tolist(aws
acmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordtype
zoneid = awsroute53zone.domain.zoneid
ttl = 60
}

resource "awsacmcertificatevalidation" "sitecertvalidation" {
provider = aws.us-east-1
certificate
arn = awsacmcertificate.sitecert.arn
validation
recordfqdns = [awsroute53record.sitecert_dns.fqdn]
}
```

If you run all of the Terraform from this section in a single plan apply cycle, the validation stage will wait until it can verify the details in DNS so it is safe to run, wait until you see the hosted zone created, update your DNS all in one stage.

The allowoverwrite flag permits Terraform to update existing validation records without error. The tolist expressions extract the first domain validation option for the primary domain. For certificates with multiple domains, iteration over domainvalidation_options is required.

Validation method comparison:

Method Automation Use case
DNS Full automation with Route 53 Preferred for Terraform
EMAIL Manual approval Complete example with EMAIL validation

Lifecycle and Safe Rotation

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.

Create before destroy ensures the new certificate is provisioned and validated before the old certificate is removed. This is critical for production environments where load balancers, CloudFront distributions, and API gateways reference the certificate ARN.

Best practices include:

  • Always set lifecycle createbeforedestroy true on awsacmcertificate
  • Tag certificates with Environment and ManagedBy for governance
  • Merge tags with module level tags to maintain consistency

Integration Patterns with Load Balancers and CloudFront

Once validated, reference the certificate ARN in your resources.

For an Application Load Balancer HTTPS listener:

hcl 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. The validation resource outputs the ARN only after successful validation, preventing services from being attached to an unvalidated certificate.

Certificate management architecture includes:

  • 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
  • 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

CloudFront requires certificates to be issued in us-east-1. This regional constraint is enforced by providing provider = aws.us-east-1 on the certificate resource and validation resources.

Module Structure and Project Layout

A typical Terraform ACM project separates configuration into modules and variables.

Project structure:

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

Prerequisites for the project:

  • 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

The module interface exposes domainname, subjectalternative_names, and tags. The module outputs the certificate ARN and validation status for downstream consumers.

Regional Constraints and Provider Configuration

ACM certificates used with CloudFront must exist in us-east-1. Regional constraints affect CloudFront and other services.

Provider aliasing ensures resources are created in the correct region:

hcl resource "aws_acm_certificate" "site_cert" { provider = aws.us-east-1 domain_name = var.domain_name validation_method = "DNS" lifecycle { create_before_destroy = true } }

The same provider alias is used for the Route 53 record and the validation resource to maintain consistency.

Conditional Creation and External DNS Examples

Sometimes you need to have a way to create ACM certificate conditionally but Terraform does not allow to use count inside module block, so the solution is to specify argument create_certificate.

Module usage with conditional creation:

hcl module "acm" { source = "terraform-aws-modules/acm/aws" create_certificate = false }

Complete example scenarios include:

  • Complete example with DNS validation via external DNS provider such as CloudFlare
  • Complete example with EMAIL validation
  • Complete example with EMAIL validation and validation domain override

External DNS providers require the validation records to be created manually or via provider specific resources. The certificate ARN remains the same, but the DNS record creation step is delegated outside Route 53.

Conclusion

Managing AWS Certificate Manager with Terraform requires attention to validation automation, lifecycle safety, and regional placement. DNS validation is strongly preferred because it can be fully automated with Route 53 records derived from domainvalidationoptions. The createbeforedestroy lifecycle rule prevents downtime during certificate rotation. Referencing awsacmcertificatevalidation outputs instead of the raw certificate ARN guarantees services only attach validated certificates. Provider aliases ensure CloudFront compatible certificates are created in us-east-1. Module based designs with createcertificate flags allow conditional provisioning and reuse across environments. Combining these patterns produces a reliable, automated certificate workflow that supports public load balancers, CloudFront distributions, and internal services with consistent tagging and transparency logging.

Sources

  1. awsfundamentals.com
  2. thecloudpanda.com
  3. oneuptime.com
  4. headforthe.cloud
  5. github.com

Related Posts