<?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: wanjiru murira</title>
    <description>The latest articles on DEV Community by wanjiru murira (@wanjiru).</description>
    <link>https://dev.to/wanjiru</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%2F1186053%2Fbf3c6509-b197-43b8-b338-4a858d6989c7.png</url>
      <title>DEV Community: wanjiru murira</title>
      <link>https://dev.to/wanjiru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wanjiru"/>
    <language>en</language>
    <item>
      <title>Linux User Creation Bash Script</title>
      <dc:creator>wanjiru murira</dc:creator>
      <pubDate>Wed, 03 Jul 2024 14:19:04 +0000</pubDate>
      <link>https://dev.to/wanjiru/linux-user-creation-bash-script-5ff3</link>
      <guid>https://dev.to/wanjiru/linux-user-creation-bash-script-5ff3</guid>
      <description>&lt;p&gt;The purpose of this script is to read a text file containing an 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 and generate random passwords for the users.&lt;/p&gt;

&lt;p&gt;The first line in this script is called a shebang which tells the OS which interpreter to use and in this case, the script will be interpreted and executed using Bash shell.&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;Some instances within the script require elevated permissions. To ensure that they are no errors when the script is executed, it is best to ensure that one is a root user when executing the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ROOT_UID=0     
if [ "$UID" -ne "$ROOT_UID" ]; then
    echo"***** You must be the root user to run this script!*****"
    exit
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Functions&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. create_directories()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to first create two directories, &lt;em&gt;/var/log/user_management.log&lt;/em&gt; and &lt;em&gt;/var/secure/user_passwords.csv&lt;/em&gt;.The &lt;em&gt;/var/log/user_management.log&lt;/em&gt; will be used to log all events that will be happening in our script and can be reviewed for troubleshooting.The &lt;em&gt;/var/secure/user_passwords.csv&lt;/em&gt; will be used to store the created usernames and their passwords.This file is highly sensitive and should only be accessible to the owner.To achieve this, the permissions will be set to 700 on this file. &lt;em&gt;chmod&lt;/em&gt; is used to set the appropriate permissions and &lt;em&gt;chown&lt;/em&gt; is used to set ownership of the 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_dir="/var/log"
log_file="$log_dir/user_management.log"

secure_dir="/var/secure"
password_file="$secure_dir/user_passwords.csv"

