AWS provides seamless integration to manage secure traffic routing through an Amazon Route 53 hosted zone to an Application Load Balancer (ALB), using a secure certificate from AWS Certificate Manager (ACM). I build upon a previously discussed use case such that by the end of this note, you’ll have the concept of creating an ALB that securely accepts traffic through HTTPS with a custom domain and Route 53 handling the DNS records using Terraform and GitHub Actions.

Previously, I discussed three identical use cases. In the first use case, I showed how to attach a load balancer to three Amazon EC2 instances. In the second use case, I showed how to attach a load balancer to three Amazon EC2 instances created in the private subnet. Finally, in the third use case, I showed how to attach a load balancer to three Amazon EC2 instances that are part of an auto-scaling group created in a private subnet. In all the use cases, I could access the static web page hosted on the Amazon EC2 instances via the load balancer DNS using the HTTP protocol listening on port #80.

In this note, I’ll extend the concept and demonstrate how to use a secure mechanism (port #443) to access the static web page and use a custom DNS instead of the load balancer DNS. For that, I used two additional AWS cloud resources: Amazon Route 53 and Amazon Certificate Manager. Later, I also covered the AWS cloud resource provisioning mechanism via GitHub Actions.

Provision the AWS cloud resources An Amazon Route 53 hosted zone is a container for DNS records that define how traffic must be routed for a specific domain or subdomain. It acts as a central management point for all the DNS records associated with your domain, allowing you to create, update, and delete records such as A, CNAME, and others.

Amazon Certificate Manager (ACM) is a fully managed service that simplifies the process of provisioning, managing, and deploying SSL/TLS certificates for use with AWS services. With ACM, cloud engineering teams can efficiently secure the website or application by encrypting traffic between clients and servers, ensuring data integrity and confidentiality.

If you are interested and want to follow along, please refer to the GitHub repository: kunduso/add-aws-elb-ec2-private-subnet-terraform. Please note the branch name is add-acm-r53. I used an externally purchased domain (from Squarespace); hence, these steps will apply to similar scenarios.

Pre-requisite: Purchase a domain and have access to change the domain nameservers. Since I was building upon a previous use case, I recommend you first review that -attach-an-application-load-balancer-to-amazon-ec2-instances-in-a-private-subnet.

This use case can be classified into seven detailed steps: 1. Create the Amazon Route 53 Hosted Zone 2. Request an SSL/TLS Certificate from the AWS Certificate Manager 3. Add ACM Certificate Validation Records to Route 53 hosted zone 4. Validate the ACM Certificate 5. Configure Load Balancer Listeners for HTTPS Redirection 6. Update Security Group Rule for HTTPS Traffic 7. Create an A Record for the Load Balancer in Route 53 Hosted Zone

Step 1: Create the Amazon Route 53 Hosted Zone As discussed, a hosted zone is a container for all the records, and it is the first AWS cloud resource to be created. The hosted zone manages DNS records for the domain, which is stored as a variable domain_name. 112-image-1 Step 2: Request an SSL/TLS Certificate from the AWS Certificate Manager The ACM certificate ensures secure communication between clients and the application load balancer. Per AWS-Docs, with AWS Certificate Manager (ACM), you can provision and manage SSL/TLS certificates for your AWS-based websites and applications. The validation method is DNS to prove domain ownership. 112-image-2 Managing certificates via ACM is convenient because (i) it is free to use with AWS services, (ii) it renews automatically, and (iii) AWS manages it, hence freeing one from manual certificate management tasks. After requesting the SSL/TLS certificate, ACM requires domain ownership verification through DNS validation.

Step 3: Add ACM Certificate Validation Records to the Amazon Route 53 hosted zone This step creates the necessary CNAME records in the Route 53 hosted zone using the validation information provided by ACM. The Terraform code uses a for_each loop to create these validation records, where each record contains specific values (name, type, and record value) that ACM will check to verify the domain ownership and issue the certificate. 112-image-3 Until this step, the ACM certificate is still in the “Pending validation” status. 112-image-4 Step 4: Validate the ACM Certificate This step ensures that Terraform waits for ACM to complete the certificate validation process before proceeding. 112-image-5 The resource takes two essential parameters: the certificate ARN from the previously created certificate and a list of the fully qualified domain names (FQDNs) from the validation records. By creating this validation resource, Terraform pauses the execution until ACM successfully validates the certificate using the DNS records created in the previous step. This is crucial because other AWS resources, such as Load Balancers, require a fully validated certificate before they can be used.

Step 5: Configure Load Balancer Listeners for HTTPS Redirection I modified the load balancer configuration to handle secure HTTPS traffic in this step. 112-image-6 In the previous use case, the listener on port #80 (HTTP) was configured to forward all HTTP traffic to the target group. In this updated use case, the listener is reconfigured to automatically redirect all incoming HTTP traffic to HTTPS (port #443) using a permanent redirect (HTTP 301 status code). Subsequently, a new HTTPS listener is created on port #443, which uses the validated ACM certificate to terminate SSL/TLS connections. This listener is configured with a modern security policy (ELBSecurityPolicy-TLS13-1-2-2021-06) and forwards the decrypted traffic to the target group. This setup ensures all communication with the application is encrypted, as any attempts to access the application via HTTP will automatically be redirected to use HTTPS. 112-image-7 By offloading SSL termination to the ALB, businesses can centralize certificate management, simplify configurations, and reduce the computational load on backend servers, improving performance.

Step 6: Update Security Group Rule for HTTPS Traffic In the previous use case, the security group ingress rule allowed HTTP traffic on port #80. The updated security group rule now permits inbound HTTPS traffic on port #443 from any source IP address to the load balancer, enabling secure encrypted communication between clients and the application. 112-image-8 Note: While this use-case allows traffic from 0.0.0.0/0 (any IP address), this is a common configuration for public-facing load balancers. However, if your application needs to be accessed only from specific IP ranges, you should restrict the cidr_blocks accordingly.

Step 7: Create an A Record for the Load Balancer in Route 53 Hosted Zone This final step creates an alias record in Route 53 that points the domain name to the Application Load Balancer. 112-image-9 Instead of a traditional A record with an IP address, I created an alias record that automatically tracks the load balancer’s DNS name. The alias record is configured to evaluate the target’s health, ensuring traffic is only routed when the load balancer is healthy. This setup allows users to access the application using the domain name instead of the load balancer’s default DNS name, which was the case in the previous use case.

Those are all the resources required to ensure the application receives requests over HTTPS. When users access the domain, they will be automatically redirected to the secure HTTPS version if they try to use HTTP. The traffic flows through the Application Load Balancer, which terminates SSL using the ACM certificate and then forwards the requests to the application running on the EC2 instances in the private subnet. This setup provides a secure, highly available infrastructure that follows AWS best practices for web applications.

This setup is beneficial for organizations looking to improve the security, scalability, and manageability of their web applications. Using Amazon Route 53, ACM, and an Application Load Balancer (ALB), cloud engineering teams can securely route traffic to their backend servers, ensuring HTTPS encryption.

The next step is understanding how to automate the deployment using GitHub Actions.

Automation Using GitHub Actions Because of the nature of the AWS cloud resources and the fact that I had an externally purchased domain, I required the terraform apply step to execute in two phases (via two GitHub Actions jobs). This use case required a mechanism to create the Amazon Route53 hosted zone first so that the nameserver value was available to update in the external domain (Squarespace) name server. Then, the rest of the AWS cloud resources can be created.

If you are new to GitHub Actions and Terraform, please review - ci-cd-with-terraform-and-github-actions-to-deploy-to-aws.

For this approach, I used two GitHub Actions jobs and two environments. The deployment to the second environment was managed using two environments and a protection rule (required reviewers). Below is an image of the deployment protection rule for the second environment, production-infrastructure. As you can see, it requires my approval to proceed. 112-image-10 Let us now review the terraform.yml file at .github\workflows path in the repository.

As we discussed earlier, the AWS Route53 hosted zone must be created in the first GitHub Actions job so that we have the values of the domain name servers. As you can examine from the image below of the GitHub Actions workflow, this step only creates the Amazon Route53 hosted zone. That is managed via the -target flag in the terraform apply command. 112-image-11 These nameserver values were displayed at the end of a terraform apply step via the output reference, as seen from the below reference image. 112-image-12 I updated these name_server values in the Domain Nameservers section of my externally registered domain (Squarespace). That update triggers a DNS propagation. I do not manage the DNS propagation mechanism, so after updating the name_server values, I approved the second phase of the terraform apply step so that the remaining resources (as part of the second GitHub Action jobs) were provisioned.

Once the DNS changes had propagated, the ACM validation also completed. From the image below, you can see that it took upward of 3 minutes. At times, it has also taken close to 9 minutes. 112-image-13 As the image below shows, provisioning and updating all the AWS cloud resources took a little over 6 minutes. 112-image-14 Once both the GitHub Actions jobs had been completed, I navigated to the domain and was greeted by the static page. The request was directed to another Amazon EC2 instance on each page refresh. 112-image-15 That brings us to the end of this note. This was a pretty long note, so let’s do a quick recap.

This blog explored how to securely route traffic using Amazon Route 53, an Application Load Balancer (ALB), and AWS Certificate Manager (ACM) to serve a static web page with HTTPS using a custom domain. We also learned how to automate the deployment process using GitHub Actions, splitting it into two phases: first, setting up Amazon Route 53 and then provisioning the rest of the AWS resources.

Following these steps, you’ll have a secure and scalable infrastructure that encrypts traffic and ensures your application is accessible using a custom domain over HTTPS. If you have any questions or suggestions, please use the comments section below.