Terraform and Ansible, Best Buddies


You might be already know that Terraform and Ansible are both champs in their own domains. Terraform is the master of provisioning infrastructure on cloud. Ansible, meanwhile, is expert at configuring those systems, ensuring everything's set up and running perfectly.
But did you know they can team up to create something unstoppable? Let’s dive into how these two can work together seamlessly. In this post, I’ll walk you through integrating Terraform and Ansible in a GitHub-driven CI/CD workflow for for automatically deploying and configuring EC2 instances on AWS. No manual fiddling required, pure automation magic!
The Setup: Terraform Provisions, Ansible Configures
Picture this: Terraform kicks things off by creating a fleet of EC2 instances on AWS, then Ansible takes over to handle the configuration, like adding users or dropping files. Here's a simple Terraform snippet to launch those instances:
resource "aws_instance" "my_vms" {
ami = var.instance_ami
instance_type = var.instance_type
count = var.instance_count
key_name = var.key_name
subnet_id = var.subnet_id
associate_public_ip_address = true
vpc_security_group_ids = [var.security_group_id]
tags = {
Name = "vm${count.index + 1}"
}
}
But here’s the catch! Ansible needs an inventory (a list of EC2 VM with their IP addresses or hostnames) to know where to connect and do its thing.
In fact, Terraform can easily generate that inventory after the instances are up. Check out this resource that grabs the public DNS names and dumps them into a file called inventory.txt
.
resource "local_file" "public_dns_file" {
content = "[all]\n${join("\n", aws_instance.my_vms[*].public_dns)}"
filename = "${path.module}/inventory.txt"
}
Once Terraform runs apply and creates that file, Ansible can take over. Here's a basic playbook (demo_ec2.yaml
) to configure the hosts — adding an Ansible user and creating a welcome text file:
---
- name: Quick Demo Playbook
hosts: all
become: yes
tasks:
- name: add Ansible user
user:
name: ansible
state: present
tags:
- user
- name: Create a text file in home dir
copy:
content: "This server is managed by Ansible. Hello from Terraform!"
dest: /home/ec2-user/welcome.txt
owner: ec2-user
group: ec2-user
mode: '0644'
tags:
- file
The Missing Link: Handing Off with GitHub Actions
But how can Terraform pass that inventory file to Ansible seamlessly? So there’s one more piece to the puzzle, who’s going to coordinate this handoff? That’s where GitHub steps in!
With GitHub Actions (or other CI/CD tool), we can actually automate the whole process. Here is an example of Github workflows:
name: CI TEST
on:
workflow_dispatch:
inputs:
action:
description: 'Select action'
required: true
default: 'plan'
type: choice
options:
- plan
- apply
- play
jobs:
plan:
if: inputs.action == 'plan'
runs-on: self-hosted
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.11.4
terraform_wrapper: false
- name: Terraform Init
run: terraform init
- name: Terraform Plan
run: terraform plan
apply:
if: inputs.action == 'apply'
runs-on: self-hosted
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.11.4
terraform_wrapper: false
- name: Terraform Init
run: terraform init
- name: Terraform Apply
run: terraform apply -auto-approve
play:
runs-on: self-hosted
needs: apply
steps:
- name: display ansible inventory
run: cat inventory.txt
- name: run ansible play
run: ansible-playbook -i inventory.txt -u ec2-user demo_ec2.yaml
In this setup, Terraform generates Inventory file on my self-host runner, then the job play
executes the playbook together the inventory file ansible-playbook -i inventory.txt -u ec2-user demo_ec2.yaml
.
apply:
...
- name: Upload Inventory Artifact
uses: actions/upload-artifact@v4
with:
name: inventory
path: inventory.txt
Wrapping it Up
This is just a PoC showing how Terraform and Ansible can collaborate like best buds in a GitHub workflow, no need for fancy enterprise editions, no complex integrations, no hidden costs. It's all open-source goodness! Tweak it for your setup, add more security, or scale it up. If you've got questions or your own twists, drop a comment.
Subscribe to my newsletter
Read articles from Bruce L directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Bruce L
Bruce L
I’ve been rocking the DevOps journey for a decade, starting with building Cisco’s software-defined datacenters for multi-region OpenStack infrastructures. I then shifted to serverless and container deployments for finance institutions. Now, I’m deep into service meshes like Consul, automating with Ansible and Terraform, and running workloads on Kubernetes and Nomad. Stick around for some new tech and DevOps adventures!