skip to content

In an Ansible repository, when would you encrypt an entire vars file with ansible-vault versus using ansible-vault encrypt_string for individual values?

level: middleimportance: should knowfreq 55%

answer

  1. blob versus one tagged scalar
  2. diff reviewability is the real axis
  3. rekey walks files, not embedded strings
  4. vault_ prefix and a plaintext pointer file
  5. same cipher either way

basics

~20 s

Encrypt a whole file when nearly everything in it is secret; use encrypt_string when a mostly-plaintext file needs one or two secret values. Whole-file encryption makes diffs unreadable; inline vault strings keep the surrounding YAML reviewable.

solid answer

~50 s

Both produce the same ciphertext format, so the choice is about reviewability and blast radius. A fully encrypted file is a single opaque blob: a reviewer sees only that `vault.yml` changed, never which variable. That is fine when the file holds nothing but secrets, and it is the cheapest thing to rotate because `ansible-vault rekey` operates on whole files. Inline strings, produced by `ansible-vault encrypt_string`, embed a `!vault |` tagged scalar next to ordinary plaintext variables, so a reviewer can see that `db_password` changed and that `db_host` did not. The cost is that inline strings are scattered, verbose, and invisible to `rekey`, so rotating a password means regenerating each one by hand. The common compromise is a plaintext vars file of readable names pointing at `vault_`-prefixed variables that live in one encrypted file — reviewers see the wiring, the secrets stay in one blob.

code

bash · 3 lines
bash
# produce a single inline vault string to paste into a plaintext YAML file
ansible-vault encrypt_string --vault-id prod@prompt \
  'correct-horse-battery-staple' --name 'vault_db_password'

go deeper

for a junior

Know that both forms exist: ansible-vault encrypt for a whole file and ansible-vault encrypt_string for one value pasted in as a !vault scalar, and that both need the same password at run time.

for a middle

Explain the tradeoff mechanically — salted ciphertext makes encrypted-file diffs opaque, inline strings keep surrounding YAML reviewable, and rekey only touches whole files.

for a senior

Show the repository-level judgment: a dedicated vault.yml per environment plus a plaintext file of vault_-prefixed references, so code review stays meaningful and rotation is one command instead of a manual sweep.

for a principal

Own the convention for the estate — where secrets are allowed to live, how review of a credential change is made auditable, and when the answer is to stop storing the value in git at all and read it from a managed store.

## Two packagings of the same cipher Ansible Vault encrypts at two granularities. `ansible-vault encrypt secrets.yml` turns a whole file into one blob. `ansible-vault encrypt_string` encrypts a single scalar and prints a YAML fragment you paste into an otherwise plaintext file, tagged so the parser knows to decrypt it: ```yaml db_host: db-prod-01.internal db_user: app db_password: !vault | $ANSIBLE_VAULT;1.1;AES256 62313365396662343061393464336163383437343266333962... ``` The cipher, the header and the password are identical in both cases. Anywhere Ansible loads variables — `group_vars`, `host_vars`, a `vars_files` entry, role `defaults` — either form works, and Ansible decrypts lazily when it reads the file. ## What whole-file encryption costs you The cost is code review, and it is bigger than it sounds. Because the payload is salted, re-encrypting identical content produces completely different ciphertext, so a diff on an encrypted file is always a full-blob replacement. A reviewer approving a pull request that touches `group_vars/prod/vault.yml` learns exactly one thing: it changed. They cannot see whether you rotated one API token or accidentally deleted four unrelated variables, and merge conflicts on that file cannot be resolved by hand at all — you have to decrypt both sides, merge, and re-encrypt. That matters least when the file contains nothing but secrets, which is why the dominant convention is a dedicated `vault.yml` per environment holding only encrypted values, and never a mixed file where a hostname change is indistinguishable from a credential change. ## What inline strings cost you Inline strings fix reviewability at the cost of manageability. Each one is ten-odd lines of hex embedded in your data structure, so a file with a dozen secrets becomes unreadable for a different reason. More importantly, `ansible-vault rekey` works on encrypted **files** — it will not walk a plaintext YAML file re-encrypting the `!vault` scalars inside it. Rotating the vault password across a repository full of inline strings means finding and regenerating every one of them with `encrypt_string` under the new password. Inline strings also break the trick of simply not loading the encrypted file when you do not need the secret, since the surrounding file is always loaded. Generating one looks like this: ```bash ansible-vault encrypt_string --vault-id prod@prompt \ 'correct-horse-battery-staple' --name 'db_password' ``` Read the value from stdin rather than passing it as an argument when you care about shell history and the process table. ## The pattern most teams land on The widely used compromise is indirection. Keep two files per environment: a plaintext one that a reviewer can read, and an encrypted one that holds the raw values under prefixed names. ```yaml # group_vars/prod/vars.yml (plaintext, reviewable) db_host: db-prod-01.internal db_password: "{{ vault_db_password }}" # group_vars/prod/vault.yml (fully encrypted) vault_db_password: correct-horse-battery-staple ``` This gives you the best of both: the plaintext file documents which variables exist and where each one comes from, so a review of "we now pass a password to the app" is meaningful; the encrypted file is a single blob that `rekey` can rotate in one command; and the `vault_` prefix makes it obvious at a glance which values are sensitive and greppable in templates. The tradeoff is one extra layer of naming, and a failure mode where the plaintext file references a `vault_` variable the encrypted file no longer defines — an undefined-variable error at run time rather than at review time. ## Choosing in an interview Say the decision rule out loud: whole-file when the file is all secrets and you want cheap rotation and a clean rekey story; inline strings when one secret has to live inside a mostly public structure — a single token in a role's `defaults/main.yml`, or a value in an inventory file you want to stay readable. Then mention that at any real scale you use the indirection pattern so review stays possible, and that neither form changes the underlying security properties: same password, same cipher, same lack of per-user access control.

  • Why does a pull request that changes an encrypted vars file always show the whole file as modified?
    Encryption uses a random salt, so re-encrypting even identical content produces entirely different ciphertext. Git sees a wholesale replacement and cannot align lines. That also makes merge conflicts on such files unresolvable in place — you decrypt both versions, merge the plaintext, and re-encrypt the result.
  • What breaks when you rotate the vault password in a repo full of inline encrypt_string values?
    `ansible-vault rekey` only re-encrypts whole encrypted files, so it silently leaves every `!vault` scalar embedded in a plaintext YAML file on the old password. The run then fails to decrypt them, or keeps working only because the old password is still supplied. Each inline string has to be regenerated with `encrypt_string` under the new password.
  • Can one playbook run mix encrypted files and inline strings?
    Yes. Ansible decrypts each piece of vault content as it loads it, so a run can include fully encrypted vars files, inline `!vault` scalars, and plain variables together. If several vault passwords are involved you supply all of them, typically as multiple `--vault-id` arguments, and Ansible tries them against each piece of content.

saying these in an interview costs you the question

  • Believing inline strings use weaker or different encryption than files
  • Assuming rekey also rotates embedded !vault scalars
  • Mixing hostnames and credentials in one encrypted file, then blaming review
  • Claiming an encrypted file produces a readable line-by-line diff
  • Passing the secret as a shell argument without thinking about history

context