Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
Ansible is a powerful IT automation tool that simplifies the management of complex infrastructure, including user and password administration. When working with several servers, it can be very difficult and time-consuming to manually add new users and passwords. So, instead of logging into all servers by hand, we can leverage Ansible automation capability to automate these tasks on our behalf.
In this tutorial, we’ll see how to add users and passwords using Ansible.
Before we get into various ways of managing users, let’s ensure we’ve got the necessary tools and prerequisites in place:
With our setup ready, we can move forward with this tutorial.
Ansible’s user module is the primary tool for managing users on target hosts. Specifically, it provides a comprehensive set of options:
In addition to the ones above, we can employ many other options with the user module:
In general and in this tutorial, we use the user module for managing users on the client node.
Particularly, there are two main methods for adding users using Ansible:
Let’s see the use cases for each of the methods.
Ad-hoc commands provide a rather quick and easy way to execute Ansible tasks directly from the command line.
For instance, let’s take an example of an ad-hoc command to create a user named Baeldung-CS:
$ ansible -i project_inventory.ini client1 -m user -a "name=Baeldung-CS state=present createhome=yes" -b
192.168.221.171 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1006,
"home": "/home/Baeldung-CS",
"name": "Baeldung-CS",
"shell": "/bin/sh",
"state": "present",
"system": false,
"uid": 1005
}
Let’s see a breakdown of the options used here:
Further, the -a flag passes the entire string inside the quotes as a single argument to ansible. The user module uses certain options to create the user:
Finally, the json format output of the command shows the new user’s details. For example, the user shell is /bin/bash, and the home directory is /home/Baeldung-CS. Also, the gid and uid are set to 1006 and 1005 respectively.
Furthermore, to verify whether the user was created with the given details, we switch to the client node. We then list the home directory contents with the ls command:
$ ls /home
vagrant Baeldung-CS
Thus, the target user is created on the client node.
Playbooks are YAML files that define a sequence of tasks to be executed on target hosts.
Let’s now see how to use a playbook to create a user on the remote node. First, we compile a playbook to create a user named baeldung:
$ cat add_user.yml
---
- name: Create a user
hosts: client1
become: yes
tasks:
- name: Add user baeldung
user:
name: baeldung
shell: /bin/bash
home: /home/baeldung
Notably, the above playbook sets the shell and home directory for the user. Let’s run it:
$ ansible-playbook -i project_inventory.ini add_user.yml
PLAY [Create a user] ***********************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.221.171]
TASK [Add user baeldung] *******************************************************
changed: [192.168.221.171]
PLAY RECAP *********************************************************************
192.168.221.171 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Moreover, to verify the user creation, we switch to the client node and list the home directory contents with ls:
$ ls /home/
vagrant baeldung
Finally, the user is created on the client with its home directory.
User management generally involves assigning users to specific groups. Ansible simplifies this process within the playbook.
Let’s start by creating a group and adding the above user, baeldung, to it:
$ cat add_grp.yml
---
- name: Create a group and add a user
hosts: client1
become: yes
tasks:
- name: Ensure the group exists
group:
name: developers
state: present
- name: Add user to the group
user:
name: baeldung
groups: developers
append: yes
In this playbook, the first task ensures the group developers exists. Then, the second task adds the user baeldung to the developers group using the user module.
Let’s run the playbook:
$ ansible-playbook -i project_inventory.ini add_grp.yml
PLAY [Create a group and add a user] *******************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.221.171]
TASK [Ensure the group exists] *************************************************
changed: [192.168.221.171]
TASK [Add user to the group] ***************************************************
changed: [192.168.221.171]
PLAY RECAP *********************************************************************
192.168.221.171 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
To check if the given user is added to the new group, we first switch to the client1 node. Then, we run the groups command to see the groups associated with the user baeldung:
$ groups baeldung
baeldung : baeldung developers
Similarly, we can add a user to common groups like sudo.
Securing user accounts is paramount, and the Ansible user module provides straightforward methods for managing passwords.
The password option enables us to specify the encrypted password directly in the Ansible task. Generally, encrypted passwords can be generated in different ways. For example, the mkpasswd utility is a common option for this.
The whois package provides the mkpasswd utility. Let’s install it using the apt package manager:
$ sudo apt install whois
Now, let’s see how to use the mkpasswd command.
We can use the mkpasswd utility directly with an Ansible ad-hoc command:
$ ansible -i project_inventory.ini client1 -m user -a "name=Baeldung-CS password=$(mkpasswd --method=sha-512 '123')" --become
192.168.221.171 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"append": false,
"changed": true,
"comment": "",
"group": 1006,
"home": "/home/Baeldung-CS",
"move_home": false,
"name": "Baeldung-CS",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/sh",
"state": "present",
"uid": 1005
}
Here, in the above example, we set the password of user Baeldung-CS on client1 to 123. Moreover, to verify the set password, we can try logging in with the new password:
$ su - Baeldung-CS
Password:
$
At this point, the new password should be in effect.
If we wish to use mkpasswd with a playbook, we can use it to first generate the hash of a password on the command line:
$ mkpasswd --method=sha-512
Password:
$6$r6pnvoHc$gpG9kpqIbQfGL2o/NsTD/uN04OsZ15zAydVFPYkflnbSWCTTUBn9yC6IJb7MoRvzQqmadKuf.GEYv8ldQrlZO1
We can then place the obtained hashed password inside the playbook:
$ cat play_pass1.yml
---
- name: Create a password for user
hosts: client1
become: yes
tasks:
- name: Create a password for user baeldung
user:
name: baeldung
password: '$6$2OCdN3heBd$5swl1SfNkeiKd7n/WwZl/FpvhH4VJANl4u9j8kEA9gEjfl5lrqqQibiH2JU2rxW./Za3sp3BS2FabhTuTEAOQ.'
Let’s run the above playbook:
$ ansible-playbook -i project_inventory.ini play_pass1.yml
PLAY [Using Playbook] *****************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.221.171]
TASK [Create a password for user] **********************************************
changed: [192.168.221.171]
PLAY RECAP *********************************************************************
192.168.221.171 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Afterward, we should be able to log in with the new password on client1:
$ su - Baeldung-linux
Password:
$ pwd
/home/Baeldung-linux
$
Also, we can directly use the password_hash command to encrypt the password in the playbook:
$ cat play_pass2.yml
---
- name: Create a password for user
hosts: client1
become: yes
tasks:
- name: Create a password for user baeldung
user:
name: baeldung
password: "{{ '1234' | password_hash('sha512') }}"
Let’s again run the playbook:
$ ansible-playbook -i project_inventory.ini pass_playbook1.yml
PLAY [Create a password for user] **********************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.221.171]
TASK [Create a password for user baeldung] *************************************
changed: [192.168.221.171]
PLAY RECAP *********************************************************************
192.168.221.171 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Thus, both approaches enable us to log in with the new password.
Ansible simplifies the setup of remote access for users over SSH. For example, we can set passwordless access for our remote user on client1.
First, we create a playbook:
$ cat user_ssh.yml
---
- name: Create user, SSH directory, and transfer SSH keys
hosts: client1
become: yes # Use become to run tasks as a privileged user (e.g., sudo)
tasks:
- name: Create SSH directory for baeldung
file:
path: /home/baeldung/.ssh
state: directory
owner: baeldung
group: baeldung
mode: 0700
- name: Generate SSH key for baeldung
user:
name: baeldung
generate_ssh_key: yes
ssh_key_type: rsa
ssh_key_bits: 4096
ssh_key_file: /home/baeldung/.ssh/id_rsa # Full path is needed here
- name: Transfer public key to the target host
authorized_key:
user: baeldung
key: "{{ lookup('file', '/home/vagrant/.ssh/id_rsa.pub') }}"
Now, let’s break down the first play:
Similarly, the second play performs two main tasks:
Finally, the third play has the final action:
To modify the authorized_keys file of the remote user, baeldung, we run the above playbook:
$ ansible-playbook -i project_inventory.ini ssh_user.yml
PLAY [Create user, SSH directory, and transfer SSH keys] ***********************************************
TASK [Gathering Facts] *********************************************************************************
ok: [192.168.221.171]
TASK [Create SSH directory for baeldung] ***************************************************************
changed: [192.168.221.171]
TASK [Generate SSH key for baeldung] *******************************************************************
changed: [192.168.221.171]
TASK [Transfer public key to the target host] **********************************************************
changed: [192.168.221.171]
PLAY RECAP *********************************************************************************************
192.168.221.171 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Let’s now try to log in to the user baeldung from the controller node:
$ ssh [email protected]
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-110-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system is built by the Bento project by Chef Software
More information can be found at https://github.com/chef/bento
Last login: Tue Nov 21 06:56:07 2023 from 192.168.221.163
baeldung@client1:~$
Consequently, this time we don’t need a password to log in.
In this article, we discussed many ways to work with user management in Ansible.
First, we saw how to add a user on the remote machine using ad-hoc commands as well as with the playbook way. Further, we added the created user to a new group. Then, we secure the remote user by appending it with an encrypted password. Finally, we set up passwordless SSH access for the remote user from the controller node.