DEV Community

Amarachi Iheanacho
Amarachi Iheanacho

Posted on • Updated on

Automating user creation with Bash Scripting

Managing users and groups is a fundamental aspect of system administration. Whether you're overseeing a small personal server or a large enterprise network, having a streamlined process for user creation is essential for maintaining security, organization, and efficiency. One of the most powerful tools for automating this task is Bash scripting.

This article walks you through solving user management issues with a Bash script. The script will cover creating accounts, assigning them to personal and general groups, and managing and securing their passwords.

This project is available on GitHub. Check out the repository for the complete script.

The problem statement

You are presented with a problem.

Your company has hired many new developers, and you need to automate the creation of user accounts and passwords for each of them.

As a SysOps engineer, write a Bash script that reads a text file containing the employees’ usernames and group names, where each line is formatted as username;groups.

The text file can also specify multiple groups for the user, formatted as username; group1, group2.

In addition to the multiple groups specified by the text file, each user must have a personal group named after their username.

The script should create users and groups as specified, set up home directories with appropriate permissions and ownership, and generate random user passwords.

Additionally, store the generated passwords securely in /var/secure/user_passwords.csv, and log all actions to /var/log/user_management.log.

How do you automate this workflow with Bash scripting?

Setting up the project

Before diving head first into creating the script itself, let's define what it needs to automate. The script must:

  1. Read User and Group Information: The script will rely on a text file containing user and group information
  2. Create User and Group: For each user specified in the file, the script will create a user account and a personal group
  3. Assign Additional Groups: If additional groups are listed for a user (e.g., user;group1,group2), the script will also assign the user to those groups
  4. Create Home Directories: Each user will have a dedicated home directory created.
  5. Generate Random Passwords: Secure random passwords will be generated for each user and stored in /var/secure/user_passwords.csv
  6. Log Actions: The script will log all its activities to /var/log/user_management.log

Creating the user and group text file
The Bash script relies on a text file to define the users and groups it needs to create.

To create this text file, navigate to your project’s root directory and create a file named text_file.txt. This file should contain lines formatted as follows:

    villanelle; sudo, dev
    eve; dev, www-data
Enter fullscreen mode Exit fullscreen mode

You can replace the usernames and groups with any names you’d like.

Now that you have the text file prepared let's create the Bash script that interacts with it.

Creating the Bash script
Within your project's root directory, create a new file named create_user.sh. This script will handle user creation, group assignment, activity logging, and more.

This script will be made up of different parts, and these are:

1.Ensuring root privileges

The script requires elevated privileges to perform actions like creating users, groups, and modifying permissions. So, you will begin by checking if the user running the script has root access.
In your create_user.sh file, add the following commands to check if the user is root:

    #!/bin/bash
    # Check if the current user is a superuser, exit if the user is not
    if [ "$EUID" -ne 0 ]; then
      echo "Please run as root"
      exit 1
    fi
Enter fullscreen mode Exit fullscreen mode

This code ensures only users with root access can execute the script. If you're not logged in as root, running the script will display an error message and exit.

2.Check if the text file was passed in as an argument

Next, you need to ensure the script receives the text file (text_file.txt) as an argument. To perform this check, add the following lines of code to your create_user.sh file:

    # Check if the file was passed into the script
    if [ -z "$1" ]; then 
        echo "Please pass the file parameter"
        exit 1
    fi
Enter fullscreen mode Exit fullscreen mode

In the code block above, these commands:

  • [ -z "$1" ]: This checks if the first argument ($1) is empty.
  • echo "Please pass the file parameter": This message informs the user if the script is missing the required file.
  • exit 1: Exits the script with an error code if the check fails.

By including this code, you guarantee the script receives the necessary text file to function correctly.

3.Create environment variables for the file

Next, you will create environment variables to hold the paths for the input text file (text_file.txt), the log file (/var/log/user_management.log), and the password file (/var/secure/user_passwords.csv).
To create these variables, add the following lines of code to your create_user.sh file:

    # Define the file paths for the log file, and the password file
    INPUT_FILE="$1"
    LOG_FILE="/var/log/user_management.log"
    PASSWORD_FILE="/var/secure/user_passwords.csv"
Enter fullscreen mode Exit fullscreen mode

4.Create the log and password files

Next, create the log and password files and give them the necessary permissions with this command:

    # Generate logfiles and password files and grant the user the permissions to edit the password file
    touch $LOG_FILE
    mkdir -p /var/secure
    chmod 700 /var/secure
    touch $PASSWORD_FILE
    chmod 600 $PASSWORD_FILE
Enter fullscreen mode Exit fullscreen mode

