Architecting SSL/TLS Infrastructure with Terraform and AWS Certificate Manager

The security of modern web infrastructure relies fundamentally on the implementation of HTTPS to protect user data and establish trust. In the current digital landscape, SSL/TLS certificates are non-negotiable; browsers frequently issue warnings or block access to sites utilizing self-signed certificates or no encryption at all. Historically, managing these certificates involved significant manual overhead and recurring costs through various Certificate Authorities (CAs) or the manual rotation of tools like OpenSSL and Let's Encrypt.

Amazon Web Services (AWS) solved this friction point with the introduction of AWS Certificate Manager (ACM) in 2016. ACM provides a streamlined approach to provisioning, managing, and deploying public and private SSL/TLS certificates. One of the most significant advantages of ACM is that public certificates used for integrated AWS services are provided at no additional cost and feature automatic renewal, provided the validation method remains intact.

To manage this infrastructure at scale, Infrastructure as Code (IaC) via Terraform is the industry standard. By defining certificates, validation records, and regional constraints in code, DevOps engineers can ensure reproducible environments, eliminate manual configuration errors, and integrate security directly into the CI/CD pipeline.

Core Components of ACM Architecture

An enterprise-grade certificate architecture requires a multi-layered approach to handle different traffic patterns, ranging from public-facing global edges to internal microservices.

Public Certificate Ecosystem

Public certificates are designed for end-user traffic arriving from the internet. These are integrated into the AWS ecosystem to terminate SSL at the edge or the load balancer level.
- CloudFront: Used for global content delivery. Certificates for CloudFront must reside in the us-east-1 region regardless of where the origin server is located.
- Application Load Balancer (ALB): Used for regional application traffic. Certificates are deployed in the same region as the ALB.
- Compute Services: Traffic decrypted at the ALB or CloudFront is then distributed to compute resources such as Amazon Elastic Kubernetes Service (EKS), Amazon Elastic Container Service (ECS), or AWS Elastic Beanstalk.

Private Certificate Ecosystem

For internal communication between services (East-West traffic) where public trust is not required but encryption is still mandatory, AWS Private CA is utilized. This allows for the issuance of internal certificates that are trusted only within the organization's private network, often terminated at an internal ALB.

DNS Validation Layer

The critical link between requesting a certificate and using it is validation. Route 53 serves as the primary mechanism for DNS validation, allowing Terraform to automatically create the necessary CNAME records that prove domain ownership to ACM.

Implementing ACM with Terraform: Technical Configuration

To effectively manage ACM via Terraform, a structured project layout is recommended to maintain modularity and scalability.

Recommended Project Structure

A professional Terraform repository for ACM management should be organized as follows:

text terraform-acm/ ├── main.tf # Primary resource orchestration ├── variables.tf # Input variable definitions ├── outputs.tf # Exported values (e.g., Certificate ARNs) ├── modules/ │ └── acm/ # Reusable ACM logic │ ├── main.tf │ ├── variables.tf │ └── outputs.tf └── config/ └── domains.json # Domain configuration data

The ACM Certificate Resource

The aws_acm_certificate resource is the primary building block. When configuring this resource, the validation_method is a critical choice. While ACM supports email validation, DNS validation is strongly preferred because it enables full automation via Terraform.

```hcl

Request an ACM certificate

resource "awsacmcertificate" "main" {
domainname = var.domainname
validationmethod = "DNS"
subject
alternativenames = var.subjectalternative_names

options {
certificatetransparencylogging_preference = "ENABLED"
}

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

# Critical for avoiding downtime during updates
lifecycle {
createbeforedestroy = true
}
}
```

The Importance of Lifecycle Management

A common pitfall when managing certificates with Terraform is the destruction of an existing certificate before a new one is created. If a certificate is modified in a way that forces replacement, Terraform's default behavior is to destroy the old resource first. This results in immediate downtime for any ALB or CloudFront distribution relying on that certificate.

The lifecycle { create_before_destroy = true } block prevents this by ensuring the new certificate is provisioned and ready before the old one is removed, maintaining continuous HTTPS availability.

Automating DNS Validation with Route 53

Requesting a certificate is only the first step. ACM will not issue the certificate until the requester proves ownership of the domain. This is achieved by creating a specific DNS record (a CNAME) in the domain's hosted zone.

The Validation Workflow

The process involves three distinct Terraform resources working in sequence:
1. aws_acm_certificate: Requests the certificate and generates the required DNS record values.
2. aws_route53_record: Takes those values and creates the record in Route 53.
3. aws_acm_certificate_validation: A "wait" resource that tells Terraform to pause until ACM confirms the DNS record is live and the certificate is issued.

Implementation Code

The following configuration demonstrates the full loop from request to validation:

