<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sudo Bro</title>
    <description>The latest articles on DEV Community by Sudo Bro (@sudobro).</description>
    <link>https://dev.to/sudobro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1708802%2F5681d499-f21b-4323-a9f0-56a21dd88414.jpeg</url>
      <title>DEV Community: Sudo Bro</title>
      <link>https://dev.to/sudobro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sudobro"/>
    <language>en</language>
    <item>
      <title>Automating Creation of Users and groups using Bash Script (Step-by-Step Guide)</title>
      <dc:creator>Sudo Bro</dc:creator>
      <pubDate>Wed, 03 Jul 2024 00:44:10 +0000</pubDate>
      <link>https://dev.to/sudobro/automating-creation-of-users-and-groups-using-bash-script-step-by-step-guide-3dm0</link>
      <guid>https://dev.to/sudobro/automating-creation-of-users-and-groups-using-bash-script-step-by-step-guide-3dm0</guid>
      <description>&lt;p&gt;As a DevOps engineer, it is quite a common task to create, update, and delete users and groups. Automating this process can save a lot of time and help reduce human errors, especially when onboarding numerous users. In this article, I'll walk you through using bash to automate the creation of users and their respective groups, setting up home directories, generating random passwords, and logging all actions performed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objectives&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create users and their personal groups. &lt;/li&gt;
&lt;li&gt;Add users to specified groups.&lt;/li&gt;
&lt;li&gt;Set up home directories with appropriate permissions.&lt;/li&gt;
&lt;li&gt;Generate and securely store passwords.&lt;/li&gt;
&lt;li&gt;Log all actions for auditing purposes.&lt;/li&gt;
&lt;li&gt;Ensure error handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let's Begin
&lt;/h2&gt;

&lt;p&gt;First and foremost, at the beginning of any shell script we're writing, we start with &lt;strong&gt;"shebang"&lt;/strong&gt; in the first line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shebang tells us that the file is executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the directory for user logs and file
&lt;/h2&gt;

