Fatskills
Practice. Master. Repeat.
Study Guide: TECH **Terraform + Configuration Management (Ansible, Chef): Zero-Fluff Study Guide**
Source: https://www.fatskills.com/cloud-application-developer/chapter/tech-terraform-configuration-management-ansible-chef-zero-fluff-study-guide

TECH **Terraform + Configuration Management (Ansible, Chef): Zero-Fluff Study Guide**

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~8 min read

Terraform + Configuration Management (Ansible, Chef): Zero-Fluff Study Guide

Deploy infrastructure with Terraform, then configure it with Ansible or Chef—without breaking production.


1. What This Is & Why It Matters

You’re a cloud engineer at a fintech startup. Your team uses Terraform to spin up AWS EC2 instances, RDS databases, and VPCs. But Terraform only gets you halfway—it provisions the infrastructure, but doesn’t install software, apply security patches, or configure services (e.g., Nginx, PostgreSQL, Docker).

That’s where configuration management (CM) tools like Ansible or Chef come in. They take over after Terraform deploys the infrastructure and handle: - Software installation (e.g., apt install nginx) - Configuration files (e.g., /etc/nginx/nginx.conf) - Security hardening (e.g., disabling root SSH, setting firewall rules) - Service management (e.g., systemctl enable postgresql)

Why This Matters in Production

  • Terraform alone is not enough. If you only use Terraform, your servers are like empty houses—walls up, but no furniture, electricity, or plumbing.
  • CM tools make infrastructure usable. They turn raw VMs into web servers, databases, or Kubernetes nodes.
  • Idempotency is critical. Both Terraform and CM tools (Ansible, Chef) are idempotent—running them multiple times won’t break things. This is non-negotiable in production.
  • Separation of concerns. Terraform handles infrastructure as code (IaC), while CM tools handle configuration as code (CaC). Mixing them (e.g., using Terraform’s remote-exec for everything) leads to spaghetti code that’s hard to debug and scale.

Real-World Scenario

You inherit a legacy Terraform codebase that uses null_resource + remote-exec to install software on EC2 instances. Every deploy takes 20+ minutes, fails randomly, and is impossible to debug. Your mission:
1. Replace remote-exec with Ansible (or Chef) for configuration management.
2. Make deployments faster, more reliable, and auditable.
3. Ensure rollbacks work cleanly.


2. Core Concepts & Components


? Terraform + Ansible/Chef Workflow

Step Tool What It Does Production Insight
1 Terraform Provisions infrastructure (EC2, VPC, RDS, etc.) ⚠️ Always use terraform apply with -target for testing, but never in production (can cause drift).
2 Terraform Outputs Exports IPs, hostnames, or ARNs for CM tools Use output "instance_ips" { value = aws_instance.web.*.public_ip } to pass data to Ansible/Chef.
3 Ansible/Chef Configures software, security, and services Ansible is agentless (uses SSH), Chef requires an agent (more complex but better for large fleets).
4 Dynamic Inventory Automatically discovers Terraform-provisioned resources Ansible’s aws_ec2 plugin or Chef’s knife ec2 can pull instance data from AWS.

? Key Terraform Resources for CM Integration

Resource Purpose Production Insight
aws_instance / azurerm_linux_virtual_machine The VMs you’ll configure Tag instances with Name, Environment, and Role for CM targeting.
local_file Generates Ansible/Chef inventory files Use templatefile() to dynamically create inventory files from Terraform outputs.
null_resource + local-exec Triggers CM tools after Terraform ⚠️ Avoid remote-exec—it’s slow and hard to debug. Use local-exec to call Ansible/Chef instead.
terraform_data (v1.4+) Replaces null_resource for triggers More reliable than null_resource for running CM tools.

? Ansible vs. Chef: Quick Comparison

Feature Ansible Chef When to Use
Agent Agentless (SSH) Requires Chef Client Ansible for simplicity, Chef for large-scale compliance.
Language YAML (easy) Ruby (powerful but complex) Ansible for most teams, Chef for Ruby shops.
Learning Curve Low High Ansible for beginners, Chef for advanced automation.
Dynamic Inventory aws_ec2 plugin knife ec2 Ansible is easier to integrate with Terraform.
Idempotency Built-in Built-in Both are idempotent—critical for production.


