Table of Contents

Introduction

Terraform and Ansible are the two most popular infrastructure automation tools — and they’re even better together. Terraform provisions your cloud infrastructure (VMs, networks, databases), while Ansible configures what’s running on them (packages, services, applications). This guide shows you how to integrate both for end-to-end automation.

If you’re new to Ansible, check out Ansible Pilot for 500+ tutorials and hands-on guides.

The Architecture

┌─────────────────────────────────────────────┐
│           Your CI/CD Pipeline               │
├─────────────────┬───────────────────────────┤
│   Terraform     │        Ansible            │
│   (Provision)   │     (Configure)           │
├─────────────────┼───────────────────────────┤
│ • Create VPC    │ • Install packages        │
│ • Launch EC2    │ • Configure nginx         │
│ • Setup RDS     │ • Deploy application      │
│ • Create ALB    │ • Setup monitoring        │
│ • DNS records   │ • Security hardening      │
└─────────────────┴───────────────────────────┘

Step 1: Terraform Provisions Infrastructure

# main.tf
resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  key_name      = aws_key_pair.deployer.key_name

  vpc_security_group_ids = [aws_security_group.web.id]
  subnet_id              = aws_subnet.public[count.index].id

  tags = {
    Name        = "web-${count.index + 1}"
    Role        = "webserver"
    Environment = var.environment
  }
}

# Output IPs for Ansible
output "web_server_ips" {
  value = aws_instance.web[*].public_ip
}

output "web_server_private_ips" {
  value = aws_instance.web[*].private_ip
}

Step 2: Generate Ansible Inventory from Terraform

# Generate Ansible inventory dynamically
resource "local_file" "ansible_inventory" {
  content = templatefile("inventory.tpl", {
    web_servers = aws_instance.web[*]
    db_endpoint = aws_db_instance.main.endpoint
  })
  filename = "../ansible/inventory/hosts"
}
# inventory.tpl
[webservers]
%{ for server in web_servers ~}
${server.tags.Name} ansible_host=${server.public_ip} ansible_user=ubuntu
%{ endfor ~}

[all:vars]
db_endpoint=${db_endpoint}
environment=${var.environment}

Step 3: Ansible Configures the Servers

# playbook.yml
---
- hosts: webservers
  become: true
  roles:
    - common
    - nginx
    - app-deploy
    - monitoring

- hosts: webservers
  tasks:
    - name: Configure nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/sites-available/default
      notify: restart nginx

    - name: Deploy application
      git:
        repo: "https://github.com/company/webapp.git"
        dest: /var/www/app
        version: "{{ app_version }}"
      notify: restart app

Step 4: CI/CD Pipeline Integration

# .gitlab-ci.yml
stages:
  - provision
  - configure
  - test

provision:
  stage: provision
  script:
    - cd terraform/
    - terraform init
    - terraform apply -auto-approve
    - terraform output -json > ../ansible/tf_outputs.json

configure:
  stage: configure
  script:
    - cd ansible/
    - ansible-playbook -i inventory/hosts playbook.yml
  dependencies:
    - provision

Best Practices

  1. Use Terraform for cloud resources — anything with an API (AWS, Azure, GCP)
  2. Use Ansible for OS-level configuration — packages, files, services
  3. Share data via outputs/variables — Terraform outputs → Ansible variables
  4. Use dynamic inventory — ansible-inventory plugins for cloud providers
  5. Separate repos or directories — keep Terraform and Ansible code organized
  6. Test both independently — terraform validate + ansible-lint

Learning Resources

Conclusion

Terraform + Ansible is the gold standard for full-stack infrastructure automation. Terraform handles the “what exists” question, Ansible handles the “how it’s configured” question. Together, they give you complete control over your infrastructure from creation to configuration. Check out our Terraform course and Ansible Pilot to master both tools.