In the fast-paced world of DevOps Engineering, automation is key to efficiency and reliability. Managing user accounts and groups manually can be a stressful, time-consuming, and error-prone task, especially in environments with numerous users. Recognizing this challenge, the HNG Internship provided a practical task that simulates a real-world scenario, where interns are required to automate user and group management on a Linux system.
The task is to create a Bash script that automates the creation of users and groups, securely manages passwords, and logs all actions performed. This exercise not only enhances scripting skills but also deepens the understanding of Linux system administration.
Task
Your company has employed many new developers. As a SysOps engineer, write a bash script called create_users.sh
that reads a text file containing the employee’s usernames and group names, where each line is formatted as user;groups.
The script should create users and groups as specified, set up home directories with appropriate permissions and ownership, generate random passwords for the users, and log all actions to /var/log/user_management.log
. Additionally, store the generated passwords securely in /var/secure/user_passwords.txt
.
Ensure error handling for scenarios like existing users and provide clear documentation and comments within the script.
Requirements:
- Each User must have a personal group with the same group name as the username, this group name will not be written in the text file.
- A user can have multiple groups, each group delimited by comma ","
- Usernames and user groups are separated by semicolon ";"- Ignore whitespace e.g.
light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data
For the first line, light is username and groups are sudo, dev, www-data.
My solution
To tackle this problem, I first broke down the requirements stated into clear, actionable steps:
-
Read Input File:
- Read the text file containing the employee’s usernames and group names.
- Each line is formatted as
user;groups
.
-
Process Each Line:
- Split each line into the username and the corresponding groups.
- Remove any whitespace for accurate processing.
-
Create Users and Groups:
- Ensure each user has a personal group with the same name as their username.
- Create additional groups if they do not already exist.
- Add the user to the specified groups.
-
Set Up Home Directories:
- Create home directories for each user.
- Set appropriate permissions and ownership for the directories.
-
Generate and Store Passwords:
- Generate random passwords for each user.
- Securely store the passwords in
/var/secure/user_passwords.txt
.
-
Log Actions:
- Log all actions performed (e.g., user creation, group assignment) to
/var/log/user_management.log
.
- Log all actions performed (e.g., user creation, group assignment) to
-
Error Handling:
- Implement error handling to manage scenarios like existing users or groups.
From this list of requirements, I mapped out a clear plan to solve the problem. These are the steps I followed:
-
Create folders for logs and secure passwords, but do nothing if they already exist.
mkdir -p /var/log /var/secure
-
Create files for logs and password storage.
touch /var/log/user_management.log touch /var/secure/user_passwords.txt
-
Make the password file secure, giving it read and write permission for the file owner only.
chmod 600 /var/secure/user_passwords.txt
-
Define a function that logs actions performed by the script to the log file.
log_action() { echo "$(date) - $1" >> "/var/log/user_management.log" }
-
Create a function that handles user creation. This function does the following:
- Checks if the user already exists by calling the id command and redirecting the output to
/dev/null
. If the user exists, it logs a message and returns. - Creates a personal group for the user using the
groupadd
command. - Creates the additional groups if they do not exist.
- Creates the user with the
useradd
command, setting the home directory, shell, and primary group. - Logs a message indicating the success or failure of the
useradd
command. - Adds the user to the other groups using the
usermod
command. - Generates a random password for the user using
/dev/urandom
and stores the user and their respective password in/var/secure/user_passwords.txt
, the secure password file. - Sets the permissions and ownership for the user's home directory.
Here is the source code:
create_user() { # defines 3 variables passed to the function: user, groups, and password 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 the group array 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." }
- Checks if the user already exists by calling the id command and redirecting the output to
-
In the main script, check if the list of users was provided in the script's arguments.
if [ $# -ne 1 ]; then echo "Usage: $0 <user_list_file>" exit 1 fi
-
If it was provided, check that it is a valid file:
filename="$1" if [ ! -f "$filename" ]; then echo "Users list file $filename not found." exit 1 fi
-
Read the file line-by-line, extract the user and groups from each line, and call the
create_user
function passing the user and groups as an argument:
filename="$1" if [ ! -f "$filename" ]; then echo "Users list file $filename not found." exit 1 fi
Here is the complete code file:
#!/bin/bash
# create folders for logs and secure 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 password file secure (read and write permissions for file owner only)
chmod 600 /var/secure/user_passwords.txt
# function to log actions to log file
log_action() {
echo "$(date) - $1" >> "/var/log/user_management.log"
}
create_user() {
# defines 3 variables passed to the function: user, groups, and password
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 the group array
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 "User creation process completed. Check /var/log/user_management.log for details."
The create_users.sh
bash script has successfully automated user and group management on a Linux system. It reads a text file containing employee usernames and group names, creates users and groups as specified, sets up home directories with appropriate permissions and ownership, generates random passwords for the users, and logs all actions to /var/log/user_management.log
. Additionally, it securely stores the generated passwords in /var/secure/user_passwords.txt
. Thanks for reading!
Top comments (1)