ansible.builtin.user: Change User Password with Ansible (Secure Guide)
By Luca Berton · Published 2024-01-01 · Category: installation
How to change user passwords with Ansible user module. Hash passwords securely, use Vault for credentials, manage password rotation across servers.

Introduction
In today's episode of Ansible Pilot, I'm Luca Berton, and we'll be delving into the process of changing a user password on a Linux system using Ansible. Specifically, we'll be utilizing the ansible.builtin.user module, an integral part of Ansible's collection of built-in modules.
See also: Ansible Change User Password: Secure Password Management Guide
The Ansible User Module
The ansible.builtin.user module is a stable and well-established component of Ansible, designed to manage user accounts. It boasts compatibility with a wide range of Linux distributions, including RHEL, CentOS, Fedora, Ubuntu, Debian, SUSE, as well as SunOS, macOS, and FreeBSD. For Windows systems, the equivalent module is ansible.windows.win_user.
Parameters
The user module comes with various parameters, but the three key ones for our password-changing task are:
• name (string): Specifies the username.
• state (string): Indicates the desired state of the user account (present or absent).
• password (string): For Linux systems, the password must be provided in encrypted form, while macOS accepts cleartext passwords.
Writing the Ansible Playbook
Let's take a practical approach by crafting an Ansible Playbook that changes the password for a user account on a Linux system.
Ansible Playbook Code: change_password.yml
---
- name: user module Playbook
hosts: all
become: true
vars:
myuser: "example"
mypassword: "password"
tasks:
- name: change password
ansible.builtin.user:
name: "{{ myuser }}"
state: present
password: "{{ mypassword | password_hash('sha512') }}"
Executing the Playbook
To execute the playbook, use the following command:
$ ansible-playbook -i Playbook/inventory change\ user\ password/user.yaml
output
$ ansible-playbook -i Playbook/inventory change\ user\ password/user.yaml
PLAY [user module Playbook] ***************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [change password] ****************************************************************************
changed: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verification
You can verify the password change by attempting to SSH into the system with the updated credentials:
$ sshpass -p 'password' example@demo.example.com
Note: Ensure that sshpass is installed on the system for this verification step.
See also: Add Secondary Groups to Linux Users with Ansible Playbook
Conclusion
In conclusion, you now possess the knowledge to change a user password on a Linux system using Ansible. The ansible.builtin.user module simplifies this task, allowing for seamless automation of user account management.
Set User Password
Ansible requires hashed passwords (not plaintext):
- name: Set user password
ansible.builtin.user:
name: deploy
password: "{{ 'MySecureP@ss' | password_hash('sha512') }}"
become: true
See also: Ansible Linux Users and Groups: Complete Management Guide (Examples)
Generate Password Hash
In playbook (using filter)
password: "{{ 'plaintext_password' | password_hash('sha512') }}"
With salt for consistency
password: "{{ 'plaintext_password' | password_hash('sha512', 'fixed_salt_value') }}"
From command line
ansible all -m debug -a "msg={{ 'MyPassword' | password_hash('sha512') }}"
# Or using Python
python3 -c "import crypt; print(crypt.crypt('MyPassword', crypt.mksalt(crypt.METHOD_SHA512)))"
Secure Password Management
Use Ansible Vault
# vars/secrets.yml (encrypted with ansible-vault)
user_passwords:
alice: "SecureP@ss123"
bob: "AnotherP@ss456"
- name: Set passwords from vault
ansible.builtin.user:
name: "{{ item.key }}"
password: "{{ item.value | password_hash('sha512') }}"
update_password: always
loop: "{{ user_passwords | dict2items }}"
no_log: true # Don't log passwords
become: true
update_password options
| Value | Behavior |
|-------|----------|
| always | Update password every run |
| on_create | Only set on new user creation |
# Only set password when creating user
- ansible.builtin.user:
name: newuser
password: "{{ password | password_hash('sha512') }}"
update_password: on_create
become: true
Force Password Change on First Login
- name: Create user with password
ansible.builtin.user:
name: newuser
password: "{{ temp_password | password_hash('sha512') }}"
become: true
- name: Force password change on next login
ansible.builtin.command: chage -d 0 newuser
become: true
Set Password Expiry
- name: Set password to expire in 90 days
ansible.builtin.user:
name: deploy
password_expire_max: 90
become: true
Windows Passwords
- name: Set Windows user password
ansible.windows.win_user:
name: admin_user
password: "{{ vault_win_password }}"
password_never_expires: true
update_password: always
FAQ
Why can't I use plaintext passwords?
Linux stores hashed passwords in /etc/shadow. The user module writes directly to this file, so it needs the hash format. Plaintext would be stored as-is and never match during login.
Why does the task show "changed" every time?
If you generate the hash without a fixed salt, it's different each run. Use a fixed salt:
password: "{{ 'pass' | password_hash('sha512', 'mysalt') }}"
How do I check a user's current password?
You can't retrieve passwords. You can only check when it was last changed:
chage -l username
Set Password
- name: Set user password
ansible.builtin.user:
name: deploy
password: "{{ 'MySecurePassword' | password_hash('sha512') }}"
update_password: always
become: true
no_log: true
Password from Vault
# group_vars/all/vault.yml (encrypted)
vault_deploy_password: "SuperSecret123"
# playbook.yml
- user:
name: deploy
password: "{{ vault_deploy_password | password_hash('sha512') }}"
become: true
no_log: true
Set on First Run Only
- user:
name: newuser
password: "{{ initial_password | password_hash('sha512') }}"
update_password: on_create # Only set if user is new
become: true
no_log: true
Force Password Change at Next Login
- user:
name: deploy
password: "{{ temp_password | password_hash('sha512') }}"
become: true
no_log: true
- command: chage -d 0 deploy
become: true
Set Password Expiry
- user:
name: deploy
password: "{{ password | password_hash('sha512') }}"
password_expire_max: 90 # Days until password expires
password_expire_min: 7 # Min days between changes
become: true
no_log: true
Bulk Password Reset
- name: Reset all user passwords
ansible.builtin.user:
name: "{{ item.name }}"
password: "{{ item.password | password_hash('sha512') }}"
update_password: always
loop:
- { name: alice, password: "{{ vault_alice_pass }}" }
- { name: bob, password: "{{ vault_bob_pass }}" }
- { name: charlie, password: "{{ vault_charlie_pass }}" }
become: true
no_log: true
Generate Random Password
- set_fact:
random_password: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters,digits,punctuation') }}"
- user:
name: newuser
password: "{{ random_password | password_hash('sha512') }}"
become: true
no_log: true
- debug:
msg: "Password for newuser: {{ random_password }}"
# Only show during initial setup!
Password Hash Algorithms
# SHA-512 (recommended for Linux)
password: "{{ pass | password_hash('sha512') }}"
# SHA-256
password: "{{ pass | password_hash('sha256') }}"
# With custom salt
password: "{{ pass | password_hash('sha512', 'mysalt') }}"
Windows Password
- ansible.windows.win_user:
name: Administrator
password: "{{ vault_admin_password }}"
update_password: always
Security Best Practices
| Practice | Implementation |
|----------|---------------|
| Never hardcode passwords | Use ansible-vault |
| Hide from logs | Add no_log: true |
| Hash passwords | Always use password_hash() |
| Rotate regularly | Set password_expire_max |
| Use keys instead | authorized_key module |
FAQ
Why no_log: true?
Without it, the hashed password appears in Ansible output and logs. Always use no_log: true for password tasks.
"password not changed" but I set update_password?
update_password: on_create only sets passwords for new users. Use update_password: always to force updates.
Can I check the current password?
Ansible can't read existing passwords (they're hashed). You can only set new ones.
Set Password
- ansible.builtin.user:
name: alice
password: "{{ 'MySecurePass123!' | password_hash('sha512') }}"
update_password: always
become: true
no_log: true
Password from Vault
# group_vars/all/vault.yml (encrypted)
vault_user_password: "SecurePassword123!"
# playbook
- user:
name: alice
password: "{{ vault_user_password | password_hash('sha512') }}"
become: true
no_log: true
Update Only on Creation
- user:
name: newuser
password: "{{ initial_password | password_hash('sha512') }}"
update_password: on_create # Only set if user doesn't exist
become: true
no_log: true
Bulk Password Change
- user:
name: "{{ item.name }}"
password: "{{ item.password | password_hash('sha512') }}"
update_password: always
loop: "{{ users }}"
become: true
no_log: true
vars:
users:
- { name: alice, password: "{{ vault_alice_pass }}" }
- { name: bob, password: "{{ vault_bob_pass }}" }
Force Password Change on Next Login
- user:
name: alice
password: "{{ temp_password | password_hash('sha512') }}"
become: true
no_log: true
- command: "chage -d 0 alice"
become: true
Generate Random Password
- set_fact:
random_pass: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters,digits,punctuation') }}"
no_log: true
- user:
name: alice
password: "{{ random_pass | password_hash('sha512') }}"
become: true
no_log: true
- debug:
msg: "Password for alice has been set"
# Don't print the actual password!
Password Hashing Algorithms
# SHA-512 (recommended)
"{{ password | password_hash('sha512') }}"
# SHA-256
"{{ password | password_hash('sha256') }}"
# With custom salt
"{{ password | password_hash('sha512', 'mysalt') }}"
# bcrypt (if supported)
"{{ password | password_hash('blowfish') }}"
FAQ
Why no_log: true?
Without it, Ansible prints the hashed password in output logs. no_log prevents sensitive data from appearing in console output and logs.
Why not plain text passwords?
Ansible requires pre-hashed passwords. The password_hash filter handles hashing. Never store or transmit plain text passwords.
How to verify the password was set?
sudo chage -l username # Shows password age info
Related Articles
• become_user and become_method in Ansible • Ansible Inventory Guide • role variables and defaults in Ansible • Windows DSC and AnsibleCategory: installation
Watch the video: ansible.builtin.user: Change User Password with Ansible (Secure Guide) — Video Tutorial