Automating User and Group Management Using Bash Script

florenceokoli

Florence Okoli

Posted on July 3, 2024

Automating User and Group Management Using Bash Script

Bash, short for Bourne Again Shell, is a Unix shell and command language that has been a fundamental part of system administration and development for many years. As the default shell on many Unix-like operating systems, including Linux and macOS, Bash is renowned for its powerful capabilities in scripting and automation.

Imagine having to create user accounts, assign them to appropriate groups, set up home directories, and generate secure passwords for each new developer joining your team. Doing this manually can be tedious and error-prone. This is where Bash comes in. You can automate these repetitive tasks with Bash scripting, ensuring consistency and saving valuable time.

In this article, I used a Bash script to automate the onboarding process for new developers. This script reads a text file containing usernames and their respective groups, creates users, assigns them to groups, sets up their home directories, generates random passwords, and logs all actions.

Prerequisites

  • A Unix-based system (Linux or macOS)
  • Basic knowledge of Unix commands and Bash scripting

Objective

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

My create_users.sh Script

#!/bin/bash

# Log file and password storage
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"

# Ensure the /var/secure directory exists
if [ ! -d "/var/secure" ]; then
    mkdir -p /var/secure
    chmod 700 /var/secure
fi

# Ensure the log file and password file exist and have correct permissions
touch $LOG_FILE
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}

# Check if the file is supplied
if [ $# -ne 1 ]; then
    log_message "ERROR: No input file supplied"
    echo "Usage: $0 <name-of-text-file>"
    exit 1
fi

INPUT_FILE=$1

# Check if input file exists
if [ ! -f $INPUT_FILE ]; then
    log_message "ERROR: Input file does not exist"
    echo "ERROR: Input file does not exist"
    exit 1
fi

# Read the input file line by line
while IFS=';' read -r username groups; do
    # Trim whitespace
    username=$(echo $username | xargs)
    groups=$(echo $groups | xargs)

    # Skip empty lines
    if [ -z "$username" ]; then
        continue
    fi

    # Create a personal group for the user
    if ! getent group $username >/dev/null; then
        groupadd $username
        log_message "Group $username created."
    else
        log_message "Group $username already exists."
    fi

    # Create the user with the personal group
    if ! id -u $username >/dev/null 2>&1; then
        useradd -m -g $username $username
        log_message "User $username created."
    else
        log_message "User $username already exists."
    fi

    # Assign the user to additional groups
    IFS=',' read -ra ADDR <<< "$groups"
    for group in "${ADDR[@]}"; do
        group=$(echo $group | xargs)
        if [ ! -z "$group" ]; then
            if ! getent group $group >/dev/null; then
                groupadd $group
                log_message "Group $group created."
            fi
            usermod -aG $group $username
            log_message "User $username added to group $group."
        fi
    done

    # Generate a random password
    password=$(openssl rand -base64 12)

    # Set the user's password
    echo "$username:$password" | chpasswd
    log_message "Password set for user $username."

    # Store the password securely
    echo "$username,$password" >> $PASSWORD_FILE
done < "$INPUT_FILE"

# Set the correct permissions on the password file
chmod 600 $PASSWORD_FILE

log_message "User creation process completed."

echo "User creation process completed. Check $LOG_FILE for details."
Enter fullscreen mode Exit fullscreen mode

A detailed breakdown of the Script

Here is what this script does:

  • Shebang
    The #!/bin/bash known as the shebang indicates that the script should be run on the BASH shell.

  • Path to Log file and Password file

LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
Enter fullscreen mode Exit fullscreen mode

The LOG_FILE and PASSWORD_FILE are variables that store the path to the log file and password file respectively.

  • Create /var/secure directory and set permission if it doesn't exist
if [ ! -d "/var/secure" ]; then
    mkdir -p /var/secure
    chmod 700 /var/secure
fi
Enter fullscreen mode Exit fullscreen mode
  • Create Log file and Password file if they don't exist and set permission
touch $LOG_FILE
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE
Enter fullscreen mode Exit fullscreen mode

touch $LOG_FILE and touch $PASSWORD_FILE creates the log and password files if they do not already exist.
chmod 600 $PASSWORD_FILE sets the permissions for the password file so that only the file owner can read and write to it.

  • Log message function
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}
Enter fullscreen mode Exit fullscreen mode

