Ansible Vault - Keep Your Secrets Secret!

Ansible Vault - Keep Your Secrets Secret!

There will be scenarios when we need to supply passwords or access tokens within our Ansible playbooks or as part of Ansible Roles in variable files. Those will be present in cleartext and that poses a greater security risk.

Common types of "secret" which we use are passwords, SSH keys, SSL certs, API access tokens etc.

Ansible Vault allows us to encrypt variables and other files which contains sensitive content such as passwords or keys by providing a vault password.

To use Ansible Vault you need one or more passwords to encrypt and decrypt content. You can use any third-party tool such as a secret manager to store your vault passwords and can access them using a script.

Let us start some practical stuff.

I have a playbook here which creates an user account for a new joinee in our company and copies his/her Non Disclosure Agreement and his SSO credentials to his home directory.

---
- hosts: worker1
  become: yes
  tasks:
  - name: Create user account for Alice
    user:
      name: Alice
      comment: "Alice"
      shell: /bin/bash
      createhome: yes
      home: /home/Alice

  - name: A non-disclosure agreement
    copy:
      content: "This is an Agreement between Alice and the employer LearnCodeOnline. The Agreement is effective on your first day of employment with the Company.\n"
      dest: /home/Alice/Agreement

  - name: SSO Credentials
    copy:
      content: Alice@124!
      dest: /home/Alice/sso_creds

Now the problem here is our playbook contains the critical and confidential information which can be read by anyone who has access to our content repository. We want to protect this.

Encrypt an existing playbook or variable file

The command to encrypt an existing playbook or variable file is ansible-vault encrypt. It will prompt for providing vault password. This command can operate on multiple files at once.

vault $ ansible-vault encrypt user_creds.yml
New Vault password:
Confirm New Vault password:
Encryption successful

That's done, the file is now encrypted! Now If you try to edit the file directly, you'll just see encrypted text.

The default cipher is AES (which is shared-secret based).

vault $ cat user_creds.yml
$ANSIBLE_VAULT;1.1;AES256
61323636356165363839303366333232646431666537346330323966316464633935636564363434
6230306139303732373336646239343462373061386362620a396164336466366231633830333265
33353039393463333236653462323664346533343333623434376334343536323366393066636362
6363653435393266380a653863316366326262653539313430353737346530646364303966353661
38373061323336363830303236613863623637373533373636646161623461623533313034656166
36613436393262343466376362353131323163386632393538663534633538396133653333333865
32396535323837613265626430366130666135333438613864303133393063633033386364643866
30623130396331613539376639316566373737336265323939646366366134663632396230643436
33386231363764633262633565623635346137303462393437656261323634316133616634303332

Create a vault-encrypted file

To create a new playbook/variable file encrypted with Vault, you should use the ansible-vault create command. It will then open the file in your default text editor. You enter your data there and save & quit.

vault $ ansible-vault create vault_test.yml
New Vault password:
Confirm New Vault password:

Viewing an encrypted playbook or variable file

If you want to view an encrypted file, use the ansible-vault view command as shown below. You will have to provide the vault password in order to view it.

vault $ ansible-vault view user_creds.yml
Vault password:

VAULT-VIEW.png

Editing an encrypted playbook or variable file

If you want to edit an encrypted file, use the ansible-vault edit command as shown below. You will have to provide the vault password in order to view it.

vault $ ansible-vault edit user_creds.yml
Vault password:

VAULT-edit.png

Run an encrypted playbook file

Once a playbook file is encrypted you will not be able to run that as usual.

You will get an error as below.

vault $ ansible-playbook -i myinventory user_creds.yml -kK
SSH password:
BECOME password[defaults to SSH password]:
ERROR! Attempting to decrypt but no vault secrets found

There are two methods to run an encrypted file.

Method 1: Use --ask-vault-pass flag

By using the --ask-vault-pass flag Ansible will ask for the vault password so the playbook file can be decrypted correctly.

vault $ ansible-playbook -i myinventory user_creds.yml --ask-vault-pass -kK
SSH password:
BECOME password[defaults to SSH password]:
Vault password:

VAULT-ask-vault-pass.png

Method 2: Use --vault-password-file flag Providing vault password every time is annoying at times and not a feasible solution as well. And that makes our automation process as well These prompts make automation unsustainable.

To fix that we need a mechanism which decrypts playbooks during runtime, and that can be achieved by having a separate password file that contains the Ansible vault password and can be passed at run time.

