One of the fundamental tasks in server administration is managing user accounts and permissions. The Ansible user module is used to add user and group accounts on remote systems. It allows administrators to create, modify, and delete user accounts, set or change passwords, manage user group memberships, and configure various user-related settings.
This guide provides an in-depth look at how to use the Ansible user module to add users and groups efficiently.
Table of Contents
Basic Syntax of Ansible User Module
Before diving into specific use cases, it’s essential to understand the basic syntax of the Ansible user module. The module has several parameters that allow you to define user attributes such as name, password, group, and state.
Here are the available options for the user module.
- name: The username to manage.
- state: The state of the user account. Possible values are present and absent.
- comment: The GECOS field (usually full name).
- createhome: Whether to create the user’s home directory. Default is yes.
- home: The path to the user’s home directory.
- shell: The user’s login shell.
- system: Whether the user is a system account.
- uid: The user’s UID.
- gid: The user’s primary group.
- groups: A list of groups the user belongs to.
- append: Whether to append the user to the groups specified.
- password: The user’s password (hashed).
- update_password: Whether to update the password if the user exists. Possible values are always and on_create.
- remove: Whether to remove the user’s home directory and mail spool when the user is removed.
- move_home: Whether to move the user’s home directory.
- force: Whether to remove directories associated with the user if they are not empty.
- ssh_key: The path to the user’s SSH key.
- profile: The user’s profile settings.
Example Usage
Here is a basic example of adding a user with several attributes:
- name: Manage user accounts
user:
name: exampleuser
state: present
comment: "Example User"
createhome: yes
home: "/home/exampleuser"
shell: "/bin/bash"
groups: "wheel,developers"
append: yes
password: "{{ 'password' | password_hash('sha512') }}"
uid: 1050
gid: 1050
ssh_key: "/home/exampleuser/.ssh/id_rsa.pub"
This playbook creates a user account named exampleuser, sets a comment (“Example User”), creates a home directory at /home/exampleuser, assigns the Bash shell (/bin/bash), and adds the user to the wheel and developers groups.
The append: yes option adds these groups without removing existing ones. It also sets a hashed password, specifies the user ID (uid) and group ID (gid) as 1050, and associates an SSH key located at /home/exampleuser/.ssh/id_rsa.pub with the account.
Add a User Using Ad-hoc Command
Ad-hoc commands in Ansible are helpful for quick, one-off tasks. To add a user using an ad-hoc command, you can use the following syntax:
# ansible all -m user -a "name=newuser state=present createhome=yes" -b
Output.
This command adds a user named newuser to all the hosts in your inventory. The -b flag indicates that the command should be executed with root privileges on the remote host.
Create a User Using Playbook
For more complex and repeatable tasks, creating a playbook is the best approach. Below is an example playbook to add a user:
---
- name: Add a new user
hosts: all
tasks:
- name: Add user 'newuser'
user:
name: newuser
state: present
Create a User with a Specific UID and Home Directory
Sometimes, you need to create a user with a specific User ID (UID) and assign a custom home directory. Below is an example playbook that creates a user with a specific UID and assigns a custom home directory.
---
- name: Create a user with a specific UID and home directory
hosts: all
tasks:
- name: Add user 'customuser' with a specific UID and home directory
user:
name: customuser
state: present
uid: 1500
home: "/opt/customuser"
createhome: yes
shell: "/bin/bash"
comment: "Custom User with specific UID"
The above playbook creates a customuser with UID 1500 and home directory /opt/customuser
Removing a User Using Playbook
To remove a user using an Ansible playbook, you can use the user module with the state parameter to absent.
---
- name: Remove a user
hosts: all
become: true
tasks:
- name: Remove the user
user:
name: newuser
state: absent
remove: yes
This playbook removes a user newuser with their home directory from all remote hosts specified in the inventory file.
Add Multiple Users Using Playbook
When managing multiple users, you can utilize a loop in your playbook to streamline the process. This approach ensures you can efficiently add, update, or manage several user accounts.
Here is an example playbook that creates multiple users on all remote hosts.
---
- name: Add multiple users
hosts: all
vars:
users:
- { name: 'user1', password: '{{ "password1" | password_hash("sha512") }}', groups: 'developers' }
- { name: 'user2', password: '{{ "password2" | password_hash("sha512") }}', groups: 'developers' }
- { name: 'user3', password: '{{ "password3" | password_hash("sha512") }}', groups: 'developers' }
tasks:
- name: Add users
user:
name: "{{ item.name }}"
password: "{{ item.password }}"
groups: "{{ item.groups }}"
append: yes
loop: "{{ users }}"
Explanation:
- vars: Defines a list of users with their respective attributes.
- loop: Iterates over each user in the users list to add them to the system.
Create a Group
To create a group, you can use the ansible.builtin.group module.
---
- name: Create a group on the target host
hosts: all
become: true
tasks:
- name: Create a group named "devops"
ansible.builtin.group:
name: developers
state: present
Explanation:
- name: developers specifies the name of the group.
- state: present ensures the group is created if it doesn’t exist.
Add a User to a Group
Often, users need to be part of specific groups to have the necessary permissions. The following example demonstrates how to add a user to a group:
---
- name: Add a user to a group
hosts: all
tasks:
- name: Add user 'newuser' to 'developers' group
user:
name: newuser
groups: developers
append: yes
This Ansible playbook adds the user newuser to the developers group on all target hosts defined in the inventory. The append: yes parameter ensures that the user is added to the specified group without removing them from other groups.
Add User to Multiple Groups
In some cases, users need to belong to multiple groups to have the necessary permissions to access different resources on a server. In this case, you can specify multiple groups as a comma-separated list.
Below is an example playbook that adds a user named multigroupuser to multiple groups named developers, admins, andqa.
---
- name: Add user to multiple groups
hosts: all
tasks:
- name: Add user 'multigroupuser' to multiple groups
user:
name: multigroupuser
state: present
groups: "developers,admins,qa"
append: yes
Add a User to Sudoers
To grant a user administrative privileges, you can add them to the sudoers file. This can be achieved by adding the user to the sudo group:
---
- name: Add a user to sudoers
hosts: all
tasks:
- name: Add user 'newuser' to 'sudo' group
user:
name: newuser
groups: sudo
append: yes
This Ansible playbook adds the user newuser to the sudo group on all target hosts specified in the inventory.
Add a Password Using Ad-Hoc Command
To set a password for a user using an ad-hoc command, you need to hash the password using a supported hash algorithm. This ensures that the password is stored securely.
First, generate a hashed password using Python or an online tool:
# python3 -c "import crypt; print(crypt.crypt('password', crypt.mksalt(crypt.METHOD_SHA512)))"
This will output a hashed password string.
$6$CG0/PrF24h.YsF7M$aeUdWeWUdSyH8ZmfV5nHobt5fzoPUD65d6jc4uk4G8UHE3gL/0KKkmccSsfA2ZdQFYYKRQMdmAFDk3lI47v270
Now, use the above password in the ad-hoc command to set it for newuser.
# ansible all -m user -a "name=newuser password='$6$CG0/PrF24h.YsF7M$aeUdWeWUdSyH8ZmfV5nHobt5fzoPUD65d6jc4uk4G8UHE3gL/0KKkmccSsfA2ZdQFYYKRQMdmAFDk3lI47v270'"
Add a Password Using Playbook
When using a playbook to set a user’s password, you can use the password parameter with a hashed password:
The following playbook sets a password for newuser.
---
- name: Set password for user
hosts: all
tasks:
- name: Set password for 'newuser'
user:
name: newuser
password: "{{ 'password' | password_hash('sha512') }}"
Set a Passwordless Access for Remote User
For scenarios where passwordless SSH access is required, you can use the authorized_key module to copy the public key to the user’s ~/.ssh/authorized_keys file. This allows the user to log in without needing to enter a password.
---
- name: Set up passwordless SSH access
hosts: all
tasks:
- name: Ensure the user 'newuser' exists
user:
name: newuser
state: present
- name: Create .ssh directory if it doesn't exist
file:
path: /home/newuser/.ssh
state: directory
mode: '0700'
owner: newuser
group: newuser
- name: Generate SSH key for newuser
user:
name: newuser
generate_ssh_key: yes
ssh_key_type: rsa
ssh_key_bits: 4096
ssh_key_file: /home/newuser/.ssh/id_rsa
- name: Add authorized key for 'newuser'
authorized_key:
user: newuser
state: present
key: "{{ lookup('file', '/home/newuser/.ssh/id_rsa.pub') }}"
- name: Ensure correct permissions on authorized_keys
file:
path: /home/newuser/.ssh/authorized_keys
state: file
mode: '0600'
owner: newuser
group: newuser
Explanation:
- Ensure the user ‘newuser’ exists: This task ensures that the user newuser is present on the system.
- Create .ssh directory if it doesn’t exist: This task creates the .ssh directory in the user’s home directory with the appropriate permissions.
- Generate SSH key for newuser: This task generates an SSH key pair for newuser using the Ansible user module. The key type is RSA, and the key length is 4096 bits.
- Add authorized key for ‘newuser’: This task adds the public key to the user’s authorized_keys file, enabling passwordless SSH login.
- Ensure correct permissions on authorized_keys: This task ensures that the authorized_keys file has the correct permissions and ownership.
Real-World Use Case
You are a DevOps engineer in a large organization with multiple environments (development, staging, and production). Each environment has specific requirements for user accounts, permissions, and SSH access. You need to manage user accounts across all these environments, ensuring that each environment adheres to its security and operational policies. Additionally, you need to enforce different access levels and permissions for different teams and environments.
Objectives:
- Add and remove users based on team membership.
- Assign appropriate groups and permissions for each environment.
- Set up SSH key-based authentication for secure access.
- Ensure different levels of sudo access for different environments.
- Automate user deprovisioning when a user leaves the team.
Step 1: Define the Users and Environments
Create a YAML file named users.yml to define users, and their SSH keys
users:
- name: alice
teams: ['dev', 'qa']
ssh_key: "ssh-rsa AAAAB3Nza... alice@example.com"
- name: bob
teams: ['dev']
ssh_key: "ssh-rsa AAAAB3Nza... bob@example.com"
- name: charlie
teams: ['qa']
ssh_key: "ssh-rsa AAAAB3Nza... charlie@example.com"
- name: dave
teams: ['dev', 'prod']
ssh_key: "ssh-rsa AAAAB3Nza... dave@example.com"
Create another YAML file named environments.yml for environment-specific settings.
environments:
- name: development
users:
dev: ['alice', 'bob', 'dave']
qa: ['alice', 'charlie']
sudo: ['alice', 'dave']
- name: staging
users:
qa: ['alice', 'charlie']
sudo: ['alice']
- name: production
users:
prod: ['dave']
sudo: ['dave']
Step 2: Create the Playbook
Create an Ansible playbook named manage_users.yml to manage users based on the defined YAML files.
---
- name: Manage user accounts across multiple environments
hosts: all
vars_files:
- users.yml
- environments.yml
tasks:
- name: Ensure users exist
user:
name: "{{ item.name }}"
state: present
generate_ssh_key: yes
ssh_key_type: rsa
ssh_key_bits: 4096
loop: "{{ users }}"
notify:
- Add SSH key for user
- name: Ensure user is part of required groups
user:
name: "{{ item }}"
groups: "{{ groups }}"
append: yes
loop: "{{ environment_users }}"
when: environment_users is defined
- name: Add users to sudoers if required
lineinfile:
path: /etc/sudoers.d/{{ item }}
state: "{{ 'present' if item in sudo_users else 'absent' }}"
create: yes
line: "{{ item }} ALL=(ALL) NOPASSWD:ALL"
validate: 'visudo -cf %s'
loop: "{{ environment_users }}"
when: sudo_users is defined
- name: Remove users not in the current environment
user:
name: "{{ item }}"
state: absent
remove: yes
loop: "{{ removed_users }}"
when: removed_users is defined
handlers:
- name: Add SSH key for user
authorized_key:
user: "{{ item.name }}"
state: present
key: "{{ item.ssh_key }}"
loop: "{{ users }}"
vars:
environment_users: "{{ environments | selectattr('name', 'equalto', ansible_hostname) | map(attribute='users') | first }}"
sudo_users: "{{ environments | selectattr('name', 'equalto', ansible_hostname) | map(attribute='sudo') | first }}"
removed_users: "{{ users | map(attribute='name') | difference(environment_users | map(attribute='dev') | list | union(environment_users | map(attribute='qa') | list | union(environment_users | map(attribute='prod') | list))) }}"
Explanation:
- Ensure Users Exist: This task ensures that all users defined in users.yml exist on the system, with SSH keys generated.
- Ensure User is Part of Required Groups: This task assigns users to the appropriate groups for the current environment (e.g., dev, qa, prod).
- Add Users to Sudoers if Required: This task adds users to the sudoers file if they require sudo privileges in the current environment.
- Remove Users Not in the Current Environment: This task removes users who are not part of the current environment, ensuring no unauthorized access.
- Add SSH Key for User: This handler adds the SSH public key for each user, enabling secure, passwordless login.
Step 3: Running the Playbook
Execute the playbook with the following commands, specifying the environment as an extra variable:
# ansible-playbook -i inventory manage_users.yml -e "environment=development"
# ansible-playbook -i inventory manage_users.yml -e "environment=staging"
# ansible-playbook -i inventory manage_users.yml -e "environment=production"
Output.
PLAY [Manage user accounts across multiple environments] **********************
TASK [Gathering Facts] ********************************************************
ok: [server1]
TASK [Ensure users exist] *****************************************************
changed: [server1] => (item={'name': 'alice', 'teams': ['dev', 'qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... alice@example.com'})
changed: [server1] => (item={'name': 'bob', 'teams': ['dev'], 'ssh_key': 'ssh-rsa AAAAB3Nza... bob@example.com'})
changed: [server1] => (item={'name': 'charlie', 'teams': ['qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... charlie@example.com'})
changed: [server1] => (item={'name': 'dave', 'teams': ['dev', 'prod'], 'ssh_key': 'ssh-rsa AAAAB3Nza... dave@example.com'})
TASK [Ensure user is part of required groups] *********************************
changed: [server1] => (item=alice)
changed: [server1] => (item=bob)
changed: [server1] => (item=dave)
TASK [Add users to sudoers if required] ***************************************
changed: [server1] => (item=alice)
changed: [server1] => (item=dave)
TASK [Remove users not in the current environment] ****************************
changed: [server1] => (item=charlie)
RUNNING HANDLER [Add SSH key for user] ****************************************
changed: [server1] => (item={'name': 'alice', 'teams': ['dev', 'qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... alice@example.com'})
changed: [server1] => (item={'name': 'bob', 'teams': ['dev'], 'ssh_key': 'ssh-rsa AAAAB3Nza... bob@example.com'})
changed: [server1] => (item={'name': 'charlie', 'teams': ['qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... charlie@example.com'})
changed: [server1] => (item={'name': 'dave', 'teams': ['dev', 'prod'], 'ssh_key': 'ssh-rsa AAAAB3Nza... dave@example.com'})
PLAY RECAP ********************************************************************
server1 : ok=6 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Conclusion
Managing users and passwords is a critical task in system administration, and Ansible’s user module provides a robust and flexible way to handle it. Whether you’re adding users, setting passwords, or configuring permissions, Ansible makes these tasks simple and repeatable. By leveraging both ad-hoc commands and playbooks, you can ensure that your user management processes are efficient and automated.
FAQs
1. Can I create a user with a specific shell using the Ansible user module?
Yes, use the shell parameter to define the default shell for the user, such as /bin/bash or /bin/zsh.
2. How do I manage a user's SSH keys using the user module?
Use the ssh_key parameter to add SSH public keys to the user's ~/.ssh/authorized_keys file, providing easy access to the system.
3. How can I lock a user account using the Ansible user module?
Use the password_lock: yes parameter to lock the user's account, preventing them from logging in.