DEV Community

Cover image for Automating Linux User Creation with a Bash Script
sipsdaoracle
sipsdaoracle

Posted on

Automating Linux User Creation with a Bash Script

A Practical Script for SysOps Engineers

In the SysOps engineer world, automation is key, especially for repetitive tasks that save valuable time and ensure consistency. As a SysOps engineer, knowing how to write robust and efficient scripts along with strong Linux skills, boosts productivity and gives you a better workflow. This article will walk you through a bash script designed to automate the creation of Linux users.

The script creates users and groups as specified, sets up home directories with appropriate permissions and ownership, it generates random passwords for the users, and logs all actions to /var/log/user_management.log. Additionally, it stores the generated passwords securely in /var/secure/user_passwords.txt. and covers error handling for scenarios like existing users.

Prerequisite:

  • Bash shell environment.
  • Text editor for editing the script and preparing the input file.

Let's have a look at our script which we will later use to accomplish this task, and break it down by a detailed explanation of each section:

#!/bin/bash

# Check if the script is run as root
if [[ "$(id -u)" -ne 0 ]]; then
    echo "You must run the script as root" >&2
    exit 1
fi

# Check if a filename is provided
if [[ -z "$1" ]]; then
    echo "Usage: $0 <name-of-text-file>" >&2
    exit 1
fi

# File paths
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.csv"

# Ensure /var/secure storage for passwords
mkdir -p /var/secure
touch $PASSWORD_FILE
chown root:root /var/secure
chmod 700 /var/secure
chmod 600 $PASSWORD_FILE

# Function to log actions
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}

# Function to generate a random password
generate_password() {
    tr -dc 'A-Za-z0-9!@#$%^&*()_+=-[]{}|;:<>,.?/~' </dev/urandom | head -c 16
}

# Function to hash passwords
hash_password() {
    echo "$1" | openssl passwd -6 -stdin
}

# 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

    # Check if user already exists
    if id "$username" &>/dev/null; then
        log_action "User $username already exists!"
        continue
    fi

    # Create personal group
    if groupadd "$username"; then
        log_action "Group $username created successfully."
    else
        log_action "Failed to create group $username."
        continue
    fi

    # Create user with a home directory and personal group
    if useradd -m -s /bin/bash -g "$username" "$username"; then
        log_action "User $username created successfully."
    else
        log_action "Failed to create user $username."
        continue
    fi

    # Create groups and add user to them
    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
            if groupadd "$group"; then
                log_action "Group $group created."
            else
                log_action "Failed to create group $group."
                continue
            fi
        fi
        if usermod -aG "$group" "$username"; then
            log_action "User $username added to group $group."
        else
            log_action "Failed to add user $username to group $group."
        fi
    done

    # Generate random password
    password=$(generate_password)
    hashed_password=$(hash_password "$password")
    if usermod --password "$hashed_password" "$username"; then
        echo "$username,$password" >> $PASSWORD_FILE
        log_action "Password set for user $username."
    else
        log_action "Failed to set password for user $username."
    fi

    # Set home directory permissions
    if mkdir -p "/home/$username" && chown -R "$username:$username" "/home/$username" && chmod 755 "/home/$username"; then
        log_action "Home directory permissions set for user $username."
    else
        log_action "Failed to set home directory permissions for user $username."
    fi

done < "$1"

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

Breaking Down the Script

1. Check for Root Privileges

if [[ "$(id -u)" -ne 0 ]]; then
    echo "You must run the script as root" >&2
    exit 1
fi
Enter fullscreen mode Exit fullscreen mode

This part checks if the script is run by the root user, this is because only the root user has permission to create and manage other users. If the script is not run as root, it will print an error message and exit.

2. Check for Filename Argument

if [[ -z "$1" ]]; then
    echo "Usage: $0 <name-of-text-file>" >&2
    exit 1
fi
Enter fullscreen mode Exit fullscreen mode

This section will check if the user provided a filename as an argument when running the script. If no filename is found, it will print a usage message and exit.

3. Define File Paths

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

These lines define the file paths for logging actions and storing passwords.

4. Ensure Secure Storage for Passwords

mkdir -p /var/secure
touch $PASSWORD_FILE
chown root:root /var/secure
chmod 700 /var/secure
chmod 600 $PASSWORD_FILE
Enter fullscreen mode Exit fullscreen mode

This part of the script ensures that the /var/secure directory and the password file exist with appropriate permissions for secure storage. mkdir -p creates the directory if it doesn't exist, touch creates the password file, and chmod and chown set the permissions so only the root user can read and write to it.

5. Logging Function

log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
Enter fullscreen mode Exit fullscreen mode

The log_action function's job is to log messages with timestamps to the log file. It uses the date command to add a timestamp to each log entry and tee to append the message to the log file.

6. Password Generation Function

generate_password() {
    tr -dc 'A-Za-z0-9!@#$%^&*()_+=-[]{}|;:<>,.?/~' </dev/urandom | head -c 16
}
Enter fullscreen mode Exit fullscreen mode

The generate_password function generates a random password. tr is used to filter characters from /dev/urandom (a random number generator), and head -c 16 ensures the password is 16 characters long.

7. Password Hashing Function

hash_password() {
    echo "$1" | openssl passwd -6 -stdin
}
Enter fullscreen mode Exit fullscreen mode

The hash_password function hashes the generated password using the openssl command with SHA-512 encryption. This makes the password secure before storing it.

8. Read and Process Input File

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

This part reads the input file line by line, separating the username and groups by the semicolon (;). It also trims any whitespace around the username and groups and skips any empty lines.

9. Check for Existing User

if id "$username" &>/dev/null; then
    log_action "User $username already exists!"
    continue
fi
Enter fullscreen mode Exit fullscreen mode

This checks if the user already exists. If so, it logs the action and skips to the next user.

10. Create Personal Group

if groupadd "$username"; then
    log_action "Group $username created successfully."
else
    log_action "Failed to create group $username."
    continue
fi
Enter fullscreen mode Exit fullscreen mode

This creates a personal group with the same name as the username.

11. Create User

if useradd -m -s /bin/bash -g "$username" "$username"; then
    log_action "User $username created successfully."
else
    log_action "Failed to create user $username."
    continue
fi
Enter fullscreen mode Exit fullscreen mode

This creates the user with a home directory and assigns the personal group as the primary group.

12. Create and Assign Groups

Copy code
IFS=',' read -ra group_array <<< "$groups"
for group in "${group_array[@]}"; do
    group=$(echo
Enter fullscreen mode Exit fullscreen mode

How to use the script?

  1. Save the script as create_users.sh in your preferred directory.

  2. Prepare a text file (users_and_groups.txt) with one username per line, followed by groups separated by commas. For example: light;sudo,dev,www-data idimma;sudo mayowa;dev,www-data

  3. Make the script executable with chmod +x create_users.sh.

  4. Run the script with the path to your text file as an argument: ./create_users.sh users_and_groups.txt.

Conclusion

By following the structured steps outlined above, SysOps engineers can efficiently manage large numbers of user accounts and their associated groups, providing a robust solution for onboarding new developers.

Acknowledgment

This script was developed as part of the HNG Internship DevOps track. For more details on the program, visit the HNG Internship Website.

You can learn more about the HNG Internship program here and here.

Thank you for reading.

Top comments (0)