Password management using ansible-vault
Tags: ansible, password, secrets, management
Published: 2022-07-03 09:19:36

Good Day Everyone!

Here is another post out of my learning these days on using ansible-vault. 

I have been doing KodeKloud performance based tasks for a while and one of the tasks involved creating users and groups using ansible playbook. Passwords for the users have to be managed using ansible-vault.

I have not used ansible-vault earlier, so it's definitely a fun learning.

## Task

Create an ansible playbook to perform the following task.

1. Create users and groups given in the file users.yml
```
# cat /home/centos/users.yml
admins:
  - rob
  - tim
developers:
  - mark
  - john
```
2. For users in "_admins_" group, home directory should be created in the "_/home/_" directory.

3. For users in "_developers_" group, home directory should be set to "_/var/www_". Also it should not create any home directory with username in "_/var/www/_".

4. Password of users of admins group should be set to "_adminpassword_".

5. Password of users of developers group should be set to "_developerpassword_".

6. To encrypt the password, make use of ansible-vault secret file which is located at "_/home/centos/vault/password.txt_".

## Solution

In order to complete the task, we'll need to look and complete the task from the last to first.

- Passwords for the users are supposed to be encrypted with the ansible-vault. Therefore, we need to make sure that the ansible.cfg file is configured with the vault password file.

**Note:** Password for ansible-vault must be kept at a safe location. I'm showing it for the sake of the exercise.

```
[centos@localhost vault]$ pwd
/home/centos/vault
[centos@localhost vault]$ cat password.txt 
redhat
[centos@localhost vault]$ grep vault_password_file /etc/ansible/ansible.cfg 
vault_password_file = /home/centos/vault/password.txt
```

- There are two strings given in the tasks points 4 & 5 which are required to be encrypted with ansible-vault and those encrypted password would then be used during the user creation process.

For this purpose, we will use ansible-vault command to encrypt the string. We will also name the encrypted string for admins user password to a variable called "admin_pwd" and for developers user password to a variable called "developer_pwd".

**Note:** Important thing to ensure here is that the variable name must not contain the hyphen "-". Otherwise, the password won't work for the user. This is from my experience while attempting the task.

```
[centos@localhost ~]$ ansible-vault encrypt_string 'adminpassword' --name 'admin_pwd'
admin_pwd: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          30323636346564376638376364386335646463626662646535633863663265383563383238363236
          3863623764366533313162346335653736323438656331370a373263643733623766373264613530
          37333537663761383232313564343131663438303966386336663733633332343030633866613737
          3139373661623137650a303936363562383335613437653365323737373430363831633164366334
          3336
Encryption successful
[centos@localhost ~]$ ansible-vault encrypt_string 'developerpassword' --name 'developer_pwd'
developer_pwd: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          61656230636461653861356530346230386461646436636533366665346264366666623264383130
          3539343339626664383731363665306238386434306435620a653139353735366330336466346635
          39623832663063373738306238343433396661373566653232383236613662343437313832326562
          3166616232663137380a343133353439396261323939323365313339663464393266373437303335
          36323633306333386435616639653730396266616334643536643936623465383131
Encryption successful
```

- As mentioned in the task point 3, users under developer group must have their home directory set to "/var/www". Let's ensure that directory is created into the system and appropriate permissions are applied to the directory.

```
[centos@localhost var]$ pwd
/var
[centos@localhost var]$ ls -ld www
drwxrwxrwx. 2 root root 27 Jul  2 17:53 www
```

Observe the permissions on the directory www. If it's not set, then use below command to update the permissions.

```
[centos@localhost var]$ sudo chmod 777 www
```

- Now that we have configured the vault_password_file, created the variables containing password for the users under admins and developers group and created the home directory for developers users, let us start working on creating the playbook to create the groups and users

```
[centos@localhost ~]$ cat playbook.yml 
---
- hosts: localhost
  vars_files: /home/centos/users.yml
  vars:
    admin_pwd: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          30323636346564376638376364386335646463626662646535633863663265383563383238363236
          3863623764366533313162346335653736323438656331370a373263643733623766373264613530
          37333537663761383232313564343131663438303966386336663733633332343030633866613737
          3139373661623137650a303936363562383335613437653365323737373430363831633164366334
          3336
    developer_pwd: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          61656230636461653861356530346230386461646436636533366665346264366666623264383130
          3539343339626664383731363665306238386434306435620a653139353735366330336466346635
          39623832663063373738306238343433396661373566653232383236613662343437313832326562
          3166616232663137380a343133353439396261323939323365313339663464393266373437303335
          36323633306333386435616639653730396266616334643536643936623465383131
  tasks:
  - name: create group
    group:
      name: "{{ item }}"
      state: present
    loop:
      - admins
      - developers
  - name: create admins users
    user:
      name: "{{ item }}"
      create_home: yes
      groups: admins, wheel
      append: yes
      password: "{{ admin_pwd | string | password_hash('sha512') }}"
    loop: "{{ admins }}"
  - name: create developers users
    user:
      name: "{{ item }}"
      create_home: yes
      home: /var/www
      groups: developers
      append: yes
      password: "{{ developer_pwd | string | password_hash('sha512') }}"
    loop: "{{ developers }}"
```

> - vars_files is pointing to the file users.yml which contains the groups and users information.
> - vars is pointing to the variables which were created using the ansible-vault command
> - tasks list consists of the task first to create the groups given in the users.yml, then create the users using group and user modules of the ansible respectively.
> - create_home=yes -> home directory is supposed to be created in the /home
> - users in the admins group are also supposed to be sudo user, this is why groups: admins, wheels & append: yes have been added into the task. Similarly for users in the developers group, groups: developers
> - password for users in the admins and developers should be set to admin_pwd and developer_pwd variables created during encrypt string step. Password strings are also required to be hashed so as not to expose during the playbook execution or otherwise.
> - both user creation tasks consists of loop where values under the admins and developers list (array) are being used from users.yml

- Now it's time for playbook execution. Execute the ansible-playbook command to implement changes from playbook.yml

```
[centos@localhost ~]$ ansible-playbook playbook.yml 

PLAY [localhost] *************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************
ok: [localhost]

TASK [create group] **********************************************************************************************************
ok: [localhost] => (item=admins)
ok: [localhost] => (item=developers)

TASK [create admins users] ***************************************************************************************************
changed: [localhost] => (item=rob)
changed: [localhost] => (item=tim)

TASK [create developers users] ***********************************************************************************************
changed: [localhost] => (item=mark)
changed: [localhost] => (item=john)

PLAY RECAP *******************************************************************************************************************
localhost                  : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[centos@localhost ~]$ 

```

**Note:** If you'd like to see the detailed output of the playbook execution, use "-vv" option with the ansible-playbook command.

`# ansible-playbook playbook.yml -vv`

## References

- [Ansible user module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html)
- [Ansible group module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/group_module.html)
- [Ansible vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html)
- [Ansible variable](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html)