# User and group management tasks - name: Ensure admin group exists when defined ansible.builtin.group: name: "{{ admin_group }}" when: admin_group | default('') | length > 0 - name: Ensure managed groups exist ansible.builtin.group: name: "{{ item.name }}" gid: "{{ item.gid | default(omit) }}" state: "{{ item.state | default('present') }}" loop: "{{ managed_groups | default([]) }}" loop_control: label: "{{ item.name }}" - name: Ensure primary groups for managed users exist ansible.builtin.group: name: "{{ item.primary_group }}" gid: "{{ item.primary_gid | default(omit) }}" state: present loop: "{{ managed_users | default([]) }}" loop_control: label: "{{ item.name }}" when: item.primary_group is defined - name: Ensure managed users are present ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid | default(omit) }}" shell: "{{ item.shell | default('/bin/bash') }}" home: "{{ item.home | default(omit) }}" group: "{{ item.primary_group | default(omit) }}" groups: "{{ (user_groups | join(',')) if user_groups else omit }}" append: "{{ true if user_groups else omit }}" create_home: "{{ item.create_home | default(true) }}" state: "{{ item.state | default('present') }}" vars: user_groups: >- {{ ((item.groups | default([])) + ([admin_group] if item.admin | default(false) and admin_group | default('') | length > 0 else [])) | unique }} loop: "{{ managed_users | default([]) }}" loop_control: label: "{{ item.name }}" when: item.state | default('present') != 'absent' register: user_result failed_when: - user_result is failed - '"currently used by process" not in user_result.msg' - name: Remove managed users marked absent ansible.builtin.user: name: "{{ item.name }}" state: absent remove: "{{ item.remove | default(false) }}" loop: "{{ managed_users | default([]) }}" loop_control: label: "{{ item.name }}" when: item.state | default('present') == 'absent' - name: Install authorized keys from GitHub ansible.posix.authorized_key: user: "{{ item.0.name }}" state: "{{ item.1.state | default('present') }}" key: "https://github.com/{{ item.1.value }}.keys" manage_dir: "{{ item.1.manage_dir | default(true) }}" exclusive: "{{ item.1.exclusive | default(false) }}" loop: "{{ managed_users | default([]) | subelements('authorized_keys', skip_missing=True) }}" loop_control: label: "{{ item.0.name }} (github: {{ item.1.value }})" when: - item.1.type | default('github') == 'github' - item.0.state | default('present') != 'absent' - name: Install authorized keys from files ansible.posix.authorized_key: user: "{{ item.0.name }}" state: "{{ item.1.state | default('present') }}" key: "{{ lookup('file', item.1.value) }}" manage_dir: "{{ item.1.manage_dir | default(true) }}" exclusive: "{{ item.1.exclusive | default(false) }}" loop: "{{ managed_users | default([]) | subelements('authorized_keys', skip_missing=True) }}" loop_control: label: "{{ item.0.name }} (file: {{ item.1.value }})" when: - item.1.type | default('github') == 'file' - item.0.state | default('present') != 'absent' - name: Install authorized keys from inline strings ansible.posix.authorized_key: user: "{{ item.0.name }}" state: "{{ item.1.state | default('present') }}" key: "{{ item.1.value }}" manage_dir: "{{ item.1.manage_dir | default(true) }}" exclusive: "{{ item.1.exclusive | default(false) }}" loop: "{{ managed_users | default([]) | subelements('authorized_keys', skip_missing=True) }}" loop_control: label: "{{ item.0.name }} (string key)" when: - item.1.type | default('github') == 'string' - item.0.state | default('present') != 'absent' - name: Configure sudo for ansible user ansible.builtin.template: src: sudoers_ansible.j2 dest: "{{ sudoers_dir }}/ansible" mode: '0440' validate: "{{ visudo_path }} -cf %s" - name: Configure sudo for graham user ansible.builtin.template: src: sudoers_graham.j2 dest: "{{ sudoers_dir }}/graham" mode: '0440' validate: "{{ visudo_path }} -cf %s" - name: Enable passwordless sudo for admin group ansible.builtin.lineinfile: path: "{{ sudoers_path }}" state: present regexp: '^%{{ admin_group }}' line: '{{ admin_group }} ALL=(ALL) NOPASSWD: ALL' validate: "{{ visudo_path }} -cf %s"