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."

Why doesn't it work here when it works everywhere else?

You have a server. It works.

Great.

You have 10 servers.

  • 10 SSH sessions
  • 10 manual 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 few months. Some brand new.
  • None of them are exactly alike.
! · · ·

Unique. Unreproducible. Undocumented.

Welcome to Snowflake Hell.

This is fine

Configuration drift is silent…

  • Prod breaks on a Tuesday
  • Can't reproduce the bug locally
  • Can't scale reliably
  • Can't onboard a new server without fear
T0 T1 T2 ALL IDENTICAL DRIFTING… ! ! ! CHAOS

What if your infrastructure was just… code?

Your AI assistant can write it*. You still need to understand what it deploys.

{ } deploy *Like this presentation 🤖

Configuration as Code

Machine-readable files. Version-controlled. Automated.

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

Meet the three musketeers of infrastructure.

Puppet  ·  Ansible  ·  Terraform

Each solves a different problem.

Terraform

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

HCL: HashiCorp Configuration Language

Declarative, human-readable — pure JSON works too.

  • terraform plan — preview what will change
  • Review — validate the plan before proceeding
  • terraform apply — create or update resources
  • terraform destroy — tear everything down
HCL Code plan review apply Resources

Terraform remembers what it built.

  • The .tfstate file maps code to real-world resources
  • Store it remotely — never commit it to Git
  • May contain sensitive values: credentials, tokens, secrets

Handle with care.

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 — DNS, monitoring, CI/CD, anything with an API

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
}
    

$ terminal


$ terraform init
Initializing provider plugins...
- Finding terraform-provider-openstack/openstack versions matching "~> 3.0"...
- Finding ovh/ovh versions matching "~> 1.0"...
- Installing terraform-provider-openstack/openstack v3.0.0...
- Installing ovh/ovh v1.3.0...
Terraform has been successfully initialized!

$ terraform plan
openstack_compute_instance_v2.web: Refreshing state...
Plan: 2 to add, 0 to change, 0 to destroy.

$ terraform apply
openstack_compute_instance_v2.web: Creating...
openstack_compute_instance_v2.web: Creation complete after 45s [id=abc-123]
ovh_domain_zone_record.web: Creating...
ovh_domain_zone_record.web: Creation complete after 3s [id=456]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    

HashiCorp changed Terraform's license.

  • BSL instead of MPL — no longer truly open-source
  • The community responded: OpenTofu, by the OpenTF Foundation

Drop-in replacement. Fully compatible. Community-driven.

Terraform at scale needs a platform.

  • Terraform Enterprise / HCP Terraform — remote state, RBAC, audit logs
  • Spacelift — GitOps-first CI/CD for Terraform and OpenTofu
  • Atlantis — open-source, plan & apply from pull requests
  • env0, Scalr — SaaS 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 — same playbook runs 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
    

$ terminal


$ ansible-playbook -i inventory playbook/webserver.yml

PLAY [Configure web server] ***************************************************

TASK [Gathering Facts] ********************************************************
ok: [finistdevs-web]

TASK [Install nginx] **********************************************************
changed: [finistdevs-web]

TASK [Deploy nginx config] ****************************************************
changed: [finistdevs-web]

RUNNING HANDLER [Restart nginx] ***********************************************
changed: [finistdevs-web]

PLAY RECAP ********************************************************************
finistdevs-web : ok=4  changed=3  unreachable=0  failed=0  skipped=0
    

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

The go-to tool for one-off tasks and recurring operations.

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
  • Ansible Automation Platform (Red Hat) — enterprise AWX with support
  • Semaphore — lightweight open-source alternative

Core 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 locally

Drift is corrected automatically.

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,
  }
}
    

$ terminal


$ puppet agent -t
Info: Using environment 'production'
Info: Retrieving pluginfacts
Info: Caching catalog for finistdevs-web.example.com
Info: Applying configuration version '1713052408'

Notice: /Stage[main]/Webserver/Package[nginx]/ensure: created
Notice: /Stage[main]/Webserver/File[/etc/nginx/nginx.conf]/content:
  --- /etc/nginx/nginx.conf
  +++ /tmp/puppet-file20260413
Notice: /Stage[main]/Webserver/Service[nginx]/ensure: started

Notice: Applied catalog in 12.34 seconds
    

Someone SSH'd in and changed something.

  • Puppet noticed. Puppet fixed it.
  • Continuous compliance — not just at deploy time. Every. 30. Minutes.
  • No manual remediation
! Drift detected 1 Agent applies catalog 2 Compliant 3 continuous enforcement loop

Puppet: large fleets, zero drift.

  • Continuous compliance, auditability, and guaranteed state — at scale
  • Best suited for enterprises with hundreds or thousands of long-lived servers
  • Fewer 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 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/