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?
I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.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"This module has many parameters to perform any task.
The only required is "name", which is the username.
The parameter "state" allows us to create or delete a user.
The "password_lock" parameter specifies to lock the user password.
This parameter uses the 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: true
See 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: true
Bulk Disable
- name: Disable multiple users
include_tasks: disable_user.yml
loop:
- contractor1
- contractor2
- temp_intern
loop_control:
loop_var: offboard_user
Temporary 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: true
Windows Disable
- name: Disable Windows account
ansible.windows.win_user:
name: "{{ username }}"
account_disabled: true
Disable 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" field
Does 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: true
Full Disable (Lock + No Shell + Expire)
- ansible.builtin.user:
name: departed_user
password_lock: true
shell: /sbin/nologin
expires: 0
become: true
Offboarding 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: true
Temporary 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: true
Bulk Disable
- user:
name: "{{ item }}"
password_lock: true
shell: /sbin/nologin
expires: 0
loop:
- old_contractor1
- old_contractor2
- departed_employee
become: true
Verify 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: true
Disable 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
• Ansible become methods compared • Ansible inventory groups and variables • creating an Ansible role from scratch • Windows DSC and AnsibleCategory: troubleshooting
Watch the video: Ansible Disable User Account: Lock & Deactivate Users (Guide) — Video Tutorial