As a devops engineer creating users and managing them is one of the primary responsibilities as a devops engineer or sysadmin.
Today we will be creating a bash script that :
Reads a text file containing the employee’s usernames and group names, where each line is formatted as user;groups.
create users and groups as specified
set up home directories with appropriate permissions and ownership
generate random passwords for the users
log all actions to /var/log/user_management.log
Additionally, store the generated passwords securely in /var/secure/user_passwords.txt
Without further ado let's get started.
Firstly lets create the file create_user.sh using the touch
command
touch create_user.sh
we want to first add our shebang #!/bin/bash
.
Now we an start ticking off some of the requirements.
requirement 5 specifically, let us create the user_management.log file
Creating the required log and txt files
if [[ ! -e /var/log/user_management.log ]]; then
sudo mkdir -p /var/log/
sudo touch /var/log/user_management.log
fi
analyzing the above code: we check if the fire /var/log/user_management.log exist, if it does not we
create the directory /var/log/ with mkdir and the -p flag for persistence, then we create the file user_management.log using touch
and then end the if statement using fi.
lets do the same for the file that all the passwords will be saved in
if [[ ! -e /var/secure/user_passwords.txt ]]; then
sudo mkdir -p /var/secure/
sudo touch /var/secure/user_passwords.txt
fi
/var/secure/user_passwords.txt and /var/log/user_management.log is difficult to type and a mouthful to say so we'll assign the to variables
log_file="/var/log/user_management.log"
pass_file="/var/secure/user_passwords.txt"
and now we can start sending outputs of all that is going on to our logfile
echo "logfile created..." >> $log_file
echo "checking if text_file exists" >> $log_file
checking if a text file containing the users and groups have been passed
Confirming a file was passed as an argument
if [[ -z "$1" ]]; then
echo "Usage: $0 filename"
echo "Text file does not exist. ...exiting" >> $log_file
exit 1
fi
The above code snippet checks if there is user_input from the terminal
and if there is not it sends a text to the log file and the program ends.
However assuming there is a file passed/user_input made in the terminal
Reading the file
echo "Reading file" >> $log_file
file_path="$1"
if [[ -f "$file_path" ]]; then
echo "fetching the usernames and groups" >> $log_file
while IFS= read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}')
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
The above code opens up the file and starts to read from it,
Fetching the usernames and groups
While IFS = read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}')
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
The above snippet basically says while there are lines in the file i.e the code has not traveled to the end of the file, we then assign user_name to the $lines being piped through awk and the delimiter '; ' to separate the line
basically,
we have a line vale; sudo, vale, data
when we pipe it into awk -F'; ' '{print $1}'
it splits the line into tow parts which are vale
and sudo, vale, data
and {print $1} let's us access the first part of the line before the delimiter. while the line below does the same thing but {print $2} gives us access to the second part of the line.
file_path="$1"
if [[ -f "$file_path" ]]; then
echo "fetching the usernames and groups" >> $log_file
while IFS= read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}')
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
if id -u "$user_name">/dev/null 2>&1; then
echo "user $user_name already exists"
echo "user $user_name already exists" >> $log_file
else
IFS=',' read -ra group_array <<< "$groups" #explain in the post
now that we have access to the users we can check if a user already exist, to do that we simply check if a user has an id, if the name already has an id it exist and we simply make it known to the user that the user_name has been created already
if id -u "$user_name">/dev/null 2>&1; then
echo "user $user_name already exists"
echo "user $user_name already exists" >> $log_file
checking if user already exists
id -u "$user_name"
is used to get the id of a user and >dev/null 2>&1
is used to send the output to a null file so no output is displayed
else
is used to read the elements in groups and put them into an array group_array where the elements are split by the ',' delimiter.
IFS=',' read -ra group_array <<< "$groups"
file_path="$1"
if [[ -f "$file_path" ]]; then
echo "fetching the usernames and groups" >> $log_file
while IFS= read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}')
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
if id -u "$user_name">/dev/null 2>&1; then
echo "user $user_name already exists"
echo "user $user_name already exists" >> $log_file
else
IFS=',' read -ra group_array <<< "$groups" #explain in the post
for group in "${group_array[@]}"; do
if ! getent group "$group" >/dev/null 2>&1; then
sudo groupadd "$group"
echo "Group $group created"
echo "Group $group created" >> $log_file
fi
done
Group creation
for group in "${group_array[@]}"; do
if ! getent group "$group" >/dev/null 2>&1; then
sudo groupadd "$group"
echo "Group $group created"
echo "Group $group created" >> $log_file
fi
done
lets break down the above block of code :
for group in "{$group_array[@]};
this creates a variable group that is equal to the current item in the group array that was created before and it keeps on changing according to the number of elements in that group
do
remember when we wanted to find out if a user exists or not? This is basically the same thing but instead of a user we use the getent function to get entities that belong to a particular group and if no entity belongs to a particular group the group most likely does not exists so we pipe the output to the null folder and create the group.
if ! getent group "$group" >/dev/null 2>&1;
password creation
we can generate a random password using openssl
password=$(openssl rand -base64 12)
This creates a variable password which would have a 12 digit password in base 64
creating users with their assigned group and passwords
luckily someone asked this question on stackoverflow and got a response
Thank you very much Netzego and Damien
sudo useradd -m -G "$groups" -p "$(openssl passwd -1 "$password")" "$user_name"
echo "adding groups :$groups for user: $user_name and password in $pass_file " >> $log_file
group_fold="/home/$user_name"
so far we have:
file_path="$1"
if [[ -f "$file_path" ]]; then
echo "fetching the usernames and groups" >> $log_file
while IFS= read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}') #explain in the post
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
if id -u "$user_name">/dev/null 2>&1; then #explain in the post
echo "user $user_name already exists"
echo "user $user_name already exists" >> $log_file
else
IFS=',' read -ra group_array <<< "$groups" #explain in the post
for group in "${group_array[@]}"; do
if ! getent group "$group" >/dev/null 2>&1; then #explain in the post
sudo groupadd "$group"
echo "Group $group created"
echo "Group $group created" >> $log_file
fi
done
password=$(openssl rand -base64 12)
sudo useradd -m -G "$groups" -p "$(openssl passwd -1 "$password")" "$user_name" #explain in post
echo "adding groups :$groups for user: $user_name and password in $pass_file " >> $log_file
group_fold="/home/$user_name"
now we just have to create the users home folders with the appropriate permissions and groups
sudo chmod 700 $group_fold > $log_file 2>&1
sudo chown $user_name:$user_name $group_fold > $log_file 2>&1
echo "Home directory for $user set up with appropriate permissions and ownership" >> $log_file
echo "$user_name,$password" >> "$pass_file"
fi
done < "$file_path"
sudo chmod 600 "$password_file"
sudo chown "$(id -u):$(id -g)" "$password_file"
echo "File permissions for $password_file set to owner-only read" >> $log_file
else
echo "File not found: $file_path" >> "$log_file"
exit 1
The complete code:
#!/bin/bash
if [[ ! -e /var/log/user_management.log ]]; then
sudo mkdir -p /var/log/
sudo touch /var/log/user_management.log
fi
if [[ ! -e /var/secure/user_passwords.txt ]]; then
sudo mkdir -p /var/secure/
sudo touch /var/secure/user_passwords.txt
fi
log_file="/var/log/user_management.log"
pass_file="/var/secure/user_passwords.txt"
echo "logfile created..." >> $log_file
echo "checking if text_file exists" >> $log_file
if [[ -z "$1" ]]; then
echo "Usage: $0 filename"
echo "Text file does not exist. ...exiting" >> $log_file
exit 1
fi
echo "Reading file" >> $log_file
file_path="$1"
if [[ -f "$file_path" ]]; then
echo "fetching the usernames and groups" >> $log_file
while IFS= read -r lines; do
user_name=$(echo "$lines" | awk -F'; ' '{print $1}') #explain in the post
groups=$(echo "$lines" | awk -F'; ' '{print $2}')
if id -u "$user_name">/dev/null 2>&1; then #explain in the post
echo "user $user_name already exists"
echo "user $user_name already exists" >> $log_file
else
IFS=',' read -ra group_array <<< "$groups" #explain in the post
for group in "${group_array[@]}"; do
if ! getent group "$group" >/dev/null 2>&1; then #explain in the post
sudo groupadd "$group"
echo "Group $group created"
echo "Group $group created" >> $log_file
fi
done
password=$(openssl rand -base64 12)
sudo useradd -m -G "$groups" -p "$(openssl passwd -1 "$password")" "$user_name" #explain in post
echo "adding groups :$groups for user: $user_name and password in $pass_file " >> $log_file
group_fold="/home/$user_name"
sudo chmod 700 $group_fold > $log_file 2>&1
sudo chown $user_name:$user_name $group_fold > $log_file 2>&1
echo "Home directory for $user set up with appropriate permissions and ownership" >> $log_file
echo "$user_name,$password" >> "$pass_file"
fi
done < "$file_path"
sudo chmod 600 "$password_file"
sudo chown "$(id -u):$(id -g)" "$password_file"
echo "File permissions for $password_file set to owner-only read" >> $log_file
else
echo "File not found: $file_path" >> "$log_file"
exit 1
This task was assigned to me during my HNG internship devops track
Top comments (0)