Managing users and groups is a fundamental aspect of system administration in Linux environments. As systems grow in complexity and the number of users increases, manual user management becomes tedious, error-prone, and difficult to scale.
This article will guide you through creating a bash script to automate user and group management based on a provided text file.
Problem Statement
The challenge lies in streamlining the process of creating new users with specific group memberships, generating secure passwords, and meticulously logging all actions for auditing and troubleshooting.
Imagine a scenario where a company onboards multiple new employees requiring immediate access to system resources. Manually creating each user account, setting appropriate permissions, and assigning them to the correct groups would be time-consuming and prone to human error.
Requirements
To address this challenge, the following requirements were identified:
- Automated User and Group Creation: The script should create new user accounts and groups based on information provided in a structured input file.
- Password Generation and Secure Storage: The script must generate strong, random passwords for each user and store them securely to prevent unauthorized access.
- Group Membership Management: The script should dynamically assign users to existing or newly created groups as specified in the input file.
- Comprehensive Logging: All actions performed by the script, including user and group creation, password settings, and any errors encountered, should be meticulously logged for auditing and debugging.
Creating the Project
To tackle the user management automation task, we'll develop a Bash script. Let's break down the script creation process step by step:
1. Defining Essential Variables and Functions
First, we need to set up some essential variables and functions that our script will use throughout its execution. We'll define where to store log information, where to store generated passwords, how to log actions taken by the script, and how to generate random passwords.
#!/bin/bash # Log file path LOG_FILE="/var/log/user_management.log" # Password file path PASSWORD_FILE="/var/secure/user_passwords.csv" # Ensure the secure directory exists mkdir -p /var/secure chmod 700 /var/secure # Log function log_action() { echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" } # Function to generate a random password generate_password() { tr -dc A-Za-z0-9 </dev/urandom | head -c 12 }
In this code, we define the LOG_FILE
variable to hold the path to our log file, recording every action taken by the script. Similarly, PASSWORD_FILE
stores the path to a file where we'll securely store the generated usernames and passwords. To ensure the security of the password file, we create a directory /var/secure
(if it doesn't exist) and set appropriate permissions using chmod 700
.
Next, we define the log_action
function. This function streamlines the logging process by automatically adding a timestamp before each message written to the log file. The generate_password
function provides a mechanism to generate random 12-character alphanumeric passwords, which we'll use to create secure user accounts.
2. Input Handling and Validation
Now that our script has its basic tools, we need to equip it to handle input. We'll design the script to accept the name of a file containing user information as an argument.
Here's how we implement this:
# Check if the input file is provided if [ $# -ne 1 ]; then echo "Missing Argument: <name-of-text-file>. Only one argument is required." exit 1 fi INPUT_FILE="$1" # Ensure the log and password files exist touch "$LOG_FILE" touch "$PASSWORD_FILE" chmod 600 "$PASSWORD_FILE"
This section ensures that the script receives exactly one argument—the name of the text file. We use an if
statement with the [ $# -ne 1 ]
condition to check the number of arguments. If the script is executed without the required input file, it will display an error message and gracefully exit with an error code of 1 exit 1
.
The provided file name is then stored in the INPUT_FILE
variable. Lastly, we use the touch
command to create both the log file ($LOG_FILE
) and the password file ($PASSWORD_FILE
) if they don't exist. We also set secure permissions (read and write only for the owner) on the PASSWORD_FILE
using chmod 600
to protect sensitive information.
3. Processing the Input File
With the input mechanism in place, we're ready to process the input file line by line. Each line in the file represents a user, containing their username and group memberships separated by a semicolon.
# Read the input file line by line while IFS=';' read -r username groups; do # Trim leading/trailing whitespace username=$(echo "$username" | xargs) groups=$(echo "$groups" | xargs) # Check if the username is empty if [ -z "$username" ]; then continue fi # ... (We'll add user creation and group assignment logic here in the next step) done < "$INPUT_FILE"
This code block uses a while loop to iterate through each line of the $INPUT_FILE
. We set the IFS
(Internal Field Separator) to a semicolon, so each line is split into fields wherever a semicolon (;) appears. The read command then assigns the first field (the username) to the username variable and the remaining fields (the groups) to the groups variable.
We then trim any extra spaces from the username
and groups
variables using xargs
. This ensures consistency and prevents issues that might arise from unintended whitespace. An empty username signifies an invalid entry, prompting us to skip to the next line using the continue
statement.
4. User and Group Management
This section is the heart of our script, where we'll implement the logic for creating users, creating their personal groups, and assigning them to the appropriate groups.
# Create the user's personal group if ! getent group "$username" > /dev/null; then groupadd "$username" log_action "Created group $username" fi # Create the user with the user's personal group if ! id -u "$username" > /dev/null 2>&1; then useradd -m -g "$username" -s /bin/bash "$username" log_action "Created user $username with group $username" else log_action "User $username already exists" fi # Set up home directory permissions chmod 700 /home/"$username" chown "$username":"$username" /home/"$username" # Assign the user to additional groups if [ -n "$groups" ]; then IFS=',' read -ra GROUP_ARRAY <<< "$groups" for group in "${GROUP_ARRAY[@]}"; do group=$(echo "$group" | xargs) if ! getent group "$group" > /dev/null; then groupadd "$group" log_action "Created group $group" fi usermod -aG "$group" "$username" log_action "Added user $username to group $group" done fi
Let's examine the code closely. First, we use getent
group to check if a group with the user's name already exists. If it doesn't, we create the group using groupadd
and log the action.
Next, we check for the existence of the user using id -u
. If the user doesn't exist, the useradd
command comes into play. The -m
flag tells useradd
to create the user's home directory, -g "$username
" assigns the user's personal group as their primary group, and -s /bin/bash sets their default shell to /bin/bash
. Of course, we diligently log this successful user creation. If a user already exists, the script logs that information.
After creating the user, we set the appropriate permissions on the user's home directory using chmod 700
, giving the owner (the user) full control (read, write, execute). We also ensure the user is the owner of their home directory using chown
.
The final part of this section handles additional group assignments. If the groups variable is not empty (meaning additional groups are specified), we split the comma-separated group names into an array called GROUP_ARRAY
. We then iterate through each group in the array; for each group, it checks if the group exists and creates it if needed (just like we did for the personal group). Finally, it adds the user to the group using usermod -aG
.
5. Password Management
Our final step involves generating a secure password for each user, setting that password for the user's account, and then securely storing this sensitive information.
# Generate a random password and set it password=$(generate_password) echo "$username:$password" | chpasswd log_action "Set password for user $username" # Store the username and password securely echo "$username,$password" >> "$PASSWORD_FILE"
We first call our generate_password
function to obtain a random password, storing it in the password
variable. Next, we use the chpasswd command to set this password for the user. The echo "$username:$password
" construct pipes the username and password in the required format to chpasswd
. As always, we record this successful password setting in our log file.
Finally, we append the newly created username and password pair (separated by a comma) to our secure PASSWORD_FILE
.
Testing the Script
It's time to put it to the test. We'll execute the script, providing it with a sample input file containing user information. You can find a sample text file in this GitHub Gist
Make sure you have saved the script as create_users.sh
and made it executable using:
sudo chmod +x create_users.sh
Now, run the script by passing the name of your input file as an argument:
sudo ./create_users.sh users.txt
Replace users.txt
with the actual name of your input file if it's different.
Verify the Results
After running the script, it's essential to confirm that everything worked as expected.
- Check the Log File: To review the actions taken by our script, open the log file located at
/var/log/user_management.log
. This file serves as a detailed record of the script's execution. Carefully examine the log entries to confirm that users and groups were created as intended and that passwords were successfully set.
ubuntu@mobi:~$ cat /var/log/user_management.log 2024-07-04 21:31:19 - Created group light 2024-07-04 21:31:19 - Created user light with group light 2024-07-04 21:31:19 - Added user light to group sudo 2024-07-04 21:31:19 - Created group dev 2024-07-04 21:31:19 - Added user light to group dev 2024-07-04 21:31:19 - Added user light to group www-data 2024-07-04 21:31:19 - Set password for user light 2024-07-04 21:31:19 - Created group idimma 2024-07-04 21:31:19 - Created user idimma with group idimma 2024-07-04 21:31:19 - Added user idimma to group sudo 2024-07-04 21:31:19 - Set password for user idimma 2024-07-04 21:31:19 - Created group mayowa 2024-07-04 21:31:19 - Created user mayowa with group mayowa 2024-07-04 21:31:20 - Added user mayowa to group dev 2024-07-04 21:31:20 - Added user mayowa to group www-data 2024-07-04 21:31:20 - Set password for user mayowa 2024-07-04 21:31:20 - Created group alice 2024-07-04 21:31:20 - Created user alice with group alice 2024-07-04 21:31:20 - Added user alice to group sudo 2024-07-04 21:31:20 - Added user alice to group dev 2024-07-04 21:31:20 - Set password for user alice 2024-07-04 21:31:20 - Created group bob 2024-07-04 21:31:20 - Created user bob with group bob 2024-07-04 21:31:20 - Added user bob to group dev 2024-07-04 21:31:20 - Added user bob to group www-data 2024-07-04 21:31:20 - Set password for user bob 2024-07-04 21:31:20 - Created group charlie 2024-07-04 21:31:20 - Created user charlie with group charlie 2024-07-04 21:31:20 - Added user charlie to group sudo 2024-07-04 21:31:20 - Set password for user charlie 2024-07-04 21:31:20 - Created group daniel 2024-07-04 21:31:20 - Created user daniel with group daniel 2024-07-04 21:31:20 - Added user daniel to group dev 2024-07-04 21:31:20 - Added user daniel to group www-data 2024-07-04 21:31:20 - Set password for user daniel 2024-07-04 21:31:20 - Created group eve 2024-07-04 21:31:20 - Created user eve with group eve 2024-07-04 21:31:20 - Added user eve to group sudo 2024-07-04 21:31:20 - Added user eve to group www-data 2024-07-04 21:31:21 - Set password for user eve 2024-07-04 21:31:21 - Created group frank 2024-07-04 21:31:21 - Created user frank with group frank 2024-07-04 21:31:21 - Added user frank to group dev 2024-07-04 21:31:21 - Set password for user frank 2024-07-04 21:31:21 - Created group george 2024-07-04 21:31:21 - Created user george with group george 2024-07-04 21:31:21 - Added user george to group sudo 2024-07-04 21:31:21 - Added user george to group dev 2024-07-04 21:31:21 - Added user george to group www-data 2024-07-04 21:31:21 - Set password for user george 2024-07-04 21:31:21 - Created group henry 2024-07-04 21:31:21 - Created user henry with group henry 2024-07-04 21:31:21 - Added user henry to group sudo 2024-07-04 21:31:21 - Set password for user henry 2024-07-04 21:31:21 - User bob already exists 2024-07-04 21:31:21 - Added user bob to group sudo 2024-07-04 21:31:21 - Added user bob to group dev 2024-07-04 21:31:21 - Added user bob to group www-data 2024-07-04 21:31:21 - Set password for user bob
- Verify Password Storage: Next, let's ensure our passwords are stored securely. Verify that the password file exists at the path specified in our script:
/var/secure/user_passwords.csv
. Open this file and examine its contents. It should contain the generated usernames and their corresponding passwords, formatted asusername,password
for each entry.
ubuntu@mobi:~$ sudo cat /var/secure/user_passwords.csv light,Q5RvEhh65dZo idimma,nKXhAtai7T97 mayowa,HRMmZ6nkIda6 alice,UMZiNsT02NQM bob,2d1ZfdYZbldF charlie,K4esdb8BC9Xt daniel,p0iq7Cstgn4c eve,DJQB3grtcFQQ frank,Nh6JxwRJ8azq george,3VC2ya1b41Xl henry,DF9FL9HxPYq0 bob,nA4JQvk3skAk
Conclusion
This article has walked you through automating user and group creation in Linux using a Bash script. With this script, system administrators can efficiently onboard new users within their organization, eliminating repetitive manual steps.
The complete script can be found in this GitHub repository.
Huge Thanks to HNG for providing this opportunity. If you're eager to level up your technical skills and embark on a rewarding tech career, be sure to explore the opportunities offered by the HNG Internship program.
Visit the HNG Internship page to learn more about upcoming internship opportunities. If you're looking for top-tier talent for your next project, you can find exceptional individuals within the HNG network at HNG Hire.
Top comments (0)