AnsibleIII · Installing and Designing the ControllerController design
Whose machine runs production change?
What you'll learn
- Compare laptop, jump host, CI runner and platform controllers on attribution, reproducibility and exposure
- Explain why "it works on my controller" is a governance symptom rather than a tooling one
- Identify what an interactive workstation adds to the attack surface of a production controller
- Design a two-controller split that keeps exploration cheap and production change reviewable
Prerequisites
Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11
Nobody decides where the controller lives. It accumulates.
Somebody installs Ansible on their laptop to try something. It works, so they use it for the next thing. Six months later the laptop is the only machine that can deploy the application, the SSH key that reaches every production server is in that person’s home directory, and the estate has made a governance decision that nobody made.
This lesson is about making it on purpose.
Four options
| Laptop | Shared jump host | CI runner | Automation platform | |
|---|---|---|---|---|
| Who ran it | The owner, unattributed | A service account — attribution needs care | The pipeline, attributed to a commit | The platform, attributed to a job and a user |
| Reproducible | Only for that person | Yes, if built from the repository | Yes, by construction | Yes |
| Reviewed before running | Only by convention | Only by convention | Enforced by the merge | Enforced by the job definition |
| Where the fleet key lives | Next to a browser | On a hardened host | In the CI secret store | In the platform’s credential store |
| Works during a network incident | Sometimes | If you can reach it | Rarely | Rarely |
| Setup cost | None | Low | Medium | High |
None of these rows is decisive on its own. Read them together and a pattern appears: the options get stronger on governance and weaker on availability as you move right, and the cost rises the whole way.
The laptop
It is the right controller for exactly one thing: exploration. Writing a
new role, running --check against staging, debugging an inventory,
learning. The feedback loop is short and nothing else can match it.
It is a poor controller for production change, for four reasons that have nothing to do with the engineer’s competence.
Attribution disappears. A run from a laptop leaves a record on the managed hosts — sudo entries, changed files, a service restart — and nothing that connects the change to a reviewed intention. Six weeks later the question is “why is this host different”, and the answer is in somebody’s shell history, if it is anywhere.
Reproducibility is personal. The laptop’s controller environment is
the one they built. Their collection versions, their ~/.ansible.cfg,
their SSH config with a ProxyJump nobody else has. It works, and it
works only there.
Availability is a property of a person’s day. The deployment happens when the laptop is open, awake and on the VPN. This is fine until it is 2 a.m. or the person is on a plane.
The exposure is the point. A laptop runs a browser, a mail client, a chat application and whatever a developer needed last Tuesday. Every one of those is an execution path for content the owner did not write. On that same machine sits a passphraseless key with root on every production host.
The shared jump host
A dedicated machine, a service account, the repository deployed from
Git, the venv built from requirements.txt. Everyone runs the same
Ansible because there is only one.
This solves reproducibility and most of the exposure problem. It leaves two things open.
Attribution needs deliberate work. If four engineers sudo -u svc-ansible and run playbooks, the managed hosts see one identity.
Shell audit on the controller, log_path in ansible.cfg, and a
convention of running through a wrapper that records who invoked it are
the mitigations — and all three are things you have to add, not things
you get.
Review is still a convention. Nothing stops an engineer editing the checkout in place and running it. The filesystem layout from the previous lesson is what makes that hard: the checkout is owned by root and deployed, not writable by the people who use it.
ansible --version | head -2
ansible-galaxy collection list
ansible-config dump --only-changed$ ansible-config dump --only-changedCONFIG_FILE() = /opt/estate/ansible.cfg
DEFAULT_HOST_LIST(/opt/estate/ansible.cfg) = ['/opt/estate/inventory/production']
DEFAULT_LOG_PATH(/opt/estate/ansible.cfg) = /var/log/ansible/ansible.log
DEFAULT_VAULT_PASSWORD_FILE(/opt/estate/ansible.cfg) = /etc/ansible/vault-pass
HOST_KEY_CHECKING(/opt/estate/ansible.cfg) = True
GALAXY_SERVERS:Illustrative output
Note what that output gives you for free: each setting is annotated with where it came from. A value attributed to a file you did not expect is the fastest possible diagnosis of a configuration surprise.
The CI runner
The strongest governance position, because review stops being a convention and becomes a mechanism. Change reaches production by being merged, and the runner has credentials that the humans do not.
What it buys:
- Every change is attributable to a commit, an author and an approval.
- The environment is built from the repository on every run, so the two-machine test is executed continuously rather than annually.
- Credentials live in the CI secret store rather than in a home directory, and can be scoped per pipeline.
What it costs, and these are real:
- Feedback is slow. A five-second change becomes a pipeline.
- Debugging is awkward. You cannot easily attach to a failing run, and reproducing it locally means reproducing the runner.
- It is a dependency during an incident. If the outage involves the network, the CI system, or the identity provider the CI system authenticates against, your remediation tool is behind the failure.
The automation platform
AWX, Ansible Automation Platform, or an equivalent. It adds job templates, a credential store, RBAC, scheduling, a surveyed interface for people who should not have a shell, and a job history that is a real audit trail.
It is the right answer for an organisation where many people need to run a limited set of automations, and where “who may run what against which inventory” is a question with a formal answer. It is a heavyweight answer for a team of four, where the platform becomes another system to patch, back up and recover.
The course does not treat the platform as the destination that everyone should reach. It treats it as one point on the same axis: further right, stronger governance, higher cost.
What most estates should actually do
Two controllers, and the split is by purpose rather than by person.
A personal controller — laptop or a small VM — with the repository
checked out, credentials that reach staging only, and no production
inventory present. Explore here. Run --check here. Break things here.
The blast radius is bounded because production is not in the file.
A production controller — a jump host, a CI runner, or both — with the production inventory, the production credentials, and a checkout nobody edits in place.
The important detail is that the boundary is enforced by which inventory exists on which machine, not by discipline. An engineer on the personal controller cannot accidentally target production, because production is not there to be targeted. This is the same argument the inventory design part makes at fleet scale, arriving early because it is also the answer to where the controller lives.
Knowledge check
Knowledge check · 4 questions
Q1. What is the strongest argument against running production change from an engineer laptop?
Q2. A CI runner is the strongest governance position for a production controller. Which of these are genuine costs of that choice? Select all that apply.
Q3. On a shared controller, three machine-level checks - ansible --version, the collection list and the config dump - are enough to explain any "works on my controller" report.
Q4. A team splits into a personal controller for exploration and a production controller for change. What actually enforces the boundary?
Passing score: 75%. Answers are checked in this browser.