Automate AWS deployments with Ansible + Terraform

This installation is made from a bastion server already available with the proper network permissions.
For different deployment types, you should adapt it to your need.

Install requirements

Ansible installation:

sudo apt update
sudo apt install -y software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible


Terraform installation:

sudo unzip -d /usr/local/bin/ ./


AWS Client installation:

curl "" -o ""
sudo ./aws/install


Connect your environment to your AWS cloud

$ aws configure
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: eu-central-a
Default output format [None]: json


Create a new Ansible project

That is my favorite Ansible layout. The one I’ve seen as the best so far:

mkdir -p ~/my_aws_project/inventory
mkdir -p ~/my_aws_project/playbooks
mkdir -p ~/my_aws_project/roles

Add the EC2 dynamic inventory

Ansible can work with a different kind of inventory called the dynamic inventory.
Instead of having a static declaration in a static file of your inventory, you can generate it from a source.
This source can be a database, an active directory, etc. A dynamic inventory is a scrip that outputs a JSON in a structure that Ansible can handle. We could then develop a script that discovers our EC2 infrastructure that would take some time. Or we can use the one already provide with Ansible:

Install prerequisites:

sudo apt install -y python3-pip
sudo pip3 install boto
sudo pip3 install ansible
sudo rm /usr/bin/python
sudo ln -s /usr/bin/python3 /usr/bin/python

Get the EC2 dynamic inventory:

wget -O ~/my_aws_project/inventory/ \
wget -O ~/my_aws_project/inventory/ec2.ini \
chmod +x ~/my_aws_project/inventory/

There are multiple configuration options you can do with the ini file. For this blog I’ll change those vars:

regions = eu-central-1
vpc_destination_variable = private_ip_address

Test the inventory script:

~/my_aws_project/inventory/ ## ---> return JSON description of your AWS infrastructure

Because I want to work on one AWS region in the private network only. Since my bastion is already in
the AWS infrastructure.

Add a role for our deployment

I’ll create a role with the only purpose to deploy my infrastructure into AWS.

ansible-galaxy init --init-path ~/my_aws_project/roles ec2_instances_dep

Cable the components (Ansible configuration)

To have that layout working fine and the simpliest way, I use that configuration:

## file ~/my_aws_project/ansible.cfg
roles_path = ./roles
inventory  = ./inventory/

Test the ansible inventory:

cd ~/my_aws_project
ansible-inventory --graph ## ---> return the Ansible interpreted inventory

Terraform with Ansible

When I need to do something with Ansible, I first check in the list of modules is the work is already done.
And, nicely, there is a module for Terraform.

So I can add this module in my task main file of my role:

## ~/my_aws_project/roles/ec2_instances_dep/tasks/main.yml
- name: I create a directory to store my Terraform config
    path: "~/aws_terraform"
    state: directory
    recurse: yes

- name: I copy my Terraform template into the working directory create above
    src: ""
    dest: "~/aws_terraform/"

- name: I deploy my configuration into AWS from Ansible
    project_path: "~/aws_terraform"
    force_init: true
    state: "present"
  register: r_aws

- name: I do whatever I need to do in my EC2 infrastructure
  debug: msg="update, install, create user, start services, etc"

- name: I destroy my AWS infrastructure 
    project_path: "~/aws_terraform"
    state: "absent"

Terraform content

Add this file into the template directory: ~/my_aws_project/roles/ec2_instances_dep

## file ~/my_aws_project/roles/ec2_instances_dep/
provider "aws" {
  region = "eu-central-1"

resource "aws_instance" "dba-essential" {
  count                       = "5"
  ami                         = "ami-0e342d72b12109f91"
  availability_zone           = "eu-central-1a"
  instance_type               = "t2.micro"
  associate_public_ip_address = false
  security_groups             = ["my_sg_01"]
  vpc_security_group_ids      = ["sg-602eff2724d52a0b7"]
  key_name                    = "my_key_01"

  root_block_device {
    delete_on_termination = true
    encrypted             = false
    volume_size           = 15
    volume_type           = "gp2"

  tags = {
    Owner           = "Nicolas"
    Name            = "crash-test-${count.index + 1}"


Create a playbook to call the role

## file ~/my_aws_project/playbooks/deploy.yml
- name: Deploy my infrastructure
  hosts: localhost

    - ec2_instances_dep

Run the playbook

cd my_aws_project
ansible-playbook playbooks/deploy.yml

Boom! Here it is. Now imagine that you can generate a unique key and unique directory for each deployment and you can deploy as much infrastructure as your credit card will accept it.

I hope this helps, and please comment below for any questions.