Skip to content
SRE & DevOpsDeep Dive Published Updated 8 min readViews unavailable

Ansible Vault Lifecycle: Password IDs, Rekeying, and Runtime Exposure

Manage Ansible Vault credentials through rotation, vault IDs, safe automation, and output controls while recognizing what encryption does not protect.

Ansible Vault encrypts variables and files so sensitive configuration can be stored alongside automation code without leaving the protected values in plaintext at rest. It does not encrypt a running process, protect a password after decryption, secure an editor’s temporary files, or guarantee that task output will not reveal a secret. A production Vault design therefore needs two separate lifecycles: the encrypted content in source control and the vault credential used to decrypt it.

Vault is a file and variable encryption mechanism, not a centralized secret manager. It can help protect repository data, but the password or key that opens the content must still be supplied at run time. Teams often move that password into a CI secret, a password manager, a hardware-backed store, or an executable lookup script. The storage and retrieval system for the vault password remains a critical security boundary and should be rotated, logged, and access-controlled independently.

Choose file-level or variable-level encryption

File-level encryption hides the entire structured file. Ansible decrypts a vaulted file when that file is loaded or referenced, which makes it useful for a secret-only variable file or a task file whose structure is also sensitive. The downside is reviewability: diffs are opaque unless reviewers decrypt them through an approved workflow, and every consumer needs the correct vault identity.

Variable-level encryption keeps surrounding YAML readable while encrypting selected values with ansible-vault encrypt_string. This is convenient for reviewing non-secret configuration next to a protected password or token. It can also expose structural context such as secret names and variable relationships. Importantly, Ansible documents that encrypted variables cannot be rekeyed in place; rotating one requires decrypting and encrypting the value again. File-level encryption supports a rekey operation with the old secret and a new vault identity.

Treat the choice as a data-model decision. Vaulting a whole file reduces accidental partial exposure but makes ordinary configuration review harder. Encrypting individual variables improves diff readability but expands the number of encrypted values and makes password rotation more manual. Never commit a plaintext value temporarily and assume that deleting it from the latest commit erased it from Git history or existing clones.

Use vault IDs to separate environments

Vault IDs label password sources and let a playbook use different vault credentials for separate classes of encrypted data. A label such as production or staging is metadata and selection context, not a cryptographic authorization boundary by itself. If one user or CI job is given every vault password, labels do not prevent that principal from decrypting all content. Restrict which password source a job can access and keep environment credentials out of generic developer environments.

Ansible can accept multiple --vault-id options to make credentials available for encrypted inputs. Use vault-ID labels consistently as selection hints, and set --encrypt-vault-id when an encrypt or rekey operation needs an explicit choice among multiple loaded credentials. Labels do not restrict decryption: Ansible can try the available secrets in order when encrypted data has no matching label. For unattended runs, use an executable password source or secret-manager integration that emits the password only to the Ansible process; do not write it to a tracked file or print it in shell tracing.

# Create a file encrypted with the staging identity through an interactive prompt.
ansible-vault encrypt \
  --vault-id staging@prompt \
  group_vars/staging/vault.yml

# Re-encrypt a vaulted file with a new password source.
ansible-vault rekey \
  --vault-id production@prompt \
  --new-vault-id production-2026@prompt \
  group_vars/production/vault.yml

# Run a playbook that needs both staging and production vault sources.
ansible-playbook site.yml \
  --vault-id staging@prompt \
  --vault-id production-2026@prompt

The commands prompt for passwords rather than embedding them in command-line arguments, but shell history, terminal recording, process logs, or automation output can still expose sensitive handling if configured carelessly. The labels in an encrypted file and the --vault-id values must be managed consistently. Check the installed ansible-vault --help output and the project documentation before automating rekeying, because the CLI options and execution environment are part of the procedure.

Plan a rekey as a controlled migration

Before rotating a vault password, inventory every encrypted file and encrypted variable, the vault ID used for each, all playbooks and roles that reference the files, and every developer or automation system that runs them. Identify file-level ciphertext by its Vault header and search for vault-encrypted variable tags. A change to one password source does not automatically update every encrypted object in the repository.

