Making users in Linux isn't necessarily as simple as making a username, and giving it a password. There are a few considerations you need to know about! Knowing these will make creating new users in Ansible easier.
First, some Linux distributions have the adduser
command, wihch is a shortcut (with sensible defaults) to the useradd
command.
By default, adduser
command will create a new user that is able to login and has a home directory. The useradd
command needs to be told to do all of these things. The way Ansible creates a user is more like useradd
than the easier adduser
.
Considerations
Here are a few things to know about creating a new user on Linux systems:
System vs Regular Users
By convention, users can be "system" users or "normal" users. System users often have a user id (UID) below 1000 and cannot be used to login. They are usually used to run programs. For example, users www-data
or apache
are often used to run web servers. Conversely, "regular" users typically have UID's at 1000 or higher and are allowed to log into the server.
If you're curious about how UID's are assigned, you can see the file /etc/login.defs
to find variables like UID_MIN and UID_MAX set for system vs regular users:
#
# Min/max values for automatic uid selection in useradd
#
UID_MIN 1000
UID_MAX 60000
# System accounts
#SYS_UID_MIN 100
#SYS_UID_MAX 999
#
# Min/max values for automatic gid selection in groupadd
#
GID_MIN 1000
GID_MAX 60000
# System accounts
#SYS_GID_MIN 100
#SYS_GID_MAX 999
Ability to Login
Users cannot login (over SSH or otherwise) unless they are assigned a shell, usually /bin/bash
. This shell is the program run when you login - it's why you can interact with the server.
The ability to login usually coincides with assigning the user a home directory. By convention (and default), this is created at /home/<username>
, but can be any location.
Groups
Users have a primary group, which is usually the same name as their username. However, users can be assigned one or more secondary groups.
Creating a User in Ansible
Knowing the above, we can create a user in Ansible.
We'll create a user who is able to login with the following attributes:
- User: fideloper
- Password: secret
- Home Directory: /home/fideloper
- Shell: /bin/bash
We can see we're creating a "regular" user, one that can login. That user will likely be assigned a UID of 1000 or greater.
Here's a Ansible task file with a user definition for the above. It uses the user module to create a user:
---
- name: Create a login user
user:
name: fideloper
password: '???'
groups: # Empty by default, here we give it some groups
- docker
- sudo
state: present
shell: /bin/bash # Defaults to /bin/bash
system: no # Defaults to no
createhome: yes # Defaults to yes
home: /home/fideloper # Defaults to /home/<username>
Let's cover that task definition:
name
: Set the username (the primary group they belong to will be the same).password
: Set their password, we'll cover how this works in a minute.groups
: Assign secondary groups. Here we add this user to groups "docker" and "sudo" (groupsudo
allows the user to run sudo commands on Ubuntu and Debian linux).state
: Tell ansible we want the user to exist.shell
: You can define any shell. The default is/bin/bash
. I just re-iterate the default here.system
: Set this to "yes" to make it a system user. No shell or home directory will be made unless specified otherwise.createhome
: Yes to create a home directory, no to not create onehome
: If you don't want to use the default location, set it here
Note that we have a few ways we can create users. Using the "system" setting we essentially flip a few defaults. A system user will have a lower UID, no shell, and no home directory. A "regular" user (system: no
) will have these things assigned, and likely a UID at 1000 or over.
Generating Password Strings
The one thing I left off here is how to make a valid password string. You can't put a plaintext password into Ansible. Instead you need to generate one!
The easiest way to do this is with the mkpasswd
command:
mkpasswd --method=sha-512
This will prompt you for the plaintext password and will give you a hashed password string you can paste into the task definition. For password secret
, I get hash $6$F4NWXRFtSdCi8$DsB5vvMJYusQhSbvGXrYDXL6Xj37MUuqFCd4dGXdKd6NyxT3lpdELN07/Kpo7EjjWnm9zusFg/LLFv6oc.ynu/
.
That would make my Yaml look like this:
---
- name: Create a login user
user:
name: fideloper
password: '$6$F4NWXRFtSdCi8$DsB5vvMJYusQhSbvGXrYDXL6Xj37MUuqFCd4dGXdKd6NyxT3lpdELN07/Kpo7EjjWnm9zusFg/LLFv6oc.ynu/'
groups: docker, sudo # Empty by default.
state: present
shell: /bin/bash # Defaults to /bin/bash
system: no # Defaults to no
createhome: yes # Defaults to yes
home: /home/fideloper # Defaults to /home/<username>
Installing mkpasswd
- On Debian/Ubuntu systems,
mkpasswd
likely exists, but if not, it's part of thewhois
package:sudo apt-get install -y whois
. - On CentOS, I believe the
expect
package has it:sudo yum install expect
. However, you can check to see ifgrub-crypt
is available too and use it just likemkpasswd
. - On Macintosh, you can install the
mkpasswd
gem viagem install mkpasswd
. Source code here.
Resources
- Check the docs for more info, such as creating an SSH key on the fly
- Use the authorized_keys module to add an authorized public key