44

I'd like to see the actual git commit changes in the ansible vault file.

Is there an easy way how to achieve this?

udondan
  • 57,263
  • 20
  • 190
  • 175
Ikar Pohorský
  • 4,617
  • 6
  • 39
  • 56

5 Answers5

98

You can do this very neatly, so that the normal git tools like git log and git diff can see inside the vaulted files, using a custom git diff driver and .gitattributes.

  • Make sure that your vault password is in .vault_password and that that file is not committed - you should also add it to .gitignore.
  • Add a .gitattributes file that matches any files in your repository that are encrypted with ansible-vault and give them the attribute diff=ansible-vault. For example, I have:

    env_vars/production.yml diff=ansible-vault merge=binary
    env_vars/staging.yml diff=ansible-vault merge=binary
    

    You can also use wildcarded patterns - the first element of each line, the pattern, follows the same rules as .gitignore files. The merge=binary option tells git not to attempt to do a three-way merge of these files.

  • Then you have to set the diff driver for files with attribute diff=ansible-vault to ansible-vault view:

    git config --global diff.ansible-vault.textconv "ansible-vault view"
    

And that should be it - when git is calculating diffs of the files your pattern matches, it'll decrypt them first.

Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • 6
    It's also good to add `merge=binary` filter to prevent git from 3-way merging of encrypted files and `git config diff.ansible-vault.cachetextconv false` to prevent caching sensitive information: https://selivan.github.io/2016/11/29/ansible-human-readable-git-diff-for-vault.html – Selivanov Pavel Nov 29 '16 at 16:24
  • My `PAGER` was `most` instead of `less`. Executing a `git diff` made me stuck in the `Vault password: ` prompt. I had to set my git pager to use `cat` by running the command `git config --global core.pager cat` – GMaster Dec 13 '16 at 12:25
  • @Selivanov Pavel Thanks for that tip - I've updated the answer with that. – Mark Longair Dec 15 '16 at 17:16
  • @GMaster : you can use your favorite pager and make ansible-vault use `cat`. Just set PAGER variable before command: `git config --global diff.ansible-vault.textconv "PAGER=cat ansible-vault view"` – Selivanov Pavel Dec 15 '16 at 17:26
  • @Selivanov Pavel: I tried that several times and it didn't work, git kept using `/usr/bin/most` instead of `cat`. Using `git config --global core.pager cat` to explicitly tell git to use `cat` as the pager worked for me. – GMaster Dec 15 '16 at 21:18
  • Is there a way to configure this so that it *does* allow merging of the decrypted text content? Does that need a separate mergetool configured or something? – Ken Williams Sep 08 '17 at 15:57
  • If only I could apply a "thousand times this" sticker. – Joe May 12 '18 at 14:47
  • 2
    I had to set the ANSIBLE_VAULT_PASSWORD_FILE environment. – BARJ Oct 08 '18 at 08:37
  • 3
    me too @BARJ: `export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_password` – Jaime M. Nov 26 '18 at 14:09
  • 2
    Additionally to the specified `diff.ansible-vault` command you can append `--vault-password-file=.vault_password`, or as has been suggested below by @victor-schröder set the corresponding property in the `ansible.cfg`. – Aliaksandr Kazlou Nov 14 '19 at 07:43
  • 4
    One more hint: If you have vaults with different passwords, you can use `vault_identity_list=foo@/path/to/vaultfile1,bar@/path/to/vaultfile2` ([doc](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-vault-identity-list)). This works even if your vaults don’t have IDs, since apparently all identities will be attempted (i.e., the labels `foo` and `bar` are arbitrary and have no effect). – tjanson Mar 31 '20 at 13:02
  • I am a bit curious about the vaule password file naming. Is `.vault-password` a standard file like `.dockerignore`, `.env`, `.gitattributes` – Shiplu Mokaddim Dec 11 '20 at 18:34
  • @MarkLongair - I suggest to NOT put .vault_password but instead to `apt-get install pinentry`. May I update your reply with a phrase saying you can do .vault-password but you should rather pinentry? – Tomáš Pospíšek Jun 20 '22 at 21:09
10

So after some digging I constructed the non-trivial solution.

First of all store your vault password into the (.gitignored) .vault_password file.

In the following example a HEAD and HEAD~2 versions of the file inventory/group_vars/xyz/vault.yml are vimdiff-ed:

vimdiff \
  <(ansible-vault view --vault-password-file=.vault_password \
    <(git show HEAD:inventory/group_vars/xyz/vault.yml)) \
  <(ansible-vault view --vault-password-file=.vault_password \
    <(git show HEAD~2:inventory/group_vars/xyz/vault.yml))
Ikar Pohorský
  • 4,617
  • 6
  • 39
  • 56
9

You can use atk-git-diff utility from https://github.com/dellis23/ansible-toolkit

This

Becomes

kmmbvnr
  • 5,863
  • 4
  • 35
  • 44
4

For completeness, it's worth to mention how to configure the diff for ansible-vaulted files globally. For example, I work with really a lot of ansible repositories over here and almost all of them have some vaulted secrets. So what I want is my configuration to be global and portable from one machine to another.

In your ~/.gitconfig add these sections:

[core]
    # The following line defines a global .gitattributes file
    attributesfile = ~/.gitattributes

[diff "ansible-vault"]
    textconv = "ansible-vault view"

For this to work, you need some naming pattern for ansible-vaulted files, which is something good that you should do anyways. In my case, I like to name them with the extension .vault.yml. So my ~/.gitattributes file looks like this:

*.vault.yml diff=ansible-vault merge=binary

Finally, to avoid typing the password all the time, make sure you have a file in a convenient place in each repository (normally something like .vault, placed at the root). This file must contain the password in plain text (properly .gitignored, of course) or an executable script that produces such password.

Having that in place, go ahead and tell ansible to use the .vault file, by adding the following line to the global or local ansible.cfg:

vault_password_file = .vault

Done. Now running git diff will produce the readable diff that you would expect from non-vaulted files :)

Victor Schröder
  • 6,738
  • 2
  • 42
  • 45
1

A hint for Windows users:
When running on windows you have the problem, that ansible-vault is not available. But you can install it inside your WSL.
After installing ansible-vault in WSL, the following is working for me

.gitattributes

**/vault.yml diff=ansible-vault

.gitconfig

[core]
  attributesfile = ~/.gitattributes
[diff "ansible-vault"]
  textconv = sh -c 'cat $0 | wsl ansible-vault decrypt --output - --vault-password-file=~/.vault_pass'

The vault password must be inside the wsl in ~/.vault_pass

KeKru
  • 444
  • 3
  • 13