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
domainname = var.domainname
validationmethod = "DNS"
lifecycle {
createbeforedestroy = true
}
}
resource "awsroute53record" "sitecertdns" {
allowoverwrite = true
name = tolist(awsacmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordname
records = [tolist(awsacmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordvalue]
type = tolist(awsacmcertificate.sitecert.domainvalidationoptions)[0].resourcerecordtype
zoneid = awsroute53zone.domain.zoneid
ttl = 60
}
resource "awsacmcertificatevalidation" "sitecertvalidation" {
provider = aws.us-east-1
certificatearn = awsacmcertificate.sitecert.arn
validationrecordfqdns = [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 |
| 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.