{"id":3352,"date":"2018-05-12T15:40:36","date_gmt":"2018-05-12T20:40:36","guid":{"rendered":"https:\/\/dev.iachieved.it\/iachievedit\/?p=3352"},"modified":"2018-05-12T15:40:36","modified_gmt":"2018-05-12T20:40:36","slug":"ansible-and-aws-part-3","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/ansible-and-aws-part-3\/","title":{"rendered":"Ansible and AWS &#8211; Part 3"},"content":{"rendered":"<p>This is the third article in a series looking at utilizing <a href=\"https:\/\/en.wikipedia.org\/wiki\/Ansible_(software)\">Ansible<\/a> with <a href=\"https:\/\/aws.amazon.com\/\">AWS<\/a>.  So far the focus has been Ansible itself, and we&#8217;ll continue that in this post and look at the <a href=\"http:\/\/docs.ansible.com\/ansible\/latest\/user_guide\/vault.html\">Ansible Vault<\/a>.  The final version of the Ansible playbook are on the <code>part3<\/code> branch of <a href=\"https:\/\/github.com\/iachievedit\/ansible-helloworld\">this repository<\/a>.<\/p>\n<p>You will frequently come across occasions where you want to submit something that needs to be kept secret to a code repository.  API keys, passwords, credentials, or other sensitive information that really <i>is<\/i> a part of the configuration of a server or application, and <i>should<\/i> be revisioned controlled, but <i>shouldn&#8217;t<\/i> be exposed to &#8220;the world&#8221; are great candidates for things to lock up in an Ansible vault.  I&#8217;ll illustrate several different applications of a vault, and then share a great technique for diffing vault files.<\/p>\n<h2>Vault It!<\/h2>\n<p>Any file can be encrypted (vaulted) with the <code>ansible-vault<\/code> command.  <code>now.txt<\/code> contains:<\/p>\n<p>[code lang=text]<br \/>\nNow is the time for all good men to come to the aid of their country.<br \/>\n[\/code]<\/p>\n<p>Let&#8217;s encrypt it with <code>ansible-vault<\/code>:<\/p>\n<p>[code lang=text]<br \/>\n# ansible-vault encrypt now.txt<br \/>\nNew Vault password:<br \/>\n[\/code]<\/p>\n<p>Type in a good password and you&#8217;ll be prompted to confirm it.  If the passwords match you&#8217;ll see <code>Encryption successful<\/code>.  Now, <code>cat<\/code> the file:<\/p>\n<p>[code lang=text]<br \/>\n# cat now.txt<br \/>\n$ANSIBLE_VAULT;1.1;AES256<br \/>\n30323261363061623735613964633862613232393261323638396435373561396237313161336531<br \/>\n&#8230;<br \/>\n33363033636132353034306130383064306264613935353133386664613062613438383361663462<br \/>\n33393438396236383230<br \/>\n[\/code]<\/p>\n<p>You&#8217;ll notice that <code>ansible-vault<\/code> did not change the name of your file or add an extension.  Thus from looking at the filename you can&#8217;t tell this file is a &#8220;vault&#8221; file.<\/p>\n<p>To edit the file, use <code>ansible-vault edit now.txt<\/code>.  You&#8217;ll be prompted for the password (I hope you remember it!), and if provided successfully <code>ansible-vault<\/code> will open the file with the default editor (on my Mac it&#8217;s <code>vi<\/code> but you can set the <code>EDITOR<\/code> shell variable explicitly).  Make any changes you like and then save them in your editor.  <code>ansible-vault<\/code> will reencrypt the file for you automatically.<\/p>\n<p><code>ansible-vault view<\/code> is another handy command; if you just want to look at the contents of the file and not edit them use <code>ansible-vault view FILENAME<\/code> and supply the password.<\/p>\n<h2>Practical Use<\/h2>\n<p>The most practical use of the vault capability is to protect sensitive information such as API keys, etc.  We&#8217;re going to use it for two applications:  encrypt AWS IAM credentials for accessing an S3 bucket, and an SSL certificate key.<\/p>\n<p>First though, let&#8217;s talk about where to put the actual variables.  We could put them in <code>vars.yml<\/code> and then encrypt the entire file.  This is overkill.  Better is to create a file called <code>vault<\/code> (so we know it&#8217;s a vault!) and put our values there.  <i>But<\/i>, we&#8217;re going to use a little indirection technique like this:<\/p>\n<p><code>vault<\/code>:<\/p>\n<pre class='lang:yaml'>\n---\nVAULT_AWS_ACCESS_KEY:  theAwsAccessKey\nVAULT_AWS_SECRET_KEY:  theAwsSecretKey\n<\/pre>\n<p>By the way, to be clear, the <code>vault<\/code> file here is located in our <code>host_vars<\/code> directory for the target host, alongside our <code>vars.yml<\/code> <i>for that host<\/i>.<\/p>\n<p><code>vars.yml<\/code>:<\/p>\n<pre class=\"lang:yml\">\n---\nHOSTNAME:  helloworld\n\nAWS_ACCESS_KEY:  '{{ VAULT_AWS_ACCESS_KEY }}'\nAWS_SECRET_KEY:  '{{ VAULT_AWS_SECRET_KEY }}'\n<\/pre>\n<p>Again, this is the <code>vars.yml<\/code> file we created previously for our host.<\/p>\n<p>Our playbooks and template files will reference <code>AWS_ACCESS_KEY<\/code> and <code>AWS_SECRET_KEY<\/code> which in turn will get their values from the vault.  In this manner you can quickly view your <code>vars.yml<\/code> and know which values you get from the vault (hence the prefix <code>VAULT_<\/code>).  <b>NB<\/b>:  This is purely a convention I&#8217;ve come to find to be extremely useful!<\/p>\n<h3>The Real Thing<\/h3>\n<p>To access S3 buckets we&#8217;re going to use the <code>s3cmd<\/code> package, so let&#8217;s add it to our playbook <code>apt<\/code> task:<\/p>\n<pre class=\"lang:yaml\">\n  - name:  Install base packages\n    apt:\n      name:  \"{{ item }}\"\n      state: present\n      update_cache: yes\n    with_items:\n      - htop\n      - zsh\n      - s3cmd\n<\/pre>\n<p>Then, in our AWS console we&#8217;ll create a new IAM user named <code>S3Reader<\/code> and give it <code>Programmatic access<\/code>.  For this user we can <code>Attach existing policies directly<\/code> and use the existing policy <code>AmazonS3ReadOnlyAccess<\/code>.  You should be given both an access key and a secret key.  We&#8217;ll plug these both in to our <code>vault<\/code> file and then encrypt it with <code>ansible-vault encrypt<\/code>.<\/p>\n<p>Even though <code>s3cmd<\/code> is installed, it needs a configuration file <code>.s3cfg<\/code>.  We&#8217;re going to create one with our credentials (the ones just obtained), again through the use of the <code>template<\/code> task.  Create a file in the <code>templates<\/code> directory called <code>s3cfg.j2<\/code> (make note we aren&#8217;t putting a dot in front of the file) with the following content:<\/p>\n<p>[code lang=text]<br \/>\n[default]<br \/>\naccess_key={{ AWS_ACCESS_KEY }}<br \/>\nsecret_key={{ AWS_SECRET_KEY }}<br \/>\n[\/code]<\/p>\n<p>Now, add the <code>template<\/code> task that will create the <code>.s3cfg<\/code> file:<\/p>\n<pre class=\"lang:yaml\">\n  # Create .s3cfg\n  - name:  Create .s3cfg\n    template:\n      src:   s3cfg.j2\n      dest:  \/home\/ubuntu\/.s3cfg\n      user:  ubuntu\n      group: ubuntu\n<\/pre>\n<p>Note the use of the <code>user<\/code> and <code>group<\/code> parameters for this task.  The file is being created in the <code>\/home\/ubuntu\/<\/code> directory and since our Ansible playbook is issuing commands as the <code>root<\/code> user (the <code>become_user<\/code> directive in the playbook we&#8217;ve glossed over thus far), it would have, by default, set the owner and group of the file to <code>root<\/code>.  We don&#8217;t want that, so we explicitly call out that the user and group should be set to <code>ubuntu<\/code>.<\/p>\n<p>Execute your playbook, this time including <code>--ask-vault<\/code> to ensure you get prompted for your vault password (we&#8217;ll show you in a minute how to set this in a configuration file).<\/p>\n<p>[code lang=text]<br \/>\n# ansible-playbook playbook.yml &#8211;ask-vault<br \/>\n[\/code]<\/p>\n<p>If everything was done correctly you&#8217;ll have a new file <code>.s3cfg<\/code> in your <code>\/home\/ubuntu<\/code> directory that has your S3 credentials (the ones you placed in the <code>vault<\/code> file).  Indeed, we can now run the <code>s3cmd ls<\/code>:<\/p>\n<p>[code lang=text]<br \/>\nubuntu@helloworld:~$ s3cmd ls<br \/>\n2016-10-01 14:06  s3:\/\/elasticbeanstalk-us-east-1-124186967073<br \/>\n2017-10-04 00:20  s3:\/\/iachievedit-cbbucket<br \/>\n2015-12-21 23:47  s3:\/\/iachievedit-repos<br \/>\n&#8230;<br \/>\n[\/code]<\/p>\n<p>Nice.<\/p>\n<h3>key.pem<\/h3>\n<p>If you run a website you&#8217;re undoubtedly familiar with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transport_Layer_Security#Digital_certificates\">SSL certificates<\/a> and the need to have one (or more).  You&#8217;re also familiar with the <a href=\"https:\/\/www.digicert.com\/blog\/where-is-your-private-key\/\">private key<\/a> for your certificate (unless you started your career with <a href=\"https:\/\/letsencrypt.org\/\">Let&#8217;s Encrypt<\/a> and it&#8217;s abstracted some of the &#8220;magic&#8221;).  That private key is, strictly speaking, a part of the server configuration, and we want everything on our server to be revisioned controlled, including that private key.  So let&#8217;s vault it.<\/p>\n<p>I have a private key named <code>key.pem<\/code> and the contents look like what you&#8217;d expect:<\/p>\n<p>[code lang=text]<br \/>\n# cat key.pem<br \/>\n&#8212;&#8211;BEGIN PRIVATE KEY&#8212;&#8211;<br \/>\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDXnM+DZ0tTn9M<br \/>\n38CRP2dwOuRJhH3xRc3WcTmL1S+EIxdFGIffy0+YVXU9Uzbn0XDl0TgtfZwBcMeU<br \/>\n&#8230;<br \/>\nwVumMxo0FpnH9Wb3QtVwlv1zxaW2VakRvdiZ31PkUWK7oCkFJPVj0yGe\/MDsCfQX<br \/>\nlCDhi\/ncV+DL\/FWXgPafUIA=<br \/>\n&#8212;&#8211;END PRIVATE KEY&#8212;&#8211;<br \/>\n[\/code]<\/p>\n<p>We don&#8217;t want to submit this as-is to revision control, so let&#8217;s encrypt it with <code>ansible-vault<\/code> and put it in a directory called <code>files<\/code>.<\/p>\n<p>[code lang=text]<br \/>\n# ansible-vault encrypt $HOME\/key.pem<br \/>\n# cd ansible-helloworld<br \/>\n# mkdir files<br \/>\n# cp $HOME\/key.pem files\/<br \/>\n[\/code]<\/p>\n<p>Note here that you will want to use the same vault password as you did for <code>vault<\/code>.  Also, the directory <code>files<\/code> (like <code>templates<\/code>) is a special name to Ansible.  Don&#8217;t call it <code>file<\/code> or <code>my_files<\/code>, etc., just <code>files<\/code>!<\/p>\n<p>Our <code>key.pem<\/code> will be copied to <code>\/etc\/ssl\/private<\/code>, so let&#8217;s create a task for that in the playbook:<\/p>\n<pre class=\"lang:yaml\">\n  # Copy key.pem\n  - name:  Copy key.pem\n    copy:\n      src:  key.pem\n      dest: \/etc\/ssl\/private\n      mode: 0400\n<\/pre>\n<p>If you run the playbook now and then check <code>\/etc\/ssl\/private\/key.pem<\/code> on your server you&#8217;ll see that Ansible <i>decrypted<\/i> the file and stored the decrypted contents; precisely what we wanted!<\/p>\n<h3>Your Vault Password<\/h3>\n<p>If you grow tired of supplying the vault password to <code>--ask-vault<\/code> each time you run a playbook, or even when using <code>ansible-vault edit<\/code> you can save the password in plain text in your home directory or other secure location.  This is an example of a file you would <i>not<\/i> submit to revision control!<\/p>\n<p>[code lang=text]<br \/>\n# export ANSIBLE_VAULT_PASSWORD_FILE=~\/.ansible_vault_pass.txt<br \/>\n# ansible-playbook playbook.yml<br \/>\n[\/code]<\/p>\n<p>The file <code>~\/.ansible_vault_pass.txt<\/code> contains the vault password in the clear.  Add the environment variable <code>ANSIBLE_VAULT_PASSWORD_FILE<\/code> to your shellrc file (e.g., <code>.zshrc<\/code>, <code>.bashrc<\/code>, etc.) to make things even simpler.<\/p>\n<h2>Vault Diffs<\/h2>\n<p>I found this one weird trick just the other day and it&#8217;s a lifesaver if you are responsible for reviewing changes to API keys, passwords, etc.  Courtesy of <a href=\"https:\/\/longair.net\/mark\/\">Mark Longair<\/a> on <a href=\"https:\/\/stackoverflow.com\/questions\/29937195\/how-to-diff-ansible-vault-changes\">Stack Overflow<\/a>.<\/p>\n<p>We have two &#8220;vaulted&#8221; files in our repository, a file named <code>vault<\/code> in our <code>host_vars<\/code> directory and <code>key.pem<\/code>.  We&#8217;d like to easily diff them for changes, so following along with the Stack Overflow post, create a <code>.gitattributes<\/code> file with:<\/p>\n<p>[code lang=text]<br \/>\nhost_vars\/*\/vault diff=ansible-vault merge=binary<br \/>\nfiles\/key.pem diff=ansible-vault merge=binary<br \/>\n[\/code]<\/p>\n<p>Then, set the diff driver for files with that <code>diff=ansible-vault<\/code> attribute:<\/p>\n<p>[code lang=text]<br \/>\n# git config &#8211;global diff.ansible-vault.textconv &quot;ansible-vault view&quot;<br \/>\n[\/code]<\/p>\n<p>With this, if you make changes to your vaulted files, a <code>git diff<\/code> will automatically show you the actual diff vs. the encrypted diff (which is, obviously, unreadable).<\/p>\n<h2>Final Thoughts<\/h2>\n<p>Credentials, API keys, passwords, private keys.  It&#8217;s been hammered in your head to not submit those to revision control systems, and rightfully so if they aren&#8217;t encrypted.  But these pieces of information are critical to the successful build of a server or environment, and part of the charm that Ansible brings is the ability to rebuild a server (or sets of servers) and not worry about whether or not you missed a step.  With the Ansible vault, however, you can encrypt this information and include it alongside the rest of your Ansible playbook; supply the vault password and watch the magic happen.<\/p>\n<h2>This Series<\/h2>\n<p>Each post in this series is building upon the last.  If you missed something, here are the previous posts.  We&#8217;ve also put everything on <a href=\"https:\/\/github.com\/iachievedit\/ansible-helloworld\">this Github repository<\/a> with branches that contain all of the changes from one part to the next.<\/p>\n<ul>\n<li><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/ansible-and-aws-part-1\/\">Part 1<\/a>\n<li><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/ansible-and-aws-part-2\/\">Part 2<\/a>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This is the third article in a series looking at utilizing Ansible with AWS. So far the focus has been Ansible itself, and we&#8217;ll continue that in this post and look at the Ansible Vault. The final version of the Ansible playbook are on the part3 branch of this repository. You will frequently come across [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3318,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[67],"class_list":["post-3352","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-ansible-vault-tutorial"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3352"}],"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=3352"}],"version-history":[{"count":8,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3352\/revisions"}],"predecessor-version":[{"id":3361,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3352\/revisions\/3361"}],"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=3352"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=3352"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=3352"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}