The commands in the code block above are:

  • touch $LOG_FILE: Creates a /var/log/user_management.log file
  • mkdir -p /var/secure: Creates a /var/secure directory that will hold the password file
  • chmod 700 /var/secure: Sets the permissions so that only the user has read, write, and execute permissions for the /var/secure directory
  • touch $PASSWORD_FILE: Creates a /var/secure/user_passwords.csv file
  • chmod 600 $PASSWORD_FILE: Sets the permissions so that only the user has read and write permissions for the /var/secure/user_passwords.csv file

5.Generate the passwords

Next, create the log_message() and generate_password() functions. These functions will handle creating log messages for each action and generating user passwords:

    # Generate logs and passwords 
    log_message() {
        echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
    }

    generate_password() {
        openssl rand -base64 12
    }
Enter fullscreen mode Exit fullscreen mode

Here's what each function does:

  • log_message(): This function appends a log message with the current date and time (formatted as %Y-%m-%d %H:%M:%S) to the $LOG_FILE. It takes a positional parameter $1 representing the message to be logged.
  • generate_password(): This function uses OpenSSL to generate a random password each time it is called, which is then printed to standard output.

To learn more about the OpenSSL library, refer to the official OpenSSL documentation

6.Creating the users and groups

You have verified that the user is running this script as a superuser. Additionally, you have created variables that hold different file paths pointing to the log, password, and input files.

Next, the script should loop through each entry in the input text file, split these entries by usernames and groups, and then create the users and their respective groups.

To achieve this, include the following commands in your create_user.sh file:

    # Read the input file line by line and save them into variables
    while IFS=';' read -r username groups || [ -n "$username" ]; do
        username=$(echo "$username" | xargs)
        groups=$(echo "$groups" | xargs)
        # Check if the personal group exists, create one if it doesn't
        if ! getent group "$username" &>/dev/null; then
            echo "Group $username does not exist, adding it now"
            groupadd "$username"
            log_message "Created personal group $username"
        fi

        # Check if the user exists
        if id -u "$username" &>/dev/null; then
            echo "User $username exists"
            log_message "User $username already exists"
        else

            # Create a new user with the created group if the user does not exist
            useradd -m -g $username -s /bin/bash "$username"
            log_message "Created a new user $username"
        fi

        # Check if the groups were specified
        if [ -n "$groups" ]; then
            # Read through the groups saved in the groups variable created earlier and split each group by ','
            IFS=',' read -r -a group_array <<< "$groups"
            # Loop through the groups 
            for group in "${group_array[@]}"; do

                # Remove the trailing and leading whitespaces and save each group to the group variable
                group=$(echo "$group" | xargs) # Remove leading/trailing whitespace
                # Check if the group already exists
                if ! getent group "$group" &>/dev/null; then
                    # If the group does not exist, create a new group
                    groupadd "$group"
                    log_message "Created group $group."
                fi

                # Add the user to each group
                usermod -aG "$group" "$username"
                log_message "Added user $username to group $group."
            done
        fi

        # Create and set a user password
        password=$(generate_password)
        echo "$username:$password" | chpasswd
        # Save user and password to a file
        echo "$username,$password" >> $PASSWORD_FILE
    done < "$INPUT_FILE"

    log_message "User created successfully"

    echo "Users have been created and added to their groups successfully"

Enter fullscreen mode Exit fullscreen mode

Let’s break down the code snippet to understand what each part does:

  • Read the Input File Line by Line:
   while IFS=';' read -r username groups || [ -n "$username" ]; do
       # Code to create the user groups
    done < “$INPUT_FILE
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • while …; do … done: This loop iterates over each line in the input field and executes the commands within the do block for each of the line

    • IFS=';': Sets the Internal Field Separator (IFS) to a semicolon (;). This tells the read command to split each line in the input file based on semicolons.
    • read -r username groups: Reads each line of the input file and splits it into two variables: username and groups. You will need these variables for creating usernames and groups
    • || [ -n "$username" ]: This ensures that the loop continues processing the last line even if it doesn't end with a newline character.
  • Trimming Whitespace:

    username=$(echo "$username" | xargs)
    groups=$(echo "$groups" | xargs)
Enter fullscreen mode Exit fullscreen mode

Explanation:
- This step removes any leading or trailing spaces from the username and groups variables. Extra spaces can cause issues with user and group creation.
- xargs: This command removes any whitespace at the beginning or end of the variable values.

  • Checking and Creating the Personal Group:
    if ! getent group "$username" &>/dev/null; then
      echo "Group $username does not exist, adding it now"
      groupadd "$username"
      log_message "Created personal group $username"
    fi
Enter fullscreen mode Exit fullscreen mode

