Ansible: How to encrypt some variables in an inventory file in a separate vault file?

EncryptionAnsibleAnsible PlaybookAnsible Vault

Encryption Problem Overview


The settings

Consider an Ansible inventory file similar to the following example:

[san_diego]
host1
host2

[san_francisco]
host3
host4

[west_coast]
san_diego
san_francisco

[west_coast:vars]
db_server=foo.example.com
db_host=5432
db_password=top secret password

The problem

I would like to store some of the vars (like db_password) in an Ansible vault, but not the entire file.

How can a vault-encrypted ansible file be imported into an unencrypted inventory file?

What I've tried

I have created an encrypted vars file and tried importing it with:

include: secrets

To which ansible-playbook responded with:

ERROR: variables assigned to group must be in key=value form

Probably because it tried to parse the include statement as a variable.

Encryption Solutions


Solution 1 - Encryption

Since Ansible 2.3 you can encrypt a Single Encrypted Variable. IMO, a walkthrough is needed as the doco's seem pretty terse.

Given an example of: mysql_password: password123 (within main.yml)

Run a command such as:

ansible-vault encrypt_string password123 --ask-vault-pass

This will produce:

    !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336462626566653063336164663966303231363934653561363964363833
3136626431626536303530376336343832656537303632313433360a626438346336353331
Encryption successful

paste this into your main.yml:

mysql_password: !vault |
    $ANSIBLE_VAULT;1.1;AES256
    66386439653236336462626566653063336164663966303231363934653561363964363833
    3136626431626536303530376336343832656537303632313433360a626438346336353331

run playbook:

Ie, ansible-playbook -i hosts main.yml --ask-vault-pass

Verify via debug:

- debug:
    msg: "mysql Pwd: {{ mysql_password }}"

Solution 2 - Encryption

If your issue is to have both unencrypted and encrypted vars files per group_hosts.

You can use this ansible feature : http://docs.ansible.com/ansible/playbooks_best_practices.html#best-practices-for-variables-and-vaults

group_vars/ 
  san_diego/
    vars.yml  # unencrypted yaml file
    vault.yml # encrypted yaml file

Ansible will read automatically vault.yml as encrypted yaml file.

Update : The solution below is also good solution (since Ansible 2.3)

Solution 3 - Encryption

At this time with Ansible 2.3 it's possible to have in a plain yaml both encrypted and unencrypted variables. The format of the variables encrypted is like this:

dbServer: PlainDatabaseServer
dbName: PlainDatabaseName
dbUser: PlainUser
dbPasswd: !vault |
      $ANSIBLE_VAULT;1.1;AES256
      63633363616165656538656537323835343634633063386137353637646663333939623464666437
      6263383933656635316436313934366564316337623435350a386362613838373363393534383232
      39663162363066313431623466363763356466376538613532333731613538373431623239626330
      6463373238366630360a623566616535376339326431363465663431623462356238636333306663
      6439

You can encrypt the variable using a password or a password file with the statement:

ansible-vault encrypt_string "dummy" --vault-password-file pass-ansible.txt

This statement returns the text shown in dbPasswd variable in the yaml above.

To run a playbook that uses the encrypted variable just add the following var:

 ansible-playbook playbooks/myplaybook --vault-password-file pass-ansible.txt

Or you can do the same with --ask-vault-pass which ask you for the password when executing the playbook:

ansible-playbook playbooks/myplaybook --ask-vault-pass

Solution 4 - Encryption

You can do something similar to this.

  1. Create a password file (a plain text file with your password on a single line)

  2. Create an ansible.cfg in your ansible project folder

     [defaults]
     vault_password_file = <path/to/your/password/file>
    
  3. Create a playbook file (e.g. playbook.yml)

      - name: my ansible playbook
        hosts: 127.0.0.1
        vars_files:
          - 'vars.yml'
        tasks:
          - name: print secure variable
            debug: msg="my secure variable '{{ my_secure_variable }}'"`
    
  4. Create a variable file (e.g. vars.yml)

     my_secure_variable: "X_my_secret_X"
    
  5. Encrypt the variable file (from the ansible project location with the ansible.cfg)

     ansible-vault encrypt vars.yml
    
  6. Run your playbook (from the ansible project location with the ansible.cfg)

     ansible-playbook -i "localhost," playbook.yml
    

You should get output similar to:

$ ansible-playbook playbook.yml -i 'localhost,'

PLAY [my ansible playbook] ****************************************************

GATHERING FACTS ***************************************************************

ok: [127.0.0.1]

TASK: [print secure variable] *************************************************

ok: [127.0.0.1] => {
    "msg": "my secure variable 'X_my_secret_X' "
}

PLAY RECAP ********************************************************************

127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0

Solution 5 - Encryption

It depends on your workflow. You can use a group_vars file as per Sebastian Stigler suggestion or if you want to use an inventory file, you can just add another "ini-like" file in an inventory directory and encrypt it.

$ mkdir my_inventory/
$ cat >> hosts << EOF
[san_diego]
host1
host2

[san_francisco]
host3
host4

[west_coast]
san_diego
san_francisco
EOF

$ cat >> inventory_crypted_vars << EOF
[west_coast:vars]
db_server=foo.example.com
db_host=5432
db_password=top secret password
EOF

Then, use -i my_inventory/ in your command line, or create a local ansible.cfg containing:

[defaults]
hostfile = ./my_inventory/

and you should be set. Ansible will merge both files at run time.

Use ansible-vault encrypt my_inventory/inventory_crypted_vars before committing and you're set.

You probably want a pre-commit hook to ensure that you're not committing unencrypted version of the file. For instance a pre-commit hook like this would do the trick (adjust FILES_PATTERN accordingly).

Solution 6 - Encryption

You can use group_vars (see http://docs.ansible.com/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable).

Create a subdirectory in your playbook named group_vars.
There you create a file named west_coast and put the following entries in it:

---
db_server: foo.example.com
db_host: 5432
db_password: top secret password

This file can then be converted to an ansible vault.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdam MatanView Question on Stackoverflow
Solution 1 - Encryptionwired00View Answer on Stackoverflow
Solution 2 - EncryptionAntoineView Answer on Stackoverflow
Solution 3 - EncryptionV. MorateView Answer on Stackoverflow
Solution 4 - EncryptiongrandmaView Answer on Stackoverflow
Solution 5 - EncryptionleucosView Answer on Stackoverflow
Solution 6 - EncryptionSebastian StiglerView Answer on Stackoverflow