[Demo Webinar] ⛏️ How to build a user-friendly infra self-service portal with Spacelift

➡️ Register Now

Ansible

How to Create Ansible Users & Add Passwords

ansible user module

🚀 Level Up Your Infrastructure Skills

You focus on building. We’ll keep you updated. Get curated infrastructure insights that help you make smarter decisions.

Managing users efficiently is a key part of automating system administration with Ansible. In this guide, you’ll learn how to create users, set passwords, add users to groups, and configure remote access using Ansible’s powerful tools. 

We’ll cover:

  1. What is the Ansible user module?
  2. How to add a user in Ansible
  3. How to add a user to a group
  4. How to add a password to a user
  5. Remote access configuration
  6. Best practices for creating Ansible users

What is the Ansible user module?

The Ansible user module is used to manage user accounts on Linux and UNIX-like operating systems on target systems. It can set user properties such as UID, home directory, login shell, and password hash. Ansible tasks are idempotent, so re-running the task will not create duplicate users.

Unlike using shell commands directly, the user module handles edge cases and reports clearly whether a change was made. Compared to manual scripting, it integrates better with Ansible’s check mode (--check) and handlers.

The Ansible user module offers a wide set of options to control user account properties:

  • name (required): Username to manage
  • state: Whether the user should exist (present) or be removed (absent)
  • uid: User ID to assign to the user
  • groups: Primary and additional group names (use instead of deprecated group parameter)
  • shell: Login shell of the user (e.g., /bin/bash)
  • home: Home directory path for the user
  • password: Hashed password to set for the user
  • ssh_key_bits: Number of bits for SSH key generation when generate_ssh_key is true
  • ssh_key_type: Type of SSH key to generate (rsa, ecdsa, or ed25519)
  • login_class: (BSD) Login class to set
  • seuser: SELinux user mapping

Each platform (Linux, BSD, Solaris) might slightly affect behavior for less common options like login_class or seuser, so you should check the module documentation when targeting different systems.

How to add a user in Ansible

The two primary methods for adding a user in Ansible are:

  1. Using the user module – The ansible.builtin.user module is the standard, recommended way to create and manage users directly. 
  2. Using raw or shell/command modules – Alternatively, you can manually run user creation commands (useradd, adduser) via the ansible.builtin.shell, ansible.builtin.command, or ansible.builtin.raw modules. This is strongly discouraged for production use because it bypasses idempotency and risks race conditions or duplication.

Method 1: Using the user module in Ansible playbooks

To add a user in Ansible, you use the user module within a playbook or ad-hoc command.

The user module manages user accounts on target systems. Depending on the state parameter, it can create, modify, or remove users. You can also set options like home directory, shell, UID, and encrypted passwords.

Before adding a user to a group, ensure the group exists. Otherwise, the task may fail, depending on the system’s behavior. For example:

- name: Add a new user
  ansible.builtin.user:
    name: "newuser"
    state: present
    shell: /bin/bash
    groups: "sudo"
    create_home: yes

This task ensures that newuser exists, has a home directory, uses /bin/bash, and belongs to the sudo group.

Note: If you need to set a password, it must be pre-hashed (e.g., using openssl passwd -6 'password' or mkpasswd with SHA-512) and passed using the password parameter. We will cover this later in the article.

Method 2: Using ad-hoc Ansible commands

The user module is the standard, idempotent way to manage users in Ansible. However, bypassing it using shell or command modules risks race conditions and duplication. If unavoidable, always wrap shell usage with creates or proper error checking.

To add a user in Ansible with an ad-hoc command without using the user module, you can use the ansible.builtin.shell or ansible.builtin.command module to directly execute a system command like useradd.

Using shell allows execution of more complex commands, while command is safer but more limited (no pipes, redirection, etc.).

Here’s a clean example using the shell module:

ansible all -m shell -a "useradd newusername" -b

If you want to specify additional options, such as setting a home directory or shell, you can extend the command:

ansible all -m shell -a "useradd -m -s /bin/bash newusername" -b

For a safer experience without the user module, always check if the user exists first:

ansible all -m shell -a "id -u newusername || useradd -m -s /bin/bash newusername" -b

Always check if the user exists first, or use the creates argument to prevent issues.

How to add a user to a group