Explanation:
- getent group "$username" &>/dev/null: This checks if a group with the username exists. If it doesn't, the groupadd command creates the group, and a log message is recorded.

  • Checking and Creating the User:
    if id -u "$username" &>/dev/null; then
      echo "User $username exists"
      log_message "User $username already exists"
    else
      useradd -m -g $username -s /bin/bash "$username"
      log_message "Created a new user $username"
    fi
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • id -u "$username" &>/dev/null: This checks if a user with the specified username exists. If the user does not exist, the useradd function is used to create one, and a log message is recorded.

  • useradd -m -g "$username" -s /bin/bash "$username": This command creates a new user with the specified name ($username), a home directory (-m), the user's name as the primary group (-g $username), and the Bash shell as the default login shell (-s /bin/bash). For more details, check out how to create users in Linux using the useradd command.

  • Checking and Assigning Groups:

     # Check if the groups were specified
    if [ -n "$groups" ]; then
        # Read through the groups saved in the groups variable created earlier and split each group by ','
        IFS=',' read -r -a group_array <<< "$groups"

        # Loop through the groups 
        for group in "${group_array[@]}"; do
            # Remove the trailing and leading whitespaces and save each group to the group variable
            group=$(echo "$group" | xargs) # Remove leading/trailing whitespace

            # Check if the group already exists
            if ! getent group "$group" &>/dev/null; then
                # If the group does not exist, create a new group
                groupadd "$group"
                log_message "Created group $group."
            fi

            # Add the user to each group
            usermod -aG "$group" "$username"
            log_message "Added user $username to group $group."
        done
    fi

Enter fullscreen mode Exit fullscreen mode

Explanation:

  • [ -n "$groups" ]: This checks if the $groups variable is not empty
  • IFS=',' read -r -a group_array <<< "$groups": This splits the $groups variable by commas, storing each group name as a separate element in an array named group_array.
  • for loop: This iterates through each group name in the group_array and runs the following commands:
    • group=$(echo "$group" | xargs): This removes any leading or trailing spaces from the current group name in the loop.
    • if ! getent group "$group" &>/dev/null: This checks if a group exists. If the group does not exist, the groupadd function creates the group, and a log message is recorded.
  • usermod -aG "$group" "$username": This command adds the user ($username) to the current group ($group)

  • Generating and Setting a User Password:

    password=$(generate_password)
    echo "$username:$password" | chpasswd
    echo "$username,$password" >> $PASSWORD_FILE
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • password=$(generate_password): Calls the generate_password() function created earlier and stores its output in a password variable
  • echo "$username:$password" | chpasswd: Sets the user's password using the password variable
  • echo "$username,$password" >> $PASSWORD_FILE: Saves the username and password to the password file at the path var/secure/user_passwords.csv

  • Feeding the Input File into the While Loop:

    done < "$INPUT_FILE"
Enter fullscreen mode Exit fullscreen mode

Explanation:
- done < "$INPUT_FILE": This redirection operator, <, tells the while loop to read its input from the file specified by $INPUT_FILE

When you are done with this section, your create_user.sh file should look like this:

https://gist.github.com/Iheanacho-ai/a572c299428c68e309b549d8d4d4cb4e

With this, you have successfully created a script that effectively manages users and groups in your system.

Testing this script

Once you've written your script, it's time to verify that it works as intended. Here's how to test it:

  1. Running the Script in a Linux Environment

You'll need a terminal that supports Linux commands to run the script. Some options include:

2.Making the Script Executable

Before running the script, you need to grant it execute permission with this command:

    chmod +x create_user.sh
Enter fullscreen mode Exit fullscreen mode

3.Running the Script

Next, execute the script with this command:

    ./create_user.sh ./text_file.txt
Enter fullscreen mode Exit fullscreen mode

If your script is running as it should, you should see this in your terminal:

Next, check your /var/log/user_management.log file to see your logs by running this command:

cat /var/log/user_management.log
Enter fullscreen mode Exit fullscreen mode

Finally, check your /var/secure/user_passwords.csv file with this command to see the users and their passwords:

cat /var/secure/user_passwords.csv
Enter fullscreen mode Exit fullscreen mode

In summary

Throughout this article, you have walked through using Bash to manage users, groups, and their passwords. You have also logged all the actions into a file so that you and anybody else can look back on them and troubleshoot. But this is only the tip of the iceberg when it comes to Bash's capabilities.

With Bash, you can automate a wide variety of administrative tasks, streamline your workflows, and enhance the efficiency of your system management. Whether it's scheduling regular maintenance tasks with cron jobs, managing system updates, or monitoring system performance, Bash provides a powerful
toolset for system administrators.

So stay curious and check out Bash resources for more resources on scripting with Bash for Linux systems.

Top comments (2)

Collapse
 
array_dot_reduce profile image
Jay

I was looking for something like this today!
I might not be able to use this code as-is, but it points me in a direction I can explore, thanks!

Collapse
 
amaraiheanacho profile image
Amarachi Iheanacho

Sure anytime!