Automating User and Group Creation with Bash Scripts
Tags: bash, linux, devops, sre
Published: 2024-07-04 10:44:40

As a SysOps engineer, one of your tasks might involve creating and managing user accounts on a Linux server. To streamline this process, you can automate the creation of users and their associated groups using a bash script. This type of script can be useful in large companies to automate the creation of user accounts and assigning groups, saving time and ensuring consistency, especially when onboarding multiple new employees.

The following guide walks you through a bash script called `create_users.sh`, which: 

1. **Reads a text file** containing usernames and groups.
2. **Creates users** with home directories and random passwords.
3. **Creates groups** and assigns users to them.
4. **Sets up home directories** with appropriate permissions.
5. **Logs actions** to `/var/log/user_management.log`.
6. **Stores passwords** securely in `/var/secure/user_passwords.csv`.

### Prerequisites:

Ensure you have the necessary permissions and tools:
- Before running the script, ensure you have root user privileges because the script requires administrative privileges to create users, and groups, and set permissions.
- The script also uses the OpenSSL command-line tool to generate secure, random passwords for the new users.
Ensure that OpenSSL is installed on your system.

### The Script

`create_users.sh` script:

```bash
#!/bin/bash

# Create log file and secure password file with proper permissions
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.csv"

# Ensure the script is run as root
if [[ "$(id -u)" -ne 0 ]]; then
    echo "This script must be run as root."
    exit 1
fi

# Ensure the log file exists
touch "$LOG_FILE"

# Setup password file
if [[ ! -d "/var/secure" ]]; then
    mkdir /var/secure
fi
if [[ ! -f "$PASSWORD_FILE" ]]; then
    touch "$PASSWORD_FILE"
    chmod 600 "$PASSWORD_FILE"
fi

# Check if the input file is provided
if [[ -z "$1" ]]; then
    echo "Usage: bash create_users.sh <name-of-text-file>"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ERROR: No input file provided." >> "$LOG_FILE"
    exit 1
fi

# Read the input file line by line
while IFS=';' read -r username groups; do
    # Skip empty lines
    [[ -z "$username" ]] && continue
    
    # Remove whitespace
    username=$(echo "$username" | xargs)
    groups=$(echo "$groups" | xargs)

    # Create user if not exists
    if ! id "$username" &>/dev/null; then
        # Create the user with a home directory
        useradd -m -s /bin/bash "$username"
        if [[ $? -ne 0 ]]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S') - ERROR: Failed to create user $username." >> "$LOG_FILE"
            continue
        fi
        echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: User $username created." >> "$LOG_FILE"

        # Generate a random password for the user
        password=$(openssl rand -base64 12)
        echo "$username:$password" | chpasswd

        # Save the password to the secure password file
        echo "$username,$password" >> "$PASSWORD_FILE"
        echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: Password for user $username generated and stored." >> "$LOG_FILE"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: User $username already exists." >> "$LOG_FILE"
    fi

    # Create groups and add user to them
    IFS=',' read -ra group_list <<< "$groups"
    for group in "${group_list[@]}"; do
        group=$(echo "$group" | xargs)
        # Create group if not exists
        if ! getent group "$group" >/dev/null; then
            groupadd "$group"
            echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: Group $group created." >> "$LOG_FILE"
        fi
        # Add user to the group
        usermod -a -G "$group" "$username"
        echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: User $username added to group $group." >> "$LOG_FILE"
    done

    # Set ownership and permissions for the home directory
    chown -R "$username:$username" "/home/$username"
    chmod 700 "/home/$username"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: Home directory for user $username set up with appropriate permissions." >> "$LOG_FILE"

done < "$1"

echo "$(date '+%Y-%m-%d %H:%M:%S') - INFO: User creation script completed." >> "$LOG_FILE"

exit 0
```


### Creating the Employee List
create a text file (`employees.txt`) with the following format using any editor: e.g

```
john; marketing
emma; marketing
alex; sales
lisa; it
mike; it
sara; hr
chris; finance
linda; marketing
james; sales
```

### Running the Script

1. **Upload the script and text file**:
   Place `create_users.sh` and `employees.txt` in a directory on your Ubuntu VM (e.g., `/opt/scripts`).

2. **Set permissions and execute**:
   ```bash
   chmod +x /opt/scripts/create_users.sh
   sudo /opt/scripts/create_users.sh /opt/scripts/employees.txt
   ```

### Verifying Execution

After running the script, verify its success by checking:

1. **User creation**:
   ```bash
   id john
   ```

2. **Group assignments**:
   ```bash
   groups john
   ```

3. **Log file**:
   ```bash
   cat /var/log/user_management.log
   ```

4. **Password storage**:
   ```bash
   cat /var/secure/user_passwords.csv
   ```


## Logic

###Roadmap 

```
Start
  |
  V
Check for root privileges
  |
  V
Ensure log and password files exist
  |
  V
Check if input file is provided
  |
  V
Read input file line by line
  |
  V
For each line:
  - Separate username and groups
  - Remove whitespace
  - If user doesn't exist, create user and generate password
  - If group doesn't exist, create group
  - Assign user to groups
  - Log actions
  |
  V
End
```


So let’s think about it. As per the requirements, we need to be able to write a script that takes input from a text file. This file will be arranged in a specific way, with usernames and groups separated by a semicolon. Our script has to differentiate between these sections and handle the input accordingly.

**Understanding the Process**
The script should pick the first column as the username and use it to create the users. The other column after the ';', which lists the groups, will be used to assign those groups to the users.

All actions should be logged to a specified log file, and the generated passwords need to go to /var/secure/user_passwords.txt. 

To keep things organized and avoid repetition, we declare the log file and the password file at the beginning of the script.

**Root Privileges and File Checks**
We start by ensuring the script runs with root privileges. This helps to avoid any hiccups and ensures all commands execute smoothly. Next, we need to check if the log file and the CSV file for passwords exist. If they don't, the script creates them.

**Handling Input and Differentiating Data**
Another requirement is to handle the input file. Using an if block and a while loop, we first ensure the text file has been passed as an argument to the script. The script then differentiates usernames and groups, using the semicolon to separate the columns.

To remove any whitespaces, we created variables containing the sorted usernames and group values obtained from the text file.

**Creating Users and Generating Passwords**
The next step is to create a user if it doesn’t already exist. This involves another if block to execute the 'user add' command if the user is not yet created. 

Before we create groups and assign users, we need to generate random passwords. We use OpenSSL to generate a random password greater than 12 characters.

The generated password is then saved securely to the CSV file using redirection.

**Creating Groups and Assigning Users**
Finally, we create the necessary groups and assign the users to them. The script checks if the group already exists, creates it if it doesn’t, and then assigns the user to the group. All these actions are logged to the /var/log/user_management.log file. 

-------------------------------------------------

This article is part of a requirement for stage 1 task in HNG11 Internship. For more detailed information, check out the [HNG Internship](https://hng.tech/internship) and [HNG Hire](https://hng.tech/hire). These resources provide excellent learning opportunities and support for aspiring SREs and DevOps Engineers.