
How to Create Route 53 Records from AWS Cross-Accounts with Terraform
Over the last few weeks, I wrote a couple of stories on how to use Terraform to create internal and external load balancers and use ACM to create SSL certificates and write records in Route 53 (see below).
- How to Deploy EC2 Instances with an Internal Load Balancer, and ACM SSL Certificate in AWS with Terraform
- How to Deploy EC2 Instances in Multiple AZs, with a Load Balancer, and SSL Certificate in AWS with Terraform
However, these two examples work only when we have the Route 53 public hosted zone in the same AWS account.
In this story, we will learn how to create records in a Route 53 Hosted Zone located on a different AWS account (usually called cross-account).
This story can be used as a reference to implement multi-account solutions in AWS with Terraform or share Route 53 domains across multiple AWS Accounts.
Note: There are several ways to do this, however, I found this way the simplest one to implement.
Defining Multiple AWS Accounts in the Provider File
A typical provider file should look like this:
# Terraform Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}# AWS Provider Credentials
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.aws_region
}To be able to access another AWS account, in this case, we are going to call it main, we need to add a second provider with an alias. So the provider file will look like this:
# Terraform Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}# AWS Provider
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.aws_region
}# Main AWS Provider
provider "aws" {
alias = "main"
access_key = var.aws_access_key_main
secret_key = var.aws_secret_key_main
region = var.aws_region_main
}Creating Route 53 Records in the Cross-Account
Then, for this example, we are going to create a Load Balancer and an ACM SSL certificate in the Application AWS Account and Route 53 Records for the load balancer and ACM validation in the Main AWS Account.
Creating the Application Load Balancer
The code below will:
- Create an Internal Application Load Balancer
- Create a Load Balancer Target Group for HTTP
- Attach EC2 Instances to the Application Load Balancer Target Group
- Create an Application Load Balancer Listener for HTTP.
All these tasks are executed in the AWS Application Account.
# Create an Application Load Balancer
resource "aws_lb" "linux-alb" {
name = "linux-alb"
internal = true
load_balancer_type = "application"
security_groups = [aws_security_group.linux-alb-sg.id]
subnets = local.ec2_subnet_list enable_deletion_protection = false
enable_http2 = false
}# Create a Load Balancer Target Group for HTTP
resource "aws_lb_target_group" "linux-alb-target-group-http" {
name = "linux-alb-tg-http"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.vpc.id
deregistration_delay = 60 stickiness {
type = "lb_cookie"
} health_check {
path = "/"
port = 80
healthy_threshold = 3
unhealthy_threshold = 3
timeout = 10
interval = 30
matcher = "200,301,302"
}
}# Attach EC2 Instances to Application Load Balancer Target Group
resource "aws_alb_target_group_attachment" "linux-alb-target-group-http-attach" {
count = var.ec2_count target_group_arn = aws_lb_target_group.linux-alb-target-group-http.arn
target_id = aws_instance.linux-server[count.index].id
port = 80
}# Create the Application Load Balancer Listener
resource "aws_lb_listener" "linux-alb-listener-http" {
depends_on = [
aws_lb.linux-alb,
aws_lb_target_group.linux-alb-target-group-http
]
load_balancer_arn = aws_lb.linux-alb.arn
port = 80
protocol = "HTTP"
default_action {
target_group_arn = aws_lb_target_group.linux-alb-target-group-http.arn
type = "forward"
}
}Creating Amazon Route 53 A Record for the Load Balancer DNS record
Here, we create a reference to the Amazon Route 53 Public Zone, and then, using that data, we create a Route 53 DNS record for the load balancer. Both tasks are executed on our AWS Main Account.
# Reference to the Route 53 Main Public Zone
data "aws_route53_zone" "public-zone" {
provider = aws.main
name = var.public_dns_name
private_zone = false
}# Create Route 53 A Record for the Load Balancer in the Main Zone
resource "aws_route53_record" "linux-alb-a-record" {
provider = aws.main depends_on = [aws_lb.linux-alb] zone_id = data.aws_route53_zone.public-zone.zone_id
name = "${var.dns_hostname}.${var.public_dns_name}"
type = "A"
alias {
name = aws_lb.linux-alb.dns_name
zone_id = aws_lb.linux-alb.zone_id
evaluate_target_health = true
}
}Creating the SSL Certificate using ACM
In this step, we will create the SSL certificate and the DNS Records in Route 53 for the ACM validation.
The resource “aws_acm_certificate” will create the ACM certificate in the AWS Application Account.
Then the resource “aws_route53_record” will create the Route 53 Validation Record on the AWS Main Account.
Finally, the resource “aws_acm_certificate_validation”, will create the ACM Certificate Validation in the AWS Application Account.
# Create Certificate
resource "aws_acm_certificate" "linux-alb-certificate" {
domain_name = "${var.dns_hostname}.${var.public_dns_name}"
validation_method = "DNS"
}# Create AWS Route 53 Certificate Validation Record in the Main Zone
resource "aws_route53_record" "linux-alb-certificate-validation-record" {
provider = aws.main for_each = {
for dvo in aws_acm_certificate.linux-alb-certificate.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
} allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = data.aws_route53_zone.public-zone.zone_id
}# Create Certificate Validation
resource "aws_acm_certificate_validation" "linux-certificate-validation" {
certificate_arn = aws_acm_certificate.linux-alb-certificate.arn
validation_record_fqdns = [for record in aws_route53_record.linux-alb-certificate-validation-record : record.fqdn]
}Creating the Application Load Balancer Listener for HTTPS
Finally, we will create a listener for the port 443 and HTTPS protocol to forward traffic to the HTTP target group, in the AWS Application Account and we will link the SSL certificate created in the previous steps.
resource "aws_alb_listener" "linux-alb-listener-https" {
depends_on = [
aws_acm_certificate.linux-alb-certificate,
aws_route53_record.linux-alb-certificate-validation-record,
aws_acm_certificate_validation.linux-certificate-validation
] load_balancer_arn = aws_lb.linux-alb.arn
port = 443
protocol = "HTTPS"
certificate_arn = aws_acm_certificate.linux-alb-certificate.arn
default_action {
target_group_arn = aws_lb_target_group.linux-alb-target-group-http.arn
type = "forward"
}
}Creating the Input Definition Variables File
In the last step, we will create the input definition variables file “terraform.tfvars” and add the following code to the file.
Then we add the AWS credentials for both our AWS Application Account and AWS Main Account, and we are ready to go!
# Application Definition
app_name = "kopicloud" # Do NOT enter any spaces
app_environment = "dev" # Dev, Test, Staging, Prod, etc# Network
vpc_cidr = "10.11.0.0/16"
private_subnet_cidr_1 = "10.11.1.0/24"
private_subnet_cidr_2 = "10.11.2.0/24"
private_subnet_cidr_3 = "10.11.3.0/24"
public_subnet_cidr = "10.11.4.0/24"# AWS Settings
aws_region = "eu-west-1"
aws_access_key = "complete-this"
aws_secret_key = "complete-this"# AWS Settings Main
aws_region_main = "eu-west-1"
aws_access_key_main = "complete-this"
aws_secret_key_main = "complete-this"# DNS
public_dns_name = "kopicloud.com"
dns_hostname = "lbmultitest"# Linux Virtual Machine
ec2_count = 2
linux_instance_type = "t2.micro"
linux_root_volume_size = 20
linux_root_volume_type = "gp2"
linux_data_volume_size = 10
linux_data_volume_type = "gp2"The full code is available at https://github.com/KopiCloud/terraform-aws-ec2-internal-alb-acm-multi-account
And that’s all, folks. If you liked this story, please show your support by 👏 this story. Thank you for reading!