# Function to create directories if they don't exist and assigning the necessary permission
create_directories() {
    # Create log directory if it doesn't exist
    if [ ! -d "$log_dir" ]; then
        sudo mkdir -p "$log_dir"
        sudo chmod 755 "$log_dir"
        sudo chown root:root "$log_dir"
    fi

    # Create secure directory if it doesn't exist
    if [ ! -d "$secure_dir" ]; then
        sudo mkdir -p "$secure_dir"
        sudo chmod 700 "$secure_dir"
        sudo chown root:root "$secure_dir"
    fi
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. log()&lt;/strong&gt;&lt;br&gt;
The log() function records script activities with timestamps (date) in &lt;em&gt;/var/log/user_management.log&lt;/em&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;log() {
    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
    echo "$timestamp $1" &amp;gt;&amp;gt; "$log_file"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. generate_password()&lt;/strong&gt;&lt;br&gt;
Before we can write a function to create a user, we first need to generate a random password for the newly created users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generate_password() {
    # Set the desired length of the password
    local password_length=12 
    # Generate the password
    local password="$(openssl rand -base64 12 | tr -d '/+' | head -c $password_length)"  
    # Output the generated password
    echo "$password"  
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;File Handling&lt;/strong&gt;&lt;br&gt;
The &lt;em&gt;process_user_file()&lt;/em&gt; ensures the file exists and is readable before proceeding to create users and manage groups accordingly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; process_user_file() {
    local filename="$1"
    # Check if the file exists and is readable
    if [ ! -f "$filename" ]; then
        echo "****Error: File '$filename' not found or is not readable.****"
    log  "Error: File '$filename' not found or is not readable."
        return 1
    fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the file is valid, a while loop will be used which will read the lines in the files and splits each line into &lt;em&gt;username&lt;/em&gt; and &lt;em&gt;groups&lt;/em&gt; , and then  calls the function &lt;em&gt;create_user&lt;/em&gt; with username and groups as arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; while IFS=';' read -r username groups; do
        if [[ ! -z "$username" &amp;amp;&amp;amp; ! -z "$groups" ]]; then
            create_user "$username" "$groups"
        else
            echo "****Invalid format in line: '$username;$groups'****" 
            log "Invalid format in line: '$username;$groups'"
        fi
    done &amp;lt; "$filename"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;User Management&lt;/strong&gt;&lt;br&gt;
Using the variables provided by the &lt;em&gt;process_user_file&lt;/em&gt; function, we can create a user and generate a random password for them using &lt;em&gt;generate_password&lt;/em&gt; function.&lt;br&gt;
This command creates a user with a home directory &lt;em&gt;/home/$"username&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo useradd -m -p "$(openssl passwd -6 "$password")" "$username"
# Making the user the owner of the directory
sudo chown "$username:$username" "/home/$username"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default when a user is created in most linux distribution,  a group with the same name as the users username is created this group is usually the primary group of the user.However, to be on the safe side we can check if the group already exists and if not, we can create the group and add the user to the group then make the group the primary group of the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if ! grep -q "^$username:" /etc/group; then
           sudo groupadd "$username"
            #Adding the user to the group which is the primary group
            sudo usermod -aG group_name "$username"
            #change the primary group of a user
            sudo usermod -g "$username" "$username"
        fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this last segment, we are going to add the users to the specified groups.&lt;br&gt;
The variable &lt;em&gt;groups&lt;/em&gt; is stored in an array known as &lt;em&gt;group_list&lt;/em&gt; where we user the for function to iterate over each element in the &lt;em&gt;group_list&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Function to add users to specified groups
add_to_groups() {
    local username="$1"
    local groups="$2"
    IFS=',' read -ra group_list &amp;lt;&amp;lt;&amp;lt; "$groups"
    for group in "${group_list[@]}"; do
        if grep -q "^$group:" /etc/group; then
            sudo usermod -aG "$group" "$username"
            log "User '$username' added to group '$group' successfully."
            echo "****User '$username' added to group '$group' successfully.****"
        else
            log "Group '$group' does not exist. Skipping addition of user '$username'."
            echo "****Group '$group' does not exist. Skipping addition of user '$username'.****"
        fi
    done
}

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

&lt;/div&gt;



&lt;p&gt;To make the script excutable, you need to use the chmod command in combination with the +x option&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x path/directory/script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute the script, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./path/directory/script.sh text_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can view the full script at &lt;a href="https://github.com/wanjirumurira/Linux-User-Creation-Bash-Script.git"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This script was a task which was to be completed during my HNG internship. For those interested in practical learning and real-life scenarios, check out the &lt;a href="https://hng.tech/internship"&gt;HNG internship program&lt;/a&gt;. It's a great opportunity to gain hands-on experience! To maximize your internship experience, consider upgrading to their premium package at &lt;a href="https://hng.tech/premium"&gt;HNG Premium&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Cloud Resume Challenge</title>
      <dc:creator>wanjiru murira</dc:creator>
      <pubDate>Tue, 24 Oct 2023 12:50:41 +0000</pubDate>
      <link>https://dev.to/wanjiru/the-cloud-resume-challenge-5720</link>
      <guid>https://dev.to/wanjiru/the-cloud-resume-challenge-5720</guid>
      <description>&lt;p&gt;The Cloud Resume Challenge by &lt;a href="https://cloudresumechallenge.dev/docs/the-challenge/aws/"&gt;Forrest Brazeal&lt;/a&gt; is for anyone who wants to get hand-on practice on the cloud.One of the key motivations behind taking up this challenge was my desire to gain hands-on experience with AWS cloud technologies. While I had a theoretical understanding of most AWS services, I knew that real-world experience was invaluable.&lt;/p&gt;

&lt;p&gt;This challenge involves hosting a static website in an S3 bucket via Amazon CloudFront distribution. The static website is then connected to a Lambda function through AWS API Gateway. Whenever a user accesses the static website hosted on S3, the Lambda function is triggered, and it writes the count of website visits to a DynamoDB table. This project aims to track and record user visits to the website for analytics and monitoring purposes.You can view the challenge &lt;a href="https://d7wkc8k0b35t4.cloudfront.net/"&gt;here&lt;/a&gt;. The source code to this challenge can be found on &lt;a href="https://github.com/wanjirumurira/AWS_CLOUD_RESUME.git"&gt;git&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've documented how I went about the challange and some of the issues I faced below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FRONT-END PART OF WEBSITE&lt;/strong&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%2Fx0hwx3tlgnu73pcbzd2t.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%2Fx0hwx3tlgnu73pcbzd2t.png" alt="Image description" width="523" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hosting the website on the s3 bucket was probably the easiest part of this challenge. I did spend quite some time in designing the layout of the website as  Frontend is not my strong suite.I tried so many layouts and this was taking longer  than expected. I finally decided to settle with Tomas Hrubovcak design, which was one of the cleanest and minimal layouts I have seen so far of The Cloud Resume Challenge.&lt;/p&gt;

&lt;p&gt;I did have to learn about Amazon CloudFront cache invalidation since I didn’t understand why any updates I made on my s3 bucket didn’t reflect immediately. This was happening because CloudFront was still serving the content it had cached in the edge locations which takes some time before it expires. Invalidation allows you to force CloudFront to refresh its cache and retrieve the latest version of your content from your origin server. Read more about invalidation &lt;a href="https://saturncloud.io/blog/what-is-amazon-cloudfront-cache-invalidation-and-how-to-use-it-after-aws-s3-sync-cli-to-update-s3-bucket-contents/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you will make a few changes to the content of your s3 bucket, I decided to put into practice CI/CD (Continuous Integration / Continuous Deployment) to manage any changes to my code.They are several tools you can use for this such as Jenkins, GitHub Actions etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BACK-END PART OF WEBSITE&lt;/strong&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%2Fflz4lfetqvbipsj2hkm7.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%2Fflz4lfetqvbipsj2hkm7.png" alt="Image description" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend part on the website took the longest to complete but I thoroughly enjoyed this. While at the start I provisioned all my resources manually which greatly helped me understand AWS services better, I did eventually opt to use Terraform as the IaC. I deliberately choose to use Terraform instead of AWS CloudFormation because it’s one of the most preferred IaC tool by developers and I wanted to familiarize myself with it.&lt;/p&gt;

&lt;p&gt;The backend part of this website includes an API Gateway, DynamoDB Table and Lambda Function.&lt;br&gt;
The lambda function is used to increase the count of the number of users who have visited the website and then updates this count in a DynamoDB table. You need to attach a IAM role to the Lambda function, which allows it to write to the DynamoDB table.&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%2Fxtla96hc358922rc57b9.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%2Fxtla96hc358922rc57b9.png" alt="Image description" width="493" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Lambda function is triggered by a RESTful APIs to execute the code. &lt;br&gt;
The code below is just a snipset of the code I used to deploy my lambda function using terraform. &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%2Fgwql4funpvccap3wncb5.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%2Fgwql4funpvccap3wncb5.png" alt="Image description" width="562" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, whenever I tried to run the API Gateway, I kept on getting various errors.Some of the errors I got were CORS errors and how to go about an API with lambda proxy integration enabled.&lt;/p&gt;

&lt;p&gt;For the CORS errors, I enabled CORS on my API Gateway and also added the correct headers to my lambda function.&lt;br&gt;
It took some time for me to realize that when provisioning an API Gateway using terraform, lambda proxy integration is enabled automatically. This means that API gateway doesn’t transform the incoming request. The lambda function should send the response and status code in the correct format as shown below (which was the reason I kept on getting errors since my previous lambda response format was different)&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%2Fzh05d3dk5s4hdhxmorjx.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%2Fzh05d3dk5s4hdhxmorjx.png" alt="Image description" width="753" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I was able to navigate the above errors, my website was up and running.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iac</category>
      <category>lambda</category>
      <category>apigateway</category>
    </item>
  </channel>
</rss>
