Infrastructure as Code
Intermediate 12 min read Infrastructure as Code

Configuration Management on VMs

The part of IaC that lives after boot

Provisioning creates the box; configuration management (Chef, Puppet, Ansible) shapes the box after it boots. Ansible is agentless; Chef/Puppet use agents with pull-based convergence. Both belong in the 'after boot' phase of the IaC story.

ansiblechefpuppetconfig managementplaybookroleidempotent
Before we start

What you will learn

  • Place config management relative to provisioning
  • Use Ansible plays/roles idempotently
  • Decide agent vs agentless for your estate
In 60 seconds

After Terraform/CloudFormation hands over the VM, config management ensures packages, files, users, and services match policy — Ansible (SSH, no agent) or Chef/Puppet (agent + server pull). Horses for courses: both are tiers above hand-rolled scripts.

Introduction

What is this?

Ansible: inventory (hosts/groups), modules (yum/apt/template/systemd…), playbooks/roles/collections; agentless over SSH; YAML state targets; idempotent modules ('ensure'). Chef: recipes/cookbooks, server + agent pull, ohai facts, converge-and-report. Puppet: manifests, catalog, agent pull. Others: SaltStack. Cross-over: cloud-init (first-boot user data), launch templates' userdata for bake-vs-bake cycles, packer for golden images. Drift vs bake: config management converges live boxes (drift-friendly); golden images (Packer) convert config into pre-baked state (fast + immutable).

Motivation

Why do you need it?

  • Bare provisioning doesn't configure: packages, users, firewall rules, app files still need a second act.
  • Config management converges drift: a manually-changed config gets corrected at the next pull.
  • Ansible's no-agent model keeps SSH-only environments manageable.
  • Roles/playbooks make server setup reviewable and repeatable like the infra code above it.
Think about it

Mental model

Imagine

Real-estate: architect draws (Terraform) and the fit-out team outfits the rooms (config mgmt)

Think of

Provisioning vs config management

The shell exists after construction; furnishing, fixtures and wiring-in (packages, users, config files) is a separate, repeatable contract with a checklist that converges.

Mechanics

How it works

  • Inventory maps hosts → groups with variables.
  • Playbooks declare plays: hosts, tasks (module + args), handlers.
  • Modules check desired state and only act on diff (idempotent).
  • Handlers fire on changes (e.g., restart nginx only when config changed).
  • Agent versions pull from a central server; agentless runs from a control host via SSH.

Config management flow.

Control node
Inventory
Tasks
Host
Report
Hands-on

Examples

Idempotent play for nginx

Idempotent play for nginx
- hosts: web
become: true
tasks:
- name: install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: config from template
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: ensure running
ansible.builtin.service:
name: nginx
state: started
enabled: true

State: present/started/enabled — re-runs converge without redeploying; templates render from vars.

Real world

In production

  • Ansible for workstation/VM fleet config: packages, users, ssh keys, hardening across clouds.
  • Agent-based Chef/Puppet for large pull-based estates with audit/reporting.
  • Golden-image workflow: Packer bakes config so new instances boot ready (fast, immutable).
Guidelines

Best practices

  • Prefer idempotent 'ensure' modules; test running a play twice = unchanged.
  • Keep hosts/repo driven by IaC inventory, not hand-maintained files.
  • Separate secrets from playbooks (ansible-vault, secret mounts).
  • Prefer golden images for scale; config management for drift-prone mutable fleet.
  • Restrict arbitrary command/shell tasks to genuine holes in module coverage.
Watch out

Common mistakes

  • Terraform 'then' scripts that never rerun against a live changing box.
  • Playbooks that do 'one big shell' — loses idempotency and reporting.
  • Running config mgmt against a fleet that should be immutable, introducing drift.
  • False sense of security: 'we manage config' but templates drift from tests.
When things break

Debugging tips

  • Task reports changed every run → missing state in the module (e.g., version not pinned).
  • Play succeeds but app broken → compare os-release/arch inventory vars vs role assumptions.
  • Agentless timing-out on big fleets → test one host, check SSH multiplexing/limits.
  • Diff the template against the live file to see exactly what a run will change.
Interviews

Interview checkpoint

Test yourself

Quick quiz

0/2
1

Ansible's default model is:

2

A play run twice that reports 'ok' with no changes is:

Go deeper

Official documentation