What is the current state of the art for user management with Ansible?

I have been using Ansible, to great success, for ~3 years now for managing an ever-growing flock of linux systems. Before diving into my question, I need to set some context.

As part of my day job, I do systems design, deployment, and maintenance for various companies that all operate under the umbrella of a single venture/incubator company. There is a lot of cross-pollination among our portfolio companies, and as such, we cannot say that only users A, B, and C will need access to company X's systems. They may also need access to company Y's systems as well. This is complicated by the fact that each company's ansible environment lives in a different git repository. This means that there is a lot of code duplication for deploying users to different company's systems. I end up copy/pasting blocks of code like this around to deploy users to a certain company's systems:

- name: add several users
  user: >
    name={{ item.name }}
    state=present
    groups={{ item.groups }}
    uid={{ item.uid }}
    password={{ item.password }}
    shell=/bin/bash
  with_items:
    - { name: 'user1', groups: 'ssh-access,sudo', uid: '501', password: '<redacted>' }
    - { name: 'user2', groups: 'ssh-access,sudo', uid: '502', password: '<redacted>' }
  tags: users

- name: authorized_keys - user1 
  action: authorized_key user=user1 key="{{ lookup('file', 'pubkeys/user1') }}" manage_dir=yes
  tags:
    - pubkeys
    - users

- name: authorized_keys - user2 
  action: authorized_key user=user2 key="{{ lookup('file', 'pubkeys/user2') }}" manage_dir=yes
  tags:
    - pubkeys
    - users

This worked OK when I had a <5 users to manage, but as the user base grows, it becomes more and more onerous to keep things up to date with key rotation, new passwords, etc.

With the backstory and context set, on with my question:

Assuming that using a centralized authentication system (LDAP, etc.) is not an option, how could I tackle creating a centralized user database that various ansible playbooks could consume? I would love to be able to maintain one central list of users, uids, password hashes, and public keys, and then be able to deploy the users (with custom per-host group memberships) to each company's hosts.

I'm envisioning some sort of play structure like:

- name: Deploy users
  user_management:
    - { name: "user1", groups: "sudo" }
    - { name: "user1", groups: "sudo" }

...where each user's uid, hash, and public key would be pulled from the central list and deployed as usual.

So, what options do I have? I've been mulling this around for quite a while, and haven't been able to come up with anything better than what I'm already doing. Could I do something with a custom facts file to hold my user database?


You need to separate your plays and your data.

I have a single repo with all my roles, facts, etc that deploy to a wide range of customer systems. I ensure all roles are resuable and free of data. In host_vars/fqdn.yml or group_vars/customer_name.yml I define the data that is unique to that customer or remote system.

Most of my roles are expanded over time as needed and instead of doing everything from roles/foo/main.yml I have roles/foo/debian-foo.yml and roles/foo/openbsd-foo.yml that are only included when the OS or another condition matches.

Simplified, roles/adduser/main.yml could include this:

- user: name={{ item.name }} ...
  with_items:
  - customer_users

and group_vars/ACME.yml could include this:

customer_users:
- name: sausage
   uid: 32153
- name: beans
   uid: 1024

In your case it may be OK to have separate ansible environments in each their git repo as long as the roles folder is a shared submodule that is identical across all your customers.