Automating User and Group Creation with a Bash Script
Published: 2024-07-01 14:42:38

As a DevOps engineer, it is quite a common task to create, update and delete users and groups. Automating this process can save time and reduce errors, especially when onboarding multiple new developers. In this article, we'll walk through a Bash script designed to automate the creation of users and their respective groups, set up home directories, generate random passwords, and log all actions.

**Objectives**

- Create users and their personal groups.
Add users to specified groups.

- Set up home directories with appropriate permissions.
Generate and securely store random passwords.

- Log all actions for auditing purposes.




**Requirements**

- Input File: A text file containing usernames and groups, formatted as username;group1,group2.
- Log File: A log file to record all actions.
- Password File: A file to securely store generated passwords.



## Let's Begin
First and foremost, at the beginning of any shell script we're writing, we start the first line with a line called a **"shebang"**, sounds catchy right? 

```bash

#!/bin/bash
```

The presence of a **shebang** indicates that a file is executable. 

Now that that is out of the way we can move on to the juicy details.



## Script Initialization

The script starts by defining the locations of the log file and the password file(you can name these file whatever you want, ):

```bash
LOGFILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.csv"
```




## Check File Input

The script checks if an input file is provided as an argument:

```bash
if [ -z "$1" ]; then
  echo "Usage: $0 <name-of-text-file>"
  exit 1
fi
```

If no file is provided, the script exits with a usage message, telling our users how to use our script.






## Create Log and Password Files

This code snippet creates the necessary directories and files, setting appropriate permissions:

```bash
mkdir -p /var/secure
touch $LOGFILE $PASSWORD_FILE
chmod 600 $PASSWORD_FILE
```

We make a directory called "/var/secure/" which will keep our passwords. After that we create the two files that were defined above for logging and saving passwords. Modifying our $PASSWORD_FILE with `chmod 600` will ensure that only the user with appropriate permissions can view it(which happens to be the current user we are logged in as).





## Generate Random Password Function

We're gonna write a function to generate some random and secure passwords for our different users.

```bash
generate_random_password() {
    local length=${1:-10} # Default length is 10 if no argument is provided
    tr -dc 'A-Za-z0-9!?%+=' < /dev/urandom | head -c $length
}
```

The function takes an argument which is how long you want the passwords to be, if none is passed, it defaults to 10.

- `tr -dc 'A-Za-z0-9!?%+='`: This command is used to translate and delete characters that are not in the regex `A-Za-z0-9!?%+=`

- `< /dev/urandom`: uses the Linux kernel's random number generator and passes the result to the command above.

- `| head -c $length`: outputs the length of the random string specified.




## Logging Function

```bash
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOGFILE
}
```

Takes an argument and logs the date and time of the message in the $LOGFILE





## Create User Function

The `create_user()` function handles the creation of users and their groups. It takes two arguments: username and groups.

```bash
create_user() {
  local username=$1
  local groups=$2

  if getent passwd "$username" > /dev/null; then
    log_message "User $username already exists"
  else
    useradd -m $username
    log_message "Created user $username"
  fi

  # Add user to specified groupsgroup
  groups_array=($(echo $groups | tr "," "\n"))

  for group in "${groups_array[@]}"; do
    if ! getent group "$group" >/dev/null; then
      groupadd "$group"
      log_message "Created group $group"     
    fi
    usermod -aG "$group" "$username"
    log_message "Added user $username to group $group"
  done

  # Set up home directory permissions
  chmod 700 /home/$username
  chown $username:$username /home/$username
  log_message "Set up home directory for user $username" 

  # Generate a random password
  password=$(generate_random_password 12) 
  echo "$username:$password" | chpasswd
  echo "$username,$password" >> $PASSWORD_FILE
  log_message "Set password for user $username"
}
```




### Let's break it down.....

- **Checking if User Already Exists**

```bash
if id "$username" > /dev/null; then
  log_message "User $username already exists"
else
  useradd -m $username
  log_message "Created user $username"
fi
```
If a user exists our script logs it and moves on else the user is created and then logged.

NOTE: `> /dev/null` is passing the response to null so that it doesn't interfere with our logs.

