Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    Infrastructure as Code for People, Not Just Servers

    A proposal: treat developer machines like any other infrastructure, with a shared baseline, personal overlays, versioned roles and a golden path that gets a new starter productive on day one.

    Growingtended planted 5 min read
    On this page

    We treat servers as cattle: declared in code, rebuilt at will, never hand-edited. Developer laptops are still mostly pets. Each one is set up by hand from a wiki page that was accurate two years ago, and each one drifts in its own direction. A new starter’s first week often goes on installing things.

    I’ve automated my own machine for years (Dotfiles: An Environment That Follows Me, Provisioning My Laptop with Ansible). This note is a proposal, not a case study: what it would look like to take the same idea to a team or an organisation. I haven’t rolled this out across a team, so read it as reflection on what I’d do, built from what worked and what didn’t on my own machines.

    The goal: clone, run one command, productive on day one

    The test I’d hold any setup to: a new developer gets a laptop, clones one repo, runs one command, and by lunch they can build, test and run the main services. That’s a golden path for devices. It’s the same idea as the Web Accelerator I built at Elanco for new web projects: put the decisions in the starting point, not in a document.

    A shared baseline plus personal overlays

    The mistake would be one giant playbook that tries to make everyone’s machine identical. Developers care about their tools, and a setup that fights them gets abandoned. I’d split it in layers:

    1. Organisation baseline. The non-negotiables: security agent, disk encryption checks, VPN, approved runtimes, the CLI tools every repo assumes, the right git hooks.
    2. Team layer. What a team’s stack needs: language toolchains, local databases, cloud CLIs, editor extensions that the repo’s linting relies on.
    3. Personal overlay. Your dotfiles, your editor, your shell prompt. Optional, pulled from your own repo, never required.

    In Ansible terms that’s roles and variables: the baseline and team layers as roles, the personal overlay as a final role that clones a dotfiles repo if you’ve set one. My own playbook already did a tiny version of this: the last task cloned my dotfiles and ran their Stow script.

    Share it like code: versioned roles and collections

    Copying a playbook into every team’s repo is how you get forty slightly different playbooks. Instead:

    • Publish the baseline and team layers as versioned roles or a collection, in an internal Galaxy-style repository or simply tagged git repos.
    • Teams pin a version and upgrade deliberately, like any other dependency.
    • Changes go through pull requests and CI that applies the roles to a clean container or VM, twice, to prove they’re idempotent.

    That’s the same trick that made shared front-end components work across many sites: a versioned package beats a copied template, because improvements flow to everyone instead of rotting in forks.

    Where each tool fits

    There isn’t one tool for this, and pretending there is causes most of the pain.

    ToolBest atNot great at
    MDM (Jamf, Intune, Kandji…)Org-wide policy: encryption, OS updates, security agents, app catalogue, compliance reportingDeveloper toolchains and per-team detail; usually owned by IT, not engineers
    AnsibleReadable, agentless, works on macOS and Linux, good for “install and configure” across layersExact reproducibility; it converges state rather than guaranteeing it
    Nix / nix-darwin / Home ManagerReproducible, declarative environments, rollbacks, per-project shellsSteep learning curve; a big ask for a whole organisation
    Devcontainers / CodespacesThe project’s toolchain in a container, identical for everyone, laptop-agnosticNative GUI tools, performance-sensitive work, offline use

    My rough split: MDM for policy, a provisioning tool (Ansible or Nix) for the machine baseline, devcontainers for per-project toolchains, dotfiles for personal taste. The more you can push into the repo itself (devcontainers, version files like .nvmrc, a make setup), the less the laptop matters at all.

    Drift and self-healing

    On my laptop, a cron job re-ran the playbook every ten minutes, so drift fixed itself. At organisation scale I’d be more careful:

    • Report before you remediate. Run in check mode on a schedule and surface drift (a dashboard, or a message to the machine’s owner) before anything changes automatically.
    • Self-heal only the baseline. Security settings and required tools can converge automatically; personal overlays never should.
    • Least privilege. My personal setup gave its automation user passwordless sudo for everything. That’s not acceptable on a fleet. Scope privileges to specific commands, pull only from protected, reviewed branches, and treat the provisioning repo as production code, because it effectively is.

    Secrets

    No secrets in the repo, ever. The provisioning should fetch them at run time from the organisation’s secret store or the developer’s password manager CLI, or use short-lived credentials from SSO. If something must be committed, encrypt it with ansible-vault or SOPS, and rotate anything that ever leaked.

    Optional but attractive

    The best platform work I’ve seen, and the best I’ve done, wins adoption by being the easiest option, not by mandate (Internal Developer Platform, Golden Paths and the Recommended Routine). Device provisioning is no different.

    • Make the baseline genuinely save time on day one, so new starters choose it.
    • Let experienced developers keep their own setup, as long as the baseline checks pass.
    • Measure it: time from laptop to first merged pull request is a good onboarding metric.
    • Keep the docs short, because the code is the documentation.

    Echoes from network automation

    At Sky I worked on a low-code platform where network engineers built automation from reusable tasks, including configuration templates, wrapped as building blocks in a workflow (Building a Low-Code BPMN Workflow Platform). The lesson carries over directly: the value isn’t the automation tool, it’s packaging repeatable configuration as tested, reusable pieces that people who didn’t write them can safely use. Developer machines deserve the same treatment.

    What I’d try first

    If I were starting tomorrow, I’d begin small: one team, a baseline role for the tools every repo needs, a devcontainer for the main service, and a single make setup that does both. Measure a new starter’s first week before and after. If it works, publish the role, let the next team pin it, and grow from there. Progressive overload, not a big bang.

    • #infrastructure-as-code
    • #developer-experience
    • #onboarding
    • #golden-paths
    • #ansible
    • #platform-engineering

    ↪ Links to (7)