Skip to main content
RunBook Academy

Git, CI/CD & GitOpsCX · Ansible Delivery PipelinePipelineShape

The Ansible delivery pipeline — an end-to-end view

Advanced⏱ ~28 mingitansible

What you'll learn

  • Draw the end-to-end Ansible delivery pipeline and identify the role of each stage
  • Distinguish the three credential boundaries: no-target, ephemeral-target, and apply-time
  • Identify which artefact each stage produces and which stages consume them
  • Recognise why the pipeline is monotonic: each stage is a gate the next stage depends on

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A production Ansible delivery pipeline is not one job that runs ansible-playbook. It is a chain of deterministic gates, each one owning a single class of mistake and producing an artefact the next stage consumes. Treating the pipeline as a single job is the architectural mistake this Part of the course is designed to correct. The pipeline is monotonic: each stage is a prerequisite for the next, and the pipeline fails closed if any stage refuses to pass.

The end-to-end shape

The pipeline runs on every push to a feature branch and again on every merge to the protected default branch. Each stage is a job with its own runner, its own timeout, and its own set of artefacts it writes for the next stage. The pipeline differs from a Terraform pipeline in one important way: Ansible mutates systems in place rather than declaring a new state, so the idempotency stage replaces the plan-apply split.

flowchart LR
    A["Commit pushed"] --> B["yamllint"]
    B --> C["ansible-lint"]
    C --> D["ansible-playbook --syntax-check"]
    D --> E["molecule converge"]
    E --> F["molecule verify"]
    F --> G["Second converge (idempotency)"]
    G --> H["Human approval on PR"]
    H --> I["ansible-playbook against inventory"]
    I --> J["Live host reports no change"]

Three properties of this diagram are worth pulling out before the rest of the Part walks through it stage by stage:

  • Every stage is a gate. The pipeline does not advance past a failed stage. A lint error blocks the syntax-check. A failed Molecule verify blocks the apply. An idempotency drift blocks the merge.
  • Every stage produces an artefact the next stage consumes. The syntax-check writes a parsed inventory reference; Molecule writes a converged container image; the apply reads the same inventory the verify stage read.
  • Three credential boundaries. The first three stages (yamllint, ansible-lint, syntax-check) hold no managed-host credentials. The Molecule stage holds ephemeral-container credentials. The apply stage holds production SSH or WinRM credentials obtained only from the protected default branch secrets store.

What each stage owns

Each stage of the pipeline has a deliberately narrow job. The narrowness is the point: a stage that tries to do everything does nothing well, and a stage that fails to do its single job is a stage that is missing entirely.

StageWhat it catchesWhat it deliberately does not catch
yamllintIndentation, document structure, truthy stringsAnsible semantics, task correctness
ansible-lintBest-practice rule violations, FQCN usage, deprecated patternsRuntime behaviour, idempotency
—syntax-checkPlaybook parseability, variable resolution, module existenceWhether any task would succeed against a real host
molecule convergeWhether the role converges to the expected state on a fresh ephemeral hostWhether production hosts match that state
molecule verifyWhether assertions about post-state holdWhether the same assertions hold against production
second convergeWhether the role is idempotent (no further changes on re-run)Whether production hosts were already in the desired state
approvalAuthor intent, business rationale, change-window fitAnything mechanical - humans are not linters
applyMechanical execution of the approved playbookAnything new - the playbook was already validated
live host checkWhether production hosts drifted during the applyWhether the playbook itself is correct

The shape is intentional: each row above the apply handles a class of mistake the apply step would otherwise perform blindly.

Three credential boundaries

The pipeline touches managed-host credentials in three distinct ways, and the three must never collapse into one:

  • No-target stages (yamllint, ansible-lint, syntax-check) hold no SSH keys, WinRM credentials, or vault passwords. They run on the pull-request job and do not authenticate to any managed host. This is enforced by configuring the runner with no ANSIBLE_* variables that point at an inventory and by excluding any inventory.yml from the lint scope.
  • Ephemeral-target stages (Molecule) hold credentials for throwaway containers or cloud VMs that are created and destroyed per run. They never use production SSH keys and never reach the production network. A Molecule scenario that uses a production credential is a scenario that has already failed its security review.
  • Apply-time stages hold production credentials and obtain them only from the protected default branch secrets store. The PR job cannot reach these credentials; only the merge job, against the protected default branch, can.

The boundaries are enforced by the CI system’s environment-variable scoping, by the inventory file location per stage, and by the secrets store’s protected-branch rules. A pipeline that uses one credential set for all three has no PR-to-merge separation and is the structural risk this Part is designed to address.

Production discipline

  1. One job per stage. Parallelism within a stage is fine; collapsing stages into a single job is not. The boundaries between stages are the boundaries between credentials.
  2. No managed-host credentials on the PR job. A PR job that can SSH to a production host is a PR job that has compromised the pipeline before review.
  3. Molecule scenarios are artefacts, not scripts. Upload the convergence log, hash it, key it by commit SHA, and retain it until the apply completes and the live hosts report no further drift.
  4. The second-converge idempotency check is not optional. A role that changes state on every run is a role that cannot be safely re-applied after a partial failure.
  5. The pipeline fails closed. A missing or skipped gate is treated as a failure, not a default. Branch protection should require every required check before merge.

Cross-course references

  • Ansible for Production Sysadmins - Part XXVI (Testing) covers the Molecule scenario format this pipeline depends on.
  • Ansible for Production Sysadmins - Part XXV (CheckDiff) covers the --check and --diff semantics the idempotency check layers into the pipeline.
  • This course, Part LI (AnsibleCI) - lessons git-cicd-gitops-li-01 through git-cicd-gitops-li-06 cover the per-gate mechanics this Part assembles into a delivery pipeline.
  • This course, Part CVIII (IaCIntegration) - lesson git-cicd-gitops-cviii-03 covers how Ansible fits alongside Terraform and Kubernetes in a unified delivery architecture.

Quiz

Knowledge check · 4 questions

  1. Q1. Which statement best describes the relationship between stages in a production Ansible delivery pipeline?

  2. Q2. A pull-request job that runs yamllint, ansible-lint, and ansible-playbook --syntax-check must have a vault password configured so ansible-lint can decrypt role variables.

  3. Q3. Name the three credential boundaries in a production Ansible delivery pipeline and the stage that lives in each.

  4. Q4. Diagnose a pipeline that collapses three credential boundaries into one, and prescribe the structural correction.

    A team has a single CI job that runs ansible-lint, syntax-check, Molecule, and the production apply. The job uses one SSH key that has root access to every production host. An attacker compromises a developer's GitHub PAT, pushes a branch that triggers the job, and the Molecule stage installs a backdoored package from a private collection. Because the same SSH key is mounted, the apply job can read the backdoor and propagate it.

Passing score: 75%. Answers are checked in this browser.