User(s) Creation Automation with Bash

RMAG news

Hey there!

So here is a synopsis of my stage 1 task at the HNG DevOps Internship

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.

Sample Input

light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data

Solution

The programme I wrote solves the problem by following these procedures;

First, we read the input file using a function that adds the users to a global variable called users and the groups to another variable called groups. It does this simultaneously allowing the index of each user in users to match their corresponding groups in groups.

I also ensure the user has entered a valid input file before running this.

Here’s the code that does all of this:

declare -a users
declare
-a groups

function read_input() {
local file=$1

while IFS= read -r line; do
user=$(echo $line | cut -d‘;’ -f1)
groups_data=$(echo $line | cut -d‘;’ -f2 | tr -d ‘[:space:]’)
users+=($user)
groups+=($groups_data)
done < $file
}

if [[ $# -ne 1 ]]; then
echo “Usage: $0 <input_file>”
exit 1
fi

input_file=$1
echo “Reading input file: $input_file
read_input $input_file

Next, I go on to create the required files and their directories if they don’t already exist using this code:

log_file=“/var/log/user_management.log”
password_file=“/var/secure/user_passwords.txt”

if [ ! -f $log_file ]; then
mkdir -p /var/log
touch $log_file
fi

if [ ! -f $password_file ]; then
mkdir -p /var/secure
touch $password_file
fi

Then the main event, at this point I have a list of the users in users, a list of their corresponding groups in groups and all the files I will need to store valuable information such as logs and the passwords of the users I created.

Now, I use a for loop to iterate over each user and their corresponding groups with an index.

Remember we created the users and groups array simultaneously by looping over each line in the file this means the user at index
0 in users needs to be added to the groups at index 0 in groups, so our for loop will look like this:

for (( i = 0; i < ${#users[@]}; i++ )); do
user=${users[$i]}
user_groups=${groups[$i]}

So user is the user we are working on and user_groups are the groups we are adding them to.

Next, we check if the user exists, if they do we just continue with the next iteration; else, we create them with this code:

if id $user &>/dev/null; then
echo “User $user already exists, Skipped” | tee -a $log_file
else
# Create user
useradd -m -s /bin/bash $user
if [[ $? -ne 0 ]]; then
echo “Failed to create user $user | tee -a $log_file
exit 1
fi
echo “User $user created” | tee -a $log_file

Then we set a password for them by using openssl to generate 50 random base64 characters then we filter the result to extract the alphabets, numbers and some special characters. We finally slice the first 10 characters and this will serve as the user’s password.

We go ahead to store the users password in /var/secure/user_passwords.txt.

These are done using the code below:

# Set password
password=$(openssl rand -base64 50 | tr -dc ‘A-Za-z0-9!?%=’ | head -c 10)
echo $user:$password | chpasswd
if [[ $? -ne 0 ]]; then
echo “Failed to set password for $user | tee -a $log_file
exit 1
fi

echo “Password for $user set” | tee -a $log_file
echo $user:$password >> $password_file

Finally, we add the user to their groups.

We do this by first of all checking if a personal group was created for the user–most linux distros do this by default on user creation due to security reasons. But if it didn’t we create a personal group for the user and add the user to the group.

See code below:

# Add user to personal group
usermod -aG $user $user
if [[ $? -ne 0 ]]; then
echo “Failed to add $user to $user group” | tee -a $log_file
exit 1
fi
echo “Added $user to $user group” | tee -a $log_file

After which we split the previously created variable user_groups by , and iterate through each element creating the group if it doesn’t already exist and adding the user to the group. Then we finally close our initial loop

We do this using this code:

# Add user to other groups
for group in $(echo $user_groups | tr ‘,’ ‘n’); do
if
grep -q “^$group:” /etc/group; then
echo “Group $group already exists” | tee -a $log_file
else
echo “Group $group does not exist, creating $group | tee -a $log_file
groupadd $group

if [[ $? -ne 0 ]]; then
echo “Failed to create group $group | tee -a $log_file
exit 1
fi
fi

usermod -aG $group $user
if [[ $? -ne 0 ]]; then
echo “Failed to add $user to $group group” | tee -a $log_file
exit 1
fi
echo “Added $user to $group group” | tee -a $log_file
done
fi
done

And just like that, all the new employees now have user profiles!

You can also reuse this script for new employees. Exciting right?

You will also notice how I appropriately log each event in the log file and gracefully handle failures in each command so even if we run into unexpected problems in our execution we not only end the programme gracefully we also have a log for further investigation.

That’s it for now, but be sure to tune in for the Stage 2 task 😉

I am also open to constructive criticism so be sure to leave a comment.

Also, you can learn more about HNG here