Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Ansible / Config Mgmt

Migrating from Puppet, Chef or SaltStack to Ansible

We migrate Puppet, Chef or SaltStack to Ansible gradually: inventory what the old tool manages, rebuild each module or cookbook as a tested role, run both in parallel on a few hosts, then cut over group by group and retire the agents. There is no big-bang switch.

Key takeaways

  • Migrate behaviour, not syntax: a line-by-line conversion carries over the old tool's flaws.
  • Run both tools in parallel on pilot hosts and compare resulting state before cutting over.
  • Agent-based pull models and agentless push models change how drift, scheduling and security work.
  • Secrets, node classification and reporting are the parts teams forget to plan.
  • Sometimes the right answer is not to migrate; we will tell you if so.

Migrations fail on assumptions

A Puppet master or Chef server that has run for years holds more than configuration. It holds decisions nobody wrote down: that one node class exists because of a 2019 incident, that a certain cookbook is only used by a team that was disbanded, that a module quietly sets a kernel parameter every other tool depends on. Teams that start a migration by converting files one by one usually discover this halfway through, when the new tool produces a server that is subtly different.

Our approach under the Ansible configuration management service starts with understanding and finishes with a clean shutdown of the old system. In between, both tools coexist so nothing is a leap of faith.

Should you migrate at all?

Be sceptical of any consultant who says yes before looking. Reasons to migrate include licence or support costs, a team that cannot hire for the old tool, a wish to unify automation with network and application tasks, and a desire to drop agents and certificates. Reasons to stay include a stable estate with a happy team and strong enforcement needs that the existing tool already meets.

There is a third possibility. Part of what your old tool does may belong elsewhere: packages baked into images with Packer, cloud resources managed by Terraform, container workloads handled by Kubernetes. Migrating that part to Ansible would be moving it to the wrong place.

What good looks like

  • Every behaviour you need is captured in a tested role, and every behaviour you do not need is gone.
  • The old and new tools never manage the same resource on the same host at the same time.
  • Cutover happens in small groups with a rollback path.
  • At the end the old server, agents and certificates are decommissioned, not left running.

How it works in practice

Concept mapping

PuppetChefSaltStackAnsible
ModuleCookbookFormulaRole
ManifestRecipeState fileTasks file or playbook
HieraAttributes, data bagsPillargroup_vars, host_vars, Vault
FacterOhaiGrainsFacts
Node classificationRun list, rolesTop fileInventory groups and playbooks
Agent pullsClient pullsMinion (agent) or SSHController pushes over SSH or WinRM

The mapping is a guide, not a translation table. Puppet’s declarative resource graph and Ansible’s ordered tasks behave differently, so ordering assumptions need checking. Idempotence is a given in Puppet types and must be earned in Ansible tasks, which is why we write idempotent, tested roles.

Discovery

We extract the real picture rather than trusting the repository:

  • Which modules or cookbooks are applied to at least one live node? Use the master’s reports or the Chef server’s node data.
  • Which nodes are in which classes?
  • Which resources actually changed in the last month, versus sat unchanged?
  • Where do secrets come from, and who can read them?

Modules applied to no nodes are deleted, not migrated. In our experience, a meaningful portion of a long-lived codebase is dead, but we will not guess the share for you until we have looked.

Rebuilding one unit

Take a Puppet class that manages ntp:

class profile::time {
  package { 'chrony': ensure => installed }
  file { '/etc/chrony.conf':
    content => template('profile/chrony.conf.erb'),
    notify  => Service['chronyd'],
  }
  service { 'chronyd': ensure => running, enable => true }
}

The Ansible role does the same, expressed as ordered tasks with a handler:

- name: Install chrony
  ansible.builtin.package:
    name: chrony
    state: present

- name: Configure chrony
  ansible.builtin.template:
    src: chrony.conf.j2
    dest: /etc/chrony.conf
    mode: "0644"
  notify: Restart chronyd

- name: Enable and start chronyd
  ansible.builtin.service:
    name: chronyd
    state: started
    enabled: true

ERB templates need rewriting as Jinja2, and the variables that fed them move from Hiera to group variables. Each role gets a Molecule scenario whose assertions describe the end state the old tool produced.

Parallel running

Choose pilot hosts that represent each role. On those hosts, put the old agent in report-only mode (Puppet’s --noop, or an equivalent for Chef and Salt) so it flags any difference from what Ansible has applied, without fighting it. Differences are either bugs in the new role or accidental behaviour in the old one, and each is resolved on purpose. Only then do real groups move, in waves from least to most critical.

