Ansible Random String Generator

To minimize configuration drift we can’t directly log into a system with admin privileges. Root is disabled through SSH and console on both servers and workstations. We can’t even directly log into a prod server at all. Every admin level task is done through Tower. Because of this, having a root password that’s usable and remember-able is essentially pointless (and insecure anyway).

I created an Ansible module to generate a random string based on a size parameter. This way any time the provisioning playbook is run against a system it will generate a new random password for the root user. If for some reason we need to triage a system, we can grant local admin access through tower for that time and then revoke it later so it’s audited.

Here’s the important bits of the module:

import string
import random 
from ansible.module_utils.basic import AnsibleModule


def random_generator(size, chars=string.ascii_letters + string.digits + '$#&@'):
    return ''.join(random.choice(chars) for _ in range(size))

module = AnsibleModule(
    argument_spec = dict(
    size = dict(required=True, type='int')
    )
)
size = module.params.get('size')

try:
    random_generator(size)
    success = True
    ret_msg = str(random_generator(size))
except KeyError:
   success = False
   ret_msg = "Error"

if success:
    module.exit_json(msg=ret_msg)
else:
    module.fail_json(msg=ret_msg)


if __name__ == "__main__":
  main()

Here’s an example playbook. Obviously in prod you wouldn’t have it display the string, this is just as an example.

- name: generate password 
  random_generator:
    size: 40
  register: pass

- name: print password [not in production]
  debug:
    var: pass

- name: set root password
  user:
    name: root
    password: "{{ pass.msg|password_hash('sha512') }}"

And here’s the output from a playbook run:

random

Another option is to use Jinja filters so you don’t need to create a module (I was doing it for practice). This way you just need to pass something into the password_hash filter. Here’s an example:

- name: generate random password
  user:
    name: root
    password: "{{ ansible_fqdn | password_hash('sha512') | password_hash('sha512') }}"

This will take the value for ansible_fqdn and pass it into the sha512 hash filter. This gives you a random 107 character password. Then it passes that string into the sha512 hash filter again to actually set the hash to that value.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s