<?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>Forem: Praveen HA</title>
    <description>The latest articles on Forem by Praveen HA (@praveenha).</description>
    <link>https://forem.com/praveenha</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%2F1174309%2F1ffce073-b235-4975-a9ba-0476e21771dc.jpeg</url>
      <title>Forem: Praveen HA</title>
      <link>https://forem.com/praveenha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/praveenha"/>
    <language>en</language>
    <item>
      <title>Streamline Your AWS Asset Inventory with Automated Discovery and Reporting</title>
      <dc:creator>Praveen HA</dc:creator>
      <pubDate>Mon, 03 Jun 2024 07:23:41 +0000</pubDate>
      <link>https://forem.com/praveenha/streamline-your-aws-asset-inventory-with-automated-discovery-and-reporting-4c29</link>
      <guid>https://forem.com/praveenha/streamline-your-aws-asset-inventory-with-automated-discovery-and-reporting-4c29</guid>
      <description>&lt;p&gt;Managing resources across multiple AWS accounts and regions can be a daunting task, especially as your cloud infrastructure grows. To simplify this process, I have developed an AWS Inventory Discovery tool that scans all your AWS accounts across all regions and compiles a comprehensive, searchable HTML report. In this blog, I'll walk you through the features, benefits, and technical details of this solution.&lt;/p&gt;

&lt;p&gt;Introduction&lt;br&gt;
As organizations scale their use of AWS, keeping track of resources scattered across various accounts and regions becomes increasingly challenging. Manual inventory management is not only time-consuming but also prone to errors. This is where the AWS Inventory Discovery tool comes in.&lt;/p&gt;

&lt;p&gt;Features&lt;br&gt;
Comprehensive Scanning: The tool scans all your AWS accounts across all regions, ensuring no resource is left unaccounted for.&lt;br&gt;
Detailed Reporting: Generates a detailed HTML report that lists all discovered resources, including their ARNs and regions.&lt;br&gt;
Searchable Interface: The HTML report includes a search functionality, making it easy to find specific resources quickly.&lt;br&gt;
Visual Representation: Includes pie charts to provide a visual summary of your resources, helping you quickly understand the distribution of resources across various dimensions.&lt;br&gt;
User-Friendly: The generated report is easy to navigate, allowing users to drill down into resource details with just a few clicks.&lt;br&gt;
Benefits&lt;br&gt;
Improved Visibility: Gain a clear overview of all your AWS resources across accounts and regions.&lt;br&gt;
Time Savings: Automate the discovery process, freeing up time for your team to focus on more critical tasks.&lt;br&gt;
Error Reduction: Minimize the risk of overlooking resources or making mistakes in manual inventories.&lt;br&gt;
Enhanced Security: Quickly identify and manage resources to ensure compliance with security policies and best practices.&lt;br&gt;
How It Works&lt;br&gt;
Prerequisites&lt;br&gt;
Before you begin, ensure you have the following set up:&lt;/p&gt;

&lt;p&gt;AWS CLI: Install the AWS Command Line Interface (CLI).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install awscli
AWS Credentials: Export your AWS profile or access keys and secrets, and specify the region.
export AWS_PROFILE=your-aws-profile

