fix(rotate): correct the next steps after a rotation; retire the rotate-secret playbook #149
Loading…
Reference in a new issue
No description provided.
Delete branch "jfraeys/fix/rotate-playbook-replay-vars"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while rotating Vaultwarden on 2026-10-14:
scripts/with-vault.sh ansible-playbook playbooks/rotate-secret.yml -e secret_name=vaultwardenrotated the vault (play 1) and then failed in the replay play with'dry_run_mode' is undefined, leaving a rotated, uncommitted vault and nothing deployed.Net change of this PR
scripts/rotate-secret.sh(SOPS mode): the printed next steps were wrong: a barewith-vault.sh ansible-playbook ... services.yml(skips the promotion gate and the Tailscale key mint), "run again with --save-to-bitwarden" to get the plaintext (that rotates again and changes the value), no commit/merge of the vault change, no verification. Now, in order: save the plaintext to personal Bitwarden now (it exists nowhere else); commit and merge the vault change as achore(secrets)PR;./infra deploy --tags <tags> --limit servicesin one command; service-specific verification (vaultwarden:/admintakes the plaintext token, not the hash). Dry runs say nothing changed. Legacyvault.ymltext unchanged.playbooks/rotate-secret.ymlis removed. Besides thedry_run_modebug, its replay play applied only the role matchingsecret_namestraight to the host: for vaultwarden that deploys Vaultwarden with the new OIDC client secret while Authelia keeps the old one (SSO breaks until Authelia is deployed; the script's own tags arevaultwarden,authelia), it skips the promotion gate andservices.yml's pre-tasks, and it deploys a vault change that is not merged yet../infra deploycannot be called from inside a play (interactive, runs ansible itself), and nothing else referenced the playbook except comments and two doc lines;./infra rotate(daily-commands.md) already does the rotation. Doc references removed; the.ansible-lintexclusion for it is gone.The first commits on this branch fixed the playbook before the decision to retire it; the net diff does not touch it any more.
Checked:
ansible-lint roles playbooks(the CI command) passes,bash -n, test-infra-cli, test-rotation-lock and test-bitwarden-save pass; the next-steps text was rendered with stub variables for vaultwarden, ci-ephemeral-wakeup, authelia (dry run) and lldap (legacy).🤖 Generated with Claude Code
https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
Second commit: the line-24 lint/syntax-check error (the
mandatoryfilter in the play name, plus the same problem in the second play's name) is fixed instead of excluded. Both play names usedefault('(secret_name not set)'), an explicit first task fails with the same message whensecret_nameis not set, and the.ansible-lintexclusion for this playbook is removed. Verified locally:ansible-lint roles playbooks(the CI command) passes on 106 files, yamllint passes, and--syntax-checkpasses with and without-e secret_name.`mandatory(...)` and a bare `{{ secret_name }}` in the two play names made syntax-check (and ansible-lint) fail without -e secret_name, so the playbook was excluded from lint. Use default() in both names, check secret_name in an explicit first task with the same message, and remove the .ansible-lint exclusion. ansible-lint on the full CI command (106 files) and yamllint pass; syntax-check passes with and without secret_name. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZThird commit: the next steps printed after a rotation (
scripts/rotate-secret.shSOPS mode, and the playbook's messages) are corrected. Before: replay with a barewith-vault.sh ansible-playbook ... services.yml(skips the promotion gate and the Tailscale key mint), 'run again with --save-to-bitwarden' to get the plaintext (that rotates again, changing the value), and no mention of committing the vault change or verifying. Now, in order: (1) save the plaintext to personal Bitwarden now, it exists nowhere else; (2) commit and merge the vault change as a chore(secrets) PR; (3)./infra deploy --tags <tags> --limit servicesin one command; (4) service-specific verification (vaultwarden: /admin takes the plaintext token, not the $argon2id hash). Dry runs say nothing was changed; the legacy vault.yml text is unchanged. Rendered for vaultwarden, ci-ephemeral-wakeup, authelia (dry run) and lldap (legacy) with stub variables; test-infra-cli, test-rotation-lock and test-bitwarden-save pass. Also noted in the playbook: its replay play deploys the roles directly, without the ./infra deploy gate.fix(rotate): define dry_run_mode in the replay play tooto fix(rotate): correct the next steps after a rotation; retire the rotate-secret playbookFourth commit: every script and doc that told the operator to rotate or deploy the old way now points at the new mechanism. Scripts:
regenerate-ci-ephemeral-ssh-key.shandrotate-ovh-s3-credentials.shnow say merge the vault change as a chore(secrets) PR, then./infra deploy --tags <tags> --limit services(was a bare ansible-playbook);rotate-secret.sh's legacy branch no longer says to re-run to save plaintext. Docs: SECURITY_CHECKLIST (./infra rotate), vault-lockout and mail-pipeline-failure (./infra deploy --tags ..., the latter also drops stale vault.yml wording and names vault-set.py), README, deployment.md and updating-tool-versions.md (./infra deployinstead of deploy-services.sh / with-vault.sh ansible-playbook). Left on purpose: ./setup's internal ansible calls, staging/validation hints in playbooks/tests, ROLLBACK.md's test playbook, the web deploy (no ./infra equivalent), node-failure.md's node-rebuild step, the legacy non-SOPS branch in rotate-secret.sh, and with-vault.sh/deploy-services.sh themselves. ansible-lint (CI command), test-infra-cli, test-promotion, test-rotation-lock and test-bitwarden-save pass.