{"id":3439,"date":"2018-06-12T21:22:09","date_gmt":"2018-06-13T02:22:09","guid":{"rendered":"https:\/\/dev.iachieved.it\/iachievedit\/?p=3439"},"modified":"2020-07-05T11:16:45","modified_gmt":"2020-07-05T16:16:45","slug":"ansible-vault-ids","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/ansible-vault-ids\/","title":{"rendered":"Ansible Vault IDs"},"content":{"rendered":"<p>There are times when not only you&#8217;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 <i>vault ids<\/i>, a feature of Ansible 2.4 (and later).<\/p>\n<p>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.<\/p>\n<p>First, we&#8217;ll create three separate files that contain our <i>vault passwords<\/i>.  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:<\/p>\n<ul>\n<li><code>~\/.vault-pass.common<\/code><\/li>\n<li><code>~\/.vault-pass.staging<\/code><\/li>\n<li><code>~\/.vault-pass.production<\/code><\/li>\n<\/ul>\n<p>As you can already guess we&#8217;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&#8217;ll keep it simple for the contents of each password file:<\/p>\n<pre class=\"toolbar-overlay:false lang:shell\">\n# echo 'commonVaultPassword' > ~.\/.vault-pass.common\n# echo 'stagingVaultPassword' > ~\/.vault-pass.staging\n# echo 'productionVaultPassword' > ~\/.vault-pass.production\n<\/pre>\n<p><b>Obligatory Warning:<\/b>  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:<\/p>\n<pre class=\"toolbar-overlay:false lang:shell\">\n# tr -cd '[:alnum:]' < \/dev\/urandom | fold -w32 | head -n1 > ~\/.vault-pass.common\n# cat ~\/.vault-pass.common\nRt8pN0FrctcMnQB3p69gwYPikTVVzoGP\n<\/pre>\n<p>Once you&#8217;ve created your three vault password files, now add to your <code>ansible.cfg<\/code> <code>[general]<\/code> section:<\/p>\n<p>[code lang=text]<br \/>\nvault_identity_list = common@~\/.vault-pass.common, staging@~\/.vault-pass.staging, production@~\/.vault-pass.production<br \/>\n[\/code]<\/p>\n<p>It&#8217;s important to note here that your <code>ansible.cfg<\/code> vault identity list will be consulted when you execute your Ansible playbooks.  If the first password won&#8217;t open the vault, it will move on to the next one, until one of them works (or, conversely, doesn&#8217;t).<\/p>\n<h2>Encrypting Your Vaults<\/h2>\n<p>To encrypt your vault file you must now explicitly choose which id to encrypt with.  For example,<\/p>\n<p><code>vault_common<\/code>:<\/p>\n<pre class=\"toolbar-overlay:false lang:yaml\">\n---\ncommon_secret:  itsASecretToEverybody\n<\/pre>\n<p>we will encrypt with our <code>common<\/code> vault id, like this:<\/p>\n<p>[code lang=text]<br \/>\n# ansible-vault encrypt &#8211;encrypt-vault-id common common_vault<br \/>\nEncryption successful<br \/>\n[\/code]<\/p>\n<p>Run <code>head -1<\/code> on the resulting file and notice that the vault id used to encrypt is in the header:<\/p>\n<pre class=\"toolbar-overlay:false lang:shell\">\n# head -1 common_vault\n$ANSIBLE_VAULT;1.2;AES256;common\n<\/pre>\n<p><i>If<\/i> you are in the same directory as your <code>ansible.cfg<\/code> file, go ahead and view it with <code>ansible-vault view common_vault<\/code>.  Your first identity file (<code>.vault-pass.common<\/code>) will be consulted for the password.  If, however, you are not in the same directory with your <code>ansible.cfg<\/code> file, you&#8217;ll be prompted for the vault password.  To make this global, you&#8217;ll want to place the <code>vault_identity_list<\/code> in your <code>~\/.ansible.cfg<\/code> file.<\/p>\n<p>Repeat the process for other vault files, making sure to specify the id you want to encrypt with:<\/p>\n<p>For a staging vault file:<\/p>\n<pre class=\"toolbar-overlay: false lang:shell\">\n# cat staging_vault\n---\nsecret:  theStagingSecret\n# ansible-vault encrypt --encrypt-vault-id staging staging_vault\nEncryption successful\n# head -1 staging_vault\n$ANSIBLE_VAULT;1.2;AES256;staging\n<\/pre>\n<p>For a production vault file:<\/p>\n<pre class=\"toolbar-overlay:false lang:shell\">\n# cat production_vault\n---\nsecret:  theProductionSecret\n# ansible-vault encrypt --encrypt-vault-id production production_vault\nEncryption successful\n#head -1 production_vault\n$ANSIBLE_VAULT;1.2;AES256;production\n<\/pre>\n<p>Now you can view any of these files without providing your vault password since <code>ansible.cfg<\/code> will locate the right password.  The same goes running <code>ansible-playbook<\/code>!  Take care though that when you <code>decrypt<\/code> a file, if you intend on re-encrypting it that you must provide an id to use with the <code>--encrypt-vault-id<\/code> option!<\/p>\n<h2>A Bug, I Think<\/h2>\n<p>I haven&#8217;t filed this with the Ansible team, but I think this might be a bug.  If you are in the same directory as your <code>ansible.cfg<\/code> (or the identity list is in <code>.ansible.cfg<\/code>), using <code>--ask-vault<\/code> to require a password on the command line will ignore the password if it can find it in your <code>vault_identity_list<\/code> 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:<\/p>\n<p>[code lang=text]<br \/>\n# ansible-vault &#8211;ask-vault view common_vault<br \/>\nVault password:<br \/>\n[\/code]<\/p>\n<p>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 <code>~\/.vault-pass.common<\/code> and view the file anyway.<\/p>\n<h2>Some Additional Thoughts<\/h2>\n<p>I wanted to take a moment to address a comment posted on this article, which can be summarized as:<\/p>\n<blockquote><p>What\u2019s 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.<\/p><\/blockquote>\n<p>First, to be clear, a &#8220;shared vault-passwords file&#8221; is not passed around &#8211; 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 &#8220;extra layer of obfuscation.&#8221;  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:<\/p>\n<ul>\n<li>permit separate sets of services passwords for different environments, i.e., staging and production<\/li>\n<li>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)<\/li>\n<li>allow for decryption of those vaults in a secured environment such as a development operations user account or build server account<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>There are times when not only you&#8217;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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3318,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[68,21],"tags":[70],"class_list":["post-3439","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ansible","category-devops","tag-ansible-vault-multiple-encryption-passwords-devops"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3439"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=3439"}],"version-history":[{"count":17,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3439\/revisions"}],"predecessor-version":[{"id":4165,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3439\/revisions\/4165"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media\/3318"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=3439"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=3439"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=3439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}