3. Step-by-Step: Terraform + Ansible (Hands-On)

Goal: Deploy an AWS EC2 instance with Terraform, then configure Nginx using Ansible.

Prerequisites

✅ AWS account with IAM permissions for EC2 ✅ Terraform installed (terraform --version) ✅ Ansible installed (ansible --version) ✅ SSH key pair (~/.ssh/id_rsa.pub)


Step 1: Write Terraform to Deploy EC2

Create main.tf:


terraform {
  required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
} } } provider "aws" { region = "us-east-1" } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" # Ubuntu 22.04 LTS instance_type = "t3.micro" key_name = "your-key-pair" # Replace with your SSH key name tags = {
Name = "web-server"
Role = "nginx" } } # Output the public IP for Ansible output "instance_ip" { value = aws_instance.web.public_ip }

Apply Terraform:


terraform init
terraform apply -auto-approve


Step 2: Generate Ansible Inventory from Terraform

Add this to main.tf:


resource "local_file" "ansible_inventory" {
  filename = "inventory.ini"
  content  = <<-EOT
[webservers]
${aws_instance.web.public_ip} ansible_user=ubuntu EOT }

Re-apply Terraform:


terraform apply -auto-approve

This creates inventory.ini with the EC2 IP.


Step 3: Write Ansible Playbook to Install Nginx

Create nginx.yml:


---
- name: Install and configure Nginx
  hosts: webservers
  become: yes
  tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start and enable Nginx
service:
name: nginx
state: started
enabled: yes


Step 4: Run Ansible Playbook

ansible-playbook -i inventory.ini nginx.yml

Verify Nginx is running:


curl http://<EC2_PUBLIC_IP>

You should see the Nginx welcome page.


Step 5: Automate the Entire Workflow

Use null_resource (or terraform_data in v1.4+) to trigger Ansible after Terraform:


resource "null_resource" "run_ansible" {
  triggers = {
instance_ip = aws_instance.web.public_ip } provisioner "local-exec" {
command = "ansible-playbook -i inventory.ini nginx.yml" } depends_on = [local_file.ansible_inventory] }

Re-apply Terraform:


terraform apply -auto-approve

Now Terraform automatically runs Ansible after deploying the EC2 instance.


4. ? Production-Ready Best Practices


? Security

  • Never hardcode secrets. Use ansible-vault for Ansible or Chef’s encrypted data bags.
  • Restrict SSH access. Use aws_security_group to allow SSH only from your IP or a bastion host.
  • Use IAM roles for EC2. Avoid embedding AWS keys in Ansible/Chef configs.

? Cost Optimization

  • Spot instances for non-critical workloads. Use aws_spot_instance_request in Terraform.
  • Shut down dev environments at night. Use Terraform + Ansible to schedule start/stop.
  • Right-size instances. Use t3.micro for dev, m5.large for prod.

? Reliability & Maintainability

  • Tag everything. Use Environment=prod, Role=web, Owner=team-x for easy filtering.
  • Use dynamic inventory. Avoid hardcoding IPs—use Ansible’s aws_ec2 plugin or Chef’s knife ec2.
  • Modularize Terraform. Split into vpc.tf, ec2.tf, ansible.tf for better maintainability.
  • Idempotency is non-negotiable. If your Ansible playbook isn’t idempotent, fix it immediately.

? Observability

  • Log everything. Use cloud-init in Terraform to send logs to CloudWatch.
  • Monitor CM runs. Use Ansible’s --check mode in CI/CD to catch errors early.
  • Alert on failures. Set up SNS alerts for Terraform apply failures.


5. ⚠️ Common Mistakes & Traps

