DEV Community

Udoh Deborah
Udoh Deborah

Posted on

Day 54: Understanding Infrastructure as Code and Configuration Management

1) Quick conceptual recap (one-liner)
• IaC = provision the house (networks, VMs, load-balancers, security groups).
• CM = arrange & maintain the furniture & appliances inside the house (install packages, configure services, keep things consistent).

2) Tools — choose what fits
• IaC: Terraform (multi-cloud), CloudFormation (AWS native), Pulumi (code-first).
• CM: Ansible (agentless, SSH), Puppet/Chef (agent model), SaltStack.
(Use Terraform + Ansible is a very common, practical combo.)

3) Hands-on step-by-step (provision with Terraform → configure with Ansible)

Step 3.1 — Prepare a project layout

project/
  terraform/
    main.tf
    variables.tf
    outputs.tf
  ansible/
    inventory.ini   <-- generated from terraform output
    playbook.yml
  .github/workflows/ci.yml   (optional CI)


Enter fullscreen mode Exit fullscreen mode

Step 3.2 — Example Terraform (IaC) — terraform/main.tf

This provisions a security group + one EC2 instance and outputs its public IP.

# terraform/main.tf
provider "aws" {
  region = var.region
}

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }
}

resource "aws_security_group" "web_sg" {
  name        = "day54-web-sg"
  description = "allow ssh & http"
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami                    = data.aws_ami.amazon_linux.id
  instance_type          = var.instance_type
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  key_name               = var.ssh_key_name
  tags = {
    Name = "day54-web"
  }
}

output "public_ip" {
  value = aws_instance.web.public_ip
}
Enter fullscreen mode Exit fullscreen mode

terraform/variables.tf (simple vars)

variable "region" { default = "us-east-1" }
variable "instance_type" { default = "t3.micro" }
variable "ssh_key_name" { type = string }
Enter fullscreen mode Exit fullscreen mode

Commands

cd terraform
terraform init
terraform plan -out plan.tfplan
terraform apply "plan.tfplan"        # or 'terraform apply -auto-approve' for demos

Enter fullscreen mode Exit fullscreen mode

Step 3.3 — Generate Ansible inventory from Terraform output

Simplest approach (Terraform >=0.12 supports -raw output for single values):

cd ..   # project root
TF_IP=$(terraform -chdir=terraform output -raw public_ip)
cat > ansible/inventory.ini <<EOF
[web]
$TF_IP ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/<your-key>.pem
EOF
Enter fullscreen mode Exit fullscreen mode

If -raw not available, use terraform output -json + jq.)

Step 3.4 — Example Ansible playbook (CM) — ansible/playbook.yml

Installs and starts nginx on the EC2 (idempotent tasks).

- name: Configure web server
  hosts: web
  become: true
  tasks:
    - name: Install nginx (Amazon Linux / RedHat)
      package:
        name: nginx
        state: present

    - name: Ensure nginx is started and enabled
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Deploy index.html
      copy:
        src: ../terraform/index.html   # or templates
        dest: /usr/share/nginx/html/index.html
        owner: root
        mode: '0644'
Enter fullscreen mode Exit fullscreen mode

Run Ansible:

cd ansible
ansible-playbook -i inventory.ini playbook.yml \
  --private-key ~/.ssh/<your-key>.pem -u ec2-user
Enter fullscreen mode Exit fullscreen mode

cd ansible
ansible-playbook -i inventory.ini playbook.yml \
--private-key ~/.ssh/.pem -u ec2-user

4) Automate with CI/CD (recommended flow)

Typical pipeline:
1. Commit Terraform code → CI runs terraform plan → produce plan artifact.
2. Human review / PR approval.
3. CI runs terraform apply on main (or post-approval).
4. After apply, CI fetches outputs (IP(s)), generates inventory, and runs Ansible to configure servers.

Example (GitHub Actions snippet) — Terraform job + Ansible job:

# .github/workflows/infra.yml (shortened)
on: [push]

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with: terraform_version: '1.5.0'
      - name: Terraform Init & Plan
        run: |
          cd terraform
          terraform init
          terraform plan -out plan.tfplan
      # optionally apply only on main
      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: |
          cd terraform
          terraform apply -auto-approve plan.tfplan

  configure:
    needs: terraform
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Ansible
        run: sudo apt-get update && sudo apt-get install -y ansible
      - name: Generate inventory & run ansible
        run: |
          cd terraform
          TF_IP=$(terraform output -raw public_ip)
          echo "[web]" > ../ansible/inventory.ini
          echo "$TF_IP ansible_user=ec2-user ansible_ssh_private_key_file=/tmp/key.pem" >> ../ansible/inventory.ini
          cd ../ansible
          ansible-playbook -i inventory.ini playbook.yml
Enter fullscreen mode Exit fullscreen mode

Use secrets for SSH keys (GitHub Actions Secrets), never commit keys to repo.

6) Best practices / dos & don’ts (short)
• IaC
• Use a remote backend for state (S3 + DynamoDB lock for Terraform).
• Keep state per environment (prod, staging).
• Modularize (reusable modules).
• Review terraform plan before apply.
• CM
• Make playbooks idempotent and small.
• Use variables / templates for environment differences.
• Avoid baking sensitive secrets into playbooks; use Vault/Secrets Manager.
• Security
• Least privilege IAM roles for CI systems.
• Don’t store private keys in source control; use secret stores.
• Testing
• Test IaC with unit/integration tools (Terratest/kitchen-terraform).
• Use linting: terraform validate, tflint, ansible-lint.
• Drift detection
• Periodically run terraform plan to detect drift. Use monitoring/alerts.

7) Quick commands cheat-sheet
• Terraform: terraform init, terraform plan -out plan.tfplan, terraform apply plan.tfplan, terraform destroy
• Ansible: ansible-playbook -i inventory.ini playbook.yml --private-key ~/.ssh/key.pem -u ec2-user
• Build inventory from TF: terraform output -raw public_ip (or parse JSON)

Top comments (0)