DEV Community

Cover image for Automating Linux User Creation with a Bash Script
sipsdaoracle
sipsdaoracle

Posted on

Automating Linux User Creation with a Bash Script

A Practical Script for SysOps Engineers

In the SysOps engineer world, automation is key, especially for repetitive tasks that save valuable time and ensure consistency. As a SysOps engineer, knowing how to write robust and efficient scripts along with strong Linux skills, boosts productivity and gives you a better workflow. This article will walk you through a bash script designed to automate the creation of Linux users.

The script creates users and groups as specified, sets up home directories with appropriate permissions and ownership, it generates random passwords for the users, and logs all actions to /var/log/user_management.log. Additionally, it stores the generated passwords securely in /var/secure/user_passwords.txt. and covers error handling for scenarios like existing users.

Prerequisite:

  • Bash shell environment.
  • Text editor for editing the script and preparing the input file.

Let's have a look at our script which we will later use to accomplish this task, and break it down by a detailed explanation of each section:

#!/bin/bash # Check if the script is run as root if [[ "$(id -u)" -ne 0 ]]; then echo "You must run the script as root" >&2 exit 1 fi # Check if a filename is provided if [[ -z "$1" ]]; then echo "Usage: $0 <name-of-text-file>" >&2 exit 1 fi # File paths LOG_FILE="/var/log/user_management.log" PASSWORD_FILE="/var/secure/user_passwords.csv" # Ensure /var/secure storage for passwords mkdir -p /var/secure touch $PASSWORD_FILE chown root:root /var/secure chmod 700 /var/secure chmod 600 $PASSWORD_FILE # Function to log actions log_action() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE } # Function to generate a random password generate_password() { tr -dc 'A-Za-z0-9!@#$%^&*()_+=-[]{}|;:<>,.?/~' </dev/urandom | head -c 16 } # Function to hash passwords hash_password() { echo "$1" | openssl passwd -6 -stdin } # Read the input file line by line while IFS=";" read -r username groups; do # Trim whitespace username=$(echo "$username" | xargs) groups=$(echo "$groups" | xargs) # Skip empty lines if [[ -z "$username" ]]; then continue fi # Check if user already exists if id "$username" &>/dev/null; then log_action "User $username already exists!" continue fi # Create personal group if groupadd "$username"; then log_action "Group $username created successfully." else log_action "Failed to create group $username." continue fi # Create user with a home directory and personal group if useradd -m -s /bin/bash -g "$username" "$username"; then log_action "User $username created successfully." else log_action "Failed to create user $username." continue fi # Create groups and add user to them IFS=',' read -ra group_array <<< "$groups" for group in "${group_array[@]}"; do group=$(echo "$group" | xargs) if ! getent group "$group" >/dev/null 2>&1; then if groupadd "$group"; then log_action "Group $group created." else log_action "Failed to create group $group." continue fi fi if usermod -aG "$group" "$username"; then log_action "User $username added to group $group." else log_action "Failed to add user $username to group $group." fi done # Generate random password password=$(generate_password) hashed_password=$(hash_password "$password") if usermod --password "$hashed_password" "$username"; then echo "$username,$password" >> $PASSWORD_FILE log_action "Password set for user $username." else log_action "Failed to set password for user $username." fi # Set home directory permissions if mkdir -p "/home/$username" && chown -R "$username:$username" "/home/$username" && chmod 755 "/home/$username"; then log_action "Home directory permissions set for user $username." else log_action "Failed to set home directory permissions for user $username." fi done < "$1" log_action "User creation process completed. Check $LOG_FILE for details." 
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Script

1. Check for Root Privileges

if [[ "$(id -u)" -ne 0 ]]; then echo "You must run the script as root" >&2 exit 1 fi 
Enter fullscreen mode Exit fullscreen mode

This part checks if the script is run by the root user, this is because only the root user has permission to create and manage other users. If the script is not run as root, it will print an error message and exit.

2. Check for Filename Argument

if [[ -z "$1" ]]; then echo "Usage: $0 <name-of-text-file>" >&2 exit 1 fi 
Enter fullscreen mode Exit fullscreen mode

