Skip to content

feat(collection-fleet): optional ansible-vault encrypted inventory secrets - #207

Merged
thiras merged 2 commits into
mainfrom
feat/fleet-ansible-vault
Nov 1, 2026
Merged

thiras merged 2 commits into
mainfrom
feat/fleet-ansible-vault

Conversation

@thiras

@thiras thiras commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Closes #25, scoped down: the roles read plain variables, so the collections need nothing. The work is in the consumer template, examples/collection-fleet, plus docs. Opt-in: the git-ignored secret.yml flow is unchanged, and a fleet without a vault.yml works exactly as before. A secret file written on the host stays the first choice.

What changes

examples/collection-fleet (the private-repo template)

  • Encrypted secrets go in vault.yml beside where secret.yml would go (host_vars/<host>/, group_vars/<group>/, at any depth, since Ansible loads those directories recursively). secret.* stays ignored, so a plaintext file still can't be committed by accident.
  • New scripts/check-vault-encrypted.sh and a vault-encrypted pre-commit hook. A vault file must be the exact ansible-vault header (1.1, or 1.2 with a --vault-id label) followed by hex lines only, so appended plaintext, plaintext on the header line and an empty body are all refused. check-json and yamllint skip the ciphertext.
  • CI: with an ANSIBLE_VAULT_PASSWORD Actions secret, every committed vault file must decrypt (ansible-vault view, including files of hosts the inventory doesn't name). Without it (and on fork and Dependabot PRs), each vault file is replaced by {} in that checkout, with a ::warning::. The secret reaches the step through env: and is written to a umask 077 file.
  • README § "Encrypted secrets (optional)": create/edit, the password and how to supply it (never in ansible.cfg), precedence (vault > secret > main), readable diffs, rekey-plus-rotate when someone leaves, CI. AGENTS.md updated.

decdn/devops (public)

  • The root and ansible/ .gitignore ignore vault.* in both inventory trees. Even encrypted, ciphertext in a public repo can be attacked offline.
  • ansible/README.md § Private fleet inventory, the four secret.yml.example headers (still byte-identical across both trees), and the statements that called secret.yml the only inventory home for a credential (grafana_alloy env example and defaults comment, docs/publishers.md, docs/requirements.md, CONTRIBUTING.md). The two grafana_alloy edits are comments only.
  • Not changed: roles/grafana_alloy/tasks/preflight.yml's fail_msg still names only the two existing homes for the token. Left for a role change.

Tests

tests/scripts-test.sh (make test-scripts) adds checks for:

  • Ignore rules: vault.* is ignored in this repo at every depth and in both trees (including ansible/inventory/<dir>/), while a private copy, which carries only the example's .gitignore, can commit it. Each rule has a negative case. Global git excludes are switched off, so a broken rule can't pass locally.
  • The check script: passes on encrypted 1.1 and 1.2-labelled files, and refuses each plaintext shape, by inventory scan and by file argument.
  • The hook's patterns: its files: regex selects exactly what the script scans, and the check-json and yamllint excludes skip exactly the vault files.

Verification

  • make test-scripts, make lint and actionlint pass.
  • End to end in a scratch copy of the example, with real ansible-vault files:
    • pre-commit: passes with an encrypted vault.yml and a nested vault.json; fails on plaintext appended to one.
    • Password and precedence: without the password, ansible-inventory --list fails ("no vault secrets found"); with it, vault.yml wins over secret.yml.
    • The CI step's real script:
      • a host-less file encrypted with another password fails the build with an ::error;
      • when every file decrypts, the inventory loads;
      • without the secret, the files are stubbed and the inventory loads.
    • Readable diffs: the textconv recipe shows the decrypted diff.

🤖 Generated with Claude Code

…crets

A private fleet repo built from examples/collection-fleet can now commit its
inventory secrets ansible-vault encrypted as vault.yml (host_vars/<host>/ or
group_vars/<group>/, at any depth). The git-ignored plaintext secret.yml flow
is unchanged, and a fleet without a vault.yml works exactly as before.

- scripts/check-vault-encrypted.sh + a vault-encrypted pre-commit hook: the
  exact vault header, then ciphertext only; check-json and yamllint skip it.
- CI decrypts every committed vault file with the ANSIBLE_VAULT_PASSWORD
  secret when set, else replaces each with {} and warns.
- This public repo git-ignores vault.* in both inventory trees; a private
  copy (only the example's .gitignore) can commit them. scripts-test.sh
  checks both sides, the script and the hook's patterns.
- Docs: the example README's "Encrypted secrets (optional)", ansible/README.md
  private overlay, secret.yml.example headers, and the statements that called
  secret.yml the only inventory home for a credential.

Closes #25

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 1, 2026 19:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The setup command can overwrite an existing vault password without rekeying files, risking lost access, while the documented guard paths miss the overlay’s vault files.

2 open issues
What changed in this PR

Adds optional ansible-vault support to the private fleet template, addressing the scoped-down goal of #25 without changing role behavior or the existing plaintext-secret workflow.

Changes:

  • Adds encrypted-file checks, pre-commit integration, and CI decryption or password-free stubbing.
  • Documents vault setup, password handling, precedence, and rotation.
  • Keeps vault files out of the public repository and adds regression checks.
File Description
tests/​scripts-test.sh Tests vault validation, ignore rules, and hook patterns.
examples/​collection-fleet/​scripts/​check-vault-encrypted.sh Checks vault headers and ciphertext-only bodies.
examples/​collection-fleet/​README.md Documents optional encrypted secrets and CI behavior.
examples/​collection-fleet/​inventory/​host_vars/​origin-1/​secret.yml.example Documents the encrypted alternative for origins.
examples/​collection-fleet/​inventory/​host_vars/​decdn-node-1/​secret.yml.example Documents the encrypted alternative for nodes.
examples/​collection-fleet/​AGENTS.md Updates private-fleet secret-handling guidance.
examples/​collection-fleet/​.pre-commit-config.yaml Adds vault checks and ciphertext lint exclusions.
examples/​collection-fleet/​.gitignore Explains why private vault files remain committable.
examples/​collection-fleet/​.github/​workflows/​ci.yml Decrypts vault files or substitutes empty mappings.
docs/​requirements.md Lists private encrypted inventory as a secrets option.
docs/​publishers.md Documents encrypted inventory for origin credentials.
CONTRIBUTING.md Describes expanded script-test coverage.
ansible/​roles/​grafana_alloy/​files/​grafana-alloy.env.example Updates credential-storage comments only.
ansible/​roles/​grafana_alloy/​defaults/​main.yml Updates token-storage comments only.
ansible/​README.md Documents vault use in private overlays.
ansible/​inventory/​host_vars/​origin-1/​secret.yml.example Mirrors origin secret guidance.
ansible/​inventory/​host_vars/​decdn-node-1/​secret.yml.example Mirrors node secret guidance.
ansible/​.gitignore Ignores vault files in public Ansible inventories.
AGENTS.md Clarifies that vault support is private-repository only.
.gitignore Ignores vault files in the public fleet example.

Review effort: Balanced

Comment thread examples/collection-fleet/README.md Resolved
Comment thread ansible/README.md Resolved
…an overlay

Review follow-ups on #207: the README's setup line refuses to replace an
existing password file (set -C), and ansible/README.md says the copied hook
and CI step need the inventory/ prefix dropped for an overlay whose vars sit
beside hosts.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thiras
thiras merged commit 516c820 into main Nov 1, 2026
49 checks passed
@thiras
thiras deleted the feat/fleet-ansible-vault branch November 1, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support encrypted-at-rest inventory secrets (ansible-vault / SOPS)

2 participants