title: Granularly manage system users with Ansible
body: <p>I am using an <strong>Ansible</strong> playbook to manage users (taken from <a href="https://keksi.io/tutorials/2016/12/05/how-to-manage-remote-server-users-with-ansible/" rel="nofollow noreferrer">https://keksi.io/tutorials/2016/12/05/how-to-manage-remote-server-users-with-ansible/</a>):</p>
  
  <p><strong><em>vars/users.yml</em> file (users, user to group assignments, passwords, SSH keys):</strong></p>
  
  <pre><code>---
  users:
  
    - username: user1
      comment: "User 1"
      group: admin
      password: "sha password"
      keys:
        active:
          - "ssh-rsa etc"
      admin: yes
  
    - username: user2
      comment: "User 2"
      group: users
      groups: deployer
      keys:
        active:
          - "ssh-rsa etc"
  
    - username: user3
      [...]
  </code></pre>
  
  <p><strong>And this is the playbook:</strong></p>
  
  <pre><code>- hosts: all
    become: true
  
    tasks:
      - include_vars: ../vars/users.yml
  
      - name: Install sudo
        apt: name=sudo state=present
  
      - name: Add the group admin
        group:
          name: admin
          state: present
  
      - name: Create users
        user:
          name: "{{ item.username }}"
          comment: "{{ item.comment | default('User {{item.username}}') }}"
          password: "{{ item.password | default('!') }}"
          state: "{{ item.state | default('present') }}"
          shell: "{{ item.shell | default('/bin/bash') }}"
          group: "{{ item.group | default('users') }}"
        when: item.username is defined
        with_items: '{{ users }}'
  
      - name: Setup administrator users with complete sudo access
        user: name={{ item.username }} groups=sudo append=yes
        with_items: '{{ users }}'
        when: item.admin is defined and item.admin == True
  
      - name: Add SSH-keys to users
        authorized_key:
          user: "{{ item.0.username }}"
          key: "{{ item.1 }}"
        with_subelements:
          - "{{ users }}"
          - keys.active
          - flags:
            skip_missing: True
        when: item.0.state is not defined or item.0.state != "absent"
  
      - name: Remove old SSH-keys from users
        authorized_key:
          user: "{{ item.0.username }}"
          key: "{{ item.1 }}"
          state: absent
        with_subelements:
          - "{{ users }}"
          - keys.disabled
          - flags:
            skip_missing: True
        when: item.0.state is not defined or item.0.state != "absent"
  </code></pre>
  
  <p>I can correctly execute this playbook on all servers and have admin and normal users created and managed on them.</p>
  
  <p>Now I want to add a new step. I have several servers, and not every users should be configured on every server, and some users should be in an additional group only on some servers (for example developers on developing servers).</p>
  
  <p>So I wish to create some assignments for users on hosts or host groups, something like:</p>
  
  <pre><code>- host: host1
    admins:
      - user1
      - user2
    deployers:
      - user2
      - user3
    users:
      - user4
      - user5
  
  - host: hostgroup1
    admins:
      - user2
    users:
      - user3
      - user5
  </code></pre>
  
  <p>So I would like to be able to execute the playbook on all servers to have users created or updated based on this declarations, without writing a duplication of the playbook for every host.</p>
  
  <p>I don't have any idea about how to achieve this, could you help me please?</p>
  
  <hr>
  
  <p><strong>Edit: I tried to add a new "hosts" key in my users.yml variable file, this way:</strong></p>
  
  <pre><code>---
  users:
  
    - username: user1
      comment: "User 1"
      group: admin
      password: "sha password"
      keys:
        active:
          - "ssh-rsa etc"
      admin: yes
  
    - username: user2
      comment: "User 2"
      group: users
      groups: deployer
      keys:
        active:
          - "ssh-rsa etc"
      hosts:
        user:
          - host1
          - host2
        deployer:
          - host3
  </code></pre>
  
  <p>And I modified the task this way:</p>
  
  <pre><code>- name: Create users
    user:
      name: "{{ item.username }}"
      comment: "{{ item.comment | default('User {{item.username}}') }}"
      password: "{{ item.password | default('!') }}"
      state: "{{ item.state | default('present') }}"
      shell: "{{ item.shell | default('/bin/bash') }}"
      group: "{{ item.group | default('users') }}"
    with_items: '{{ users }}'
    when: item.username is defined and ((item.admin is defined and item.admin == True) or (item.hosts is defined and item.hosts.user is defined and inventory_hostname in item.hosts.user)
  </code></pre>
  
  <p>My explanation: I need to create the user if it's admin (so it must be created on every host or if the current host's inventory_hostname is listed into one of the hosts subkeys arrays (in a second step I wish to extend this check also if the current host is in an hostgroup listed in one of item.hosts subkeys.</p>
  
  <p>The problem is that this way user1 is created (because item.admin is True) but user2 not because the other condition is always False.</p>