DEV Community

Ugochukwu Chukwuma
Ugochukwu Chukwuma

Posted on

User(s) Creation Automation with Bash

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • 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]}"

Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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:

    # Create personal group if linux distro didn't create it by default
    if grep -q "^$user:" /etc/group; then
      echo "Personal group $user already exists" | tee -a "$log_file"
    else
      echo "Personal group $user does not exist, creating $user" | tee -a "$log_file"
      groupadd "$user"
      if [[ $? -ne 0 ]]; then
        echo "Failed to create personal group $user" | tee -a "$log_file"
        exit 1
      fi
    fi

    # 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"

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)