Bash Scripting: Automating User and Group Creation

Introduction

The HNG Internship is a premier training program designed to equip participants with hands-on experience in real-world software development and system administration. One of the key tasks in this internship is to manage the onboarding process for new developers efficiently and securely. This involves creating user accounts, setting up configurations, and ensuring compliance with security standards.

To address these needs, the create_users.sh script was developed. This script is a robust automation tool designed to streamline the onboarding process for new developers by efficiently creating user accounts and configuring them on Linux systems. The script significantly enhances operational efficiency within an organization’s IT infrastructure, ensuring that each new developer's environment is secure, compliant, and primed for immediate productivity.

This technical article will dissect the script’s architecture, elucidate the logic behind each function, and illustrate how these methods uphold industry standards for secure system management. Beyond being a mere functional tool, the script also acts as a crucial educational resource for the HNG Internship participants, equipping them with the necessary skills to tackle real-world IT challenges. For more insights into how the internship cultivates real-world software development skills, visit the HNG Internship here.

Step-by-Step Guide to create_users.sh

Step 1: Check for Root Privileges

Purpose: Ensure the script is run with administrative (root) privileges.

code:

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi

Explanation:

  • $EUID: Represents the Effective User ID of the current user. A value of 0 indicates root.

  • Why?: Managing users and groups requires root access. If the script is not run as root, it will terminate early to prevent errors.

Step 2: Define Log and Password File Paths

Purpose: Specify where logs and password information will be stored.

Code:

LOG="/var/log/user_management.log"
PASSWORD="/var/secure/user_passwords.csv"

Explanation:

  • Variables: LOG and PASSWORD hold paths for the log file and password file.

  • Why?: Centralizing file paths improves readability and makes future modifications easier.

Step 3: Create Log File If It Does Not Exist

Purpose: Ensure the log file exists to record script actions.

if [ ! -f $LOG ]; then
  echo "Log file does not exist, creating now..."
  sudo touch $LOG
  sudo chmod 644 $LOG
  echo "Log file created successfully."
else
  echo "Log file already exists."
fi

Explanation:

  • [ ! -f $LOG ]: Checks if the log file does not exist.

  • touch $LOG: Creates the log file.

  • chmod 644 $LOG: Sets file permissions to allow read/write for the owner and read-only for others.

  • Why?: Ensures that logging can occur throughout the script execution.

Step 4: Ensure the Secure Directory Exists

Purpose: Create a secure directory for storing password files if it does not already exist.

Code:

if [ ! -d "/var/secure" ]; then
    echo "Secure directory /var/secure does not exist, creating now..."
    sudo mkdir -p /var/secure
    sudo chmod 700 /var/secure
    echo "Secure directory created."
fi

Explanation:

  • [ ! -d "/var/secure" ]: Checks if the directory does not exist.

  • mkdir -p /var/secure: Creates the directory.

  • chmod 700 /var/secure: Sets permissions to allow only the owner (root) to access.

  • Why?: Ensures that sensitive information (passwords) is stored securely.

Step 5: Create Password File If It Does Not Exist

Purpose: Ensure the password file exists to store user passwords securely.

Code:

if [ ! -f $PASSWORD ]; then
  echo "Password file does not exist, creating now..."
  sudo touch $PASSWORD
  sudo chmod 600 $PASSWORD
  if [ -f $PASSWORD ]; then
    echo "Password file created successfully."
  else
    echo "Failed to create password file."
  fi
else
  echo "Password file already exists."
fi

Explanation:

  • [ ! -f $PASSWORD ]: Checks if the password file does not exist.

  • touch $PASSWORD: Creates the password file.

  • chmod 600 $PASSWORD: Sets file permissions to allow read/write for the owner only.

  • Why?: Ensures that user passwords are stored securely and are accessible only by the root user.

Step 6: Define Logging Function

Purpose: Create a function to log script actions to the log file.

Code:

log_action() {
    local message=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') : $message" >> $LOG
}

Explanation:

  • log_action Function: Accepts a message and appends it to the log file with a timestamp.

  • Why?: Provides a standardized way to log actions throughout the script for auditing and debugging.

Step 7: Generate Secure Passwords

Purpose: Generate a random, secure password for each new user.

Code:

generate_password() {
    local password_length=12
    local password=$(tr -dc 'A-Za-z0-9!@#$%^&*()_+{}|:<>?=' < /dev/urandom | head -c $password_length)
    echo $password
}

Explanation:

  • Local Variables: password_length sets the desired length of the password.

  • tr -dc ...: Filters random data to include only specified characters.

  • Why?: Ensures that each user has a strong, unique password, enhancing security.

Step 8: Process Input File and Create Users

Purpose: Read the input file, create users, assign groups, and set passwords.

Code:

while IFS=';' read -r user groups; do
    user=$(echo $user | xargs)
    groups=$(echo $groups | xargs)

    echo "Processing user: $user with groups: $groups"

    if id "$user" &>/dev/null; then
        log_action "User $user already exists. Skipping creation."
        echo "User $user already exists, skipping..."
        continue
    fi

    useradd -m -s /bin/bash $user
    log_action "Created user $user with home directory."

    if [ -n "$groups" ]; then
        IFS=',' read -ra GROUP_ARRAY <<< "$groups"
        for group in "${GROUP_ARRAY[@]}"; do
            group=$(echo $group | xargs)
            if ! getent group $group > /dev/null 2>&1; then
                groupadd $group
                log_action "Created group $group."
            fi
            usermod -aG $group $user
            log_action "Added user $user to group $group."
        done
    fi

    password=$(generate_password)
    echo "$user:$password" | chpasswd
    log_action "Set password for user $user."
    echo "$user,$password" >> $PASSWORD
done < "$1"

log_action "User creation process completed."
echo "User creation process completed."

Explanation:

  • IFS=';': Sets the Internal Field Separator for reading the input file.

  • read -r user groups: Reads each line, splitting it into user and groups.

  • useradd -m -s /bin/bash $user: Creates a new user with a home directory and default shell.

  • usermod -aG $group $user: Adds the user to specified groups.

  • generate_password: Calls the function to generate a secure password.

  • Why?: Automates user creation, group assignment, and password generation, ensuring a streamlined and secure onboarding process.

    Conclusion

    The create_users.sh Bash script effectively automates the management of user accounts and groups on a Linux system. By reading a text file containing employee usernames and their corresponding group names, the script seamlessly creates users and groups as specified. It also sets up home directories with the appropriate permissions and ownership, generates random secure passwords for the users, and logs all actions to /var/log/user_management.log. Additionally, the script ensures the secure storage of generated passwords in /var/secure/user_passwords.txt. This comprehensive automation tool significantly enhances the efficiency and security of the user onboarding process. Thank you for reading!