export AWS_ACCESS_KEY_ID=your-access-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-access-key
export AWS_DEFAULT_REGION=your-default-region`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

AccountID="&amp;lt;YOUR_AWS_ACCOUNT&amp;gt;"
regions=$(aws ec2 describe-regions --query "Regions[].RegionName" --output text)
#regions=(ap-south-1 eu-north-1  eu-west-3  eu-west-1  ap-northeast-3  ap-northeast-2  ap-northeast-1  ca-central-1  sa-east-1   ap-southeast-1  ap-southeast-2  eu-central-1  us-east-1  us-east-2  us-west-1  us-west-2 )

# Initialize arrays to store data
declare -a summary_data=()
declare -a detailed_data=()

# Fetch resources from all regions
for region in $regions; do
    # Fetch resource ARNs and process them
    data=$(aws --region $region resourcegroupstaggingapi get-resources | jq -r '.ResourceTagMappingList[].ResourceARN' | \
    awk -v region=$region -F '[:/]' '
        {
            resourceType = "unknown"
            if ($3 == "s3") {
                resourceType = "bucket"
            } else if ($3 == "sns") {
                resourceType = "topic"
            } else {
                resourceType = $6  
            }

            # Construct a unique key for each service-resource pair
            pair = $3 ":" resourceType
            count[pair]++
        }
        END {
            for (pair in count) {
                split(pair, s, ":")  # Split the pair back into service and resource
                service = s[1]
                resource = s[2]
                print "{\"service\":\"" service "\", \"resource\":\"" resource "\", \"count\":" count[pair] "}"
            }
        }
    ')

    # Append to summary_data
    summary_data+=($data)

    # Fetch detailed resource information
    detailed_info=$(aws resourcegroupstaggingapi get-resources --region $region | jq -r --arg region $region '.ResourceTagMappingList[] | {Resource_Arn: .ResourceARN, Region: ($region // "Global"), Detailed_Service: (.ResourceARN | split(":")[2])}')

    # Append to detailed_data
    detailed_data+=($detailed_info)
done

# Process summary data
summary_json=$(printf "%s\n" "${summary_data[@]}" | jq -s 'group_by(.service, .resource) | map({service: .[0].service, resource: .[0].resource, count: map(.count) | add})')
total_resources=$(echo "$summary_json" | jq 'map(.count) | add')

# Process detailed data
detailed_json=$(printf "%s\n" "${detailed_data[@]}" | jq -s .)

# Generate HTML
cat &amp;lt;&amp;lt;EOF &amp;gt; index.html
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;AWS Resources&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f9;
            margin: 0;
            padding: 20px;
        }
        h1 {
            color: #333;
        }
        #searchBox, #searchBox2 {
            width: 100%;
            padding: 10px;
            margin-bottom: 20px;
            box-sizing: border-box;
            font-size: 16px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #4CAF50;
            color: white;
        }
        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        tr:hover {
            background-color: #ddd;
        }
        .total-count {
            font-size: 18px;
            margin: 20px 0;
        }
        #chartContainer {
            width: 50%;
            margin: 0 auto;
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;AWS Resources for Account ID: $AccountID&amp;lt;/h1&amp;gt;
    &amp;lt;div class="total-count"&amp;gt;Total Resources: $total_resources&amp;lt;/div&amp;gt;
    &amp;lt;input type="text" id="searchBox" onkeyup="filterTable()" placeholder="Search for services.."&amp;gt;
    &amp;lt;table id="resourcesTable"&amp;gt;
        &amp;lt;thead&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Service&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Resource&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Count&amp;lt;/th&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
        &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;

    &amp;lt;h1&amp;gt;Detailed AWS Resources&amp;lt;/h1&amp;gt;
    &amp;lt;input type="text" id="searchBox2" onkeyup="filterTable2()" placeholder="Search for resources.."&amp;gt;
    &amp;lt;table id="detailedResourcesTable"&amp;gt;
        &amp;lt;thead&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Resource ARN&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Region&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Detailed Service&amp;lt;/th&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
        &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;

    &amp;lt;div id="chartContainer"&amp;gt;
        &amp;lt;canvas id="resourceChart"&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;script src="https://cdn.jsdelivr.net/npm/chart.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        const data = $summary_json;
        const resourceData = $detailed_json;

        function loadTableData(data) {
            const tableBody = document.getElementById('resourcesTable').getElementsByTagName('tbody')[0];
            tableBody.innerHTML = "";

            data.forEach(item =&amp;gt; {
                let row = tableBody.insertRow();
                let cellService = row.insertCell(0);
                let cellResource = row.insertCell(1);
                let cellCount = row.insertCell(2);

                cellService.innerHTML = item.service;
                cellResource.innerHTML = item.resource;
                cellCount.innerHTML = item.count;
            });

            updateChart(data);
        }

        function loadDetailedTableData(resourceData) {
            const tableBody = document.getElementById('detailedResourcesTable').getElementsByTagName('tbody')[0];
            tableBody.innerHTML = "";

            resourceData.forEach(item =&amp;gt; {
                let row = tableBody.insertRow();
                let cellArn = row.insertCell(0);
                let cellRegion = row.insertCell(1);
                let cellService = row.insertCell(2);

                cellArn.innerHTML = item.Resource_Arn;
                cellRegion.innerHTML = item.Region;
                cellService.innerHTML = item.Detailed_Service;
            });
        }

        function filterTable() {
            const searchValue = document.getElementById('searchBox').value.toLowerCase();
            const filteredData = data.filter(item =&amp;gt; item.service &amp;amp;&amp;amp; item.service.toLowerCase().includes(searchValue));
            loadTableData(filteredData);
        }

        function filterTable2() {
            const searchValue = document.getElementById('searchBox2').value.toLowerCase();
            const filteredResourceData = resourceData.filter(item =&amp;gt; 
                item.Resource_Arn.toLowerCase().includes(searchValue) ||
                item.Region.toLowerCase().includes(searchValue) ||
                item.Detailed_Service.toLowerCase().includes(searchValue)
            );
            loadDetailedTableData(filteredResourceData);
        }

        function updateChart(data) {
            const services = data.reduce((acc, item) =&amp;gt; {
                acc[item.service] = (acc[item.service] || 0) + item.count;
                return acc;
            }, {});

            const labels = Object.keys(services);
            const counts = Object.values(services);

            const ctx = document.getElementById('resourceChart').getContext('2d');
            new Chart(ctx, {
                type: 'pie',
                data: {
                    labels: labels,
                    datasets: [{
                        data: counts,
                        backgroundColor: [
                            '#FF6384', '#36A2EB', '#FFCE56', '#4CAF50', '#FF9800', '#9C27B0', '#00BCD4'
                        ]
                    }]
                },
                options: {
                    responsive: true,
                    plugins: {
                        legend: {
                            position: 'top',
                        },
                        title: {
                            display: true,
                            text: 'Resource Distribution by Service'
                        }
                    }
                }
            });
        }

        document.addEventListener('DOMContentLoaded', () =&amp;gt; {
            loadTableData(data);
            loadDetailedTableData(resourceData);
        });
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
EOF

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

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>inventory</category>
      <category>report</category>
      <category>awschallenge</category>
    </item>
    <item>
      <title>AMI Age Calculator of Running AWS EC2 Instances and Generate CSV Report</title>
      <dc:creator>Praveen HA</dc:creator>
      <pubDate>Sun, 01 Oct 2023 10:32:51 +0000</pubDate>
      <link>https://forem.com/praveenha/ami-age-calculator-of-running-aws-ec2-instances-and-generate-csv-report-20gb</link>
      <guid>https://forem.com/praveenha/ami-age-calculator-of-running-aws-ec2-instances-and-generate-csv-report-20gb</guid>
      <description>&lt;p&gt;Instances running on outdated AMIs pose a security risk. Keeping our infrastructure secure requires us to regularly update these instances with the latest AMIs. Manually identifying and updating instances can be a time-consuming process, especially in large AWS accounts.&lt;/p&gt;

&lt;p&gt;How does the automation work?&lt;/p&gt;

&lt;p&gt;Our automation script leverages AWS CLI and the power of scripting to identify instances using older AMIs automatically. &lt;br&gt;
Account and Region Selection: We can specify the AWS account ID and region you want to scan when executing the Jenkins Job.&lt;/p&gt;

&lt;p&gt;AMI Age Assessment: The script checks every instance in the selected account and region and determines the age of the associated AMI based on its creation date.&lt;/p&gt;

&lt;p&gt;Automated Reporting: It generates a CSV report with details of instances using AMIs that are 4 months or older. This report includes the Account ID, Region, Instance ID, AMI ID, and AMI Age (Months).&lt;/p&gt;

&lt;p&gt;Actionable Insights: With this report, we can easily identify which instances require updates. This information can be used to patch instances with the latest AMIs, ensuring they remain secure and optimized.&lt;/p&gt;

&lt;p&gt;How can we use it?&lt;/p&gt;

&lt;p&gt;Running this automation is simple. we can execute the script filling the AWS account ID and region as parameters. script will do the rest providing us with a detailed report.&lt;/p&gt;

&lt;p&gt;What are the benefits?&lt;/p&gt;

&lt;p&gt;Enhanced Security: We can proactively identify and patch instances with older AMIs, reducing security vulnerabilities.&lt;/p&gt;

&lt;p&gt;Efficiency: Manual instance assessment is time-consuming, but this automation speeds up the process, allowing us to focus on other critical tasks.&lt;/p&gt;

&lt;p&gt;Consistency: By automating this process, we ensure that all instances are assessed uniformly and regularly.&lt;/p&gt;

&lt;p&gt;`#!/bin/bash&lt;/p&gt;

