Automating the Management of Users and Groups Using a Bash Script in Linux.
Published: 2024-07-03 20:33:59

As a SysOps engineer in a company, there is the occasional necessity to manage the creation of users and groups, maximum efficiency can be attained by automating this process. To address this, I have developed a Bash script to create users and groups, set up home directories with appropriate permissions and ownership, generate random passwords, and log all actions.
This article details the functionality and structure of the script, ensuring error handling for scenarios such as existing users, and providing comprehensive documentation and comments within the script.

## Script Overview

- The creation of Bash script that reads a text file containing users and groups.

- Creation of users and groups as specified.
 
- Setting up home directories with appropriate permissions, generating random passwords, and  logging all actions to file.

- Securely storing generated passwords.
 

## Let's dive into the script
Every Bash script begins with the shebang line.
```
#!/bin/bash
```
This indicates that the script should be run using the Bash shell.

## Directory and File Setup

```
mkdir -p /var/log /var/secure
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt

chmod 600 /var/secure/user_passwords.txt
```
This ensures that the directories `/var/log` and `/var/secure` exist. The `-p` flag allows the command to create parent directories as needed without raising an error if the directory already exists, and creates the log file user_management.log in `/var/log` and the password file user_passwords.txt in `/var/secure`. 
Having created the `/var/secure` directory. Using `chmod 600` I set the permissions for user_passwords.txt to be readable and writable only by the file's owner.

## Action Logging Function
This defines a function `log_action` that appends a timestamped log entry to the user_management.log file.

```
log_action() {
    echo "$(date) - $1" >> "/var/log/user_management.log"
}
```

## User Creation Function

- I declared the `create_user()` function, defining three variables: user (username), groups (additional groups), and password (which will be generated).

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

I proceeded to check if the user already exists using the 'id' command. If the user exists, log "$user already exists" and exit the function.

```
 if id "$user" &>/dev/null; then
        log_action "User $user already exists."
        return
    fi
```
Next, I created a personal group for the user with the same name as the username using `groupadd "$user"`.
```
 groupadd "$user"

```
## Group Handling and Creation
The script takes the list of additional groups and splits them into separate items in a `group_array`. Logs a message that lists all the groups the user will be added to. The script then goes through each group in the array, removes any extra spaces from the group name, and checks if the group already exists. If the group doesn't exist, it creates the group.
   

```
 IFS=' ' read -ra group_array <<< "$groups"

    # Log the group array
    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
```

I created the user with a home directory `(-m)`, a default shell `(-s /bin/bash)`, and set the primary group to the personal group `(-g "$user")`. Logging the success or failure of the user creation.
   

```
 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
```
Followed by, adding the user to the additional groups using usermod `-aG` and logging the action. This splits the additional groups into an array, logs them, trims whitespace, checks if each group exists, and creates any missing groups.   

```
for group in "${group_array[@]}"; do
        usermod -aG "$group" "$user"
    done
    log_action "User $user added to groups: ${group_array[*]}"
```
**Random Password Generation & Granting Home Directory Permissions**
I generated a 12-character random password using `/dev/urandom`, formatted it, and set it for the user using `chpasswd`. Appended the username and password to `user_passwords.txt` and stored them in the secure file. Setting the permissions for the user's home directory to be accessible only by the user changing ownership to the user.

```
 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."
}
```

## Main Script Execution
This begins by checking if exactly one argument `<user_list_file>` is provided. If not, it prints usage instructions and exits. Then it checks if the provided 'User list file' exists. If not, it prints an error message and exits. For each line, it reads the username and groups, trims whitespace, replaces commas with spaces, and calls the `create_user()` function with the parsed values. Finally, it prints a message indicating that user creation is complete and where to find more information.
```
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 "User created. Type cat /var/log/user_management.log for more information."
```




This is the combined script.⬇️

```
#!/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

# Grant read and write permissions for file owner only
chmod 600 /var/secure/user_passwords.txt

# Action Logging function
log_action() {
    echo "$(date) - $1" >> "/var/log/user_management.log"
}


create_user() {
    # Define three variables passed to the function: user, groups, and password
    local user="$1"
    local groups="$2"
    local password

    # Check if user already exists
    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 the group array
    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 "User created. Type cat /var/log/user_management.log for more information."


```
## Testing The Script

- 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
```

- To run the script, use this command.
`./script_name.sh user_list_file.txt`.
For a non-root user, use `sudo ./create_users.sh user_list_file.txt`

## Conclusion

The Bash script automates user management by creating users, managing groups, generating secure passwords, and logging actions. It ensures the secure handling of passwords and provides detailed logs for auditing purposes. This automation is critical for efficiently onboarding new users and maintaining system security and organization.

To rapidly upskill and advance your tech career, visit https://hng.tech/internship or https://hng.tech/premium for more information.