Ansible Vault IDs

DevOps ToolChain, WikiPedia, CC BY-SA 4.0
| | 6 Comments| 9:22 PM
Categories:

There are times when not only you’ll want to have separate vault files for development, staging, and production, but when you will also want to have separate passwords for those individual vaults. Enter vault ids, a feature of Ansible 2.4 (and later).

I had a bit of trouble getting this configured correctly, so I wanted to share my setup in hopes you find it useful as well.

First, we’ll create three separate files that contain our vault passwords. These files should not be checked into revision control, but instead reside in your protected home directory or some other secure location. These files will contain plaintext passwords that will be used to encrypt and decrypt your Ansible vaults. Our files are as follows:

  • ~/.vault-pass.common
  • ~/.vault-pass.staging
  • ~/.vault-pass.production

As you can already guess we’re going to have three separate passwords for our vaults, one each for common credentials we want to encrypt (for example, an API key that is used to communicate with a third party service and is used for all environments), and our staging and production environments. We’ll keep it simple for the contents of each password file:

Obligatory Warning: Do not use these passwords in your environment but instead create strong passwords for each. To create a strong password instead you might try something like:

Once you’ve created your three vault password files, now add to your ansible.cfg [general] section:

[code lang=text]
vault_identity_list = common@~/.vault-pass.common, staging@~/.vault-pass.staging, production@~/.vault-pass.production
[/code]

It’s important to note here that your ansible.cfg vault identity list will be consulted when you execute your Ansible playbooks. If the first password won’t open the vault, it will move on to the next one, until one of them works (or, conversely, doesn’t).

Encrypting Your Vaults

To encrypt your vault file you must now explicitly choose which id to encrypt with. For example,

vault_common:

we will encrypt with our common vault id, like this:

[code lang=text]
# ansible-vault encrypt –encrypt-vault-id common common_vault
Encryption successful
[/code]

Run head -1 on the resulting file and notice that the vault id used to encrypt is in the header:

If you are in the same directory as your ansible.cfg file, go ahead and view it with ansible-vault view common_vault. Your first identity file (.vault-pass.common) will be consulted for the password. If, however, you are not in the same directory with your ansible.cfg file, you’ll be prompted for the vault password. To make this global, you’ll want to place the vault_identity_list in your ~/.ansible.cfg file.

Repeat the process for other vault files, making sure to specify the id you want to encrypt with:

For a staging vault file:

For a production vault file:

Now you can view any of these files without providing your vault password since ansible.cfg will locate the right password. The same goes running ansible-playbook! Take care though that when you decrypt a file, if you intend on re-encrypting it that you must provide an id to use with the --encrypt-vault-id option!

A Bug, I Think

I haven’t filed this with the Ansible team, but I think this might be a bug. If you are in the same directory as your ansible.cfg (or the identity list is in .ansible.cfg), using --ask-vault to require a password on the command line will ignore the password if it can find it in your vault_identity_list password files. I find this to be counterintuitive: if you explicitly request a password prompt, the password entered should be the one that is attempted, and none other. For example:

[code lang=text]
# ansible-vault –ask-vault view common_vault
Vault password:
[/code]

If I type anything other than the actual password for the common identity, I should get an error. Instead Ansible will happily find the password in ~/.vault-pass.common and view the file anyway.

Some Additional Thoughts

I wanted to take a moment to address a comment posted on this article, which can be summarized as:

What’s the point of encrypting services passwords in a vault which you check in to a repository, then pass around a shared vault-passwords file that decrypts them outside of the repository, rather than simply sharing a properties file that has the passwords to the services? It just seems like an extra layer of obfuscation rather than actually more secure.

First, to be clear, a “shared vault-passwords file” is not passed around – either the development operations engineer(s) are or a secured build server is permitted to have the vault passwords. Second, with this technique, you have a minimal number of passwords that are stored in plain text. True, these passwords are capable of unlocking any vaults encrypted with them, but this is true of any master password. Finally, I disagree with the assertion that this is an “extra layer of obfuscation.” If that were the case, any encryption scheme that had a master password (which is what utilizing an Ansible vault password file is), could be considered obfuscation. In the end, this technique is used to accomplish these goals:

  • permit separate sets of services passwords for different environments, i.e., staging and production
  • allow for submitting those services passwords in an encrypted format into a repository (the key here is that these are submitted to a known location alongside the rest of the configuration)
  • allow for decryption of those vaults in a secured environment such as a development operations user account or build server account

6 thoughts on “Ansible Vault IDs”

  1. # date +%s | shasum -a 256 | base64 | head -c 32 > ~/.vault-pass.common

    This password generation scheme is fairly open to brute force attacks. If I know approximately when the password was generated, I can loop through the unix timestamps around that time and see which one produces a password which will unlock the vault.

    Better use /dev/urandom as a source of randomness, or a dedicated tool such as pwgen.

    1. Thanks Christian, I appreciate the feedback regarding passwords! I’m going to update the post to use tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1, another one-liner from this post.

  2. I’m trying to figure this out too – unless I misunderstood your post, I see a problem here: the vault may be encrypted, but the password to decrypt it is still stored in your config ? Doesn’t this defeat the purpose ?

  3. taikedz:

    The password to decrypt is stored in plaintext on your laptop, or whatever device you use to run your playbooks from. Notice in the examples, I use ~/, e.g., my home directory.

    You never put your passwords in your repositories, because as you said, it would defeat the purpose.

    1. Right, but what’s the point of encrypting a bunch of service passwords in a vault which you check in to a repo, then pass around a shared vault-passwords file that decrypts them outside of the repo? Rather than passing around a properties file that has the passwords to the services? It just seems like an extra layer of obfuscation rather than actually more secure.

      1. Sam:

        Thanks for your comments. I felt compelled to address them by updating the post itself to clarify why this technique is preferred for managing services passwords for various environments.

Leave a Reply

Your email address will not be published. Required fields are marked *