As a DevOps engineer, it is quite a common task to create, update, and delete users and groups. Automating this process can save a lot of time and help reduce human errors, especially when onboarding numerous users. In this article, I'll walk you through using bash to automate the creation of users and their respective groups, setting up home directories, generating random passwords, and logging all actions performed.
Objectives
- Create users and their personal groups.
- Add users to specified groups.
- Set up home directories with appropriate permissions.
- Generate and securely store passwords.
- Log all actions for auditing purposes.
- Ensure error handling.
Let's Begin
First and foremost, at the beginning of any shell script we're writing, we start with "shebang" in the first line.
#!/bin/bash
Shebang tells us that the file is executable.
Setting up the directory for user logs and file
It is necessary to create a directory and files for logging and password storage. If it already exists, DO NOT CREATE IT AGAIN!!!
mkdir -p /var/log /var/secure
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt
- /var/log: Directory for log files.
- /var/secure: Directory for secure files.
- user_management.log: Log file to record actions.
Secure the generated passwords
chmod 600 /var/secure/user_passwords.txt
- user_passwords.txt: File to store passwords securely with read and write permissions for the file owner only.
Earlier, we created the directory "/var/secure
" to store user_password.txt
. To give the appropriate permissions, we use chmod 600
to give only the current user access to view our generated passwords.
Create a function to log actions
The log_action()
function record actions with timestamps in the log file.
log_action() {
echo "$(date) - $1" >> "/var/log/user_management.log"
}
User Creation Function
The create_user()
function handles the creation of user accounts and their associated groups. It takes two arguments: username and groups.
Steps taken in the create_user()
function:
- Check for Existing User: Logs a message if the user already exists.
if id "$user" &>/dev/null; then
log_action "User $user already exists."
return
fi
id "$user" &>/dev/null
checks if the user exists by attempting to retrieve the user's information. If the user does not exist, id
will return a non-zero exit status. The &>/dev/null
part redirects any output (both stdout and stderr) to /dev/null
, effectively silencing the command's output.
If the user exists log_action "User $user already exists."
logs a message indicating that the user already exists. Using return
, it exits the create_user()
function early, preventing any further actions from being taken for the existing user.
- Create User Group: Creates a personal group for the user.
groupadd "$user"
groupadd "$user"
creates a new group with the same name as the user. This group will be the primary group for the user being created.
- Handle Additional Groups: Checks and creates additional groups if they do not exist.
IFS=' ' read -ra group_array <<< "$groups"
log_action "User $user will be added to groups: ${group_array[*]}"
for group in "${group_array[@]}"; do
group=$(echo "$group" | xargs) # Trim whitespace
if ! getent group "$group" &>/dev/null; then
groupadd "$group"
log_action "Group $group created."
fi
done
Here, we split the groups
string into an array using spaces as delimiters and log the groups that the user will be added to. Using for group in "${group_array[@]}"; do
, we are able to iterates over each group in the group_array
and trim any leading or trailing whitespace from the group name. Using if ! getent group "$group" &>/dev/null; then
to check if the group already exists else we create the group groupadd "$group"
and log that the group has been created log_action "Group $group created."
.
- Create User: Creates the user with a home directory and bash shell.
useradd -m -s /bin/bash -g "$user" "$user"
if [ $? -eq 0 ]; then
log_action "User $user created with primary group: $user"
else
log_action "Failed to create user $user."
return
fi
- Assign Groups: Adds the user to additional groups.
for group in "${group_array[@]}"; do
usermod -aG "$group" "$user"
done
log_action "User $user added to groups: ${group_array[*]}"
for group in "${group_array[@]}"; do
to iterate over each group in the group_array
then adds the user to the specified group (-aG
means append the user to the group). Next, log that the user has been added to the specified groups.
- Generate and Store Password: Generates a random password and stores it securely.
password=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 12)
echo "$user:$password" | chpasswd
echo "$user,$password" >> "/var/secure/user_passwords.txt"
We use /dev/urandom
to generate a random 12-character password and tr
to filter alphanumeric characters. Next, we set the password for the user using the chpasswd
command and append the username and password to the secure file /var/secure/user_passwords.txt
.
- Set Permissions: This part of the code is responsible for setting the appropriate permissions and ownership for the user's home directory.
chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
Using 700
, only the user has read, write, and execute permissions. chown "$user:$user" "/home/$user"
to set the owner and group of the home directory to the user.
Here is the full combined code within the create_user()
function.
create_user() {
local user="$1"
local groups="$2"
local password
if id "$user" &>/dev/null; then
log_action "User $user already exists."
return
fi
groupadd "$user"
IFS=' ' read -ra group_array <<< "$groups"
log_action "User $user will be added to groups: ${group_array[*]}"
for group in "${group_array[@]}"; do
group=$(echo "$group" | xargs)
if ! getent group "$group" &>/dev/null; then
groupadd "$group"
log_action "Group $group created."
fi
done
useradd -m -s /bin/bash -g "$user" "$user"
if [ $? -eq 0 ]; then
log_action "User $user created with primary group: $user"
else
log_action "Failed to create user $user."
return
fi
for group in "${group_array[@]}"; do
usermod -aG "$group" "$user"
done
log_action "User $user added to groups: ${group_array[*]}"
password=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 12)
echo "$user:$password" | chpasswd
echo "$user,$password" >> "/var/secure/user_passwords.txt"
chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
log_action "Password for user $user set and stored securely."
}
Main Execution Flow
if [ $# -ne 1 ]; then
echo "Usage: $0 <user_list_file>"
exit 1
fi
filename="$1"
if [ ! -f "$filename" ]; then
echo "Users list file $filename not found."
exit 1
fi
while IFS=';' read -r user groups; do
user=$(echo "$user" | xargs)
groups=$(echo "$groups" | xargs | tr -d ' ')
groups=$(echo "$groups" | tr ',' ' ')
create_user "$user" "$groups"
done < "$filename"
echo "Creation of user is complete. Go ahead and check /var/log/user_management.log for detailed information."
Here, we check if the user file is provided, then read the user list file and process each user entry, calling the create_user()
function for each line and passing the $user
and $groups
as arguments.
Let's put everything together
#!/bin/bash
# Create directory for user logs and passwords
mkdir -p /var/log /var/secure
# Create logs file and passwords file
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt
# Make the password file secure for the file owner (read and write permissions for file owner only)
chmod 600 /var/secure/user_passwords.txt
# Create a function to record actions to log file
log_action() {
echo "$(date) - $1" >> "/var/log/user_management.log"
}
create_user() {
local user="$1"
local groups="$2"
local password
# Check if user already exists by logging user information with id
if id "$user" &>/dev/null; then
log_action "User $user already exists."
return
fi
# Create personal group for the user
groupadd "$user"
# Create additional groups if they do not exist
IFS=' ' read -ra group_array <<< "$groups"
log_action "User $user will be added to groups: ${group_array[*]}"
for group in "${group_array[@]}"; do
group=$(echo "$group" | xargs) # Trim whitespace
if ! getent group "$group" &>/dev/null; then
groupadd "$group"
log_action "Group $group created."
fi
done
# Create user with home directory and shell, primary group set to the personal group
useradd -m -s /bin/bash -g "$user" "$user"
if [ $? -eq 0 ]; then
log_action "User $user created with primary group: $user"
else
log_action "Failed to create user $user."
return
fi
# Add the user to additional groups
for group in "${group_array[@]}"; do
usermod -aG "$group" "$user"
done
log_action "User $user added to groups: ${group_array[*]}"
# Generate password and store it securely in a file
password=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 12)
echo "$user:$password" | chpasswd
# Store user and password securely in a file
echo "$user,$password" >> "/var/secure/user_passwords.txt"
# Set permissions and ownership for user home directory
chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
log_action "Password for user $user set and stored securely."
}
# Check if user list file is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <user_list_file>"
exit 1
fi
filename="$1"
if [ ! -f "$filename" ]; then
echo "Users list file $filename not found."
exit 1
fi
# Read user list file and create users
while IFS=';' read -r user groups; do
user=$(echo "$user" | xargs)
groups=$(echo "$groups" | xargs | tr -d ' ')
# Replace commas with spaces for usermod group format
groups=$(echo "$groups" | tr ',' ' ')
create_user "$user" "$groups"
done < "$filename"
echo "Creation of users is complete. Go ahead and check /var/log/user_management.log for detailed information."
Usage
To use this script, provide a user list file as an argument. Each line in the file should contain a username and a comma-separated list of groups (optional), separated by a semicolon. For example:
light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data
To run the script, use this command.
./script_name.sh user_list_file.txt
If you are not a root user, use sudo ./create_users.sh user_list_file.txt
Conclusion
This script provides a robust solution for automating user creation and management, ensuring secure handling of passwords and detailed logging of actions. It simplifies the process of setting up new user accounts while maintaining security and auditability.
To learn more and kickstart your programming journey you can visit:
https://hng.tech/internship or https://hng.tech/premium
Feel free to reach out with questions or suggestions for improvements. Happy automating!ππ
Top comments (0)