Automate password changes with Ansible

Everyone should be changing root passwords from time to time on their infrastructure. It’s something we all put off as long as possible for various reasons whether they be the hatred of learning a new password or just sheer laziness. Needless to say, it is a necessity of being an admin of ANY system, hope or otherwise.

One way to get more people on the bandwagon of security and password changes is to make them as seamless as possible. Once again, I turn to Ansible to touch all my boxes for me so I can continue listening to my hero Henry Rollins wax poetic with Pete Holmes on his podcast.

It is worth noting that I do all my admin work via Ansible on my Macbook Pro. As such, I will assume you already have Ansible running on Mac OS X as well as Python.

Within Ansible, we will leverage the ‘user’ module to quickly change the password for the account root on all our servers. Ansible doesn’t allow you to pass a cleartext password through its playbooks so you have to install a password hashing library to be leveraged by Python.

To install the library:

Generate a hash for the new root password you want:

Simple Ansible playbook:

And that’s all there is to it. Execute this playbook against whatever servers you wish and you’re done. This is also a useful addition to your bootstrap playbooks for new provisioning!

2 thoughts on “Automate password changes with Ansible

  1. Instead of relying on the python command to build the password hash, what I do is put the password in a variable (“root_pw”) inside of an Ansible vault file, then have the Jinja2 parser hash it for me:

    – name: Update root password for the environment
    user:
    name: “root”
    update_password: always
    password: “{{ root_pw|password_hash(‘sha512’) }}”

    1. A minor update to my previous code. In cases where the same password is used across different systems (or different accounts), the password_hash() uses a random salt each time it runs so it’s not idempotent even if the password is the same.

      Adding a static salt to the play is no better because the same salt and encrypted password would be deployed and lead to other issues (potential for off-line hash attempts, etc).

      I’m now experimenting with this user module line for the password:

      password: “{{ item.password|password_hash(‘sha512’, 65534|random(seed=inventory_hostname)|string) }}”

      This picks a random number between 0 and 65534 using the the hostname of the system as the seed for random(), and finally converting it to a string (which password_hash() required).

      Now when it is run each time, the hash is unique between systems and even if the password is the same across multiple servers, a casual view of the systems password files won’t betray that fact.

Leave a Reply

Your email address will not be published. Required fields are marked *