Ansible, only disable existing users?

Solution 1:

Q: "Only existing users can be disabled."

A: To modify present users only, use getent to read /etc/passwd and create a list of present users. Then use it in the condition. For example

    - getent:
        database: passwd
    - set_fact:
        users_present: "{{ getent_passwd.keys()|list }}"

    - name: "disable user {{ item.name }}"
      user:
        name: "{{ item.name }}"
        shell: /sbin/nologin
      loop: "{{ users }}"
      when:
        - item.name in users_present
        - item.state|default('present') == 'absent'

Note1: It's more robust to default state to 'present' instead of testing the existence of the attribute

    - name: "create account for {{ item.name }}"
      user:
        name: "{{ item.name }}"
        create_home: no
        shell: /bin/bash
      loop: "{{ users }}"
      when: item.state|default('present') != 'absent'

Note2: The module user doesn't complain that a 'name' isn't present when 'state=absent'. Hence, it's not necessary to test the presence of a user in this case. Simply disable the user. For example

    - name: "disable user {{ item.name }}"
      user:
        name: "{{ item.name }}"
        state: absent
      loop: "{{ users }}"
      when: item.state|default('present') == 'absent'

Solution 2:

You can check if a user exists with getent with getent passwd {{ item }}.

Below is an example playbook:

---
  - name: "Check if User exists sample"
    hosts: localhost
    connection: local
    vars:
      users:
        - nginx
        - root
        - user4
        - user3

    tasks:
      - name: "check for user in /etc/passwd"
        command: getent passwd {{ item }}
        register: check_user
        ignore_errors: yes 
        loop: "{{ users }}"
        register: all_checks
      
      - name: "iterate over checks"
        debug:
          msg:
          - "{{ item.rc }}"
          - "{{ item.item }}"
        when:
          - item.rc == 0
        loop: "{{ all_checks.results }}"

So in your case you need to modify the section of your playbook you posted like this:

tasks:
      - name: "check for user in /etc/passwd"
        command: getent passwd {{ item }}
        register: check_user
        ignore_errors: yes 
        loop: "{{ users }}"
        register: all_checks
      
      - name: "iterate over checks"
        user:
          name: "{{item.item}}"
          shell: "/sbin/nologin" 
        when:
          - item.state is defined and item.state == "absent"
          - item.rc == 0
        loop: "{{ all_checks.results }}"

Tags:

Ansible