```hcl

1. Request the certificate

resource "awsacmcertificate" "sitecert" {
provider = aws.us-east-1
domain
name = var.domainname
validation
method = "DNS"

lifecycle {
createbeforedestroy = true
}
}

2. Create the DNS validation record in Route 53

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
}

3. Wait for validation to complete

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

By running these in a single terraform apply cycle, the validation stage acts as a synchronization point, ensuring the certificate is fully active before any downstream resources (like Load Balancers) attempt to use it.

Regional Constraints and Provider Aliasing

One of the most nuanced aspects of ACM is its regional nature, specifically concerning AWS CloudFront. While most AWS resources are regional, CloudFront is a global service. For a certificate to be associated with a CloudFront distribution, the certificate must be requested in the us-east-1 (N. Virginia) region, regardless of where the rest of the stack is deployed.

Configuring Multi-Region Providers

To handle this, Terraform providers must be aliased. This allows a single configuration file to manage resources across different regions.

```hcl

Default provider for the main application stack

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

Alias provider specifically for CloudFront certificates

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

In the resources defined above, the provider = aws.us-east-1 attribute ensures the certificate is created in the correct region for CloudFront compatibility, while the backend state and other resources can remain in eu-west-1.

Integration and Deployment

Once the certificate is validated, it must be attached to a service to be useful. A critical technical detail is which ARN (Amazon Resource Name) to reference.

ALB HTTPS Listener Integration

When configuring an Application Load Balancer, you should reference the aws_acm_certificate_validation resource rather than the aws_acm_certificate resource. Referencing the validation resource ensures that the ALB is not configured with a certificate that is still in the "Pending Validation" state, which would lead to SSL handshake failures.

```hcl
resource "awslblistener" "https" {
loadbalancerarn = awslb.main.arn
port = 443
protocol = "HTTPS"
ssl
policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"

# Reference the validation resource, not the certificate resource
certificatearn = awsacmcertificatevalidation.main.certificate_arn

defaultaction {
type = "forward"
target
grouparn = awslbtargetgroup.app.arn
}
}
```

Infrastructure Specifications and Requirements

The following table summarizes the requirements and characteristics of implementing ACM with Terraform.

Feature Requirement / Value Note
Terraform Version $\ge$ 1.0.0 Required for stable resource management
AWS CLI Configured Permissions Needs ACM and Route 53 write access
CloudFront Region us-east-1 Absolute requirement for CF certificates
Validation Method DNS (Preferred) Allows for full automation
Renewal Automatic Requires DNS records to remain intact
Cost (Public) Free No additional cost for AWS integrated services
Route 53 Hosted Zone $\approx$ \$0.50 / month Cost associated with the DNS zone
DNS Record TTL 60 seconds Recommended for faster validation

Advanced Configuration and Best Practices

Handling Wildcard Certificates

When dealing with multiple subdomains, requesting a wildcard certificate (e.g., *.example.com) is more efficient than requesting individual certificates for every single service. This reduces the number of DNS validation records required and simplifies the management of subject_alternative_names (SANs).

State Management

For production environments, storing the Terraform state file locally is a security and operational risk. Using an S3 backend with DynamoDB locking is mandatory for team collaboration and state consistency.

hcl terraform { backend "s3" { region = "eu-west-1" bucket = "my-terraform-state-bucket" key = "domain-r53-acm.tfstate" dynamodb_table = "terraform-lock-table" encrypt = true } }

Technical Summary of Resource Flow

The logical dependency chain in Terraform for a complete SSL setup is:
Provider Alias $\rightarrow$ Route 53 Hosted Zone $\rightarrow$ ACM Certificate Request $\rightarrow$ Route 53 DNS Record $\rightarrow$ ACM Certificate Validation $\rightarrow$ ALB/CloudFront Attachment.

Conclusion

Implementing SSL/TLS via AWS Certificate Manager and Terraform transforms a traditionally manual and error-prone process into a scalable, automated workflow. By leveraging DNS validation over email, engineers can eliminate manual intervention during both the initial provisioning and the annual renewal cycle.

The technical success of this implementation hinges on three critical factors: the use of the create_before_destroy lifecycle rule to prevent downtime, the strict adherence to the us-east-1 regional requirement for CloudFront, and the correct sequencing of resources by referencing the aws_acm_certificate_validation ARN. When these elements are combined with a modular project structure and a secure S3 backend, the resulting infrastructure is robust, secure, and easily maintainable across multiple environments.

Ultimately, the shift toward treating certificates as code ensures that security is not a final "step" in the deployment process, but an integrated component of the infrastructure definition itself.

Sources

  1. The Cloud Panda
  2. OneUptime
  3. HeadForTheCloud

Related Posts