Mistake Symptom Fix/Prevention
Hardcoding IPs in Ansible inventory Playbook fails when EC2 IPs change Use dynamic inventory (aws_ec2 plugin) or Terraform-generated inventory.
Using remote-exec for everything Slow, unreliable, hard to debug Replace with Ansible/Chef for configuration.
Not handling Terraform drift CM tools break when Terraform changes infrastructure Use terraform plan before CM runs to detect drift.
Forgetting depends_on Ansible runs before EC2 is ready Add depends_on = [aws_instance.web] to null_resource.
No rollback strategy Failed CM leaves servers in broken state Use idempotent playbooks and Terraform taint for rollbacks.


6. ? Exam/Certification Focus


Typical Terraform + CM Questions

  1. “How do you pass Terraform outputs to Ansible?”
  2. Correct: Use local_file to generate an inventory file.
  3. Wrong: Hardcode IPs in Ansible or use remote-exec.

  4. “What’s the best way to trigger Ansible after Terraform?”

  5. Correct: null_resource + local-exec (or terraform_data in v1.4+).
  6. Wrong: Manually run Ansible after Terraform.

  7. “Why avoid remote-exec for configuration?”

  8. Correct: Slow, non-idempotent, hard to debug.
  9. Wrong: “It’s fine for small deployments.”

  10. “How do you handle secrets in Ansible?”

  11. Correct: ansible-vault or AWS Secrets Manager.
  12. Wrong: Hardcode in playbooks or Terraform.

Key Trap Distinctions

Concept Terraform Ansible/Chef
Idempotency Yes (repeated applies don’t change state) Yes (repeated runs don’t break things)
Agent Required? No (API calls) Ansible: No (SSH), Chef: Yes
Best For Infrastructure provisioning Software configuration
State Management terraform.tfstate No state file (stateless)


7. ? Hands-On Challenge

Challenge:
Deploy a PostgreSQL database on AWS RDS with Terraform, then use Ansible to: 1. Install psql on an EC2 instance.
2. Create a database and user.
3. Load a sample schema.

Solution:
1. Terraform (rds.tf):
hcl
resource "aws_db_instance" "postgres" {
allocated_storage = 20
engine = "postgres"
instance_class = "db.t3.micro"
db_name = "mydb"
username = "admin"
password = "securepassword123" # Use AWS Secrets Manager in prod!
skip_final_snapshot = true
}
2. Ansible Playbook (postgres.yml):
```yaml
- name: Configure PostgreSQL client
hosts: webservers
become: yes
tasks:
- name: Install PostgreSQL client
apt:
name: postgresql-client
state: present


   - name: Create database
postgresql_db:
name: mydb
login_host: "{{ rds_endpoint }}"
login_user: admin
login_password: securepassword123

3. Run it:bash
terraform apply -auto-approve
ansible-playbook -i inventory.ini postgres.yml
```

Why It Works:
- Terraform provisions the RDS instance.
- Ansible installs psql and configures the database without manual steps.


8. ? Rapid-Reference Crib Sheet


Terraform + Ansible/Chef Commands

Command Purpose
terraform output -json > outputs.json Export Terraform outputs for CM tools.
ansible-inventory --list -i inventory.ini Verify Ansible inventory.
ansible-playbook --check -i inventory.ini playbook.yml Dry-run Ansible (no changes).
knife ec2 server list List Chef-managed EC2 instances.
terraform taint aws_instance.web Force Terraform to recreate a resource.

Key Defaults & Traps

Item Default ⚠️ Trap
Ansible SSH user root (or ec2-user on AWS) Always set ansible_user=ubuntu for Ubuntu.
Chef client interval 30 minutes Too slow for fast-changing environments.
Terraform remote-exec Runs as root Avoid—use Ansible/Chef instead.
Dynamic inventory refresh Manual Use aws_ec2 plugin for auto-refresh.


9. ? Where to Go Next

  1. Ansible Dynamic Inventory for AWS – Auto-discover Terraform-provisioned instances.
  2. Chef + Terraform Integration – Official Chef tutorial.
  3. Terraform local-exec Docs – How to trigger CM tools.
  4. AWS Secrets Manager + Ansible – Secure secrets management.


ADVERTISEMENT