Using Mac keychain to store and retrieve Ansible vault passwords

Mac Keychain App logo

When using Ansible for my home lab, an initial problem was about how to keep sudo passwords for my various machines in an practical manner (I really don’t like the idea of password-less sudo even in my homelab).

The remote users used for my ansible logins to each of my machines are different, and can be managed via the inventory file. But the sudo passwords for them are not the same, and it is pretty annoying to enter them while running ansible on the command line.

I decided to find a way to make this a little less annoying.

Storing the encrypted sudo passwords

I first started keeping the individual sudo passwords for my hosts in an ansible-vault encrypted file outside my repo. Decrypted, they would look like this:

$ ansible-vault view ~/.ansible/sudo_passwords.yml
---
become_passwords:
  host1: host1password
  host2: host2password

Using the encrypted sudo passwords automatically

To use these passwords in my playbooks transparently, I did two things:

  1. I put this in a group_vars/all/111_setpasswords.yaml file. This will now make Ansible look for sudo passwords from this variable that is kept inside the encrypted file:

    ---
    ansible_become_pass: '{{ become_passwords[inventory_hostname] }}'
    
  2. Now to make Ansible read the encrypted file right at the beginning, I put a symlink to my encrypted vault file in group_vars/all directory as well.

    $ ln -sf ~/.ansible/sudo_passwords.yml group_vars/all/000passwords.yml
    

By this point, you should be able to use Ansible by providing a single password (for the encrypted file) and still use unique sudo passwords for each of your machines.

$ ansible --ask-vault-pass  ubuntu -a "free -m"
Vault password:
host1 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:          32005        4677       22684          25        4643       27052
Swap:             0           0           0
host2 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:          15884        1088       12706           1        2089       14619
Swap:             0           0           0

Avoiding entering vault password everytime

I work on my playbooks iteratively, so I run ansible or ansible-playbook frequently. I still was mildly annoyed having to enter the vault password every time.

Fortunately, Ansible provides a way to bypass this. If you set an environment variable ANSIBLE_VAULT_PASSWORD_FILE and point it to a shell script, Ansible will execute the script and use the output as the password.

So I created a pretty simple script which would do the same and put it in ~/.ansible/vault-env.

There is nothing sensitive about the script, so you can actually put this inside the repo as well. But since I run the same playbooks from checkouts in different paths on different machines, I decided to put the script at a consistent location of each control node to make the next step easy.
$ cat ~/.ansible/vault-env
#!/bin/bash
echo $ANSIBLE_VAULT_PASSWORD

Now I needed a way to set the environment variable without exposing it in bash history. For this, I created a support script which is checked into the repo.

$ cat support_scripts/set_vault_password_env.sh
#!/bin/bash
export ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault-env
export no_proxy='*'

read -sp "Vault password:" ANSIBLE_VAULT_PASSWORD
export ANSIBLE_VAULT_PASSWORD

Now whenever I have some Ansible work to do, I change directory to my playbook repo, source this script and I don’t have to enter passwords again for the rest of the session:

$ source support_scripts/set_vault_password_env.sh
Vault password:

$ ansible ... 

$ ansible-playbook ...

Making it even simpler on Mac

On Mac, this process can be made even simpler by storing the password in the keychain and avoiding entering it ever!

Add password to keychain

Add the password to keychain. You willl have to run this script only once per mac machine you work on.

$ cat support_scripts/mac/keychain_set_vault_password.sh
#!/bin/bash

read -sp "Vault password:" ANSIBLE_VAULT_PASSWORD
echo
security add-generic-password -U -a $USER -s ansible-vault -w "$ANSIBLE_VAULT_PASSWORD"

Run it directly (i.e. you don’t source it).

Point ANSIBLE_VAULT_PASSWORD_FILE to a mac specific script

$ cat ~/.ansible/vault-env-mac
#!/bin/bash
security find-generic-password -a $USER -s ansible-vault -w

And this is the file you source before your Ansible sessions.

$ cat support_scripts/mac/set_vault_password_env_from_keychain.sh
#!/bin/bash
export ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault-env-mac
export no_proxy='*'

Now you don’t have to remember the vault password. The keychain will keep it safe.

This is a simple setup for homelab where all my vault encrypted files are encrypted by the same password. For production, you abviously will use vault-id to set a different passwords for encrypted files for different domains.
techmacansible
Installing a specific version of a Homebrew Formula Disabling comments and Google Analytics