Ansible Disable User Account: Lock & Deactivate Users (Guide)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
How to disable user accounts in Ansible with the user module. Lock passwords, set nologin shell, expire accounts, and implement offboarding with examples.

How to disable a user account with Ansible?
See also: Add Secondary Groups to Linux Users with Ansible Playbook
Ansible disable user account
Today we're talking about the Ansible module user.
The full name is ansible.builtin.user, which means that is part of the collection of modules "builtin" with ansible and shipped with it.
It's a module pretty stable and out for years, it manages user accounts.
It supports a huge variety of Linux distributions, SunOS and macOS, and FreeBSD.
For Windows, use the ansible.windows.win_user module instead.
Parameters
- name string - username
- state string - present/absent
- password_lock boolean - no/yes
- shell string - "/sbin/nologin"
passwd tool on Linux systems to disables a password by changing it to a value that matches no possible encrypted value (it adds a ´!´ at the beginning of the password).
This parameter does not disable the user, only locks the password. This parameter does not always mean the user cannot log in using other methods.
The "shell" parameter specifies the user shell. A very special is the nologin. When a user with that shell logs in, they'll get a polite message saying 'This account is currently not available.' This message can be customized with the file /etc/nologin.txt.
## Playbook Let's jump into a real-life Ansible Playbook to disable a user.
code
- user_disable.yml
---
- name: user module Playbook
hosts: all
become: true
vars:
myuser: "example"
tasks:
- name: disable user
ansible.builtin.user:
name: "{{ myuser }}"
state: present
password_lock: true
shell: "/sbin/nologin"
execution
output
$ ansible-playbook -i Playbook/inventory disable\ user\ account/user.yml
PLAY [user module Playbook] ***************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [disable user] *******************************************************************************
changed: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
verification
$ ssh devops@demo.example.com
$ sudo su -
[root@demo ~]# getent passwd
example:x:1002:1002::/home/example:/sbin/nologin
[root@demo ~]# passwd -S example
example LK 2021-09-30 0 99999 7 -1 (Password locked.)
[root@demo ~]# grep example /etc/shadow
example:!!:18900:0:99999:7:::
See also: Ansible Linux Users and Groups: Complete Management Guide (Examples)
Conclusion
Now you know how to disable a user account with Ansible.
Disable User Account
Quick disable (expire + lock)
- name: Disable user account
ansible.builtin.user:
name: departed_user
expires: 0
shell: /sbin/nologin
become: true
- name: Lock password
ansible.builtin.command: "usermod -L departed_user"
become: trueSee also: ansible.builtin.user Module: Create & Manage Linux Users (Complete Guide)
Complete Offboarding Playbook
---
- name: Offboard departed employee
hosts: all
become: true
vars:
offboard_user: john_doe
tasks:
- name: Kill active sessions
ansible.builtin.command: "pkill -u {{ offboard_user }}"
ignore_errors: true
- name: Lock password
ansible.builtin.command: "usermod -L {{ offboard_user }}"
- name: Expire account immediately
ansible.builtin.user:
name: "{{ offboard_user }}"
expires: 0
shell: /sbin/nologin
- name: Remove SSH keys
ansible.posix.authorized_key:
user: "{{ offboard_user }}"
key: ""
exclusive: true
ignore_errors: true
- name: Remove from sudo
ansible.builtin.file:
path: "/etc/sudoers.d/{{ offboard_user }}"
state: absent
- name: Remove cron jobs
ansible.builtin.command: "crontab -r -u {{ offboard_user }}"
ignore_errors: trueBulk Disable
- name: Disable multiple users
include_tasks: disable_user.yml
loop:
- contractor1
- contractor2
- temp_intern
loop_control:
loop_var: offboard_userTemporary Disable (Suspend)
# Suspend (keep home, keep password hash)
- ansible.builtin.user:
name: "{{ username }}"
expires: 0
become: true
# Reactivate later
- ansible.builtin.user:
name: "{{ username }}"
expires: -1
become: trueWindows Disable
- name: Disable Windows account
ansible.windows.win_user:
name: "{{ username }}"
account_disabled: trueDisable Methods Comparison
| Method | Effect | Reversible |
|---|---|---|
expires: 0 | Account expired | Yes (expires: -1) |
usermod -L | Password locked | Yes (usermod -U) |
shell: /sbin/nologin | No shell access | Yes (set shell back) |
state: absent | Delete user | No |
FAQ
Should I delete or disable departing users?
Disable first. Keeps audit trail and file ownership intact. Delete after retention period (30-90 days typical).
How do I verify an account is disabled?
- command: "passwd -S {{ username }}"
# Look for 'L' (locked) in output
- command: "chage -l {{ username }}"
# Check "Account expires" fieldDoes disabling kill active sessions?
No — you must explicitly kill sessions with pkill -u username. SSH connections persist until terminated.
Quick Disable (Lock Password)
- ansible.builtin.user:
name: departed_user
password_lock: true
become: trueFull Disable (Lock + No Shell + Expire)
- ansible.builtin.user:
name: departed_user
password_lock: true
shell: /sbin/nologin
expires: 0
become: trueOffboarding Playbook
---
- name: Offboard departing employee
hosts: all
become: true
vars:
user_to_disable: john.doe
tasks:
- name: Kill active sessions
command: "pkill -u {{ user_to_disable }}"
ignore_errors: true
- name: Remove SSH keys
file:
path: "/home/{{ user_to_disable }}/.ssh/authorized_keys"
state: absent
- name: Remove sudo access
file:
path: "/etc/sudoers.d/{{ user_to_disable }}"
state: absent
- name: Remove from crontab
command: "crontab -r -u {{ user_to_disable }}"
ignore_errors: true
- name: Lock and disable account
user:
name: "{{ user_to_disable }}"
password_lock: true
shell: /sbin/nologin
expires: 0
- name: Archive home directory
archive:
path: "/home/{{ user_to_disable }}"
dest: "/opt/archives/{{ user_to_disable }}-{{ ansible_date_time.date }}.tar.gz"
ignore_errors: trueTemporary Disable (Vacation/Leave)
# Disable
- user:
name: "{{ employee }}"
password_lock: true
shell: /sbin/nologin
become: true
# Re-enable later
- user:
name: "{{ employee }}"
password_lock: false
shell: /bin/bash
expires: -1
become: trueBulk Disable
- user:
name: "{{ item }}"
password_lock: true
shell: /sbin/nologin
expires: 0
loop:
- old_contractor1
- old_contractor2
- departed_employee
become: trueVerify Account is Disabled
- command: "passwd -S {{ user_to_disable }}"
register: passwd_status
changed_when: false
- debug:
msg: >
{{ user_to_disable }} status:
{{ 'LOCKED' if 'L' in passwd_status.stdout.split()[1] else 'ACTIVE' }}
- command: "getent passwd {{ user_to_disable }}"
register: user_info
changed_when: false
- debug:
msg: "Shell: {{ user_info.stdout.split(':')[-1] }}"Windows Disable
- ansible.windows.win_user:
name: john.doe
account_disabled: trueDisable Methods Comparison
| Method | Effect | Reversible |
|---|---|---|
password_lock: true | Can't use password | Yes |
shell: /sbin/nologin | Can't get shell | Yes |
expires: 0 | Account expired | Yes |
| All three combined | Fully disabled | Yes |
state: absent | User deleted | No |
FAQ
Lock vs expire vs nologin?
- Lock: Prevents password authentication (SSH keys still work!)
- Nologin shell: Prevents shell access completely
- Expire: System rejects all login attempts
- Use all three for complete disable.
SSH keys still work after locking?
Yes! password_lock only disables password auth. To fully block SSH, also remove authorized_keys and set shell: /sbin/nologin.
How do I audit disabled accounts?
# Find locked accounts
passwd -Sa | grep 'L'
# Find expired accounts
getent shadow | awk -F: '$8==0'Related Articles
Category: troubleshooting
Watch the video: Ansible Disable User Account: Lock & Deactivate Users (Guide) — Video Tutorial