This section will check if the user provided a filename as an argument when running the script. If no filename is found, it will print a usage message and exit.

3. Define File Paths

LOG_FILE="/var/log/user_management.log" PASSWORD_FILE="/var/secure/user_passwords.csv" 
Enter fullscreen mode Exit fullscreen mode

These lines define the file paths for logging actions and storing passwords.

4. Ensure Secure Storage for Passwords

mkdir -p /var/secure touch $PASSWORD_FILE chown root:root /var/secure chmod 700 /var/secure chmod 600 $PASSWORD_FILE 
Enter fullscreen mode Exit fullscreen mode

This part of the script ensures that the /var/secure directory and the password file exist with appropriate permissions for secure storage. mkdir -p creates the directory if it doesn't exist, touch creates the password file, and chmod and chown set the permissions so only the root user can read and write to it.

5. Logging Function

log_action() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE } 
Enter fullscreen mode Exit fullscreen mode

The log_action function's job is to log messages with timestamps to the log file. It uses the date command to add a timestamp to each log entry and tee to append the message to the log file.

6. Password Generation Function

generate_password() { tr -dc 'A-Za-z0-9!@#$%^&*()_+=-[]{}|;:<>,.?/~' </dev/urandom | head -c 16 } 
Enter fullscreen mode Exit fullscreen mode

The generate_password function generates a random password. tr is used to filter characters from /dev/urandom (a random number generator), and head -c 16 ensures the password is 16 characters long.

7. Password Hashing Function

hash_password() { echo "$1" | openssl passwd -6 -stdin } 
Enter fullscreen mode Exit fullscreen mode

The hash_password function hashes the generated password using the openssl command with SHA-512 encryption. This makes the password secure before storing it.

8. Read and Process Input File

while IFS=";" read -r username groups; do # Trim whitespace username=$(echo "$username" | xargs) groups=$(echo "$groups" | xargs) # Skip empty lines if [[ -z "$username" ]]; then continue fi 
Enter fullscreen mode Exit fullscreen mode

This part reads the input file line by line, separating the username and groups by the semicolon (;). It also trims any whitespace around the username and groups and skips any empty lines.

9. Check for Existing User

if id "$username" &>/dev/null; then log_action "User $username already exists!" continue fi 
Enter fullscreen mode Exit fullscreen mode

This checks if the user already exists. If so, it logs the action and skips to the next user.

10. Create Personal Group

if groupadd "$username"; then log_action "Group $username created successfully." else log_action "Failed to create group $username." continue fi 
Enter fullscreen mode Exit fullscreen mode

This creates a personal group with the same name as the username.

11. Create User

if useradd -m -s /bin/bash -g "$username" "$username"; then log_action "User $username created successfully." else log_action "Failed to create user $username." continue fi 
Enter fullscreen mode Exit fullscreen mode

This creates the user with a home directory and assigns the personal group as the primary group.

12. Create and Assign Groups

Copy code IFS=',' read -ra group_array <<< "$groups" for group in "${group_array[@]}"; do group=$(echo 
Enter fullscreen mode Exit fullscreen mode

How to use the script?

  1. Save the script as create_users.sh in your preferred directory.

  2. Prepare a text file (users_and_groups.txt) with one username per line, followed by groups separated by commas. For example: light;sudo,dev,www-data idimma;sudo mayowa;dev,www-data

  3. Make the script executable with chmod +x create_users.sh.

  4. Run the script with the path to your text file as an argument: ./create_users.sh users_and_groups.txt.

Conclusion

By following the structured steps outlined above, SysOps engineers can efficiently manage large numbers of user accounts and their associated groups, providing a robust solution for onboarding new developers.

Acknowledgment

This script was developed as part of the HNG Internship DevOps track. For more details on the program, visit the HNG Internship Website.

You can learn more about the HNG Internship program here and here.

Thank you for reading.

Top comments (1)

Collapse
 
rdwiananda profile image
Rizky Dwiananda

cool, thanks