Automating User and Group Management on Linux with a Bash Script
Tags: bash, devops, productivity
Published: 2024-07-05 09:39:44

Hey there!

I’m excited to share the details of my Stage 1 task for the HNG DevOps Internship. This task involved creating a Bash script to automate the process of user and group management on a Linux system

## 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 script solves the problem by following these procedures:

Step 1: Reading the Input File
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 group_list. It does this simultaneously, allowing the index of each user in users to match their corresponding groups in group_list. We 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 group_list

# Function to read and parse the input file
read_input_file() {
  local filename="$1"
  while IFS=';' read -r user groups; do
    users+=("$(echo "$user" | xargs)")
    group_list+=("$(echo "$groups" | tr -d '[:space:]')")
  done < "$filename"
}

# Check for input file argument
if [[ $# -ne 1 ]]; then
  echo "Usage: $0 <input_file>"
  exit 1
fi

input_file="$1"
echo "Reading input file: $input_file"
read_input_file "$input_file"

```
Step 2: Creating Required Files and Directories
Next, we 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"

# Create log and password files if they do not exist
mkdir -p /var/log /var/secure
touch "$log_file"
touch "$password_file"
chmod 600 "$password_file"

```
Step 3: Creating Users and Groups
At this point, we have a list of the users in users, a list of their corresponding groups in group_list, and all the files we need to store valuable information such as logs and the passwords of the users we created.

Now, we use a for loop to iterate over each user and their corresponding groups with an index. Since we created the users and group_list arrays simultaneously by looping over each line in the file, the user at index 0 in users needs to be added to the groups at index 0 in group_list. So our for loop will look like this:

```
# Process each user
for ((i = 0; i < ${#users[@]}; i++)); do
  username="${users[i]}"
  user_groups="${group_list[i]}"

  if [[ "$username" == "" ]]; then
    continue  # Skip empty usernames
  fi

  create_user_with_group "$username"
  set_user_password "$username"
  add_user_to_groups "$username" "$user_groups"
done

echo "User creation and group assignment completed." | tee -a "$log_file"

```
So username 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:

```
# Function to create a user with its personal group
create_user_with_group() {
  local username="$1"
  if id "$username" &>/dev/null; then
    echo "User $username already exists." | tee -a "$log_file"
  else
    groupadd "$username"
    useradd -m -g "$username" -s /bin/bash "$username"
    echo "Created user $username with personal group $username." | tee -a "$log_file"
  fi
}

```
Step 4: Setting User Password
We set a password for the user by using openssl to generate 12 random base64 characters. We then store the user's password in /var/secure/user_passwords.txt.

These are done using the code below:

```
# Function to set a password for the user
set_user_password() {
  local username="$1"
  local password=$(openssl rand -base64 12)
  echo "$username:$password" | chpasswd
  echo "$username,$password" >> "$password_file"
  echo "Password for $username set and stored." | tee -a "$log_file"
}

```
Step 5: Adding Users to Groups
Next, we add the user to their groups. We do this by first checking if the group exists. If it doesn't, we create the group and then add the user to the group.

See the code below:

```
# Function to add user to additional groups
add_user_to_groups() {
  local username="$1"
  IFS=',' read -r -a groups <<< "$2"
  for group in "${groups[@]}"; do
    if ! getent group "$group" &>/dev/null; then
      groupadd "$group"
      echo "Group $group created." | tee -a "$log_file"
    fi
    usermod -aG "$group" "$username"
    echo "Added $username to group $group." | tee -a "$log_file"
  done
}

```

## Summary
And just like that, all 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 program gracefully, but we also have a log for further investigation.

## Benefits of Automation

- Efficiency: Automates repetitive tasks, freeing up time for more critical activities.

- Consistency: Ensures that user and group configurations are applied uniformly.

- Security: Randomly generated passwords enhance security, and storing them securely minimizes risks.

- Auditing: Detailed logging helps in tracking changes and troubleshooting.

## Learn More
If you're interested in advancing your career in tech, consider joining the HNG Internship program, visit [HNG Internsip](https://hng.tech/internship) or [HNG Premium](https://hng.tech/premium). It's an excellent opportunity to gain hands-on experience and learn from industry professionals.

For those looking to hire top tech talent, HNG Hire connects you with skilled developers who have undergone rigorous training.

That's it for now, but stay tuned for the exciting tasks in Stage 2!