&lt;h1&gt;
  
  
  Initialize variables with default values
&lt;/h1&gt;

&lt;p&gt;ACCOUNTID=""&lt;br&gt;
REGION=""&lt;/p&gt;

&lt;p&gt;OUTPUT_CSV="$ACCOUNTID-$REGION-ami_age_report.csv"  # Define the CSV file name&lt;br&gt;
rm -rf $OUTPUT_CSV&lt;/p&gt;

&lt;h1&gt;
  
  
  Parse command line options
&lt;/h1&gt;

&lt;p&gt;while getopts "a🅱️" option; do&lt;br&gt;
  case $option in&lt;br&gt;
    a) ACCOUNTID=${OPTARG} ;;&lt;br&gt;
    b) REGION=${OPTARG} ;;&lt;br&gt;
    *) echo "usage: $0 [-a ACCOUNTID] [-b REGION]" &amp;gt;&amp;amp;2&lt;br&gt;
       exit 1 ;;&lt;br&gt;
  esac&lt;br&gt;
done&lt;/p&gt;

&lt;h1&gt;
  
  
  List instances and AMI IDs in the specified region
&lt;/h1&gt;

&lt;p&gt;instances_json=$(aws ec2 describe-instances --region "$REGION" --query 'Reservations[&lt;em&gt;].Instances[&lt;/em&gt;].[InstanceId,ImageId]' --output json) # For local&lt;/p&gt;