&lt;p&gt;It is necessary to create a directory and files for logging and password storage. If it already exists, DO NOT CREATE IT AGAIN!!!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p /var/log /var/secure
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;/var/log:&lt;/strong&gt; Directory for log files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/var/secure:&lt;/strong&gt; Directory for secure files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;user_management.log:&lt;/strong&gt; Log file to record actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Secure the generated passwords
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 600 /var/secure/user_passwords.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;user_passwords.txt:&lt;/strong&gt; File to store passwords securely with read and write permissions for the file owner only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Earlier, we created the directory "&lt;code&gt;/var/secure&lt;/code&gt;" to store &lt;code&gt;user_password.txt&lt;/code&gt;. To give the appropriate permissions, we use &lt;code&gt;chmod 600&lt;/code&gt; to give only the current user access to view our generated passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a function to log actions
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;log_action()&lt;/code&gt; function record actions with timestamps in the log file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;log_action() {
    echo "$(date) - $1" &amp;gt;&amp;gt; "/var/log/user_management.log"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  User Creation Function
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;create_user()&lt;/code&gt; function handles the creation of user accounts and their associated groups. It takes two arguments: username and groups.&lt;/p&gt;

&lt;p&gt;Steps taken in the &lt;code&gt;create_user()&lt;/code&gt; function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check for Existing User: Logs a message if the user already exists.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if id "$user" &amp;amp;&amp;gt;/dev/null; then
    log_action "User $user already exists."
    return
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;id "$user" &amp;amp;&amp;gt;/dev/null&lt;/code&gt; checks if the user exists by attempting to retrieve the user's information. If the user does not exist, &lt;code&gt;id&lt;/code&gt; will return a non-zero exit status. The &lt;code&gt;&amp;amp;&amp;gt;/dev/null&lt;/code&gt; part redirects any output (both stdout and stderr) to &lt;code&gt;/dev/null&lt;/code&gt;, effectively silencing the command's output.&lt;br&gt;
If the user exists &lt;code&gt;log_action "User $user already exists."&lt;/code&gt; logs a message indicating that the user already exists. Using &lt;code&gt;return&lt;/code&gt;, it exits the &lt;code&gt;create_user()&lt;/code&gt; function early, preventing any further actions from being taken for the existing user.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create User Group: Creates a personal group for the user.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;groupadd "$user"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;groupadd "$user"&lt;/code&gt; creates a new group with the same name as the user. This group will be the primary group for the user being created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle Additional Groups: Checks and creates additional groups if they do not exist.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IFS=' ' read -ra group_array &amp;lt;&amp;lt;&amp;lt; "$groups"
log_action "User $user will be added to groups: ${group_array[*]}"
for group in "${group_array[@]}"; do
    group=$(echo "$group" | xargs)  # Trim whitespace
    if ! getent group "$group" &amp;amp;&amp;gt;/dev/null; then
        groupadd "$group"
        log_action "Group $group created."
    fi
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, we split the &lt;code&gt;groups&lt;/code&gt; string into an array using spaces as delimiters and log the groups that the user will be added to. Using &lt;code&gt;for group in "${group_array[@]}"; do&lt;/code&gt;, we are able to iterates over each group in the &lt;code&gt;group_array&lt;/code&gt; and trim any leading or trailing whitespace from the group name. Using &lt;code&gt;if ! getent group "$group" &amp;amp;&amp;gt;/dev/null; then&lt;/code&gt; to check if the group already exists else we create the group &lt;code&gt;groupadd "$group"&lt;/code&gt; and log that the group has been created &lt;code&gt;log_action "Group $group created."&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create User: Creates the user with a home directory and bash shell.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useradd -m -s /bin/bash -g "$user" "$user"
if [ $? -eq 0 ]; then
    log_action "User $user created with primary group: $user"
else
    log_action "Failed to create user $user."
    return
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Assign Groups: Adds the user to additional groups.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for group in "${group_array[@]}"; do
    usermod -aG "$group" "$user"
done
log_action "User $user added to groups: ${group_array[*]}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;for group in "${group_array[@]}"; do&lt;/code&gt; to iterate over each group in the &lt;code&gt;group_array&lt;/code&gt; then adds the user to the specified group (&lt;code&gt;-aG&lt;/code&gt; means append the user to the group). Next, log that the user has been added to the specified groups.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate and Store Password: Generates a random password and stores it securely.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;password=$(&amp;lt;/dev/urandom tr -dc A-Za-z0-9 | head -c 12)
echo "$user:$password" | chpasswd

echo "$user,$password" &amp;gt;&amp;gt; "/var/secure/user_passwords.txt"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We use &lt;code&gt;/dev/urandom&lt;/code&gt; to generate a random 12-character password and &lt;code&gt;tr&lt;/code&gt; to filter alphanumeric characters. Next, we set the password for the user using the &lt;code&gt;chpasswd&lt;/code&gt; command and append the username and password to the secure file &lt;code&gt;/var/secure/user_passwords.txt&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set Permissions: This part of the code is responsible for setting the appropriate permissions and ownership for the user's home directory.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Using &lt;code&gt;700&lt;/code&gt;, only the user has read, write, and execute permissions. &lt;code&gt;chown "$user:$user" "/home/$user"&lt;/code&gt; to set the owner and group of the home directory to the user.&lt;/p&gt;

&lt;p&gt;Here is the full combined code within the &lt;code&gt;create_user()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create_user() {
    local user="$1"
    local groups="$2"
    local password

    if id "$user" &amp;amp;&amp;gt;/dev/null; then
        log_action "User $user already exists."
        return
    fi

    groupadd "$user"

    IFS=' ' read -ra group_array &amp;lt;&amp;lt;&amp;lt; "$groups"
    log_action "User $user will be added to groups: ${group_array[*]}"
    for group in "${group_array[@]}"; do
        group=$(echo "$group" | xargs)
        if ! getent group "$group" &amp;amp;&amp;gt;/dev/null; then
            groupadd "$group"
            log_action "Group $group created."
        fi
    done

    useradd -m -s /bin/bash -g "$user" "$user"
    if [ $? -eq 0 ]; then
        log_action "User $user created with primary group: $user"
    else
        log_action "Failed to create user $user."
        return
    fi

    for group in "${group_array[@]}"; do
        usermod -aG "$group" "$user"
    done
    log_action "User $user added to groups: ${group_array[*]}"

    password=$(&amp;lt;/dev/urandom tr -dc A-Za-z0-9 | head -c 12)
    echo "$user:$password" | chpasswd
    echo "$user,$password" &amp;gt;&amp;gt; "/var/secure/user_passwords.txt"

    chmod 700 "/home/$user"
    chown "$user:$user" "/home/$user"

    log_action "Password for user $user set and stored securely."
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Main Execution Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [ $# -ne 1 ]; then
    echo "Usage: $0 &amp;lt;user_list_file&amp;gt;"
    exit 1
fi

filename="$1"

if [ ! -f "$filename" ]; then
    echo "Users list file $filename not found."
    exit 1
fi

while IFS=';' read -r user groups; do
    user=$(echo "$user" | xargs)
    groups=$(echo "$groups" | xargs | tr -d ' ')
    groups=$(echo "$groups" | tr ',' ' ')
    create_user "$user" "$groups"
done &amp;lt; "$filename"

echo "Creation of user is complete. Go ahead and check /var/log/user_management.log for detailed information."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we check if the user file is provided, then read the user list file and process each user entry, calling the &lt;code&gt;create_user()&lt;/code&gt; function for each line and passing the &lt;code&gt;$user&lt;/code&gt; and &lt;code&gt;$groups&lt;/code&gt; as arguments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's put everything together
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Create directory for user logs and passwords
mkdir -p /var/log /var/secure

# Create logs file and passwords file
touch /var/log/user_management.log
touch /var/secure/user_passwords.txt

# Make the password file secure for the file owner (read and write permissions for file owner only)
chmod 600 /var/secure/user_passwords.txt

# Create a function to record actions to log file
log_action() {
    echo "$(date) - $1" &amp;gt;&amp;gt; "/var/log/user_management.log"
}

create_user() {
    local user="$1"
    local groups="$2"
    local password

    # Check if user already exists by logging user information with id
    if id "$user" &amp;amp;&amp;gt;/dev/null; then
        log_action "User $user already exists."
        return
    fi

    # Create personal group for the user
    groupadd "$user"

    # Create additional groups if they do not exist
    IFS=' ' read -ra group_array &amp;lt;&amp;lt;&amp;lt; "$groups"
    log_action "User $user will be added to groups: ${group_array[*]}"
    for group in "${group_array[@]}"; do
        group=$(echo "$group" | xargs)  # Trim whitespace
        if ! getent group "$group" &amp;amp;&amp;gt;/dev/null; then
            groupadd "$group"
            log_action "Group $group created."
        fi
    done

    # Create user with home directory and shell, primary group set to the personal group
    useradd -m -s /bin/bash -g "$user" "$user"
    if [ $? -eq 0 ]; then
        log_action "User $user created with primary group: $user"
    else
        log_action "Failed to create user $user."
        return
    fi

    # Add the user to additional groups
    for group in "${group_array[@]}"; do
        usermod -aG "$group" "$user"
    done
    log_action "User $user added to groups: ${group_array[*]}"

    # Generate password and store it securely in a file
    password=$(&amp;lt;/dev/urandom tr -dc A-Za-z0-9 | head -c 12)
    echo "$user:$password" | chpasswd

    # Store user and password securely in a file
    echo "$user,$password" &amp;gt;&amp;gt; "/var/secure/user_passwords.txt"

    # Set permissions and ownership for user home directory
    chmod 700 "/home/$user"
    chown "$user:$user" "/home/$user"

    log_action "Password for user $user set and stored securely."
}

# Check if user list file is provided
if [ $# -ne 1 ]; then
    echo "Usage: $0 &amp;lt;user_list_file&amp;gt;"
    exit 1
fi

filename="$1"

if [ ! -f "$filename" ]; then
    echo "Users list file $filename not found."
    exit 1
fi

# Read user list file and create users
while IFS=';' read -r user groups; do
    user=$(echo "$user" | xargs)
    groups=$(echo "$groups" | xargs | tr -d ' ')

    # Replace commas with spaces for usermod group format
    groups=$(echo "$groups" | tr ',' ' ')
    create_user "$user" "$groups"
done &amp;lt; "$filename"

echo "Creation of users is complete. Go ahead and check /var/log/user_management.log for detailed information."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;To use this script, provide a user list file as an argument. Each line in the file should contain a username and a comma-separated list of groups (optional), separated by a semicolon. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the script, use this command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./script_name.sh user_list_file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are not a root user, use &lt;code&gt;sudo ./create_users.sh user_list_file.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jhs11zw8wihpi5dc9ak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jhs11zw8wihpi5dc9ak.png" alt="Image description" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This script provides a robust solution for automating user creation and management, ensuring secure handling of passwords and detailed logging of actions. It simplifies the process of setting up new user accounts while maintaining security and auditability.&lt;/p&gt;

&lt;p&gt;To learn more and kickstart your programming journey you can visit:&lt;br&gt;
&lt;a href="https://hng.tech/internship"&gt;https://hng.tech/internship&lt;/a&gt; or &lt;a href="https://hng.tech/premium"&gt;https://hng.tech/premium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to reach out with questions or suggestions for improvements. Happy automating!😁👌&lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>learning</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