Choose a rotation window in which the old and new password source can coexist long enough to re-encrypt and validate the content. First create the new credential in the organization’s approved secret store and restrict access to the rekey operator. Then rekey each file using the old credential and selected new credential. For encrypted variables, decrypt and encrypt the value again through a controlled process; do not paste cleartext into chat, shell history, or issue trackers. Make the change in a focused branch and review every plaintext-to-ciphertext diff through an approved mechanism.

Test the newly encrypted files with the new identity in a clean CI job and a controlled operator environment. Validate YAML syntax after decryption without persisting plaintext artifacts unnecessarily. Run syntax checks and safe, check-mode playbook runs where supported, but remember that check mode is not a security control and some modules cannot predict changes exactly. Confirm all jobs have switched to the new vault ID before removing or revoking the old password. Keep an auditable rollback plan that does not reintroduce an exposed credential.

Encrypted variable strings cannot simply be rekeyed as a whole file can. Rotate them by generating a new encrypted representation and replacing the old value. Where secret-manager lookup plugins can fetch a value at runtime, consider whether the operational benefit outweighs the loss of a self-contained encrypted repository. Avoid maintaining both a Vault-encrypted copy and an active secret-manager copy without a clear source of truth; divergence creates incidents where old credentials continue to be used.

Prevent plaintext exposure during execution

Vault encryption protects data at rest only. Once Ansible decrypts a value, a task module, connection plugin, callback, custom filter, or shell command may expose it through standard output, errors, facts, temporary files, or logs. Mark tasks that handle secrets with no_log: true, but do not treat this as a substitute for minimizing the data in the task. no_log also reduces diagnostic detail, so record safe identifiers and outcomes separately.

Avoid debug on secret-bearing variables, verbose command output, shell set -x, environment dumps, and command-line arguments that may be visible in process listings. Prefer a module’s protected parameter field over constructing a shell command containing a password. Review callback plugins, CI log retention, Ansible fact caching, remote temporary directories, editor swap files, and controller backups. Make sure a task’s return structure does not include the secret even when the action succeeds.

Vaulted variable files are decrypted when loaded or referenced, so importing one broad file can expose more data to a play than necessary. Separate secrets by environment and service, load them only for the relevant hosts, and avoid placing unrelated credentials in one file. Use least-privilege SSH and API credentials; a vault password that unlocks a root cloud key is still a high-impact credential regardless of its encryption format.

Manage the vault password as a production secret

Do not commit a vault password file next to encrypted content. If an executable password source retrieves a secret from an external store, protect the script, its dependencies, its network permissions, and its response logging. A password script must not be writable by the same untrusted contributor whose pull request triggers a privileged pipeline. Store CI secrets only in protected contexts, and do not make them available to jobs that run fork-controlled code.

Use separate credentials or access policies for local development and production automation when the workflow permits it. Maintain a documented owner, retrieval path, rotation interval, recovery process, and revocation procedure. A password that exists only in one engineer’s memory is not a reliable disaster recovery strategy; a shared, access-controlled secret store with audit records is safer and more operationally testable.

Troubleshoot without weakening controls

If Ansible reports that it cannot decrypt a file, verify the file’s vault ID header, the provided credential source, the selected --encrypt-vault-id, and whether the file was rekeyed by a different environment. Do not solve a credential mismatch by adding every vault password to every automation job. If YAML parsing fails after decryption, validate that file separately using an approved temporary location and delete the plaintext copy securely according to the workstation’s data-handling policy.

When a task fails while handling a secret, first inspect safe metadata such as the task name, target host, secret version label, and service error code. Reproduce with a non-production secret when possible. If no_log hides the relevant details, add a safe diagnostic that reports presence, length, or a non-sensitive response category, not the value itself. Rotate the secret if logs, process arguments, or artifacts may have exposed it.

Ansible Vault is most effective as one layer in a controlled secret lifecycle. Encrypt at rest, narrowly distribute decryption capability, keep execution output clean, test every rekey against all consumers, and use a dedicated secret manager for operational rotation where appropriate. Never confuse unreadable Git content with a complete secrets-management system.

Related:

Sources:

Comments