To add a user to a group in Ansible, you can use the user module with the groups parameter.  Setting append: yes ensures the user is added to the group without altering their other memberships. 

Without append: yes, specifying groups replaces all existing secondary groups for the user, which can cause unintended permission changes.

Example 1: Adding a single user

In the example below, we add johndoe to the developers group while keeping their existing groups.

- name: Add user to a group
  ansible.builtin.user:
    name: johndoe
    groups: developers
    append: yes

If the group does not exist yet, you should first create it using the ansible.builtin.group module to prevent failure.

Example 2: Adding multiple users to multiple groups

You can add multiple users to multiple groups in Ansible by looping over users and groups, using the user module with append: yes. When adding users to groups, using with_items (for older Ansible versions) or loop (current standard) is the most efficient way. (Read more: Ansible Loops : How To Use, Tutorial & Examples)

In this example, johndoe joins developers, janedoe joins admins, and alice joins testers:

- name: Add multiple users to multiple groups
  hosts: all
  become: yes
  tasks:
    - name: Ensure users are in the right groups
      ansible.builtin.user:
        name: "{{ item.user }}"
        groups: "{{ item.group }}"
        append: yes
      loop:
        - { user: 'johndoe', group: 'developers' }
        - { user: 'janedoe', group: 'admins' }
        - { user: 'alice', group: 'testers' }

On the other hand, if you need to assign multiple groups to one user, you can list groups as a comma-separated string:

groups: "developers,admins"

When assigning multiple groups, Linux expects a comma-separated string (groups: "developers,admins"), but some UNIX variants might differ slightly. Always verify platform behavior if in doubt.

How to add a password to a user

All three primary methods of adding a password to a user in Ansible use the Ansible user module to actually create or modify the user with a password:

  • Pre-hash the password manually (with mkpasswd).
  • Hash it dynamically inside Ansible (using password_hash filter).
  • Retrieve it securely (with Vault), possibly hashing it at runtime.

The user module never directly accepts plaintext passwords. It always expects a properly hashed password string. Thus, while mkpasswd, Jinja2 filters, and Vault help prepare the password securely, the actual user creation or password assignment is always handled by the user module itself.

Method 1: Using mkpasswd

You generate a hashed password outside of Ansible using a tool like mkpasswd (part of whois package) or openssl passwd, and then pass that hashed value in your Ansible playbook. This method is simple and highly secure if you trust your manual handling of the hash.

Install mkpasswd:

  • Debian/Ubuntu: sudo apt install whois
  • RHEL/CentOS: sudo yum install expect

Now generate the hashed password:

mkpasswd --method=SHA-512

Example output:

$6$rounds=656000$Xf8DqC1dkvnyc7... 

Then use it in a playbook:

- name: Create user with pre-hashed password
  hosts: all
  become: true
  tasks:
    - name: Create user with pre-hashed password
      ansible.builtin.user:
        name: myuser
        password: "$6$rounds=656000$Xf8DqC1dkvnyc7...."

Method 2: Hashing passwords dynamically in playbooks

You can use Jinja2 filters like password_hash within Ansible to generate the hash during playbook execution. The password_hash Jinja2 filter tells Ansible to hash the plaintext password using the sha512 algorithm during playbook execution. 

Note: Hashing inside playbooks exposes plaintext passwords in memory and logs if not handled carefully. Avoid in production unless absolutely necessary.

For example:

- name: Create user with dynamically hashed password
  hosts: all
  become: true
  vars:
    plain_password: "MySecurePassword123"
  tasks:
    - name: Create user with password hashed in playbook
      ansible.builtin.user:
        name: myuser
        password: "{{ plain_password | password_hash('sha512') }}"

Alternatively, you can use the community.general.password_hash plugin for enhanced flexibility across environments.

Method 3: Using Ansible playbooks with Vault

You encrypt sensitive data, such as plaintext passwords, with Ansible Vault and then hash it at runtime or use pre-hashed values. 

Here, the password is never visible in plaintext form inside the playbook. It stays encrypted at rest and only becomes available during playbook execution. This method combines secure storage (Vault) with dynamic hashing, offering maximum security for production environments.

Vault-encrypt your password:

ansible-vault encrypt_string 'MySecurePassword123' --name 'vault_password'

Then in your playbook:

- name: Create user with password from Vault
  hosts: all
  become: true
  vars:
    vault_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256;...(vault encrypted password)
  tasks:
    - name: Create user with password from Vault, hashed
      ansible.builtin.user:
        name: myuser
        password: "{{ vault_password | password_hash('sha512') }}"

Remote access configuration

Creating a user in Ansible is often part of configuring remote access. You typically create a dedicated SSH user with specific permissions and configure Ansible to connect using that user for subsequent tasks.

Ansible connects to managed hosts using SSH by default. Remote access must be set up so that Ansible can log into each host non-interactively, typically using SSH keys. The configuration is defined globally in ansible.cfg, per playbook, or dynamically in inventory files.

Key parameters include:

  • ansible_user: The username to log into the remote machine.
  • ansible_ssh_private_key_file: The private key file for authentication.
  • ansible_port: If a non-standard SSH port is used.
  • ansible_host: If the target hostname differs from the inventory name.
  • ansible_connection: Set to ssh (lowercase). Use paramiko only if OpenSSH is unavailable. OpenSSH is now preferred for performance and security.

Example in an inventory file:

[webservers]
web1 ansible_host=192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa

You can globally configure defaults in ansible.cfg under the [defaults] and [ssh_connection]</span> sections.

lookup('file', ...) reads a local file on the control machine, not on the target hosts. It will fail if the file does not exist or the control machine lacks access. If needed, prefer the copy module with content for greater portability.

Playbook example to create a user and SSH access:

- name: Create ansible user
  hosts: all
  become: true
  tasks:
    - name: Create a new user
      user:
        name: ansible
        groups: sudo
        shell: /bin/bash
        state: present

    - name: Add authorized key
      authorized_key:
        user: ansible
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

After this, update your inventory to use ansible_user=ansible.

Best practices for creating Ansible users

Ansible’s user module allows declarative user management by specifying user attributes like name, UID, shell, and password. Ensuring user creation is idempotent (running multiple times without side effects) and secure is critical, especially in production environments.

Key best practices involve:

  1. Avoid hardcoded credentials by leveraging Ansible Vault to encrypt passwords and sensitive data.
  2. Use unique UIDs when necessary, especially in large environments, to avoid conflicts.
  3. Specify system users (system: yes) when creating service accounts to distinguish them from regular users.
  4. Ensure password hashing is done properly, typically by generating hashes externally (e.g., using mkpasswd) rather than plain-text input.
  5. Set default shells and home directory permissions explicitly to maintain consistency across different operating systems.
  6. Use different SSH keys per user whenever possible to enhance security.
  7. Set /usr/sbin/nologin as shell for system users who should not have interactive access.

How to use Spacelift for your Ansible projects

Spacelift’s vibrant ecosystem and excellent GitOps flow are helpful for managing and orchestrating Ansible. By introducing Spacelift on top of Ansible, you can easily create custom workflows based on pull requests and apply any necessary compliance checks for your organization.

Another advantage of using Spacelift is that you can manage infrastructure tools like Ansible, Terraform, Pulumi, AWS CloudFormation, and even Kubernetes from the same place and combine their stacks with building workflows across tools.

Our latest Ansible enhancements solve three of the biggest challenges engineers face when they are using Ansible:

  • Having a centralized place in which you can run your playbooks
  • Combining IaC with configuration management to create a single workflow
  • Getting insights into what ran and where

Provisioning, configuring, governing, and even orchestrating your containers can be performed with a single workflow, separating the elements into smaller chunks to identify issues more easily.

Would you like to see this in action, or just get a tl;dr? Check out this video showing you Spacelift’s Ansible functionality:

ansible product video thumbnail

If you want to learn more about using Spacelift with Ansible, check our documentation, read our Ansible guide, or book a demo with one of our engineers.

Key points

Ansible’s user module allows for efficient, idempotent management of Linux and UNIX user accounts, enabling creation, modification, password assignment, and group management declaratively. 

Secure password handling requires hashing passwords beforehand or securely using Ansible Vault, whereas SSH-based remote access setup ensures smooth automation. Following best practices like avoiding plaintext passwords, using unique UIDs, and applying strict SSH controls strengthens security and consistency across environments.

Manage Ansible better with Spacelift

Managing large-scale playbook execution is hard. Spacelift enables you to automate Ansible playbook execution with visibility and control over resources, and seamlessly link provisioning and configuration workflows.

Learn more