As a SysOps engineer, part of your job will be to manage user accounts and groups effectively for least privilege on the company's systems/servers to maintain security and access control.
Using Bash Script can greatly enhance your performance in that regard and also management and configuration of the systems.
Table of Contents
- Prerequisite
- What is Bash
- What is Bash Scripting
- Demo
- Solution
- Conclusion
Prerequisite
- A Linux system. (Ubuntu, CentOS, etc) with bash installed.
- Basic Knowledge of Linux Commands.
- Basic Knowledge of Bash Scripting.
What is Bash
Bash means Bourne again shell. It is the shell that Linux environment uses to communicate with the kernel to make requests and receive feedback.
What is Bash Scripting?
Bash scripting involves writing scripts using the Bash (Bourne Again Shell) command language to automate tasks on Unix-like operating systems. These scripts can range from simple commands executed sequentially to complex programs with control structures and functions.
Demo
Your company has employed many new developers. As a SysOps engineer, write a bash script called create_users.sh that reads a text file containing the employee’s usernames and group names, where each line is formatted as user; groups.
The script should create users and groups as specified, set up home directories with appropriate permissions and ownership, generate random passwords for the users, and log all actions to /var/log/user_management.log. Additionally, stores the generated passwords securely in /var/secure/user_passwords.txt.
Solution
First is to create a directory with the command mkdir HNG_Tasks
Then inside the directory, create a script file with the command touch create_users.sh
Next is to open the script with a text editor by running the command sudo vi create_users.sh
Then populate the script with the code below
#!/bin/bash
# Log file and password file creation
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
# Ensure script is run as root/sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run as root or use sudo."
exit 1
fi
# Create directories and files if they don't exist, and set permissions
mkdir -p /var/log
mkdir -p /var/secure
touch $LOG_FILE
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE
# Function to create log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# Function to generate a random password
generate_password() {
echo $(openssl rand -base64 12)
}
# Check if the input file is provided
if [ -z "$1" ]; then
echo "Usage: sudo bash $0 <name-of-text-file>"
exit 1
fi
# Read the input file
INPUT_FILE=$1
# Process each line in the input file
while IFS=';' read -r username groups; do
# Ignore empty lines and lines that start with a hash (#)
if [[ -z "$username" || "$username" == \#* ]]; then
continue
fi
# Removing all whitespace from username and groups
username=$(echo "$username" | xargs)
groups=$(echo "$groups" | xargs)
# Check if user already exists
if id "$username" &>/dev/null; then
log_message "User '$username' already exists."
else
# Create user with home directory and bash shell
useradd -m -s /bin/bash "$username"
if [ $? -eq 0 ]; then
log_message "Created user '$username'."
else
log_message "Failed to create user '$username'."
continue
fi
# Create personal group with the same name as the user
usermod -g "$username" "$username"
if [ $? -eq 0 ]; then
log_message "Created personal group for user '$username'."
else
log_message "Failed to create personal group for user '$username'."
fi
# Generate and set a random password for the user
password=$(generate_password)
echo "$username:$password" | chpasswd
if [ $? -eq 0 ]; then
log_message "Set password for user '$username'."
else
log_message "Failed to set password for user '$username'."
fi
# Save the password to the secure file
echo "$username,$password" >> $PASSWORD_FILE
fi
# Add user to specified groups if there are any
if [ -n "$groups" ]; then
# Split groups by comma and loop through each group
IFS=',' read -r groups_list <<< "$groups"
for group in ${groups_list//,/ }; do
group=$(echo "$group" | xargs) # Trim whitespace
if getent group "$group" &>/dev/null; then # Checking if group exist
usermod -aG "$group" "$username"
if [ $? -eq 0 ]; then
log_message "Added user '$username' to group '$group'."
else
log_message "Failed to add user '$username' to group '$group'."
fi
else
groupadd "$group"
if [ $? -eq 0 ]; then
usermod -aG "$group" "$username"
log_message "Created and added user '$username' to group '$group'."
else
log_message "Failed to create group '$group' or add user '$username' to group."
fi
fi
done
fi
done < "$INPUT_FILE"
log_message "User creation and group assignment completed."
Code Breakdown
#!/bin/bash
# Log file and password file creation
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
# Ensure script is run as root/sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run as root or use sudo."
exit 1
fi
The block of code above starts with the Shebang line, defines the log file and the password file as variables to their paths, and makes sure the script is ran as a root user or with sudo to avoid any permission issues. (if [ "$EUID" -ne 0 ]; then:
This condition checks if the effective user ID (EUID) is not equal to 0. In Unix-like systems, the root user has an EUID of 0.)
mkdir -p /var/log
mkdir -p /var/secure
touch $LOG_FILE
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE
# Function to create log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
The code above creates directories for the log and password files if those directories don't exist already. The -p
flag makes sure no error is thrown if the directories already exist.
Using the variable declaration in the first block of code, creates a log file and a password file.
It changes the permission of the password file to '600' for the owner to have read and write permission of the file, to restrict access to the password file.
The next line of code creates a function called log_message
. Tis function captures the current date and time and prints it alongside the echo command which is pipped (|) to the tee
command. The tee
command writes the output to both the standard output (so it appears in the terminal) and appends it (with the -a flag) to the log file specified by LOG_FILE.
# Function to generate a random password
generate_password() {
echo $(openssl rand -base64 12)
}
# Check if the input file is provided
if [ -z "$1" ]; then
echo "Usage: sudo bash $0 <name-of-text-file>"
exit 1
fi
The Code above has a function that generates random passwords with openssl rand -base64 12: The openssl command is used to generate random data. The rand subcommand generates random bytes, and the -base64 option encodes the output in Base64. The 12 specifies the number of random bytes to generate, which after Base64 encoding results in a 16-character string. The 'echo $' captures and prints the random password.
The code also checks if the script is run with an argument. The if condition checks if the first parameter/argument ($1) is empty with the '-z' flag and terminates with an exit status of 1 if no argument is run with the script.
# Read the input file
INPUT_FILE=$1
# Process each line in the input file
while IFS=';' read -r username groups; do
# Ignore empty lines and lines that start with a hash (#)
if [[ -z "$username" || "$username" == \#* ]]; then
continue
fi
# Removing all whitespace from username and groups
username=$(echo "$username" | xargs)
groups=$(echo "$groups" | xargs)
The next block of code assigns the variable "INPUT_FILE" to the value of the first argument "$1", and uses a while loop to read the input file line by line and with the IFS=';'
splits each line into fields based on the semicolon, reads each line and splits it into two variables: username and groups. With an if statement checks if the username is empty or if it's a comment and skips to the next condition if they are both true and uses the xargs
command to remove leading and trailing whitespace from username and groups.
# Check if user already exists
if id "$username" &>/dev/null; then
log_message "User '$username' already exists."
else
# Create user with home directory and bash shell
useradd -m -s /bin/bash "$username"
if [ $? -eq 0 ]; then
log_message "Created user '$username'."
else
log_message "Failed to create user '$username'."
continue
fi
# Create personal group with the same name as the user
usermod -g "$username" "$username"
if [ $? -eq 0 ]; then
log_message "Created personal group for user '$username'."
else
log_message "Failed to create personal group for user '$username'."
fi
This block of code uses an if condition to check if a user already exists, with the id "$username"
attempts to retrieve user information for username, &>/dev/null
redirects both standard output and standard error to /dev/null, effectively silencing any output from the id command. And if the user doesn't exist, with the useradd -m -s /bin/bash "$username"
it creates the user, a home directory for the user with the -m
flag and sets the user default shell to bash with the -s /bin/bash
. After creating a user, it creates a personal group for the user with the code usermod -g "$username" "$username"
where usermod
modifies a user account, -g "$username"
sets the primary group of the user to a group with the same name as the user and the $username
specifies the username to be modified. It checks the exit status of the usermod
command, If the group modification is successful, it logs a message indicating the personal group was created and logs the failure message if it fails.
# Generate and set a random password for the user
password=$(generate_password)
echo "$username:$password" | chpasswd
if [ $? -eq 0 ]; then
log_message "Set password for user '$username'."
else
log_message "Failed to set password for user '$username'."
fi
# Save the password to the secure file
echo "$username,$password" >> $PASSWORD_FILE
fi
This part of the script handles generating and setting a random password for the newly created user, and then saving the password to a secure file. Let's go through it step-by-step:
The first line calls the function generate_password
, and stores the value of the function in the variable. The echo "$username:$password" | chpasswd
prints the username and password in the format required by chpasswd
and pipes this input to the chpasswd
command, which updates the user's password in the system. It checks the exit status of the password if it set the password for the user or not and appends the username and password to a file specified by the variable PASSWORD_FILE.
if [ -n "$groups" ]; then
# Split groups by comma and loop through each group
IFS=',' read -r groups_list <<< "$groups"
for group in ${groups_list//,/ }; do
group=$(echo "$group" | xargs) # Trim whitespace
if getent group "$group" &>/dev/null; then # Checking if group exist
usermod -aG "$group" "$username"
if [ $? -eq 0 ]; then
log_message "Added user '$username' to group '$group'."
else
log_message "Failed to add user '$username' to group '$group'."
fi
else
groupadd "$group"
if [ $? -eq 0 ]; then
usermod -aG "$group" "$username"
log_message "Created and added user '$username' to group '$group'."
else
log_message "Failed to create group '$group' or add user '$username' to group."
fi
fi
done
fi
done < "$INPUT_FILE"
log_message "User creation and group assignment completed."
This section of the script assigns newly created users to specific groups. It checks if the groups exist and creates them if they don't exist. It checks if the variable is empty with the'-n' flag, sets the field separator to a comma (,), and reads the comma-separated groups into group_list. It starts a for loop to go over the group_list, replacing the comma(,) with a space, trims white space from the group variable, it checks if the group exists. If the group exists, it adds the user to the group, but if it does not, it creates the group and then adds the user. It logs the final message indicating the user creation and group assignment.
The next step is to save the script, exit the text editor, and make the script executable by running the command chmod +x create_users.sh
Then create a users.txt file with the command touch users.txt
for the script to read from. Open with a code editor with the command sudo vi users.txt
and populate with users and groups of your choice. Eg
Then run the script with the command sudo ./create_users.sh users.txt
The output the script gives is in the picture below
Conclusion
At the end of this article, you have learned what bash and bash scripting is, why we use bash script, and understand the code used in the demo. This is a task for the HNG internship stage one program. You can check out available roles at HNG with this link
Top comments (0)