captainarkdotnet/content/post/2019-01-19-updating-passwor...

172 lines
6.8 KiB
Markdown

---
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!