Git, CI/CD & GitOpsLXVII · Dependency PinningConfigPinning
Ansible collection and role pinning — requirements.yml with version constraints
What you'll learn
- Pin Ansible collections by exact version in `requirements.yml` and install with `ansible-galaxy collection install -r`
- Pin Ansible roles by source, scm, version, and name; prefer vendored roles for security-critical playbooks
- Resolve a collection or role to a content address and verify the source
- Establish a re-pin workflow that treats collection upgrades as supply-chain changes
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
Ansible collections and roles are pulled from Galaxy, Git, or a
private automation hub at runtime. The requirements.yml file
declares the consumer intent — which collections and roles the
playbook needs, in what version range. The resolution is performed
by ansible-galaxy against the registry; the registry can publish
a new satisfying version between two consecutive runs, and the
run will pick up the new version without any change to the
playbook. The discipline of pinning binds every collection and
every role to a content address and reviews the upgrade.
Pin collections by exact version in requirements.yml
A collection pin takes the form namespace.collection:version. An
exact pin freezes the version; a range narrows the selection but
leaves drift open.
# collections/requirements.yml
collections:
- name: community.general
version: "8.3.0"
- name: amazon.aws
version: "7.2.0"
- name: kubernetes.core
version: "3.0.0"
The version: "8.3.0" is an exact pin. The ansible-galaxy collection install -r collections/requirements.yml command
resolves each collection to the pinned version and downloads the
artifact from Galaxy. A playbook that pins version: ">= 8.0"
instead is a playbook whose bytes are chosen by Galaxy at install
time.
flowchart LR
A["Range constraint"] --> B["Galaxy resolves"]
B["Galaxy resolves"] -. "new version" .-> C["Different bytes today"]
D["Exact version"] --> E["Artifact v8.3.0"]
E["Artifact v8.3.0"] --> F["Same bytes forever"]
The Galaxy artifact is a tarball served from galaxy.ansible.com
or from a private automation hub. The tarball has a SHA-256
checksum published alongside it; the checksum is the content
address. The exact version pin freezes the tarball; the checksum
verification confirms the bytes.
Pin roles by source, scm, version, and name
Roles can be pulled from Galaxy (the same registry as collections)
or directly from a Git repository. A role pin that uses scm: git
must also pin version: to a branch, a tag, or a commit SHA.
# roles/requirements.yml
roles:
- name: geerlingguy.docker
version: "3.1.1"
- name: my-org.internal-role
src: https://github.com/my-org/ansible-role-internal.git
scm: git
version: 7d4f2a1c9b8e6f3a2c1d4e5f6a8b9c0d1e2f3a4b
The Galaxy role pin (geerlingguy.docker) freezes the artifact
version. The Git role pin (my-org.internal-role) freezes the
commit SHA; the SHA is the content address and cannot be moved
without rewriting history. A Git role pin that uses version: main is a role pin whose bytes are chosen by the upstream at
install time.
Resolution and verification
The ansible-galaxy resolution is the moment the registry is
consulted. The production discipline is to resolve in a
controlled step (CI, an isolated runner, a deliberate operator
action), record the resolved artifact, and ship the artifact to
the runtime without re-resolution.
# CI: resolve against Galaxy, install into the local collection path
ansible-galaxy collection install -r collections/requirements.yml -p ./collections
# CI: resolve Git roles, install into the local role path
ansible-galaxy role install -r roles/requirements.yml -p ./roles
The CI step records the resolved versions and the checksums. The
runtime uses the local collections/ and roles/ paths; the
runtime does not contact Galaxy. The registry is consulted once,
under review, and the result is vendored into the build.
# Runtime: use the local vendored collections and roles
ansible-playbook site.yml \
--collections-path ./collections \
--roles-path ./roles
Re-pinning as a deliberate upgrade
A collection or role upgrade is a supply-chain change. The workflow is:
- Identify the upgrade. Read the upstream release notes and advisories.
- Resolve the new version. Update
requirements.ymlwith the new exact version or the new commit SHA. - Run
ansible-galaxy installto verify the new artifact downloads and matches the checksum. Fail the PR if the checksum does not match. - Run the playbook’s test suite (molecule or equivalent) against the new artifact. The suite is the team’s evidence that the upgrade does not break the playbook.
- Commit the updated
requirements.ymlin a pull request. The PR contains the new version, the resolved checksum, the upstream release notes, and the test results.
A Renovate-equivalent bot can automate step 2 and open the PR in step 5; the team still performs steps 3 and 4.
Production discipline
- Pin every collection by exact version. No
>=or~>for security-critical playbooks. - Pin every Git role by commit SHA. No
mainormasterrefs. - Verify the checksum at install time. A download without a checksum verification is a supply-chain hole.
- Vendor security-critical collections and roles. The registry is consulted once, under review; the runtime executes the vendored copy.
- Re-pin deliberately. A collection or role bump is a supply-chain change.
Cross-course references
- Git, CI/CD & GitOps — Part LXVII-01 (Pinning Discipline) defines the discipline that motivates collection pinning.
- Git, CI/CD & GitOps — Part LI-05 (Molecule) covers the integration tests that validate a collection or role upgrade.
- Ansible for Production Sysadmins — Part XXXVII (RepoArch) covers the repository layout that hosts vendored collections and roles.
- Linux for Production Sysadmins — Part XXXIV (ConfigMgmt) covers the configuration-management analogue at the OS level.
Quiz
Knowledge check · 4 questions
Q1. Why does production-grade Ansible pinning reference a collection by exact version (e.g., `version: "8.3.0"`) rather than by range (e.g., `version: ">= 8.0"`)?
Q2. A Git role pinned by `version: main` is a role whose bytes are chosen by the upstream at install time.
Q3. Explain what vendoring a collection or role closes that an exact version pin leaves open.
Q4. Identify the gap in the team's collection-pinning practice and the rule that closes it.
Team T maintains 30 playbooks that target production Linux hosts. The playbooks use `community.general`, `amazon.aws`, and `kubernetes.core`. Each playbook's `collections/requirements.yml` uses range constraints (`version: ">= 7.0"`). The CI pipeline installs collections with `ansible-galaxy collection install -r` without checksum verification. The runtime hosts pull collections from Galaxy at playbook start, not from a vendored copy. A new minor version of `community.general` (8.4.0) is published to Galaxy; the new version contains a breaking change in a module the team relies on. Every playbook run on the production hosts fails because the module's return type changed.
Passing score: 75%. Answers are checked in this browser.