---
title: "Updating passwords with Ansible"
date: 2019-01-19T00:00:00+01:00
draft: false
share: false
---

I've recently migrated from [KeePassXC](https://keepassxc.org/) to [Bitwarden_RS](https://github.com/dani-garcia/bitwarden_rs) (which I highly recommend, by the way) to manage my passwords.

I figured it was an opportunity to update passwords I hadn't changed in... *years*. My Linux users' passwords were among those.

Instead of updating them manually on each machine, I thought there might be a way to do so with Ansible, and since it turns out there is, I thought I might as well share it here!

**Please be careful when it comes to password modification automation. You might end up locking yourself out of your servers.**

## Generating password hashes

First thing first, we'll need to generate `passwd` compatible password hashes for our users.

In this example, I'll generate a hash for the *P@ssw0rd* password :
```
mkpasswd -m sha-512
Password:
$6$wAVPV.Coc$o3FNxs9EPgXF54hv1BeKtfoMnLwE5VATL71jlHQHeVyCaevnnxfSp/x1UbJ00F3qlyyfUAmscuGXImoHmXBFa.
```

You might notice you'll get a different result if you run the same command again :
```
mkpasswd -m sha-512
Password:
$6$iFBWJD3300m$CYZJRSfZ4scHYNI9ggqe8WYef7Qym2Oi5ycgb64VsbU3.WM1GoJYlh1sawENTD7nrXVCthvs8LRPw1CVjzkP71
```

That's because, unless you specify it, the salt used by `mkpasswd` to encrypt the password is random.

You can choose a salt with the `-S` parameter if you want :
```
mkpasswd -m sha-512 -S hmmmsalt
Password:
$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/

mkpasswd -m sha-512 -S hmmmsalt
Password:
$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/
captainark@heimdall ~ %
```

## Ansible vault

Passwords are *secrets*. Even if there are hashed, you don't want them to be publicly accessible.

If, like me, your Ansible configuration is in a git repository, you should not commit them in an unencrypted file.

Ansible offers a way to encrypt a file containing variables with the `ansible-vault` command.

We first have to create a vault :
```
cd /your/ansible/project
mkdir -p group_vars/all/
ansible-vault create group_vars/all/vault.yml
New Vault password:
Confirm New Vault password:
```

As you can see, the command will ask you to provide a password for the vault. It will then open the file in your `$EDITOR` (that'll be `vim` if you're a cool kid).

The file is like any Ansible vault file. I'll create a variable for the `root` and `captainark` users in my case :
```yaml
vault_captainarkpwd: "$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/"
vault_rootpwd: "$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/"
```

An [Ansible best practice](https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#variables-and-vaults) is to prepend all variables that are stored in a vault with the `vault_` prefix. It makes where they are stored clear when reading through a playbook.

Once saved, if you try to `cat` the file, you won't be able to see its actual content :
```
cat group_vars/all/vault.yml
$ANSIBLE_VAULT;1.1;AES256
32393530376537323233633636316330373136316265316662646437393533376135666232656366
3335623863333865666133666634633233616531636634370a663965356466383039326262313066
62633434396465313666333032663130343434326665386333323733633062613832653530393761
6333653338393231640a623938616634626462653965613766313335386136333362313033363735
64313662623039363365326639633231306335366432306361613837656364356464373837656565
61636538376262333762376235306337303531386638643632316361323037393230366537393132
35373861373863613666303531353737373130353330643535353238633665653236633130653064
39346330326566633262613535386633613565633566623934613066613238353739386133346535
64643762333462653966633363653439633037373161316663646261663764393332653732656335
61373462666336343533333162663637656236333739633065623939323937663137376431346231
38653338386539383663613230656165313566363733396134386366626430313235343264643938
64306163353437366362616166666565316663366163346565313436343537366330363932303038
37653138643165353138393466343063666535313933663066633832353331643838356539303533
61626237356538353261326136613239336662346337363331393037623863623433336432353461
32356136316339623139346330333235363331653634373836333730653436636563323134616337
36643433356133376138
```

To view the variables in the file, you can use the `ansible-vault view` command :

```yaml
ansible-vault view group_vars/all/vault.yml
Vault password:
vault_captainarkpwd: "$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/"
vault_rootpwd: "$6$hmmmsalt$RwZR2r9W5cSv5bVgeSFPX0rJiovWOD5kMDFey1xPR6JtasqQZqHTiuW5JoQ.0VCW6oNHJlgOYJ.auhl82gfX8/"
```

To edit the vault's content, you can use the `ansible-vault edit group_vars/all/vault.yml` command.

## The playbook

Now that our vault is ready, all that's left is to run the following playbook :

```yaml
---
- hosts: all
  become: yes
  become_method: sudo

  tasks:
  - name: PASSWORDS | Check if the captainark user exists
    shell: id -u captainark
    register: captainark_exists
    ignore_errors: true

  - name: PASSWORDS | Update captainark password
    user:
      name: captainark
      password: "{{ vault_captainarkpwd }}"
      update_password: always
    when: captainark_exists.rc == 0

  - name: PASSWORDS | Create captainark user
    user:
      name: captainark
      password: "{{ vault_captainarkpwd }}"
      shell: /usr/bin/zsh
      uid: 1000
      groups: adm,sudo,apps
    when: captainark_exists.rc != 0

  - name: PASSWORDS | Update root password
    user:
      name: root
      password: "{{ vault_rootpwd }}"
      update_password: always
```

I've called this playbook `passwords.yml`. To run it, I simply execute the following command :
```
ansible-playbook passwords.yml --ask-vault-pass
```

The command asks for the vault password to decrypt its contents.

The playbook will first check if the `captainark` user exists, and it will update its password if it does. If it doesn't, the user will be created with the defined options.

Since the `root` user should always exist, the playbook changes its password without checking.

**N.B. :** If you've decided to store your vault somewhere else, you might need to add a task at the beginning of the playbook to load it, like so :

```yaml
  - name: PASSWORDS | Load the vault
    include_vars: /path/to/your/vault.yml
```

## Conclusion

That's all! As always, I hope someone finds this article useful!

If you do, please let me know in the comments here, on [Twitter](https://twitter.com/captainark) or on the [Fediverse](https://social.captainark.net/users/captainark/)!

Also, if you have any questions, feel free to hit me up on my [Rocket.Chat](https://chat.captainark.net) instance! Hopefully I'll write about it in the future!