The log_message function takes a message as an argument and appends it to the log file with a timestamp.

  • Check if input file is provided
if [ $# -ne 1 ]; then
    log_message "ERROR: No input file supplied"
    echo "Usage: $0 <name-of-text-file>"
    exit 1
fi
Enter fullscreen mode Exit fullscreen mode

This checks if [ $# -ne 1 ]; then checks if exactly one argument (the input file) is supplied to the script.
If not, it logs an error, prints a usage message, and exits the script.

  • INPUT_FILE=$1 assigns the first argument (input file) to the variable INPUT_FILE

  • Check if the input file exists

if [ ! -f $INPUT_FILE ]; then
    log_message "ERROR: Input file does not exist"
    echo "ERROR: Input file does not exist"
    exit 1
fi
Enter fullscreen mode Exit fullscreen mode

The if [ ! -f $INPUT_FILE ]; then checks if the input file exists.
If not, it logs an error, prints an error message, and exits the script.Cre

  • Read and process the input file

The while IFS=';' read -r username groups; do starts a loop to read the input file line by line, expecting each line to contain a username and groups separated by a semicolon (;).

  • The command below trims whitespace from the username and groups variables if any.
    username=$(echo $username | xargs)
    groups=$(echo $groups | xargs)
Enter fullscreen mode Exit fullscreen mode

While

    if [ -z "$username" ]; then
        continue
    fi
Enter fullscreen mode Exit fullscreen mode

Skips empty lines (where username is empty).

  • Create a group for user
    if ! getent group $username >/dev/null; then
        groupadd $username
        log_message "Group $username created."
    else
        log_message "Group $username already exists."
    fi
Enter fullscreen mode Exit fullscreen mode

This creates a personal group for the user if it doesn't exist and logs the action.

  • Creates user for group
 if ! id -u $username >/dev/null 2>&1; then
        useradd -m -g $username $username
        log_message "User $username created."
    else
        log_message "User $username already exists."
    fi
Enter fullscreen mode Exit fullscreen mode

This creates the user with their group if they don't already exist and logs the action.

  • Creates additional groups for users.
IFS=',' read -ra ADDR <<< "$groups"
    for group in "${ADDR[@]}"; do
        group=$(echo $group | xargs)
        if [ ! -z "$group" ]; then
            if ! getent group $group >/dev/null; then
                groupadd $group
                log_message "Group $group created."
            fi
            usermod -aG $group $username
            log_message "User $username added to group $group."
        fi
    done
Enter fullscreen mode Exit fullscreen mode

This command splits the group's string into an array, iterates over it, checks if the group exists (creating it if necessary) and adds the user to the group, logging each action.

  • Generate a random password
    The password=$(openssl rand -base64 12) generates a random password using the OpenSSL

  • Set the user's password

    echo "$username:$password" | chpasswd
    log_message "Password set for user $username."
    echo "$username,$password" >> $PASSWORD_FILE
done < "$INPUT_FILE"
Enter fullscreen mode Exit fullscreen mode

The code above sets the user's password and then appends the username and password to the PASSWORD_FILE

  • This done < "$INPUT_FILE" code ends the loop that reads from the INPUT FILE

  • The chmod 600 $PASSWORD_FILE code ensures the password file's permissions are secure after all passwords have been added.

  • Log completion of the user creation process
    log_message "User creation process completed."

Test the Script

To test this script, let's create a users.txt file
nano users.txt

In the text file, enter the usernames and groups
wendy; engineering,webteam
florenceokoli; admins, dev_team
chi; support

Execute the Script

`chmod create_users.sh

Run the Script

sudo ./create_users.sh users.txt

Output

  • Management Log
    Management Log File

  • Password.txt File
    Password.txt file

Conclusion

Bash is a powerful scripting tool used to automate various tasks on Unix-like operating systems. This script is designed to read a text file containing usernames and their respective groups, create users and their personal groups, assign users to additional groups, set up home directories, generate random passwords, and log all these actions for auditing purposes. Additionally, it stores the generated passwords securely in a dedicated file.

This project is a stage 1 task in the Devops HNG-11 Internship. For more information about the HNG Internship and its various opportunities, visit HNG Internship and HNG Hire.

💖 💪 🙅 🚩
florenceokoli
Florence Okoli

Posted on July 3, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related