Add Users and Groups using Ansible User Module

Ansible User Module Examples

Managing user accounts is a fundamental task for any Linux administrator. With Ansible’s user module, you can automate the creation, modification, and removal of users and groups across multiple servers, saving time and reducing errors.

This guide walks you through how to use Ansible to manage users, groups, passwords, sudo access, SSH keys, and more, including real-world examples and enterprise use cases.

What is the Ansible user Module?

The user module allows you to:

  • Create or remove user accounts
  • Set passwords (including hashed)
  • Assign users to groups
  • Specify shells, UIDs, home directories
  • Generate SSH keys
  • Enforce sudo access with proper security

Summary of Common Use Cases

TaskModule UsedMethod
Create useruserAd-hoc / Playbook
Add to group(s)userUse groups + append: yes
Create groupgroupPlaybook
Set hashed passworduserWith password_hash()
Set up SSH keyauthorized_keyPlaybook
Add sudo accesslineinfileValidate with visudo
Remove useruserstate: absent + remove: yes

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 all available options.

  • 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.

add user using ansible

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.

Here is an example playbook.

---
- 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 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 Loop

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, and qa.

---
- 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 Sudo Access with Validation

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') }}"

Setup Passwordless SSH Access

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. 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 uses the file module to ensure 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... [email protected]"
  - name: bob
    teams: ['dev']
    ssh_key: "ssh-rsa AAAAB3Nza... [email protected]"
  - name: charlie
    teams: ['qa']
    ssh_key: "ssh-rsa AAAAB3Nza... [email protected]"
  - name: dave
    teams: ['dev', 'prod']
    ssh_key: "ssh-rsa AAAAB3Nza... [email protected]"

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 uses a loop with a when statement to remove 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... [email protected]'})
changed: [server1] => (item={'name': 'bob', 'teams': ['dev'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})
changed: [server1] => (item={'name': 'charlie', 'teams': ['qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})
changed: [server1] => (item={'name': 'dave', 'teams': ['dev', 'prod'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})

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... [email protected]'})
changed: [server1] => (item={'name': 'bob', 'teams': ['dev'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})
changed: [server1] => (item={'name': 'charlie', 'teams': ['qa'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})
changed: [server1] => (item={'name': 'dave', 'teams': ['dev', 'prod'], 'ssh_key': 'ssh-rsa AAAAB3Nza... [email protected]'})

PLAY RECAP ********************************************************************
server1                   : ok=6    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Conclusion

Ansible makes managing Linux users secure, consistent, and repeatable. Whether you’re provisioning users in bulk, configuring SSH access, assigning group permissions, or removing accounts—Ansible’s user, group, and authorized_key modules have you covered.

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.

About Hitesh Jethva

Experienced Technical writer, DevOps professional with a demonstrated history of working in the information technology and services industry. Skilled in Game server hosting, AWS, Jenkins, Ansible, Docker, Kubernetes, Web server, Security, Proxy, Iptables, Linux System Administration, Domain Name System (DNS), and Technical Writing.

View all posts by Hitesh Jethva