Hello! Welcome to the next practical project in our Bash automation module.
In our previous lessons, we've built a solid foundation by creating scripts to automate monitoring, backups, and log management. These are all crucial "housekeeping" tasks for maintaining system health. Today, we'll shift our focus to another fundamental and frequent responsibility in any DevOps or system administration role: managing user accounts.
Manually creating user accounts one by one is slow, error-prone, and doesn't scale, especially when onboarding a new team of developers. This is a perfect scenario for automation. This project will bring together many skills we've developed, including file processing, command-line tools, conditional logic, and logging.
Today's Learning Outcome: By the end of this lesson, you will be able to write a Bash script to automate the onboarding of new Linux users based on a predefined template.
We will design and build a script that reads user information from a text file, creates the corresponding user accounts and groups, generates secure passwords, and logs all its actions for auditing purposes.
1. Defining the Automation Task
Before writing any code, it's essential to clearly define the problem and the requirements for our script. This ensures we build a tool that is both effective and reliable.
Automating user creation with Bash Scripting
The article 'Automating user creation with Bash Scripting' by Amarachi Iheanacho provides a clear and common problem statement for this task. Let's use it to frame our project.
Read the section titled 'The problem statement'. This will outline the core requirements for our script, including the input file format, group assignments, password generation, and logging.
Based on that problem statement, our script must perform the following actions for each new user:
- Read user data from a text file where each line is formatted as
username;group1,group2,.... - Create a new system user.
- Create a personal group for the user (a common security practice).
- Create any specified supplementary groups if they don't already exist.
- Add the user to their personal group and all specified supplementary groups.
- Generate a random, secure password for the user.
- Create a home directory for the user with appropriate permissions.
- Log all actions (user creation, group creation, etc.) to a file for auditing.
- Store the generated passwords in a separate, secure file for administrative access.
2. Setting Up the Project Environment
A well-structured project is easier to manage. Let's create the necessary files and directories for our script.
In your terminal, navigate to a suitable directory and run the following commands:
-
Create the main script file:
touch create_users.sh chmod +x create_users.shWe create the file and immediately make it executable.
-
Create the user input file:
touch users.txtNow, open
users.txtwith a text editor and add a few lines of user data. This will be our template. The format isusername;groups(with groups separated by commas).jdoe;developers,sudo asmith;developers,testers psingh;analytics -
Prepare the log and password storage:
Our script will need to write to/var/logand a secure location. We will add the commands to create these directly into our script, but it's good to know the structure we're aiming for.
3. Building the Script: The Skeleton
Let's start building create_users.sh. We'll begin with the foundational components: checks for privileges, argument validation, and variable definitions.
Automating User Creation and Management with Bash Scripting
The article 'Automating User Creation and Management with Bash Scripting' provides a very clear breakdown of the initial script setup. We will follow its structure to build a robust starting point.
Read the sections 'The shebang', 'Defining File Paths and Variables', 'Checking for Sudo Privileges', and 'Validating Arguments'. As you read, add the corresponding code blocks to your create_users.sh file. Pay close attention to the explanation for setting file permissions with chmod 700 and chmod 600 – this is critical for security.
After following the guide, the beginning of your create_users.sh script should look similar to this:
#!/bin/bash
# --- 1. Initial Checks ---
# Ensure the script is run with root privileges
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root. Exiting..."
exit 1
fi
# Ensure an input file is provided as an argument
if [ $# -eq 0 ]; then
echo "Usage: $0 <path-to-user-file>"
exit 1
fi
# Check if the provided file exists
USERS_FILE=$1
if [ ! -f "$USERS_FILE" ]; then
echo "Error: Input file '$USERS_FILE' not found."
exit 1
fi
# --- 2. Variable Definitions & Setup ---
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
PASSWORD_DIR="/var/secure"
# Create log file and password directory/file with secure permissions
touch "$LOG_FILE"
mkdir -p "$PASSWORD_DIR"
chmod 700 "$PASSWORD_DIR"
touch "$PASSWORD_FILE"
chmod 600 "$PASSWORD_FILE"
echo "Setup complete. Starting user creation process..." >> "$LOG_FILE"
This initial code handles essential error checking and setup, making our script safer and more reliable. The chmod commands are particularly important:
chmod 700 /var/secure: Only the owner (root) can read, write, and enter this directory.chmod 600 /var/secure/user_passwords.txt: Only the owner (root) can read and write this file. No one else can access the passwords.
4. The Core Logic: Processing Users and Groups
Now for the heart of the script. We need to read the users.txt file line by line and execute our user management commands. We will use a while read loop, which is a standard and robust way to process files in Bash.
The following sections will guide you through building this logic.
Automating user creation with Bash Scripting
The guide 'Automating user creation with Bash Scripting' provides an excellent, well-explained while loop structure for this task. Let's study and adapt its core logic.
Carefully read section 6, 'Creating the users and groups'. Do not copy the entire block at once. Instead, read the breakdown for each part of the loop: 'while IFS=';' read...', 'Trimming Whitespace', creating the personal group, creating the user, assigning supplementary groups, and setting the password. We will assemble our own version based on these pieces.
Let's integrate this logic into our script. Add the following loop to the end of your create_users.sh file. Each step is commented to explain what it does.
# --- 3. Main Processing Loop ---
while IFS=';' read -r username groups || [ -n "$username" ]; do
# Trim whitespace from username and groups
username=$(echo "$username" | xargs)
groups=$(echo "$groups" | xargs)
# Skip empty lines
if [ -z "$username" ]; then
continue
fi
echo "Processing user: $username"
# --- Check if user already exists ---
if id "$username" &>/dev/null; then
echo "User '$username' already exists. Skipping." | tee -a "$LOG_FILE"
continue
fi
# --- Create a personal group for the user ---
if ! getent group "$username" >/dev/null; then
groupadd "$username"
echo "Created personal group '$username'." | tee -a "$LOG_FILE"
fi
# --- Create the user ---
# -m: create home directory
# -g: set primary group to the user's personal group
# -s: set default shell
useradd -m -g "$username" -s /bin/bash "$username"
if [ $? -eq 0 ]; then
echo "Created user '$username'." | tee -a "$LOG_FILE"
else
echo "Failed to create user '$username'." | tee -a "$LOG_FILE"
continue
fi
# --- Add user to supplementary groups ---
if [ -n "$groups" ]; then
# Replace commas with spaces to loop through groups
for group in $(echo "$groups" | tr ',' ' '); do
# Check if group exists, create if it doesn't
if ! getent group "$group" >/dev/null; then
groupadd "$group"
echo "Created group '$group'." | tee -a "$LOG_FILE"
fi
# Add user to the group
usermod -aG "$group" "$username"
echo "Added user '$username' to group '$group'." | tee -a "$LOG_FILE"
done
fi
# --- Generate and set a random password ---
password=$(openssl rand -base64 12)
echo "$username:$password" | chpasswd
if [ $? -eq 0 ]; then
echo "Set password for user '$username'." | tee -a "$LOG_FILE"
# Store the password securely for the administrator
echo "$username,$password" >> "$PASSWORD_FILE"
else
echo "Failed to set password for '$username'." | tee -a "$LOG_FILE"
fi
done < "$USERS_FILE"
echo "User creation process finished." | tee -a "$LOG_FILE"
A Note on tee -a: We use tee -a "$LOG_FILE" to simultaneously print messages to the console (for you to see) and append them to the log file.
Test your understanding!
In the usermod -aG "$group" "$username" command, what do the -a and -G flags do, and why is it important to use them together?
Show answer
-Gspecifies a list of supplementary groups to add the user to.-astands for "append". It tellsusermodto add the user to the specified groups without removing them from any existing groups.
If you were to use usermod -G "$group" "$username" without -a, it would make $group the user's only supplementary group, removing them from all others. Using -aG is crucial for incrementally adding group memberships.
5. Testing and Verification
Your script is complete! Now it's time to test it.
-
Run the script:
Execute the script from your terminal, passing yourusers.txtfile as the argument.sudo ./create_users.sh users.txt -
Check the output:
You should see the script's progress printed to your console. -
Verify the users:
Pick one of the users you created (e.g.,jdoe) and verify their existence and group memberships with theidcommand:id jdoeThe output should show the user's
uid, their primary group (gid=jdoe), and their supplementary groups (groups=...jdoe,developers,sudo). -
Inspect the log file:
Check the contents of the log file to see a detailed audit trail of what the script did.cat /var/log/user_management.log -
Check the password file:
Finally, verify that the passwords were stored securely.sudo cat /var/secure/user_passwords.txtYou should see the usernames and their randomly generated passwords. Because of the file permissions we set, only the root user can view this file.
Conclusion
Excellent work! You have successfully built a practical and powerful Bash script to automate a critical DevOps task. This project not only saves time but also enforces consistency and provides a clear audit trail.
Key Takeaways:
- Automation is key for repetitive administrative tasks like user onboarding.
- A robust script includes privilege checks, argument validation, and clear logging.
- The
while IFS=... readloop is the standard pattern for processing files line-by-line in Bash. - Core Linux user management commands like
useradd,groupadd,usermod, andchpasswdare the building blocks for this type of automation. - Security is paramount: always set strict permissions (
chmod) on files and directories that handle sensitive information like passwords.
Next Up
We're nearing the end of our practical Bash projects module. You've tackled monitoring, backups, log rotation, and now user management. In our final project for this module, we will combine scripting with networking concepts. Our next lesson will be to develop a Bash script to check the health status of a web service, a task at the heart of service monitoring and reliability engineering.