OVHcloud

Configuration as Code

Puppet Puppet · Ansible Ansible · Terraform Terraform
— What's the difference and when to use what? —

FinistDevs · 2026

Arnaud Prémel-Cabic

Tech Lead @ OVHCloud

arnaud.premel-cabic@ovhcloud.com

"It works on my server."

Or: why doesn't it work here, when it works everywhere else?

You have a server. It works.

Great.

You have 10 servers.

Still manageable… but every small change means 10 SSH sessions, 10 vim edits, 10 chances to make a mistake.

$ ssh root@… $ vim /etc/… ssh ssh ssh

Now you have 100 servers.

Some 2 years old. Some a couple of months. Some freshly provisioned.
None of them are exactly alike.

! · · ·

Each one is unique. Unreproducible. Undocumented.

Welcome to Snowflake Hell.

This is fine

Configuration drift is silent… until it isn't.

Prod breaks on a Tuesday. You can't reproduce the bug locally. You can't scale reliably. You can't onboard a new server without fear.

T0 T1 T2 ALL IDENTICAL DRIFTING… ! ! ! CHAOS

What if your infrastructure was just… code?

Yes, even your AI assistant can write it. But you still need to understand what it deploys.

{ } deploy

Configuration as Code

Managing infrastructure through machine-readable files, stored in version control.

Reproducible Same input → same result Versionable Track every change Auditable Who changed what & when

Meet the three musketeers of infrastructure.

Puppet  ·  Ansible  ·  Terraform — each fights a different battle.

Terraform

Start here. Before you configure a server, you need to have one.

HCL: HashiCorp Configuration Language.

Declarative, human-readable — and pure JSON works too.
terraform plan previews  ·  terraform apply creates  ·  terraform destroy removes.

HCL Code plan apply Resources WRITE → PLAN → APPLY

Terraform remembers what it built.

The .tfstate file maps code to real-world resources. Store it remotely.
Depending on what you manage, it can contain plaintext sensitive values — credentials, tokens, secrets.
Handle it with care. Don't feed it to your LLM.

main.tf network.tf dns.tf Configuration .tfstate state mapping Source of Truth VM VNet DNS Zone Real Resources

One tool. Every API.

1000+ providers: AWS, GCP, Azure, Cloudflare, GitHub, Kubernetes…
Not just cloud — manage GitHub teams, Datadog monitors, PagerDuty schedules, DNS records.
If it has an API, there's a Terraform provider for it.

# main.tf


terraform {
  required_providers {
    openstack = { source = "terraform-provider-openstack/openstack", version = "~> 3.0" }
    ovh       = { source = "ovh/ovh", version = "~> 1.0" }
  }
}

resource "openstack_compute_instance_v2" "web" {
  name        = "finistdevs-web"
  image_name  = "Debian 12"
  flavor_name = "b3-8"
  network { name = "Ext-Net" }
}

resource "ovh_domain_zone_record" "web" {
  zone      = "example.com"
  subdomain = "finistdevs"
  fieldtype = "A"
  target    = openstack_compute_instance_v2.web.access_ip_v4
}
    

In 2023, HashiCorp changed Terraform's license.

BSL instead of MPL — no longer truly open-source.
The community responded: OpenTofu, by the OpenTF Foundation, is the open-source fork.
Drop-in replacement. Fully compatible. Community-driven.

Terraform at scale needs a platform.

Terraform Enterprise / HCP Terraform — HashiCorp's commercial offering: remote state, RBAC, audit logs
Spacelift — GitOps-first CI/CD for Terraform (and OpenTofu)
Atlantis — open-source: plan & apply triggered by pull requests
env0, Scalr — SaaS alternatives with policy & cost management

Ansible

Your servers are provisioned. Now make them do something.

Push, not pull. SSH, not agents.

YAML playbooks run tasks in order, across any number of hosts.
No daemon. No certificate authority. Just Python + SSH.
Idempotent modules ensure the same playbook can run safely again and again.

>_ Control Node PUSH SSH Managed Hosts no agent required

# playbook/webserver.yml


- name: Configure web server
  hosts: webservers
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Deploy nginx config
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart nginx

  handlers:
    - name: Restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted
    

Not just configuration. Operations.

Patch 200 servers tonight. Roll out a kernel upgrade with a canary strategy. Run a compliance audit across your whole fleet.
Ansible is the tool you reach for when you need to do something — once, or every week.

The community does the heavy lifting.

Ansible Galaxy — 10,000+ ready-made roles and collections.
Don't write a playbook to install Docker from scratch. Someone already did.
Just ansible-galaxy install geerlingguy.docker.

Ansible at scale: open-source vs enterprise.

AWX — open-source web UI, API, and scheduler for Ansible
Ansible Automation Platform (Red Hat) — enterprise version of AWX, with support & integrations
Semaphore — lightweight open-source alternative to AWX
The core Ansible engine remains Apache 2.0 — truly open-source.

Puppet

Your servers are configured. Now keep them that way.

Pull, not push. Agents, not SSH.

Every 30 minutes, each puppet-agent polls the Puppet Server, compiles a catalog, and enforces it.
Drift is corrected automatically — without anyone lifting a finger.

catalog Puppet Server every 30 min pull agent agent agent agent agent Managed Nodes

# manifests/webserver.pp


class webserver {
  package { 'nginx':
    ensure => installed,
  }

  file { '/etc/nginx/nginx.conf':
    ensure  => file,
    content => template('webserver/nginx.conf.erb'),
    notify  => Service['nginx'],
  }

  service { 'nginx':
    ensure => running,
    enable => true,
  }
}
    

Someone SSH'd in and changed something.

Puppet noticed. Puppet fixed it.
Continuous compliance — not just at deploy time. Every. 30. Minutes.
No more gardening your servers by hand.

! Drift detected 1 Agent applies catalog 2 Compliant 3 continuous enforcement loop

Puppet is for large fleets that can't afford drift.

Continuous compliance, auditability, and guaranteed state — at scale.
Best suited for enterprises with hundreds or thousands of long-lived servers.
Fewer friendly SaaS options than Terraform or Ansible.
Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.

The ecosystem outlives the company.

Vox Pupuli — 100+ open-source Puppet modules, community-maintained.
OpenVox — an emerging open-source fork of the Puppet core.
The community is strong, with or without Puppet Inc.

They're not competing. They're complementary.

Each one solves a different layer of the same problem.

Terraform — Provision VMs, networks, cloud resources Day 0 Ansible — Configure packages, services, app deployment Day 1 Puppet — Enforce continuous compliance, drift correction Day 2+

A common production setup:

  1. Terraform provisions the VM
  2. Ansible configures it and deploys the app
  3. Puppet continuously enforces compliance

Questions?

Thank you!

Arnaud Prémel-Cabic  ·  arnaud.premel-cabic@ovhcloud.com
Slides: ministicraft.pages.git.cloud.arnaud-pc.fr/finistdev-configuration-as-code/