**NOTE: We are not going to create a personal group for each user because unix does this for us automatically when we create a new user**




- **Adding User to Specified Groups**

We then proceed to add the users to their different groups

```bash
groups_array=($(echo $groups | tr "," "\n"))
for group in "${groups_array[@]}"; do
  if ! getent group "$group" > /dev/null; then
    groupadd "$group"
    log_message "Created group $group"   
  fi
  usermod -aG "$group" "$username"
  log_message "Added user $username to group $group"
done
```

The code snippet splits the groups string by commas and saves them in a groups_array variable. It then loops through each group and adds the user to it, also making sure to create the group if it doesn't exist:





- **Setting Up Home Directory Permissions**

```bash
chmod 700 /home/$username
chown $username:$username /home/$username
log_message "Set up home directory for user $username" 
```

`chmod 700 /home/$username:`: Sets the home directory permissions so only the user has full access (read, write, execute).

`chown $username:$username /home/$username`: Changes the ownership of the home directory to the specified user and their group.

`echo "Set up home directory for user $username" | tee -a $LOGFILE`: Logs a message indicating the home directory setup to a specified log file.





- **Assigning A Random Password To Each User**

```bash
password=$(generate_random_password 12) 
echo "$username:$password" | chpasswd
echo "$username,$password" >> $PASSWORD_FILE
log_message "Set password for user $username"
```

This snippet uses the function we wrote earlier to create a password, update the user's password to the generated password, saves the username and the corresponding password to the `$PASSWORD_FILE` and finally logs a message indicating it has been successfully changed.





## Reading the Input File

The script reads the input file line by line, calling the `create_user()` function for each line and passing the $username and $groups as arguments:


```bash
while IFS=';' read -r username groups; do
  create_user "$username" "$groups"
done < "$1"
```



## Now Put It All Together...

```bash
#!/bin/bash

# Log file location
LOGFILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.csv"

# Check if the input file is provided
if [ -z "$1" ]; then
  echo "Error: No file was provided"
  echo "Usage: $0 <name-of-text-file>"
  exit 1
fi

# Create log and password files
mkdir -p /var/secure
touch $LOGFILE $PASSWORD_FILE
chmod 600 $PASSWORD_FILE

generate_random_password() {
    local length=${1:-10} # Default length is 10 if no argument is provided
    LC_ALL=C tr -dc 'A-Za-z0-9!?%+=' < /dev/urandom | head -c $length
}

# Function to create a user
create_user() {
  local username=$1
  local groups=$2

  if getent passwd "$username" > /dev/null; then
    echo "User $username already exists" | tee -a $LOGFILE
  else
    useradd -m $username
    echo "Created user $username" | tee -a $LOGFILE
  fi

  # Add user to specified groupsgroup
  groups_array=($(echo $groups | tr "," "\n"))

  for group in "${groups_array[@]}"; do
    if ! getent group "$group" >/dev/null; then
      groupadd "$group"
      echo "Created group $group" | tee -a $LOGFILE      
    fi
    usermod -aG "$group" "$username"
    echo "Added user $username to group $group" | tee -a $LOGFILE
  done

  # Set up home directory permissions
  chmod 700 /home/$username
  chown $username:$username /home/$username
  echo "Set up home directory for user $username" | tee -a $LOGFILE

  # Generate a random password
  password=$(generate_random_password 12) 
  echo "$username:$password" | chpasswd
  echo "$username,$password" >> $PASSWORD_FILE
  echo "Set password for user $username" | tee -a $LOGFILE
}

# Read the input file and create users
while IFS=';' read -r username groups; do
  create_user "$username" "$groups"
done < "$1"

echo "User creation process completed." | tee -a $LOGFILE
```

## Conclusion

This script provides an efficient way to manage user and group creation, ensuring that all necessary steps are handled securely and logged for auditing. By automating these tasks, SysOps engineers can save time and reduce the risk of errors during user onboarding.

To learn more and kickstart your programming journey you can visit:
https://hng.tech/internship or https://hng.tech/premium

Feel free to reach out with questions or suggestions for improvements. Happy automating!