Security is important, and at my location, we don’t have centralized password management. Meaning, I can’t really just change my password one place, then it’s updated everywhere. We’re mostly a linux shop, but also have some openbsd. The notion to create a centralized password solution has been kicked around.. in the end, we end up with “no time” or “too many things on fire”.
In the meantime, when I update my password I have to do it manually across 50+ servers. Inevitably, I end up missing on and down the road I find it. I also don’t use short passwords.. usually at least 32 characters.. and I change them monthly. I’m not paranoid, I swear!
This is basically a pain.. So what’s the easy solution? Use ansible to do it. That being said, the user module in ansible doesn’t make it perfect either.
1. The user module doesn’t use plain text passwords, so you have to get a hash first, then save it to the playbook, then run it.
2. The user module will CREATE an account for you with the specified password if it doesn’t exist.. meaning, you have to be very specific about the machines you run it against, or it will create that user on every machine, and not just update the password on the machines that have it. UGG.
I don’t like those issues. I wanted a more intuitive way to do it, that made it easier for myself, and allowed others to use without asking me how to do it every time.
So I’ve created a script that does the magic for me.
This script is easy.. when it is ran, it will prompt you for the USER you want to change the password for and the PASSWORD you want to change it to. It will then get the encrypted password to use.
When it connects to each machine, it will look to see if your user exists or not, and then if it does, it will update the password for that user. Like so:
jsmith$ ansible-playbook -bK global_password_change.yml
BECOME password: (doesn’t display anything)
Enter Username: jsmith
Enter Password: (doesn’t display anything)
PLAY [localhost] *************************************************************************************
TASK [set_fact] *************************************************************************************
ok: [localhost]
PLAY [all] *************************************************************************************
TASK [set_fact] *************************************************************************************ok: [test1.local]
ok: [test2.local]
ok: [test3.local]
ok: [test4.local]
ok: [test5.local]
TASK [Check for user jsmith] *************************************************************************************ok: [test1.local]
fatal: [test2.local]: FAILED! => {"changed": false, "msg": "One or more supplied key could not be found in the database."}
...ignoring
ok: [test3.local]
ok: [test4.local]
ok: [test5.local]
TASK [Set jsmith’s password.] *************************************************************************************changed: [test1.local]
skipping: [test2.local]
changed: [test3.local]
changed: [test4.local]
changed: [test5.local]
PLAY RECAP *************************************************************************************test1.local : ok=3 changed=1 unreachable=0 failed=0 skipped=0
test2.local : ok=2 changed=0 unreachable=0 failed=0 skipped=1
test3.local : ok=3 changed=1 unreachable=0 failed=0 skipped=0
test4.local : ok=3 changed=1 unreachable=0 failed=0 skipped=0
test5.local : ok=3 changed=1 unreachable=0 failed=0 skipped=0
As you can see, the jsmith user didn't exist on test2.local, so it was skipped.
Here is the playbook.. hope this helps someone!
---
########################
##
## ansible-playbook -bK global_password_change.yml
##
#######################
- hosts: localhost
become: no
gather_facts: no
vars_prompt:
- name: username
prompt: "Enter Username"
private: no
- name: "NEWPW"
prompt: "Enter Password"
private: yes
tasks:
- set_fact:
USERNAME: "{{ username }}"
ENCPW: "{{ NEWPW | password_hash('sha512') }}"
- hosts: all:!openbsd:!network
gather_facts: no
ignore_errors: yes
tasks:
- set_fact:
USERNAME: "{{ hostvars['localhost']['USERNAME'] }}"
ENCPW: "{{ hostvars['localhost']['ENCPW'] }}"
- name: Check for user {{ USERNAME }}
getent:
database: passwd
key: "{{ USERNAME }}"
register: user_exists
- name: Set {{ USERNAME }}'s password.
user:
name: "{{ USERNAME }}"
update_password: always
password: "{{ ENCPW }}"
when: (user_exists.failed == false)
Thank you. This was very handy.
Ansible’s behavior of automatically creating accounts when I just wanted to change a password or other attribute had bugged me too…
LikeLiked by 1 person