Automating Creation of Users and groups using Bash Script (Step-by-Step Guide)

Sudo Bro - Jul 3 - - Dev Community

As a DevOps engineer, it is quite a common task to create, update, and delete users and groups. Automating this process can save a lot of time and help reduce human errors, especially when onboarding numerous users. In this article, I'll walk you through using bash to automate the creation of users and their respective groups, setting up home directories, generating random passwords, and logging all actions performed.

Objectives

  • Create users and their personal groups.
  • Add users to specified groups.
  • Set up home directories with appropriate permissions.
  • Generate and securely store passwords.
  • Log all actions for auditing purposes.
  • Ensure error handling.

Let's Begin

First and foremost, at the beginning of any shell script we're writing, we start with "shebang" in the first line.

#!/bin/bash
Enter fullscreen mode Exit fullscreen mode

Shebang tells us that the file is executable.

Setting up the directory for user logs and file

It is necessary to create a directory and files for logging and password storage. If it already exists, DO NOT CREATE IT AGAIN!!!

mkdir -p /var/log /var/secure
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt
Enter fullscreen mode Exit fullscreen mode
  • /var/log: Directory for log files.
  • /var/secure: Directory for secure files.
  • user_management.log: Log file to record actions.

Secure the generated passwords

chmod 600 /var/secure/user_passwords.txt
Enter fullscreen mode Exit fullscreen mode
  • user_passwords.txt: File to store passwords securely with read and write permissions for the file owner only.

Earlier, we created the directory "/var/secure" to store user_password.txt. To give the appropriate permissions, we use chmod 600 to give only the current user access to view our generated passwords.

Create a function to log actions

The log_action() function record actions with timestamps in the log file.

log_action() {
    echo "$(date) - $1" >> "/var/log/user_management.log"
}
Enter fullscreen mode Exit fullscreen mode

User Creation Function

The create_user() function handles the creation of user accounts and their associated groups. It takes two arguments: username and groups.

Steps taken in the create_user() function:

  • Check for Existing User: Logs a message if the user already exists.
if id "$user" &>/dev/null; then
    log_action "User $user already exists."
    return
fi
Enter fullscreen mode Exit fullscreen mode

id "$user" &>/dev/null checks if the user exists by attempting to retrieve the user's information. If the user does not exist, id will return a non-zero exit status. The &>/dev/null part redirects any output (both stdout and stderr) to /dev/null, effectively silencing the command's output.
If the user exists log_action "User $user already exists." logs a message indicating that the user already exists. Using return, it exits the create_user() function early, preventing any further actions from being taken for the existing user.

  • Create User Group: Creates a personal group for the user.
groupadd "$user"
Enter fullscreen mode Exit fullscreen mode

groupadd "$user" creates a new group with the same name as the user. This group will be the primary group for the user being created.

  • Handle Additional Groups: Checks and creates additional groups if they do not exist.
IFS=' ' read -ra group_array <<< "$groups"
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
Enter fullscreen mode Exit fullscreen mode

Here, we split the groups string into an array using spaces as delimiters and log the groups that the user will be added to. Using for group in "${group_array[@]}"; do, we are able to iterates over each group in the group_array and trim any leading or trailing whitespace from the group name. Using if ! getent group "$group" &>/dev/null; then to check if the group already exists else we create the group groupadd "$group" and log that the group has been created log_action "Group $group created.".

  • Create User: Creates the user with a home directory and bash shell.
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
Enter fullscreen mode Exit fullscreen mode
  • Assign Groups: Adds 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[*]}"
Enter fullscreen mode Exit fullscreen mode

for group in "${group_array[@]}"; do to iterate over each group in the group_array then adds the user to the specified group (-aG means append the user to the group). Next, log that the user has been added to the specified groups.

  • Generate and Store Password: Generates a random password and stores it securely.
password=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 12)
echo "$user:$password" | chpasswd

echo "$user,$password" >> "/var/secure/user_passwords.txt"
Enter fullscreen mode Exit fullscreen mode

We use /dev/urandom to generate a random 12-character password and tr to filter alphanumeric characters. Next, we set the password for the user using the chpasswd command and append the username and password to the secure file /var/secure/user_passwords.txt.

  • Set Permissions: This part of the code is responsible for setting the appropriate permissions and ownership for the user's home directory.
chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
Enter fullscreen mode Exit fullscreen mode

Using 700, only the user has read, write, and execute permissions. chown "$user:$user" "/home/$user" to set the owner and group of the home directory to the user.

Here is the full combined code within the create_user() function.

create_user() {
    local user="$1"
    local groups="$2"
    local password

    if id "$user" &>/dev/null; then
        log_action "User $user already exists."
        return
    fi

    groupadd "$user"

    IFS=' ' read -ra group_array <<< "$groups"
    log_action "User $user will be added to groups: ${group_array[*]}"
    for group in "${group_array[@]}"; do
        group=$(echo "$group" | xargs)
        if ! getent group "$group" &>/dev/null; then
            groupadd "$group"
            log_action "Group $group created."
        fi
    done

    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

    for group in "${group_array[@]}"; do
        usermod -aG "$group" "$user"
    done
    log_action "User $user added to groups: ${group_array[*]}"

    password=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 12)
    echo "$user:$password" | chpasswd
    echo "$user,$password" >> "/var/secure/user_passwords.txt"

    chmod 700 "/home/$user"
    chown "$user:$user" "/home/$user"

    log_action "Password for user $user set and stored securely."
}

Enter fullscreen mode Exit fullscreen mode

Main Execution Flow

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

while IFS=';' read -r user groups; do
    user=$(echo "$user" | xargs)
    groups=$(echo "$groups" | xargs | tr -d ' ')
    groups=$(echo "$groups" | tr ',' ' ')
    create_user "$user" "$groups"
done < "$filename"

echo "Creation of user is complete. Go ahead and check /var/log/user_management.log for detailed information."
Enter fullscreen mode Exit fullscreen mode

Here, we check if the user file is provided, then read the user list file and process each user entry, calling the create_user() function for each line and passing the $user and $groups as arguments.

Let's put everything together

#!/bin/bash

# Create directory for user logs and 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 the password file secure for the file owner (read and write permissions for file owner only)
chmod 600 /var/secure/user_passwords.txt

# Create a function to record actions to log file
log_action() {
    echo "$(date) - $1" >> "/var/log/user_management.log"
}

create_user() {
    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_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 "Creation of users is complete. Go ahead and check /var/log/user_management.log for detailed information."
Enter fullscreen mode Exit fullscreen mode

Usage

To use this script, provide a user list file as an argument. Each line in the file should contain a username and a comma-separated list of groups (optional), separated by a semicolon. For example:

light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data
Enter fullscreen mode Exit fullscreen mode

To run the script, use this command.

./script_name.sh user_list_file.txt
Enter fullscreen mode Exit fullscreen mode

If you are not a root user, use sudo ./create_users.sh user_list_file.txt

Image description

Conclusion

This script provides a robust solution for automating user creation and management, ensuring secure handling of passwords and detailed logging of actions. It simplifies the process of setting up new user accounts while maintaining security and auditability.

To learn more and kickstart your programming journey you can visit:
https://hng.tech/internship or https://hng.tech/premium

Feel free to reach out with questions or suggestions for improvements. Happy automating!😁👌

.