Deploying to AWS with Terraform and Ansible

3 hours
  • 4 Learning Objectives

About this Hands-on Lab

You were recently hired as an Infrastructure Automation Engineer at a SaaS company. The company is trying to move away from cloud-provider-specific infrastructure as code. They want to test out Terraform for infrastructure deployment as it is cloud agnostic and Ansible as it is OS agnostic and also a hybrid IaC tool.

Your first task is to use Terraform and Ansible to deploy a distributed Jenkins CI/CD pipeline and put it behind one of the company’s DNS domains for testing. It sounds easy enough but there’s quite some planning which will go into this and you’re already on top of it.

Learning Objectives

Successfully complete this lab by achieving the following learning objectives:

Log in to the Terraform Controller Node EC2 Instance
  1. Find the details for logging in to the Terraform Controller node provided by the hands-on lab interface and log in to the node using SSH.

    ssh cloud_user@<IP-OF-TERRAFORM-CONTROLLER>

    Note: This Instance already has an EC2 instance profile (role) attached to it and has all necessary AWS API permissions required for this lab. It also has the AWS CLI set up and is configured with the AWS account attached to this lab, for which the console login credentials are also provided in the lab interface page once the lab spins up.

  2. After logging in, check the version of Terraform that is installed. Execute the following command to check:

    terraform version
Clone the GitHub Repo for Terraform Code

Use the git command to clone the GitHub repo which has the Terraform code to deploy to complete this lab. GitHub repo URL.

  1. Execute the following command:

    git clone
  2. Change directory to the directory for lab Terraform code:

    cd -content-deploying-to-aws-ansible-terraform/aws_la_cloudplayground_multiple_workers_version
  3. Execute ls and examine the contents of the directory you’re in.

Deploy the Terraform Code
  1. Execute terraform init to initialize the Terraform directory you changed into to download the required provider.

  2. Execute terraform fmt to ensure Terraform code is formatted properly.

  3. Execute terraform validate to ensure code has proper syntax and no errors.

  4. Execute terraform plan and enter yes when prompted to see the execution plan and note the number of resources that will be created.

  5. Execute terraform apply and enter yes when prompted to actually deploy resources.

    After terraform apply has run successfully, you can either use AWS CLI on the Controller node to list, describe created resources, and additionally also log in to the AWS Console to verify and investigate created resources.

  6. Finally, on the Terraform Controller node CLI, execute terraform destroy and enter yes when prompted to delete all resources which were created and ensure that it runs through successfully.

Test Out Your Deployment

Jenkins Credentials:

  • Username: admin
  • Password password

Test your deployment by carrying out the following steps:

  1. Test out the URL of your website returned in Terraform outputs.
  2. Changing the workers count by modifying workers-count variable in the file and ensure that Terraform apply is successful. You can also log in to Jenkins, go in to Settings, and under the Manage nodes setting, check that the number of Jenkins workers you had set up are the number of workers showing as integrated with the Jenkins Master node.
  3. Use the variable external_ip in file to tie down SSH access to Jenkins nodes only from your home/work IP or from the Terraform Controller node. You can also pass in your current public IP through the external_ip variable dynamically on the CLI via something like this:

    terraform apply -var external_ip=$(curl

    This should pass your public IP in x.x.x.x/32 format to the external_ip variable. However, is just one method to find your public URL. Feel free to use whatever method you prefer.

Additional Resources

This is the information that you have been provided:

  1. You'll be spinning up a Jenkins Master node (EC2) in us-east-1 and a Jenkins Worker (EC2) in us-west-2. Both these nodes will need to communicate so you'll need to set up appropriate VPC peering, route table entries, and security group rules to allow that.
    The Jenkins Master node's webserver listens on port 8080/tcp, and the Jenkins Worker will need to be able communicate with the Jenkins Master on all ports over TCP.
    You've been provided the following details for the network setup:

    • us-east-1 VPC CIDR:
    • us-west-2 VPC CIDR:
    • us-east-1 VPC will have 2 subnets:,
    • us-west-2 VPC will have 1 subnet:
    • Both VPC's will have internet gateways attached so that instances can have internet access
  2. Ansible Playbooks, Jinja templates for Ansible, and a plaintext file containing the username and password for your Jenkins Application have been provided to you at the following URLs:

    a. Jenkins Master Ansible Playbook
    b. Jenkins Worker Ansible Playbook
    c. Ansible Jinja template for Jenkins Worker Setup
    d. Ansible Jinja template for Jenkins Worker credential setup
    e. Plaintext Jenkins Auth file

  3. You've been advised to create a directory named ansible_templates inside your project folder and maintain all Ansible related Playbooks, Jinja templates, and inventory configuration in this directory.

  4. You've further been advised to create another directory inside the ansible_templates directory called inventory_aws and store the Ansible dynamic inventory fetching config file there. The URL to the file is: Ansible Inventory Config for AWS

  5. You can fetch the publicly-hosted domain name provided by your company by issuing the following command:

    aws route53 list-hosted-zones | jq -r .HostedZones[].Name | egrep "cmcloud*" 
  6. You will need to create an Application Load Balancer with 2 listeners:

    a. Port 443 (HTTPS)
    b. Port 80 (HTTP)

  7. Create and attach an ACM certificate with the port 443 listener of your ALB. You can assign any permissible subdomain string to your URL for the Jenkins Application. For example, if the public domain of your company is, you can give your Jenkins DNS the URL when generating an ACM certificate for it.

  8. Ensure that the port 80 listener permanently redirects all traffic to port 443.

  9. Your ALB will only route traffic to the Jenkins Master. The Ansible playbooks will handle setup of the Jenkins Application throughout so no need to worry about the application deployment.

  10. You'll be invoking Ansible playbooks onto their respective nodes via provisioners in their Terraform code resources. You can use the following general command to wait until an EC2 instance is in ready state to issue commands/run playbooks against it:

    aws --profile default ec2 wait instance-status-ok --region <EC2-Region> --instance-ids <INSTANCE-ID>
  11. For better integrity, you intend to save the Terraform state file generated in an S3 bucket. You'll need to configure a backend in Terraform and you'll also need to create the bucket before you run a terraform apply. Create it using:

    aws s3api create-bucket --bucket <your-unique-bucket-name>
  12. For Ansible, you've been provided with a preconfigured ansible.cfg file which needs to be placed in the same folder where your Terraform template files will be. You can download the preconfigured ansible.cfg from here. Please note that this ansible.cfg file has the path to EC2 Dynamic Inventory configuration file hardcoded into it.

What are Hands-on Labs

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Sign In
Welcome Back!

Psst…this one if you’ve been moved to ACG!

Get Started
Who’s going to be learning?