&lt;h1&gt;
  
  
  Get the current timestamp
&lt;/h1&gt;

&lt;p&gt;current_time=$(date -u +%s)&lt;/p&gt;

&lt;h1&gt;
  
  
  Initialize the CSV file with headers
&lt;/h1&gt;

&lt;p&gt;echo "AccountID,Region,InstanceID,AMIID,AMIAge (months)" &amp;gt; "$OUTPUT_CSV"&lt;/p&gt;

&lt;h1&gt;
  
  
  Iterate through instances and append to the CSV file
&lt;/h1&gt;

&lt;p&gt;for row in $(echo "$instances_json" | jq -r '.[][] | @base64'); do&lt;br&gt;
  _jq() {&lt;br&gt;
    echo "$row" | base64 --decode | jq -r "$1"&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;instance_id=$(_jq '.[0]')&lt;br&gt;
  ami_id=$(_jq '.[1]')&lt;/p&gt;

&lt;p&gt;# Get the creation date of the AMI in the specified region&lt;br&gt;
  ami_create_time=$(aws ec2 describe-images --region "$REGION" --image-ids "$ami_id" --query 'Images[0].CreationDate' --output text) # For local&lt;/p&gt;

&lt;p&gt;# Calculate the age in months based on the AMI creation time&lt;br&gt;
  ami_create_timestamp=$(date -u -d "$ami_create_time" +%s)&lt;br&gt;
  months_diff=$(( (current_time - ami_create_timestamp) / 60 / 60 / 24 / 30 ))&lt;/p&gt;

&lt;p&gt;# Check if the AMI is older than 4 months&lt;br&gt;
  if [ "$months_diff" -ge 4 ]; then&lt;br&gt;
    # Append to the CSV file&lt;br&gt;
    echo "$ACCOUNTID,$REGION,$instance_id,$ami_id,$months_diff" &amp;gt;&amp;gt; "$OUTPUT_CSV"&lt;br&gt;
  fi&lt;br&gt;
done&lt;/p&gt;

&lt;p&gt;echo "CSV report saved to $OUTPUT_CSV"&lt;br&gt;
cat $OUTPUT_CSV`&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazon</category>
      <category>devops</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