The parts people forget

  • Node classification. Where the old tool decided what a node should be, Ansible needs inventory groups that reproduce that, usually from tags.
  • Secrets. Hiera-eyaml or Chef vault contents move to Ansible Vault or HashiCorp Vault.
  • Scheduling and drift. An agent converges every thirty minutes. Without it, drift appears between runs. We schedule runs from AWX, usually daily in check mode with an alert, and apply changes through the pipeline.
  • Reporting. PuppetDB or the Chef server offered dashboards. Replace them with run reports and monitoring.
  • Windows. Needs its own plan using WinRM or SSH and the ansible.windows collection.

Decisions and trade-offs

Big bang or incremental. Incremental takes longer and costs more in the short term, but a big bang ties your entire estate to one cutover weekend. We do not recommend it.

Convert or rewrite. Automated converters exist for some constructs, but they produce literal translations. We prefer rewriting from the desired behaviour, using the old code as a specification.

Push or pull afterwards. Push models need credentials to reach servers. Pull models need agents on them. Either is a legitimate security trade-off, which we explain for your environment.

Common failure modes

  • Two tools managing one file. Hosts flap between versions. Migrate by resource and keep ownership clear.
  • Hidden dependencies. One cookbook relied on a side effect of another. Parallel running exposes it.
  • Lost knowledge. The only person who understood the old tool leaves mid-migration. We document as we go.
  • No decommissioning. The old master keeps running “just in case”. Put the shutdown date in the plan.

Delivery and handover

You receive the migrated roles in Git, passing tests, a mapping document from every old unit to its new role, inventory and secrets structures, cutover records per wave, and a verified decommissioning of the old tooling. The documentation ensures the next engineer can learn Ansible from your repository rather than from memory.

How to tell it is working

  • The old server’s node count reaches zero and it is switched off.
  • Pilot comparison reports show no unexplained differences.
  • New servers are built by Ansible with no manual fixes.
  • Engineers stop asking which tool owns a given file.

To get an assessment of whether migration makes sense for you, book a consultation.

References

How we deliver it

  1. 01

    Inventory and assess

    We list every module, cookbook or state, node classification, secret source and dependent process, and judge how much is still used.

  2. 02

    Decide what to migrate

    Dead code is deleted, valuable behaviour is rebuilt, and some functions move to images, Terraform or managed services instead.

  3. 03

    Design the target

    Role boundaries, inventory structure, variable mapping and secrets approach are agreed before conversion starts.

  4. 04

    Rebuild and test

    Each unit becomes an Ansible role with Molecule tests, validated against the state the old tool produces.

  5. 05

    Run in parallel

    Pilot hosts receive Ansible with the old agent in report-only mode, and any differences are investigated and resolved.

  6. 06

    Cut over and retire

    Groups move in waves, the old agent is stopped and removed, and the old server and licences are decommissioned.

Tools and technologies

AnsiblePuppetChefSaltStackHieraFacterOhaiMoleculeAWXansible-lintTerraformPacker

Frequently asked questions

Is Ansible better than Puppet or Chef?
Not universally. Ansible is agentless, uses plain YAML and is easy to start with, which many teams value. Puppet and Chef have strong models for continuous enforcement and mature ecosystems. The better choice depends on your skills, scale and how you want drift handled. We assess before recommending a move.
How long does a migration take?
It depends on the number of modules, the quality of the existing code and how much has been abandoned. A small estate of a few dozen modules can move in weeks, whereas a large, tangled one takes months. A discovery phase gives a grounded estimate, and we would rather phase the work than promise a date blindly.
Can you run Puppet and Ansible side by side?
Yes, and that is how we recommend migrating. Pilot hosts run the Puppet agent in no-op mode or the Chef client in a reporting configuration while Ansible applies the new roles, so you can compare outcomes. Conflicting managers fighting over the same resource is avoided by migrating resource by resource.
What replaces Hiera, data bags or pillar?
Variables in group_vars and host_vars replace Hiera or pillar data, with Ansible Vault or an external secrets manager for sensitive values. Chef data bags map the same way. The hierarchy is simpler in Ansible, so some layers collapse, and we document the new precedence rules explicitly.
What do we lose moving from an agent to agentless?
You lose automatic, frequent drift correction unless you schedule runs, and the built-in reporting server. You gain simpler security and no agents to maintain. Scheduled check mode and applies from AWX or CI restore enforcement, and drift reports can be produced from run results.

Talk to an engineer about migrate puppet to ansible

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.