vault $ ansible-playbook -i myinventory user_creds.yml --vault-password-file /home/ansible_user/.ansible_vault_pass -kK
SSH password:
BECOME password[defaults to SSH password]:

VAULT-vault-pass-file.png

Change Ansible Vault Password

If you want change the Ansible vault password, it can be done easily by using ansible-vault rekey command as shown below.

vault $ ansible-vault rekey user_creds.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful

Decrypting an encrypted playbook or variable file

If you want to decrypt an encrypted file, use the ansible-vault decrypt command as shown below. You will have to provide the vault password in order to view it.

vault $ ansible-vault decrypt user_creds.yml
Vault password:
Decryption successful

Now you can view the content of that file by a simple cat command.

VAULT-decrypt.png

Encrypt specific variables

With Ansible Vault we can encrypt specific variables as well. We no need to encrypt the whole playbook or variable files all the time.

This helps us in better tracking of version changes on Git as even just opening an encrypted file changes the encrypted hash.

Here are the commands to encrypt specific variables aka strings.

vault $ ansible-vault encrypt_string 'Alice@124!' --name 'alice_sso'
New Vault password:
Confirm New Vault password:
alice_sso: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66333766346464633037666164326163343235386538373265346133396162643934373862623765
          6235323762323137393661626331303938646162646666610a353365373332306661646461366237
          37626363656232316563363162336339323937623931623735643931623635343963633737313832
          6333303730346633610a393134646462626662636438623830316536656436306139616566313136
          3139
Encryption successful

You can see from the above output that the password has been encrypted with AES 256 encryption.

Now the question is how to use this encrypted output in our playbook.

To do that copy the entire encrypted code starting from !vault |. Go and edit your playbook file and put this encrypted block instead of the plain text password.

vault $ cat user_creds.yml
---
- hosts: worker1
  become: yes
  vars:
    alice_sso: !vault |
       $ANSIBLE_VAULT;1.1;AES256
       66333766346464633037666164326163343235386538373265346133396162643934373862623765
       6235323762323137393661626331303938646162646666610a353365373332306661646461366237
       37626363656232316563363162336339323937623931623735643931623635343963633737313832
       6333303730346633610a393134646462626662636438623830316536656436306139616566313136
       3139
  tasks:
  - name: Create user account for Alice
    user:
      name: Alice
      comment: "Alice"
      shell: /bin/bash
      createhome: yes
      home: /home/Alice

  - name: A non-disclosure agreement
    copy:
      content: "This is an Agreement between Alice and the employer LearnCodeOnline. The Agreement is effective on your first day of employment with the Company.\n"
      dest: /home/Alice/Agreement

  - name: SSO Credentials
    copy:
      content: "{{ alice_sso }}"
      dest: /home/Alice/sso_creds

Let us execute the playbook.

vault $ ansible-playbook -i myinventory user_creds.yml -kK --ask-vault-pass
SSH password:
BECOME password[defaults to SSH password]:
Vault password:

VAULT-vault-encrypt-string-2.png

It seems to be successful. Now verify the content if copied properly.

vault $ ansible -i myinventory worker1 -m shell -a "cat /home/Alice/sso_creds" -b -kK
SSH password:
BECOME password[defaults to SSH password]:
worker1 | CHANGED | rc=0 >>
Alice@124!

Great! It has copied the content as expected.

Ansible Vault Best Practices

Security is very crucial part these days and keeping passwords protected should be the most important thing while working on any project. Below are several best practices to use when utilizing Ansible Vault.

  1. ACL should be implemented on Password files : Make sure that only the appropriate users can access the password file.
  2. Password Files should never be kept within version control systems, such as GIT or Subversion. Store them in some external secure vaults. Such as Hashicorp's vault etc.
  3. Always use separate vaults : Normally, many different environments are in use. Therefore, it is best to separate the required credentials into the appropriate vaults.
  4. Frequent Rekeying : You should regularly rekey the vault passwords as it might leak while reuses. It limits the exposure.
  5. Keep a proper naming convention to use secrets! A suggestion would be to name all variables stored in the ansible vault with a secret_ prefix.

That's all for this article.

Hope you like the article. Stay Tuned for more.

Thank you. Happy learning!

Did you find this article valuable?

Support Learn Code Online by becoming a sponsor. Any amount is appreciated!