DEV Community

Alexin
Alexin

Posted on

Automating User and Group Management with a Bash Script in Linux

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

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:

  1. Read Input File:

    • Read the text file containing the employee’s usernames and group names.
    • Each line is formatted as user;groups.
  2. Process Each Line:

    • Split each line into the username and the corresponding groups.
    • Remove any whitespace for accurate processing.
  3. 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.
  4. Set Up Home Directories:

    • Create home directories for each user.
    • Set appropriate permissions and ownership for the directories.
  5. Generate and Store Passwords:

    • Generate random passwords for each user.
    • Securely store the passwords in /var/secure/user_passwords.txt.
  6. Log Actions:

    • Log all actions performed (e.g., user creation, group assignment) to /var/log/user_management.log.
  7. 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:

  1. Create folders for logs and secure passwords, but do nothing if they already exist.

    mkdir -p /var/log /var/secure
    
  2. Create files for logs and password storage.

    touch /var/log/user_management.log
    touch /var/secure/user_passwords.txt
    
  3. Make the password file secure, giving it read and write permission for the file owner only.

    chmod 600 /var/secure/user_passwords.txt
    
  4. Define a function that logs actions performed by the script to the log file.

    log_action() {
    echo "$(date) - $1" >> "/var/log/user_management.log"
    }
    
  5. 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."
    }
    
  6. 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
    
  7. 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
    
  8. 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."
Enter fullscreen mode Exit fullscreen mode

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)