<?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: harsh patel</title>
    <description>The latest articles on Forem by harsh patel (@harshhp).</description>
    <link>https://forem.com/harshhp</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%2F2865274%2F146f3b5c-7836-4bcf-bba4-981e817a900c.png</url>
      <title>Forem: harsh patel</title>
      <link>https://forem.com/harshhp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/harshhp"/>
    <language>en</language>
    <item>
      <title>When to Choose Cassandra in System Design</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Wed, 04 Feb 2026 20:35:10 +0000</pubDate>
      <link>https://forem.com/harshhp/when-to-choose-cassandra-in-system-design-2b9m</link>
      <guid>https://forem.com/harshhp/when-to-choose-cassandra-in-system-design-2b9m</guid>
      <description>&lt;h2&gt;
  
  
  How It Achieves Massive Write Scalability (and What You Trade Off)
&lt;/h2&gt;

&lt;p&gt;Designing large-scale systems often comes down to one uncomfortable truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You cannot optimize reads, writes, consistency, and simplicity all at once.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When your system is &lt;strong&gt;write-heavy&lt;/strong&gt;—logs, metrics, events, feeds, IoT data—traditional databases often become the bottleneck. This is where Apache Cassandra becomes a compelling choice.&lt;/p&gt;

&lt;p&gt;This article explains:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;When Cassandra is the right database&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why it outperforms traditional databases for writes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How its internal storage model enables that performance&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  When Should You Choose Cassandra?
&lt;/h2&gt;

&lt;p&gt;Cassandra is a strong choice when &lt;strong&gt;writes dominate your workload&lt;/strong&gt; and availability matters more than strict consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose Cassandra if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You have &lt;strong&gt;very high write throughput&lt;/strong&gt; (10k–100k+ writes/sec)&lt;/li&gt;
&lt;li&gt;Data arrives continuously (events, logs, metrics, tracking)&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;horizontal scaling&lt;/strong&gt; by adding nodes&lt;/li&gt;
&lt;li&gt;Downtime is unacceptable (multi-node, multi-DC availability)&lt;/li&gt;
&lt;li&gt;Your queries are predictable and can be modeled without JOINs&lt;/li&gt;
&lt;li&gt;Eventual or tunable consistency is acceptable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Avoid Cassandra if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need complex ad-hoc queries or JOINs&lt;/li&gt;
&lt;li&gt;You rely heavily on transactions across multiple rows/tables&lt;/li&gt;
&lt;li&gt;Reads must be extremely fast and strongly consistent&lt;/li&gt;
&lt;li&gt;Your dataset is small and doesn’t need horizontal scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cassandra is not a “general-purpose” database—it’s a &lt;strong&gt;specialized write-scaling machine&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Traditional Databases Struggle with Writes
&lt;/h2&gt;

&lt;p&gt;Most relational databases (PostgreSQL, MySQL) use &lt;strong&gt;B-tree–based storage engines&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How writes work in traditional databases:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Data is updated &lt;strong&gt;in place&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Indexes must be updated immediately&lt;/li&gt;
&lt;li&gt;Writes trigger &lt;strong&gt;random disk I/O&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Locks, WAL flushes, and index maintenance add overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works well for mixed workloads, but at scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random disk seeks become expensive&lt;/li&gt;
&lt;li&gt;Index-heavy schemas slow down writes&lt;/li&gt;
&lt;li&gt;Vertical scaling hits hardware limits&lt;/li&gt;
&lt;li&gt;Sharding adds operational complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: &lt;strong&gt;traditional databases optimize for reads first&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Cassandra Is Faster for Writes
&lt;/h2&gt;

&lt;p&gt;Cassandra flips the design priorities.&lt;/p&gt;

&lt;p&gt;Instead of updating data in place, Cassandra uses a &lt;strong&gt;Log-Structured Merge Tree (LSM Tree)&lt;/strong&gt;, which turns almost every write into a &lt;strong&gt;sequential append&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key design choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never modify data in place. Always append.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sequential disk writes are orders of magnitude faster than random writes, which is why Cassandra can sustain massive write throughput on modest hardware.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cassandra’s Internal Storage Model (LSM Tree)
&lt;/h2&gt;

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

&lt;p&gt;Cassandra’s storage engine revolves around three core components.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Commit Log (Durability First)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every write is &lt;strong&gt;appended&lt;/strong&gt; to the commit log&lt;/li&gt;
&lt;li&gt;Acts as a write-ahead log&lt;/li&gt;
&lt;li&gt;Ensures data isn’t lost if a node crashes&lt;/li&gt;
&lt;li&gt;Sequential disk I/O → very fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This step guarantees durability without slowing down the write path.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Memtable (In-Memory Writes)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Writes are stored in an &lt;strong&gt;in-memory, sorted structure&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sorted by primary key&lt;/li&gt;
&lt;li&gt;Multiple updates to the same key are merged in memory&lt;/li&gt;
&lt;li&gt;No disk I/O for each write&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This absorbs write bursts efficiently.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. SSTable (Immutable Disk Storage)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;When the Memtable fills up, it is flushed to disk as an &lt;strong&gt;SSTable&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;SSTables are:

&lt;ul&gt;
&lt;li&gt;Immutable&lt;/li&gt;
&lt;li&gt;Sorted by primary key&lt;/li&gt;
&lt;li&gt;Written sequentially&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Because SSTables are never updated, Cassandra avoids random disk writes entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Cassandra Handles Updates and Deletes
&lt;/h2&gt;

&lt;p&gt;Cassandra treats &lt;strong&gt;every change as a new write&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates → new version with a higher timestamp&lt;/li&gt;
&lt;li&gt;Deletes → written as &lt;strong&gt;tombstones&lt;/strong&gt; (delete markers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The “current state” of a row is determined by &lt;strong&gt;timestamps&lt;/strong&gt;, not by overwriting data.&lt;/p&gt;

&lt;p&gt;This design enables fast writes but shifts cleanup work to the background.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reading Data: The Trade-Off
&lt;/h2&gt;

&lt;p&gt;Reads are more complex than writes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the &lt;strong&gt;Memtable&lt;/strong&gt; (latest data)&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Bloom filters&lt;/strong&gt; to identify relevant SSTables&lt;/li&gt;
&lt;li&gt;Read SSTables from &lt;strong&gt;newest to oldest&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Merge results to find the latest version&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bloom filters help skip unnecessary disk reads, but reads are still slower than in well-indexed relational databases.&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;intentional trade-off&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compaction: Paying the Cost Later
&lt;/h2&gt;

&lt;p&gt;To prevent unlimited growth of SSTables and tombstones, Cassandra runs &lt;strong&gt;compaction&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Merges multiple SSTables into fewer ones&lt;/li&gt;
&lt;li&gt;Resolves multiple versions of rows&lt;/li&gt;
&lt;li&gt;Removes deleted and expired data&lt;/li&gt;
&lt;li&gt;Improves read performance over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cassandra makes writes cheap &lt;strong&gt;now&lt;/strong&gt;, and pays the cost &lt;strong&gt;later&lt;/strong&gt; via compaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Design Scales So Well
&lt;/h2&gt;

&lt;p&gt;Putting it all together:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traditional DB&lt;/th&gt;
&lt;th&gt;Cassandra&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;In-place updates&lt;/td&gt;
&lt;td&gt;Append-only writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random disk I/O&lt;/td&gt;
&lt;td&gt;Sequential disk I/O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write blocks reads&lt;/td&gt;
&lt;td&gt;Writes isolated from reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard to shard&lt;/td&gt;
&lt;td&gt;Built-in partitioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vertical scaling&lt;/td&gt;
&lt;td&gt;Horizontal scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cassandra scales because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writes are fast and predictable&lt;/li&gt;
&lt;li&gt;Nodes are independent (shared-nothing)&lt;/li&gt;
&lt;li&gt;Adding nodes increases total throughput&lt;/li&gt;
&lt;li&gt;Failures don’t stop the system&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Cassandra is not faster because it’s “better”—it’s faster because it &lt;strong&gt;chooses a different set of trade-offs&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your system is write-heavy, highly available, and horizontally scalable, Cassandra’s LSM-based storage model can outperform traditional databases by an order of magnitude.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But if reads, transactions, or flexibility matter more—choose something else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good system design is not about the best database.&lt;br&gt;&lt;br&gt;
It’s about the right database for the workload.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>database</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Finding Vulnerabilities on EC2 Instances Using AWS Inspector</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Mon, 27 Oct 2025 02:31:48 +0000</pubDate>
      <link>https://forem.com/harshhp/finding-vulnerabilities-on-ec2-instances-using-aws-inspector-1940</link>
      <guid>https://forem.com/harshhp/finding-vulnerabilities-on-ec2-instances-using-aws-inspector-1940</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Amazon EC2 is one of the most widely used services on AWS for deploying applications in the cloud. However, as applications grow, so does the responsibility of keeping them secure.&lt;br&gt;&lt;br&gt;
That’s where &lt;strong&gt;Amazon Inspector&lt;/strong&gt; comes in — an automated security assessment service that identifies vulnerabilities and deviations from best practices. It helps developers and security teams strengthen their application’s security posture before issues turn into real threats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

&lt;p&gt;Here’s the high-level architecture of the setup we’ll build in this lab:&lt;/p&gt;

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

&lt;p&gt;In this hands-on lab, we’ll use &lt;strong&gt;Amazon Inspector&lt;/strong&gt; to detect and fix vulnerabilities in an EC2 instance. You’ll:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch an EC2 instance with a custom IAM role and security group
&lt;/li&gt;
&lt;li&gt;Install an outdated version of Node.js (to simulate a vulnerability)
&lt;/li&gt;
&lt;li&gt;Enable Amazon Inspector and analyze its findings
&lt;/li&gt;
&lt;li&gt;Apply remediations by closing an open port and updating Node.js
&lt;/li&gt;
&lt;li&gt;Re-run Inspector to validate the fixes
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end, you’ll have practical experience identifying and resolving vulnerabilities on AWS — an essential skill for cloud engineers, developers, and anyone serious about cloud security.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon Inspector&lt;/strong&gt; is a built-in AWS security assessment service that automatically scans workloads such as &lt;strong&gt;EC2 instances, container images, and Lambda functions&lt;/strong&gt; for known vulnerabilities and network exposures.&lt;br&gt;&lt;br&gt;
It continuously monitors your environment and provides actionable findings categorized by severity — allowing you to prioritize and mitigate risks efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a Role and a Security Group
&lt;/h2&gt;

&lt;p&gt;Before launching an EC2 instance, we’ll create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;IAM role&lt;/strong&gt; for SSM access, allowing the instance to communicate with AWS Systems Manager.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;security group&lt;/strong&gt; with an intentionally open port (port 21) to simulate a network vulnerability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create the IAM Role
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Console, search for &lt;strong&gt;IAM&lt;/strong&gt; and open the service.
&lt;/li&gt;
&lt;li&gt;From the sidebar, select &lt;strong&gt;Roles → Create role&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Trusted entity type&lt;/strong&gt;, choose &lt;strong&gt;AWS service&lt;/strong&gt;, and under &lt;strong&gt;Use case&lt;/strong&gt;, select &lt;strong&gt;EC2&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Attach the policy &lt;strong&gt;AmazonSSMManagedInstanceCore&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Name the role &lt;strong&gt;&lt;code&gt;ec2-ssm-role&lt;/code&gt;&lt;/strong&gt;, scroll down, and click &lt;strong&gt;Create role&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create the Security Group
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Console, search for &lt;strong&gt;Security groups&lt;/strong&gt; under the EC2 service.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Name it &lt;strong&gt;&lt;code&gt;ec2-sg&lt;/code&gt;&lt;/strong&gt; and add a short description.
&lt;/li&gt;
&lt;li&gt;Leave the default VPC selected.
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Inbound rules&lt;/strong&gt;, add:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; SSH — &lt;strong&gt;Port:&lt;/strong&gt; 22 — &lt;strong&gt;Source:&lt;/strong&gt; Anywhere (IPv4)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Custom TCP — &lt;strong&gt;Port:&lt;/strong&gt; 21 — &lt;strong&gt;Source:&lt;/strong&gt; Anywhere (IPv4)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Port 21 is used for FTP, which transmits credentials and data unencrypted. Leaving it open to “Anywhere” exposes your instance to significant security risks. Amazon Inspector will flag this later.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Create an EC2 Instance
&lt;/h2&gt;

&lt;p&gt;We’ll now create an EC2 instance, attach the role and security group, and install an outdated version of Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to Launch the Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Console, open &lt;strong&gt;EC2 → Instances → Launch instances&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name and tags:&lt;/strong&gt; Set the instance name as &lt;code&gt;ec2_inspect&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AMI:&lt;/strong&gt; Choose &lt;strong&gt;Amazon Linux 2023 (kernel 6.1)&lt;/strong&gt; (64-bit x86).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance type:&lt;/strong&gt; Select &lt;strong&gt;t2.micro&lt;/strong&gt; (Free Tier).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key pair:&lt;/strong&gt; Choose &lt;strong&gt;Proceed without a key pair&lt;/strong&gt; (for this lab).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Existing security group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;&lt;code&gt;ec2-sg&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; Keep the default &lt;strong&gt;8 GiB gp3&lt;/strong&gt; volume.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced details:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Under &lt;strong&gt;IAM instance profile&lt;/strong&gt;, choose &lt;strong&gt;&lt;code&gt;ec2-ssm-role&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instance&lt;/strong&gt;, then &lt;strong&gt;View all instances&lt;/strong&gt; and wait until the instance state is &lt;strong&gt;Running&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Install Node.js 14.x (Vulnerable Version)
&lt;/h3&gt;

&lt;p&gt;Once the instance is running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select your instance → click &lt;strong&gt;Connect → Connect&lt;/strong&gt; again.
&lt;/li&gt;
&lt;li&gt;Run the following commands:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -O https://rpm.nodesource.com/pub_14.x/el/7/x86_64/nodejs-14.21.3-1nodesource.x86_64.rpm
sudo yum install -y nodejs-14.21.3-1nodesource.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This installs &lt;strong&gt;Node.js v14.x&lt;/strong&gt;, which is outdated and contains known vulnerabilities — perfect for testing Amazon Inspector.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You now have a running EC2 instance with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An open port (21)
&lt;/li&gt;
&lt;li&gt;An outdated Node.js installation
Both of which Amazon Inspector should detect as vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Enable Amazon Inspector
&lt;/h2&gt;

&lt;p&gt;Amazon Inspector continuously scans EC2 instances, ECR repositories, and Lambda functions for vulnerabilities. Let’s enable it for our environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to Enable Inspector
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Search for &lt;strong&gt;Amazon Inspector&lt;/strong&gt; in the AWS Console and open it.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Get Started → Activate Inspector&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;This automatically creates a &lt;strong&gt;Service-Linked Role&lt;/strong&gt; with permissions to scan AWS resources.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Wait &lt;strong&gt;3–5 minutes&lt;/strong&gt; for activation.
&lt;/li&gt;
&lt;li&gt;On the left sidebar, click &lt;strong&gt;Account management&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;You’ll see scanning statuses for &lt;strong&gt;EC2&lt;/strong&gt;, &lt;strong&gt;ECR&lt;/strong&gt;, and &lt;strong&gt;Lambda&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Since we only need EC2 scanning, deactivate the others:

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Actions → Amazon ECR scanning → Deactivate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Actions → AWS Lambda scanning → Deactivate&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Viewing the Findings
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the left menu, click &lt;strong&gt;Instances&lt;/strong&gt; — Amazon Inspector should automatically detect your EC2 instance (&lt;code&gt;ec2_inspect&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Instance ID&lt;/strong&gt; to open its findings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll see results categorized by severity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Critical&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples from this lab:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High:&lt;/strong&gt; “Port 21 is reachable from an Internet Gateway - TCP”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critical:&lt;/strong&gt; “CVE-2023-26136 - tough-cookie” (from outdated Node.js 14.x)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each finding includes a &lt;strong&gt;Remediation&lt;/strong&gt; section — Inspector recommends removing open ports or updating vulnerable packages.&lt;br&gt;&lt;br&gt;
We’ll follow those recommendations next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Viewing Amazon Inspector Findings
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Detailed Finding Analysis
&lt;/h2&gt;

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

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




&lt;h2&gt;
  
  
  Apply Remediation
&lt;/h2&gt;

&lt;p&gt;Now, let’s fix the vulnerabilities Amazon Inspector identified.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delete the Open Port (21)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;EC2 → Security Groups&lt;/strong&gt; and open &lt;strong&gt;&lt;code&gt;ec2-sg&lt;/code&gt;&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Under the &lt;strong&gt;Inbound rules&lt;/strong&gt; tab, click &lt;strong&gt;Edit inbound rules&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Delete&lt;/strong&gt; beside the rule for &lt;strong&gt;Port 21&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save rules&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This immediately removes external FTP access and mitigates the “Network Reachability” issue.&lt;/p&gt;




&lt;h3&gt;
  
  
  Update Node.js to the Latest Version
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Return to the &lt;strong&gt;EC2 → Instances → ec2_inspect&lt;/strong&gt; dashboard.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect → Connect&lt;/strong&gt; again.
&lt;/li&gt;
&lt;li&gt;Run the following commands:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rm -rf /etc/yum.repos.d/nodesource*
sudo yum remove -y nodejs
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
. ~/.nvm/nvm.sh
nvm install 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify the version:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now see &lt;strong&gt;v16.x&lt;/strong&gt;, which resolves the vulnerability found earlier.&lt;/p&gt;




&lt;h3&gt;
  
  
  Refresh Amazon Inspector
&lt;/h3&gt;

&lt;p&gt;Inspector may take time to detect the changes, but you can speed this up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;Amazon Inspector&lt;/strong&gt; dashboard.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;General settings → Deactivate Inspector&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Type &lt;code&gt;deactivate&lt;/code&gt; in the confirmation box.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After 5–7 minutes, refresh and &lt;strong&gt;Activate&lt;/strong&gt; it again.
&lt;/li&gt;
&lt;li&gt;Once reactivated, go to &lt;strong&gt;Instances → [your EC2 instance ID]&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll see that the vulnerabilities &lt;strong&gt;“Port 21 is reachable”&lt;/strong&gt; and &lt;strong&gt;“CVE-2023-26136 - tough-cookie”&lt;/strong&gt; are no longer present.&lt;br&gt;&lt;br&gt;
Your EC2 instance is now significantly more secure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Validation and Results
&lt;/h2&gt;

&lt;p&gt;After re-running Amazon Inspector:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;High&lt;/strong&gt; and &lt;strong&gt;Critical&lt;/strong&gt; findings have disappeared.
&lt;/li&gt;
&lt;li&gt;The security posture of your instance has improved.
&lt;/li&gt;
&lt;li&gt;Any remaining minor findings can be further remediated as needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This confirms that Amazon Inspector successfully detected and verified the fixes — exactly how it functions in real-world AWS environments.&lt;/p&gt;




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

&lt;p&gt;Through this lab, we explored how &lt;strong&gt;Amazon Inspector&lt;/strong&gt; strengthens cloud security by automatically detecting vulnerabilities in EC2 instances and providing actionable remediation guidance.&lt;/p&gt;

&lt;p&gt;We learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create IAM roles and security groups safely
&lt;/li&gt;
&lt;li&gt;Simulate vulnerabilities using outdated software and open ports
&lt;/li&gt;
&lt;li&gt;Use Amazon Inspector to detect risks
&lt;/li&gt;
&lt;li&gt;Apply fixes and validate improvements
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key takeaway:&lt;/strong&gt; Cloud security isn’t a one-time setup — it’s a continuous process.&lt;br&gt;&lt;br&gt;
By integrating Amazon Inspector into your workflows, you can proactively identify and patch vulnerabilities before they escalate.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;Thanks for reading!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you found this guide useful, drop a ❤️ or share your experience with &lt;strong&gt;Amazon Inspector&lt;/strong&gt; in the comments below.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Mastering AWS Key Management Service (KMS): A Practical Guide to Data Encryption</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Sat, 25 Oct 2025 19:50:01 +0000</pubDate>
      <link>https://forem.com/harshhp/mastering-aws-key-management-service-kms-a-practical-guide-to-data-encryption-km3</link>
      <guid>https://forem.com/harshhp/mastering-aws-key-management-service-kms-a-practical-guide-to-data-encryption-km3</guid>
      <description>&lt;h1&gt;
  
  
  Getting Started with AWS Key Management Service (KMS) — Python Edition
&lt;/h1&gt;

&lt;p&gt;We live in a digital world where protecting sensitive information is more critical than ever. One of the most effective ways to safeguard data is &lt;strong&gt;encryption&lt;/strong&gt;. But encryption is only as strong as your &lt;strong&gt;key management&lt;/strong&gt;. That’s where &lt;strong&gt;AWS Key Management Service (KMS)&lt;/strong&gt; shines.&lt;/p&gt;

&lt;p&gt;In this hands-on lab, you’ll create and use a &lt;strong&gt;customer-managed KMS key&lt;/strong&gt;, generate &lt;strong&gt;data keys&lt;/strong&gt;, encrypt/decrypt data in Python, and integrate KMS with &lt;strong&gt;DynamoDB&lt;/strong&gt;. You’ll also see how &lt;strong&gt;key policy&lt;/strong&gt; adds a security layer beyond IAM permissions.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You’ll Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;strong&gt;customer-managed KMS key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Generate &lt;strong&gt;data keys&lt;/strong&gt; with KMS (Python + boto3)&lt;/li&gt;
&lt;li&gt;Encrypt &amp;amp; decrypt data locally with the &lt;strong&gt;plaintext data key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Integrate KMS with &lt;strong&gt;DynamoDB (SSE-KMS)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;key policy&lt;/strong&gt; to control access beyond IAM&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AWS KMS&lt;/strong&gt; is a fully managed service to create and manage cryptographic keys for encrypting data inside and outside AWS. It integrates with services like &lt;strong&gt;S3, EBS, RDS, and DynamoDB&lt;/strong&gt;, helping you meet compliance while keeping data secure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lab Setup (Pre-built Resources)
&lt;/h2&gt;

&lt;p&gt;This lab includes a pre-created &lt;strong&gt;IAM user&lt;/strong&gt; that can list DynamoDB tables and read from a specific table &lt;code&gt;Books&lt;/code&gt;. We’ll use this user later to show how KMS encryption prevents access until the key policy allows it.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  KMS Key Basics
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;KMS key&lt;/strong&gt; (a.k.a. CMK) is the root key used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate &amp;amp; encrypt &lt;strong&gt;data keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Encrypt small payloads (≤ 4 KB)&lt;/li&gt;
&lt;li&gt;Integrate with AWS services’ encryption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Types of keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS-managed keys&lt;/strong&gt;: Created/managed by AWS (limited control)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer-managed keys&lt;/strong&gt;: Created/managed by you (full control, symmetric or asymmetric)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll use a &lt;strong&gt;symmetric customer-managed key&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a Customer-Managed Key
&lt;/h2&gt;

&lt;p&gt;AWS Console → &lt;strong&gt;KMS&lt;/strong&gt; → &lt;strong&gt;Customer managed keys&lt;/strong&gt; → &lt;strong&gt;Create key&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key type:&lt;/strong&gt; Symmetric
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key usage:&lt;/strong&gt; Encrypt and decrypt
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key material origin:&lt;/strong&gt; KMS (recommended)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regionality:&lt;/strong&gt; Single-region
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alias:&lt;/strong&gt; &lt;code&gt;myKey&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Grant &lt;strong&gt;admin&lt;/strong&gt; and &lt;strong&gt;usage&lt;/strong&gt; permissions to your main user (e.g., &lt;code&gt;ed-user&lt;/code&gt;)
Finish the wizard.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Generate a Data Key (Python)
&lt;/h2&gt;

&lt;p&gt;KMS keys don’t encrypt large blobs directly; instead, they &lt;strong&gt;generate data keys&lt;/strong&gt;. You use the &lt;strong&gt;plaintext data key&lt;/strong&gt; locally for encryption, discard it, and store only the &lt;strong&gt;encrypted data key&lt;/strong&gt; (which you can decrypt later via KMS).&lt;/p&gt;

&lt;h3&gt;
  
  
  Prereqs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install boto3 cryptography
aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetch your key ARN
&lt;/h3&gt;

&lt;p&gt;Console → &lt;strong&gt;KMS → Customer managed keys → myKey&lt;/strong&gt; → copy &lt;strong&gt;ARN&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate the key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;

&lt;span class="n"&gt;kms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cmk_arn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-kms-key-arn&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_data_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cmk_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KeySpec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AES_256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;plaintext_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plaintext&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;encrypted_data_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plaintext Data Key (hex):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Encrypted Data Key (hex):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Encrypt Data Using the Data Key (Python)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives.ciphers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Cipher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modes&lt;/span&gt;

&lt;span class="n"&gt;plaintext_key_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-plaintext-data-key-hex&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unhexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext_key_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, this is my sensitive data.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;padder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PKCS7&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;padder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;padder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;modes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ECB&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;encryptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encryptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encryptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;encryptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;encrypted_b64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Encrypted Data (base64):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encrypted_b64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Decrypt the Data Key (Python)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;

&lt;span class="n"&gt;kms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;encrypted_data_key_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-encrypted-data-key-hex&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;encrypted_data_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unhexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data_key_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;encrypted_data_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;recovered_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plaintext&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Recovered Plaintext Key (hex):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recovered_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Decrypt the Data (Python)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives.ciphers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Cipher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modes&lt;/span&gt;

&lt;span class="n"&gt;plaintext_key_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-plaintext-data-key-hex&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unhexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext_key_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;encrypted_b64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-encrypted-data-base64&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_b64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;modes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ECB&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;decryptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decryptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;padded_plain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decryptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;decryptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;unpadder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PKCS7&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;unpadder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;plain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unpadder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padded_plain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;unpadder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decrypted Data:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Integrate KMS with DynamoDB (SSE-KMS)
&lt;/h2&gt;

&lt;p&gt;Now we’ll integrate KMS with &lt;strong&gt;DynamoDB&lt;/strong&gt; to encrypt table data at rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an encrypted table
&lt;/h3&gt;

&lt;p&gt;Console → &lt;strong&gt;DynamoDB → Create table&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Table name:&lt;/strong&gt; &lt;code&gt;Books&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition key:&lt;/strong&gt; &lt;code&gt;Author (String)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort key:&lt;/strong&gt; &lt;code&gt;Book_Title (String)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table settings:&lt;/strong&gt; Customize → &lt;strong&gt;Encryption at rest:&lt;/strong&gt; &lt;strong&gt;Customer managed key&lt;/strong&gt; → pick &lt;code&gt;myKey&lt;/code&gt;
Create and wait until status is &lt;strong&gt;Active&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Add an item
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Explore table items → Create item&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Author&lt;/code&gt;: &lt;code&gt;Seth Godin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Book_Title&lt;/code&gt;: &lt;code&gt;The Dip&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Test Access with a Different IAM User
&lt;/h2&gt;

&lt;p&gt;Even with read permissions, the user &lt;strong&gt;can’t read&lt;/strong&gt; the table yet because the table is encrypted with your &lt;strong&gt;customer-managed key&lt;/strong&gt;, and the &lt;strong&gt;key policy&lt;/strong&gt; doesn’t permit this user to use the key.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Modify the Key Policy to Grant Access
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Get the user’s ARN
&lt;/h3&gt;

&lt;p&gt;Console → &lt;strong&gt;IAM → Users → IAMLabUser&lt;/strong&gt; → copy &lt;strong&gt;ARN&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edit the KMS key policy
&lt;/h3&gt;

&lt;p&gt;Console → &lt;strong&gt;KMS → Customer managed keys → myKey → Switch to policy view → Edit&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Add this statement (replace &lt;code&gt;&amp;lt;IAM_ARN&amp;gt;&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow use of the key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;IAM_ARN&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms:Encrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify as IAM user
&lt;/h3&gt;

&lt;p&gt;Sign back in as &lt;code&gt;IAMLabUser&lt;/code&gt; and &lt;strong&gt;Scan&lt;/strong&gt; the &lt;code&gt;Books&lt;/code&gt; table.&lt;br&gt;&lt;br&gt;
Now it works — because the user is allowed to &lt;strong&gt;use the KMS key&lt;/strong&gt;.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;You just built a practical, secure workflow with AWS KMS — end to end and fully in Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created a &lt;strong&gt;customer-managed KMS key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Generated, stored, and recovered &lt;strong&gt;data keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Encrypted/decrypted data locally with &lt;strong&gt;AES-256&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Secured &lt;strong&gt;DynamoDB&lt;/strong&gt; with &lt;strong&gt;SSE-KMS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Used &lt;strong&gt;key policy&lt;/strong&gt; to gate access beyond IAM&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>kms</category>
    </item>
    <item>
      <title>Getting Started with AWS Config: Monitor, Detect, and Remediate Non-Compliant Resources</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Thu, 23 Oct 2025 21:48:32 +0000</pubDate>
      <link>https://forem.com/harshhp/getting-started-with-aws-config-monitor-detect-and-remediate-non-compliant-resources-439l</link>
      <guid>https://forem.com/harshhp/getting-started-with-aws-config-monitor-detect-and-remediate-non-compliant-resources-439l</guid>
      <description>&lt;h1&gt;
  
  
  Getting Started with AWS Config
&lt;/h1&gt;

&lt;p&gt;AWS Config is a powerful management service that continuously monitors and records the configuration of your AWS resources. It helps ensure compliance by evaluating these resources and their relationships within a specific AWS Region. Whenever a resource deviates from the defined configuration rules, AWS Config flags it as non-compliant, allowing you to identify and remediate issues proactively.&lt;/p&gt;

&lt;p&gt;In this Cloud Lab, you’ll learn how to use AWS Config to enforce compliance on EC2 security groups. You’ll begin by creating an IAM role that grants AWS Config the necessary permissions to perform its operations. Next, you’ll configure AWS Config to monitor security groups in the us-east-1 (N. Virginia) Region. After that, you’ll define and apply Config Rules to evaluate compliance across your resources.&lt;/p&gt;

&lt;p&gt;Once AWS Config is set up, you’ll intentionally create non-compliant resources to observe how it detects and reports them. You’ll then configure remediation actions that automatically bring these resources back into compliance.&lt;/p&gt;

&lt;p&gt;By the end of this lab, you’ll be able to confidently use AWS Config to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor AWS resources in real time
&lt;/li&gt;
&lt;li&gt;Detect configuration drift or non-compliance
&lt;/li&gt;
&lt;li&gt;Automatically enforce your organization’s security and governance policies&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architecture diagram
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  1. Create an IAM Role
&lt;/h2&gt;

&lt;p&gt;An IAM role is an AWS identity with a set of defined permissions. Unlike a user, a role can be assumed by trusted entities, including AWS services, to gain temporary access for specific actions.&lt;/p&gt;

&lt;p&gt;Every role consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A trust policy — defines who can assume the role.&lt;/li&gt;
&lt;li&gt;A permissions policy — defines what those entities can do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this step, you’ll create an IAM role for AWS Config, granting it permissions to monitor and manage AWS resources.&lt;/p&gt;




&lt;h3&gt;
  
  
  Steps to Create the IAM Role
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open the IAM Console&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Search for “IAM” in the AWS Console and select it to open the dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a New Role&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Go to Roles → Create role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Select the Trusted Entity&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Under Use case, search and select Config.&lt;br&gt;&lt;br&gt;
Click Next.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Attach Permissions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The policy AWSConfigServiceRolePolicy will be automatically selected.&lt;br&gt;&lt;br&gt;
Click Next.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review and Create&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The default name AWSServiceRoleForConfig will appear automatically.&lt;br&gt;&lt;br&gt;
Click Create role.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Note: If the error “A role with this name already exists” appears, use the existing service role instead of creating a new one.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Start the Configuration Recorder
&lt;/h2&gt;

&lt;p&gt;The Configuration Recorder is the core of AWS Config. It continuously tracks configuration changes for selected AWS resources.&lt;br&gt;&lt;br&gt;
In this step, you’ll enable it to monitor EC2 security groups within your Region.&lt;/p&gt;




&lt;h3&gt;
  
  
  Steps to Start the Configuration Recorder
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open AWS Config&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Search for “Config” and select the service.&lt;br&gt;&lt;br&gt;
You’ll land on the AWS Config Home page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up AWS Config&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Click &lt;em&gt;Set up AWS Config&lt;/em&gt; in the sidebar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Select Specific Resources&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Under Recording method, choose &lt;em&gt;Specific resource types&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
Add:   &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS EC2 SecurityGroup → Frequency: Continuous&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assign the IAM Role&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Under Data governance, choose &lt;em&gt;Select a role from your account&lt;/em&gt; and pick the previously created role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure Delivery Method&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Under Delivery method, select &lt;em&gt;Create a bucket&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
This S3 bucket will store all configuration logs.&lt;br&gt;&lt;br&gt;
Click &lt;em&gt;Next&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skip Rule Selection&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
On the Rules page, click &lt;em&gt;Next&lt;/em&gt; without selecting any rules (we’ll add them later).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review and Confirm&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Review your setup and click &lt;em&gt;Confirm&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
AWS Config will now record configuration changes for all security groups in your region.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If Config Is Already Enabled:&lt;br&gt;&lt;br&gt;
Go to Settings → Edit, select Specific resource types, and configure only AWS EC2 SecurityGroup for Continuous recording.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Add AWS Config Rules
&lt;/h2&gt;

&lt;p&gt;AWS Config Rules allow AWS Config to evaluate resources against compliance standards. AWS provides managed rules, and you can also create custom rules.&lt;/p&gt;

&lt;p&gt;In this lab, you’ll define managed rules to enforce your organization’s policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;restricted-ssh&lt;/strong&gt; → Ensures no public SSH access (port 22)
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Steps to Add AWS Config Rules
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Add the “restricted-ssh” Rule
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;From the AWS Config dashboard, select Rules → Add rule.&lt;/li&gt;
&lt;li&gt;Choose &lt;em&gt;Add AWS managed rule&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Search for and select &lt;strong&gt;restricted-ssh&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Next&lt;/em&gt;, leave defaults, and click &lt;em&gt;Next&lt;/em&gt; again.&lt;/li&gt;
&lt;li&gt;Review and click &lt;em&gt;Save&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This rule marks any EC2 security group that allows public SSH access as non-compliant.&lt;/p&gt;

&lt;p&gt;AWS Config will now begin evaluating resources against these rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Provision EC2 Resources
&lt;/h2&gt;

&lt;p&gt;Now, you’ll create EC2 resources that AWS Config can evaluate.&lt;br&gt;&lt;br&gt;
We’ll intentionally make one of them non-compliant to observe AWS Config’s detection capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Security Group
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the EC2 Dashboard → Search “EC2” in the console.&lt;/li&gt;
&lt;li&gt;Go to &lt;em&gt;Network &amp;amp; Security → Security Groups&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Create security group&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Set:

&lt;ul&gt;
&lt;li&gt;Name: MySecurityGroup
&lt;/li&gt;
&lt;li&gt;Description: Security group allowing SSH access&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;em&gt;Inbound rules&lt;/em&gt;, click &lt;em&gt;Add rule&lt;/em&gt;:

&lt;ul&gt;
&lt;li&gt;Type: SSH
&lt;/li&gt;
&lt;li&gt;Source: Anywhere-IPv4 (0.0.0.0/0)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Create security group.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This configuration allows public SSH access — intentionally non-compliant per your rule.&lt;/p&gt;




&lt;h3&gt;
  
  
  Create an EC2 Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;em&gt;Instances → Launch instances.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Set the following:

&lt;ul&gt;
&lt;li&gt;Name: client
&lt;/li&gt;
&lt;li&gt;AMI: Amazon Linux 2023 AMI
&lt;/li&gt;
&lt;li&gt;Instance type: t2.micro
&lt;/li&gt;
&lt;li&gt;Key pair: Proceed without key pair
&lt;/li&gt;
&lt;li&gt;Network settings: Select existing security group → MySecurityGroup
&lt;/li&gt;
&lt;li&gt;Storage: Default gp3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Launch instance.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Wait for the instance status to show &lt;em&gt;Running.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AWS Config will now start evaluating these resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Check the Resources’ Compliance
&lt;/h2&gt;

&lt;p&gt;Now let’s verify if your security group comply with the defined rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to Verify Compliance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open AWS Config → Rules.&lt;/li&gt;
&lt;li&gt;Under restricted-ssh, look for 1 Noncompliant resource(s).
If none appear, wait about a minute and refresh.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Click the restricted-ssh rule → view Resources in scope.&lt;/li&gt;
&lt;li&gt;Click the Resource ID to confirm it’s your MySecurityGroup.&lt;/li&gt;
&lt;li&gt;To view its details, click &lt;em&gt;View Configuration Item (JSON)&lt;/em&gt;. You’ll find:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;json
"ipPermissions": [
    {
        "fromPort": 22,
        "ipProtocol": "tcp",
        "toPort": 22,
        "ipv4Ranges": [
            {
                "cidrIp": "0.0.0.0/0"
            }
        ]
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows that port 22 (SSH) is open to the public (0.0.0.0/0) — making the security group non-compliant.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Add and Use a Remediation Action
&lt;/h2&gt;

&lt;p&gt;Once AWS Config identifies non-compliance, you can fix it using remediation actions.&lt;br&gt;&lt;br&gt;
AWS Config integrates with AWS Systems Manager Automations to perform predefined remediation workflows.&lt;/p&gt;

&lt;p&gt;Here, you’ll create and execute a remediation action to automatically remove public SSH access from your EC2 security group.&lt;/p&gt;




&lt;h3&gt;
  
  
  Add the Remediation Action
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open AWS Config → Rules → restricted-ssh.&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Actions → Manage remediation&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;em&gt;Select remediation method&lt;/em&gt;, choose &lt;em&gt;Manual remediation&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Remediation action details&lt;/em&gt;, select &lt;strong&gt;AWS-DisablePublicAccessForSecurityGroup&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;em&gt;Resource ID parameter&lt;/em&gt;, choose &lt;em&gt;GroupId&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Parameters&lt;/em&gt;, set:

&lt;ul&gt;
&lt;li&gt;IpAddressToBlock: 0.0.0.0/0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Save changes.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Use the Remediation Action
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the restricted-ssh rule again.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Resources in scope&lt;/em&gt;, select the non-compliant security group.&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Remediate.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Once the process completes, you’ll see “Action executed successfully.”&lt;/li&gt;
&lt;li&gt;Refresh the page — the resource should disappear from the non-compliant list.&lt;/li&gt;
&lt;li&gt;Finally, verify from the EC2 Dashboard → Security Groups that the inbound SSH rule allowing public access has been removed.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;You’ve successfully remediated your non-compliant resource.&lt;/p&gt;




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

&lt;p&gt;In this Cloud Lab, you learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure AWS Config to monitor and record resource changes
&lt;/li&gt;
&lt;li&gt;Define compliance rules for security groups
&lt;/li&gt;
&lt;li&gt;Detect and review non-compliant resources
&lt;/li&gt;
&lt;li&gt;Apply remediation actions to automatically fix violations
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With AWS Config, you can continuously track, audit, and enforce configuration compliance — ensuring your AWS environment remains secure and aligned with organizational policies.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>monitoring</category>
      <category>cloud</category>
    </item>
    <item>
      <title>AWS CloudFront Security Implementation Guide</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Wed, 08 Oct 2025 18:42:39 +0000</pubDate>
      <link>https://forem.com/harshhp/aws-cloudfront-security-implementation-guide-bjm</link>
      <guid>https://forem.com/harshhp/aws-cloudfront-security-implementation-guide-bjm</guid>
      <description>&lt;h2&gt;
  
  
  Combining Origin Access Control (OAC) and Signed URLs with Trusted Key Groups
&lt;/h2&gt;




&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;p&gt;This guide provides a comprehensive implementation framework for securing Amazon S3 static assets through AWS CloudFront using &lt;strong&gt;Origin Access Control (OAC)&lt;/strong&gt; and &lt;strong&gt;Signed URLs with Trusted Key Groups&lt;/strong&gt;. This architecture establishes multiple security layers to protect sensitive content while maintaining optimal delivery performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;This architecture establishes a &lt;strong&gt;two-layer security model&lt;/strong&gt; where both end-user access and origin access are independently verified and protected.&lt;/p&gt;

&lt;h3&gt;
  
  
  User → CloudFront (Signed URLs)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users must present a &lt;strong&gt;cryptographically signed URL&lt;/strong&gt; containing an expiration timestamp.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront validates&lt;/strong&gt; the signature using &lt;strong&gt;public keys&lt;/strong&gt; from &lt;strong&gt;trusted Key Groups&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Any &lt;strong&gt;invalid or expired requests&lt;/strong&gt; are &lt;strong&gt;rejected at the edge&lt;/strong&gt;, preventing unauthorized access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CloudFront → S3 (Origin Access Control)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CloudFront &lt;strong&gt;authenticates to S3&lt;/strong&gt; using &lt;strong&gt;AWS Signature Version 4&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 bucket policies&lt;/strong&gt; ensure that requests &lt;strong&gt;only come from authorized CloudFront distributions&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct access to S3 is blocked&lt;/strong&gt;, enforcing all data delivery through CloudFront.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Layers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Viewer Authentication:&lt;/strong&gt; Signed URL validation using RSA key pairs
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge Security:&lt;/strong&gt; CloudFront distribution with restricted access policies
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin Authentication:&lt;/strong&gt; OAC with SigV4 signing for S3 access
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket Security:&lt;/strong&gt; S3 bucket policies restricting access to specific CloudFront distributions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Implementation Specifications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: S3 Bucket Configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.1 Create Private S3 Bucket (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Amazon S3 Console&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create bucket&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter Bucket name: &lt;code&gt;demo-oac-secure-assets&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;AWS Region&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Block Public Access&lt;/strong&gt;, select &lt;strong&gt;Block all public access&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;(Optional) &lt;strong&gt;Enable Versioning&lt;/strong&gt; for audit trail
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create bucket&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  1.2 Upload Sample Content (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Select your newly created bucket
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload → Add files&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select your static assets (HTML, CSS, JS, images)
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Verify objects show &lt;strong&gt;No public access&lt;/strong&gt; in the permissions column&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Phase 2: Origin Access Control Setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  2.1 Create OAC Configuration (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;CloudFront Console&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In left navigation, select &lt;strong&gt;Origin access&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create control setting&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;secure-oac-configuration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; &lt;em&gt;Origin Access Control for secure S3 access&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing protocol:&lt;/strong&gt; &lt;strong&gt;SigV4&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing behavior:&lt;/strong&gt; &lt;strong&gt;Always&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Phase 3: Cryptographic Key Management
&lt;/h3&gt;

&lt;h4&gt;
  
  
  3.1 Generate Key Pair Locally
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate 2048-bit RSA private key&lt;/span&gt;
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; private_key.pem 2048

&lt;span class="c"&gt;# Extract public key&lt;/span&gt;
openssl rsa &lt;span class="nt"&gt;-in&lt;/span&gt; private_key.pem &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; public_key.pem

&lt;span class="c"&gt;# Set secure permissions&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 private_key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.2 Create CloudFront Public Key (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;CloudFront Console&lt;/strong&gt;, open &lt;strong&gt;Key management → Public keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create public key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;secure-content-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public key:&lt;/strong&gt; paste contents of &lt;code&gt;public_key.pem&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create public key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Note the generated &lt;strong&gt;Key pair ID&lt;/strong&gt; (format: &lt;code&gt;K123456789ABCDEF&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  3.3 Establish Trusted Key Group (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;CloudFront Console&lt;/strong&gt;, open &lt;strong&gt;Key management → Key groups&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create key group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;trusted-key-group&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; &lt;em&gt;Key group for signed URL validation&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public keys:&lt;/strong&gt; select your created public key
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create key group&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Phase 4: CloudFront Distribution Configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  4.1 Create Distribution (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;CloudFront Console&lt;/strong&gt; → &lt;strong&gt;Create distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin domain:&lt;/strong&gt; select your S3 bucket (&lt;code&gt;demo-oac-secure-assets.s3.amazonaws.com&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin path:&lt;/strong&gt; &lt;em&gt;(Leave blank)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;SecureS3Origin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin access:&lt;/strong&gt; &lt;strong&gt;Origin access control settings (recommended)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select control setting:&lt;/strong&gt; your created OAC
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket policy:&lt;/strong&gt; &lt;strong&gt;Yes, update the bucket policy&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  4.2 Configure Default Cache Behavior
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache policy:&lt;/strong&gt; &lt;code&gt;CachingOptimized&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viewer protocol policy:&lt;/strong&gt; &lt;strong&gt;Redirect HTTP to HTTPS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict viewer access:&lt;/strong&gt; &lt;strong&gt;Yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted key groups:&lt;/strong&gt; select your created key group
&lt;/li&gt;
&lt;li&gt;Additional:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS WAF:&lt;/strong&gt; Enable if required
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2:&lt;/strong&gt; Enabled
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv6:&lt;/strong&gt; Enabled&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.3 Distribution Settings
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Price class:&lt;/strong&gt; choose based on geographic requirements
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternate domain name (CNAME):&lt;/strong&gt; configure if using custom domain
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL certificate:&lt;/strong&gt; default or custom ACM certificate
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Wait for status to change from &lt;strong&gt;In Progress&lt;/strong&gt; → &lt;strong&gt;Deployed&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Phase 5: S3 Bucket Policy Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  5.1 Verify Automatic Policy Creation (Console)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;S3 Console&lt;/strong&gt; → select bucket &lt;strong&gt;&lt;code&gt;demo-oac-secure-assets&lt;/code&gt;&lt;/strong&gt; → &lt;strong&gt;Permissions&lt;/strong&gt; tab
&lt;/li&gt;
&lt;li&gt;Verify an &lt;strong&gt;auto-generated bucket policy&lt;/strong&gt; that allows CloudFront access via OAC
&lt;/li&gt;
&lt;li&gt;If not present, apply the manual policy below&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  5.2 Manual Bucket Policy (if required)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowCloudFrontOACAccess"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cloudfront.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::demo-oac-secure-assets/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"AWS:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:cloudfront::123456789012:distribution/E2ABCD1234EXAMPLE"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replace placeholders:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;123456789012&lt;/code&gt; → your AWS Account ID
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;E2ABCD1234EXAMPLE&lt;/code&gt; → your CloudFront Distribution ID&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Signed URL Generation Implementation
&lt;/h2&gt;

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

&lt;h3&gt;
  
  
  Python Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serialization&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashes&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives.asymmetric&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CloudFrontSigner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_pair_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;private_key_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key_pair_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key_pair_id&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;private_key_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;private_key_path&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_b64url_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Base64 URL-safe encoding without padding&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;~&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_sign_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Sign policy document using RSA private key&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;private_key_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;key_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;private_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serialization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_pem_private_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;key_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PKCS1v15&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;hashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SHA1&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_b64url_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_signed_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expires_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Generate CloudFront signed URL with custom policy&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;expiration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;expires_in&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resource_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DateLessThan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS:EpochTime&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expiration&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;policy_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;policy_encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_b64url_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_sign_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;resource_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?Policy=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;policy_encoded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;Signature=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;Key-Pair-Id=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key_pair_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Implementation Example
&lt;/span&gt;&lt;span class="n"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CloudFrontSigner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;key_pair_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;K123456789ABCDEF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;private_key_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/secure/keys/private_key.pem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;signed_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_signed_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;resource_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://d123456789.cloudfront.net/secure-document.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expires_in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7200&lt;/span&gt;  &lt;span class="c1"&gt;# 2 hours validity
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Signed URL:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signed_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Phase 6: Testing
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test Scenario&lt;/th&gt;
&lt;th&gt;Expected Result&lt;/th&gt;
&lt;th&gt;Validation Steps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Direct S3 Access&lt;/td&gt;
&lt;td&gt;HTTP 403 Access Denied&lt;/td&gt;
&lt;td&gt;1) Copy S3 object URL → 2) Open in browser → 3) Verify &lt;strong&gt;Access Denied&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unsigned CloudFront Access&lt;/td&gt;
&lt;td&gt;HTTP 403 Access Denied&lt;/td&gt;
&lt;td&gt;1) Copy CloudFront URL → 2) Access w/o params → 3) Verify &lt;strong&gt;Access Denied&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valid Signed URL&lt;/td&gt;
&lt;td&gt;HTTP 200 OK&lt;/td&gt;
&lt;td&gt;1) Generate signed URL → 2) Open in browser → 3) Verify content loads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expired Signed URL&lt;/td&gt;
&lt;td&gt;HTTP 403 Access Denied&lt;/td&gt;
&lt;td&gt;1) Generate URL with past expiration → 2) Access → 3) Verify rejection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modified Signature&lt;/td&gt;
&lt;td&gt;HTTP 403 Access Denied&lt;/td&gt;
&lt;td&gt;1) Alter signature parameter → 2) Access → 3) Verify rejection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Results Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔒 Access Without Signed URL (Blocked)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb8x4lhty6z1ib3aei1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb8x4lhty6z1ib3aei1l.png" alt="Access Denied Screenshot" width="800" height="232"&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Access With Signed URL (Successful)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ktbfeaoi4638hkl1ogb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ktbfeaoi4638hkl1ogb.png" alt="Access Allowed Screenshot" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdn</category>
    </item>
    <item>
      <title>Beyond the Proxy: Building a Secure, Observable Serverless API with Amazon API Gateway</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Sun, 05 Oct 2025 18:21:01 +0000</pubDate>
      <link>https://forem.com/harshhp/beyond-the-proxy-building-a-secure-observable-serverless-api-with-amazon-api-gateway-di2</link>
      <guid>https://forem.com/harshhp/beyond-the-proxy-building-a-secure-observable-serverless-api-with-amazon-api-gateway-di2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: Rethinking API Gateway
&lt;/h2&gt;

&lt;p&gt;If you ask many developers what &lt;strong&gt;Amazon API Gateway&lt;/strong&gt; is, they’ll often say,&lt;br&gt;&lt;br&gt;
“It’s a way to trigger Lambda functions with HTTP requests.”  &lt;/p&gt;

&lt;p&gt;While that’s a common use case, this view undersells the service dramatically.&lt;/p&gt;

&lt;p&gt;In reality, API Gateway is a &lt;strong&gt;complete API management platform&lt;/strong&gt;. It’s your first and most critical line of defense, capable of handling &lt;strong&gt;validation, transformation, authentication, throttling, and observability&lt;/strong&gt; before your Lambda function even runs.&lt;br&gt;&lt;br&gt;
It shifts the burden of common API concerns from your code to a managed, scalable layer.&lt;/p&gt;

&lt;p&gt;To prove this, we’ll build &lt;strong&gt;TrailLog&lt;/strong&gt; — a serverless API for logging hiking trips.&lt;br&gt;&lt;br&gt;
We won’t just connect endpoints; we’ll use API Gateway’s full potential to create a &lt;strong&gt;robust, secure, and observable&lt;/strong&gt; API.&lt;/p&gt;
&lt;h3&gt;
  
  
  By the end of this guide, you will learn how to:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validate &amp;amp; Transform:&lt;/strong&gt; Enforce data contracts at the gateway, keeping Lambda code clean.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Endpoints:&lt;/strong&gt; Implement a custom Lambda authorizer for token-based access control.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Achieve Observability:&lt;/strong&gt; Gain deep insights into API performance with structured CloudWatch logs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrate a Governed API:&lt;/strong&gt; Deploy a production-ready API with full visibility and control.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Blueprint: TrailLog System Architecture
&lt;/h2&gt;

&lt;p&gt;Our fully serverless architecture is designed for scalability and simplicity.&lt;br&gt;&lt;br&gt;
Each AWS service plays a clear role in this ecosystem.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon API Gateway (REST API)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The unified entry point — handles routing, validation, auth, and logging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes backend logic for creating and retrieving trips&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stores all hiking data in a serverless NoSQL table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon CloudWatch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Centralizes logs and metrics for monitoring and debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This stack scales automatically with traffic, without managing or patching servers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Architecture Diagram
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzszbofr2njg9dnn6qli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzszbofr2njg9dnn6qli.png" alt=" " width="800" height="483"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Client application sends incoming HTTPS REST requests to Amazon API Gateway, which triggers AWS Lambda functions for GET, POST, and DELETE operations. Lambda interacts with Amazon DynamoDB for data storage and sends logs to Amazon CloudWatch.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Foundation: Setting Up Permissions with IAM
&lt;/h2&gt;

&lt;p&gt;All Lambda functions in TrailLog share a single IAM role named &lt;strong&gt;&lt;code&gt;lambda-traillog-role&lt;/code&gt;&lt;/strong&gt;,&lt;br&gt;&lt;br&gt;
configured via an inline policy that grants access to DynamoDB and CloudWatch logs.&lt;/p&gt;
&lt;h3&gt;
  
  
  IAM Role: &lt;code&gt;lambda-traillog-role&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;All Lambda functions in TrailLog share a single IAM role named &lt;code&gt;lambda-traillog-role&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
This role is granted access to the DynamoDB table &lt;strong&gt;TrailLog&lt;/strong&gt; through the following inline policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DDBWriteTrailLog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:PutItem"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:579273601939:table/TrailLog"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DDBReadTrailLog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:GetItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:Scan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:Query"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:579273601939:table/TrailLog"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DDBDescribeForChecks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:DescribeTable"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:579273601939:table/TrailLog"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This role is attached to all Lambda functions in the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deep Dive 1: The &lt;code&gt;POST /trips&lt;/code&gt; Endpoint — Validation &amp;amp; Transformation
&lt;/h2&gt;

&lt;p&gt;The first endpoint demonstrates API Gateway’s ability to offload validation and data transformation&lt;br&gt;&lt;br&gt;
before invoking the backend logic.&lt;/p&gt;
&lt;h3&gt;
  
  
  DynamoDB Table: TrailLog
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partition Key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tripId&lt;/code&gt; (String)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Billing Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pay-per-request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h3&gt;
  
  
  Lambda Function: &lt;code&gt;create-trip&lt;/code&gt; (Python 3.12)
&lt;/h3&gt;

&lt;p&gt;This Lambda function remains simple because API Gateway enforces all validation upfront.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InvalidOperation&lt;/span&gt;

&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# API Gateway has already validated input; focus on core logic.
&lt;/span&gt;    &lt;span class="n"&gt;trip_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tripId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;userId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;userId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trailName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trailName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distanceKm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distanceKm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;durationMin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;durationMin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elevationGainM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elevationGainM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;createdAt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tripId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  The API Gateway Configuration: Non-Proxy Integration
&lt;/h3&gt;

&lt;p&gt;Disabling Lambda Proxy Integration gives us control over request handling and validation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lambda Function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proxy Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Validator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Body &amp;amp; Params&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TripCreate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Request Model: &lt;code&gt;TripCreate&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trailName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"distanceKm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"durationMin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"elevationGainM"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trailName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^[0-9]{4}-[0-9]{2}-[0-9]{2}$"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"distanceKm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"durationMin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"elevationGainM"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, any malformed input (for example, an invalid date format or incorrect type)&lt;br&gt;&lt;br&gt;
is rejected &lt;strong&gt;at the gateway&lt;/strong&gt;, saving Lambda invocations and improving reliability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqi0o2ie9ziqazvwa66g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqi0o2ie9ziqazvwa66g.png" alt=" " width="800" height="593"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Successfully created a new hiking trip via the &lt;code&gt;POST /trips&lt;/code&gt; endpoint, returning a 201 status and generated &lt;code&gt;tripId&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Deep Dive 2: The &lt;code&gt;GET /trips/{tripId}&lt;/code&gt; Endpoint — Simple Proxy Integration
&lt;/h2&gt;

&lt;p&gt;For simple reads, we use &lt;strong&gt;Lambda Proxy Integration&lt;/strong&gt; to pass the entire request context directly to Lambda.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lambda Function: &lt;code&gt;get-trip&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This function extracts &lt;code&gt;tripId&lt;/code&gt; from the path and fetches the corresponding item from DynamoDB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;

&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_to_native&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;trip_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pathParameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tripId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing tripId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tripId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_to_native&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Test Request
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://&amp;lt;api-id&amp;gt;.execute-api.us-east-1.amazonaws.com/dev/trips/&amp;lt;tripId&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54ask7wwg2vuy6o9m39o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54ask7wwg2vuy6o9m39o.png" alt=" " width="800" height="615"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Fetched detailed hiking trip data successfully using the &lt;code&gt;GET /trips/{tripId}&lt;/code&gt; endpoint.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Deep Dive 3: Security and Observability — &lt;code&gt;/secure/admin/stats&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This administrative endpoint combines two advanced API Gateway features:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;custom token authorization&lt;/strong&gt; and &lt;strong&gt;centralized CloudWatch observability&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Securing the Route with a Lambda Authorizer
&lt;/h3&gt;

&lt;p&gt;We use a &lt;strong&gt;custom Lambda authorizer&lt;/strong&gt; to protect the &lt;code&gt;/secure/admin/stats&lt;/code&gt; route.&lt;/p&gt;
&lt;h4&gt;
  
  
  Authorizer Function: &lt;code&gt;lambda-authorizer&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DEMO_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer trail123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorizationToken&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;DEMO_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deny&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;guest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;principalId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trail-admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyDocument&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execute-api:Invoke&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;methodArn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Any request without &lt;code&gt;X-Auth-Token: Bearer trail123&lt;/code&gt; will receive a &lt;strong&gt;403 Forbidden&lt;/strong&gt; response.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Stats Aggregation Function: &lt;code&gt;admin-stats&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This function aggregates trip statistics across all records.&lt;br&gt;&lt;br&gt;
It’s invoked only if the authorizer grants access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;

&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;scan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProjectionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tripId, distanceKm, durationMin, elevationGainM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;km&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distanceKm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;durationMin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;gain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elevationGainM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalTrips&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalKm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;km&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalHours&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalElevationM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Test Request
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer trail123"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/secure/admin/stats"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;em&gt;Access denied without a valid token — API Gateway blocking unauthorized requests using the custom Lambda authorizer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6k7jwre1tia6k4njmf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6k7jwre1tia6k4njmf7.png" alt=" " width="800" height="605"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Authorized admin access to &lt;code&gt;/secure/admin/stats&lt;/code&gt; returning aggregated trail statistics.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Crown Jewel: Deep Observability with CloudWatch
&lt;/h2&gt;

&lt;p&gt;To gain complete visibility into API behavior, enable both &lt;strong&gt;Execution Logs&lt;/strong&gt; and &lt;strong&gt;Access Logs&lt;/strong&gt; in Amazon API Gateway.&lt;br&gt;&lt;br&gt;
These logs provide the foundation for debugging, performance monitoring, and request analytics.&lt;/p&gt;


&lt;h3&gt;
  
  
  Create a Log Group for Access Logs
&lt;/h3&gt;

&lt;p&gt;Before enabling access logging, create a dedicated &lt;strong&gt;CloudWatch Log Group&lt;/strong&gt; where API Gateway will push structured log entries.&lt;br&gt;&lt;br&gt;
This ensures all API requests are tracked consistently and stored centrally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;CloudWatch Console → Log groups → Create log group&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Enter the name:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   /apigw/traillog/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;(Optional) Set the &lt;strong&gt;retention&lt;/strong&gt; period to 7, 30, or 90 days depending on your monitoring needs.
&lt;/li&gt;
&lt;li&gt;Note down the log group ARN — you’ll use it in your API Gateway stage configuration:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   arn:aws:logs:us-east-1:579273601939:log-group:/apigw/traillog/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Ensure API Gateway has permission to write logs by attaching this managed policy to its execution role:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqjxpw3tet47m748wtsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqjxpw3tet47m748wtsp.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;CloudWatch log group &lt;code&gt;/apigw/traillog/dev&lt;/code&gt; created to store structured access logs from API Gateway.&lt;/em&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Execution Logs
&lt;/h3&gt;

&lt;p&gt;Execution logs trace the &lt;strong&gt;internal request flow&lt;/strong&gt; through API Gateway —&lt;br&gt;&lt;br&gt;
from input validation and mapping templates to Lambda invocation and response transformation.&lt;br&gt;&lt;br&gt;
They’re your primary tool for &lt;strong&gt;debugging and tracing&lt;/strong&gt; how API Gateway processes a request.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Log Group&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;API-Gateway-Execution-Logs_{restApiId}/dev&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Traces internal request flow and mapping templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Debugging authorization, validation, or mapping issues&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ensure your API stage has &lt;strong&gt;CloudWatch execution logging enabled&lt;/strong&gt; and that API Gateway can push logs.&lt;br&gt;&lt;br&gt;
Attach the following managed policy to grant permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Access Logs
&lt;/h3&gt;

&lt;p&gt;Access logs summarize &lt;strong&gt;each API request and response&lt;/strong&gt; in a structured JSON format.&lt;br&gt;&lt;br&gt;
These are invaluable for analytics, performance tracking, and auditing user behavior.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Log Group ARN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arn:aws:logs:us-east-1:579273601939:log-group:/apigw/traillog/dev&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Capture per-request analytics and response metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monitoring latency, traffic, and client behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Access Log Format Template
&lt;/h4&gt;

&lt;p&gt;To enable structured access logs, open your API Gateway stage and set the log format using the following JSON template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requestId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.requestId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.identity.sourceIp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.requestTime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.httpMethod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.resourcePath"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$context.status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integrationStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$context.integration.status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userAgent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.identity.userAgent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"authorizer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.authorizer.role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$context.error.message"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once redeployed, every request will produce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Execution Logs:&lt;/strong&gt; Detailed traces for debugging.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Logs:&lt;/strong&gt; High-level JSON entries for analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7py52wla3gs29uriild.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7py52wla3gs29uriild.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;API Gateway Execution Logs showing Lambda invocation flow, request mapping, and response transformation details.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuca57j4lgvxnl22nbqum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuca57j4lgvxnl22nbqum.png" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Structured JSON access logs capturing requestId, method, path, status, and authorizer context for analytics.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: You’ve Built More Than an API
&lt;/h2&gt;

&lt;p&gt;TrailLog isn’t just a CRUD backend. It’s a &lt;strong&gt;governed, secure, and observable API platform&lt;/strong&gt; built with managed AWS services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-Lambda Validation:&lt;/strong&gt; Offload schema checks to API Gateway for cleaner, cheaper code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Authorization:&lt;/strong&gt; Implement fine-grained security without burdening business logic.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Logging:&lt;/strong&gt; Use CloudWatch for comprehensive visibility and debugging.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By embracing these patterns, you can use &lt;strong&gt;Amazon API Gateway&lt;/strong&gt; not just as a trigger mechanism, but as a &lt;strong&gt;complete API management engine&lt;/strong&gt; — the foundation of scalable, production-ready serverless systems.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>apigateway</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Managing Data Access with Amazon S3 Access Points</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Thu, 18 Sep 2025 23:48:11 +0000</pubDate>
      <link>https://forem.com/harshhp/managing-data-access-with-amazon-s3-access-points-3p5l</link>
      <guid>https://forem.com/harshhp/managing-data-access-with-amazon-s3-access-points-3p5l</guid>
      <description>&lt;p&gt;Amazon S3 Access Points are a powerful feature that simplify how organizations control and manage access to their data. Instead of relying solely on complex bucket policies, Access Points allow you to create dedicated entry points with tailored permissions. This provides more flexibility, especially when working with teams, applications, or VPCs that require different levels of access.&lt;/p&gt;

&lt;p&gt;In today's world where secure and efficient data handling is critical, mastering S3 Access Points sets you apart as someone who understands not just storage, but also governance and access control in the cloud.&lt;/p&gt;

&lt;p&gt;In this Cloud Lab, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating an S3 bucket for sensitive data&lt;/li&gt;
&lt;li&gt;Configuring a VPC-bound S3 Access Point&lt;/li&gt;
&lt;li&gt;Testing access from both an allowed VPC and a default VPC using AWS Lambda&lt;/li&gt;
&lt;li&gt;Understanding how these controls enforce network-level security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you'll have hands-on experience with S3 Access Points and the skills to design secure data access patterns for real-world cloud applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create an S3 Bucket
&lt;/h2&gt;

&lt;p&gt;The first step is to provision an Amazon S3 bucket that will act as the primary storage location for sensitive documents. We'll later use S3 Access Points to control how this data is accessed and processed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydbuz3ps4v0d5jzero7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydbuz3ps4v0d5jzero7b.png" alt=" " width="502" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the S3 Bucket
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the AWS Management Console and search for S3.&lt;/li&gt;
&lt;li&gt;Select the S3 service from the results.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter a globally unique name in the format: &lt;code&gt;s3-bucket-&amp;lt;random_text&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;&amp;lt;random_text&amp;gt;&lt;/code&gt; with any string that ensures uniqueness across AWS accounts.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Block Public Access&lt;/strong&gt; settings, make sure &lt;strong&gt;Block all public access&lt;/strong&gt; is selected.&lt;/li&gt;
&lt;li&gt;Scroll down and click &lt;strong&gt;Create bucket&lt;/strong&gt; to finalize.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point, your S3 bucket is ready to securely store documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uploading the Document
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a simple text file called &lt;code&gt;sampledata.txt&lt;/code&gt; on your local machine (e.g., with content like "This is sensitive organizational data.").&lt;/li&gt;
&lt;li&gt;In the S3 Dashboard, select the newly created bucket (&lt;code&gt;s3-bucket-&amp;lt;random_text&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload → Add files&lt;/strong&gt;, and choose the &lt;code&gt;sampledata.txt&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload&lt;/strong&gt; to complete the process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: You now have a secure S3 bucket with a sensitive file in place, ready to be accessed and controlled using Amazon S3 Access Points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a VPC-Bound Access Point
&lt;/h2&gt;

&lt;p&gt;Amazon S3 Access Points make it easier to define fine-grained permissions, ensuring that specific applications, users, or roles get only the access they need. This is particularly useful in environments where multiple teams or services share the same dataset.&lt;/p&gt;

&lt;p&gt;In this step, we'll create an S3 Access Point bound to a specific VPC. This ensures that sensitive data stored in our bucket is accessible only through that VPC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxdggtwqarmbezsm8rhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxdggtwqarmbezsm8rhy.png" alt=" " width="544" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2.1: Create the VPC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Management Console, search for &lt;strong&gt;VPC&lt;/strong&gt; and open the service.&lt;/li&gt;
&lt;li&gt;From the left menu, select &lt;strong&gt;Your VPCs → Create VPC&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Resources to create&lt;/strong&gt;, choose &lt;strong&gt;VPC and more&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name tag auto-generation&lt;/strong&gt; field, replace the default value with &lt;code&gt;org&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configure the following:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Number of public subnets → 0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Number of private subnets → 2&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPC endpoints → Select S3 Gateway&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create VPC&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Once provisioned, click &lt;strong&gt;View VPC&lt;/strong&gt; and copy the VPC ID for later use.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2.2: Create the Access Point
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the S3 service in the AWS Console.&lt;/li&gt;
&lt;li&gt;From the left menu, select &lt;strong&gt;Access Points&lt;/strong&gt; for general purpose buckets.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create access point&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name it: &lt;code&gt;vpc-bound-access-point&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Bucket name&lt;/strong&gt;, select the S3 bucket created earlier.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Network origin&lt;/strong&gt;, choose &lt;strong&gt;Virtual private cloud (VPC)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste the VPC ID of the &lt;code&gt;org-vpc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ensure &lt;strong&gt;Block all public access&lt;/strong&gt; is enabled.&lt;/li&gt;
&lt;li&gt;Add the following policy (replace &lt;code&gt;&amp;lt;Account ID&amp;gt;&lt;/code&gt; with your AWS account ID and &lt;code&gt;&amp;lt;VPC ID&amp;gt;&lt;/code&gt; with the ID you copied in the previous step):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:us-east-1:&amp;lt;Account ID&amp;gt;:accesspoint/vpc-bound-access-point/object/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"aws:SourceVpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;VPC ID&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Create access point.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; The Access Point now enforces that objects in the bucket can only be retrieved from the &lt;code&gt;org-vpc&lt;/code&gt;.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Test the VPC-Bound Access Point
&lt;/h2&gt;

&lt;p&gt;To validate the policy behavior, we'll create an AWS Lambda function. First, we'll deploy it inside the &lt;code&gt;org-vpc&lt;/code&gt; and confirm access. Then, we'll move it to the default VPC to ensure access is denied.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This step assumes you have a basic IAM role (e.g., &lt;code&gt;LambdaExecutionRole&lt;/code&gt;) with permissions for Lambda and S3 access. You may need to create this role first if it doesn't exist.  &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Step 3.1: Create a Lambda Function in org-vpc
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Console, search for &lt;strong&gt;Lambda&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Functions → Create function → Author from scratch&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Configure:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;accesspoint_function&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Python 3.11
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution role:&lt;/strong&gt; Use an existing role → &lt;code&gt;LambdaExecutionRole&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Expand &lt;strong&gt;Advanced settings → Enable VPC → Select:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPC:&lt;/strong&gt; &lt;code&gt;org-vpc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnets:&lt;/strong&gt; Select the two private subnets (e.g., &lt;code&gt;org-subnet-private1-us-east-1a&lt;/code&gt;, &lt;code&gt;org-subnet-private2-us-east-1b&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security group:&lt;/strong&gt; Default
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create function&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 3.2: Add the Lambda Code
&lt;/h3&gt;

&lt;p&gt;Replace the default code in the Lambda function editor with the following Python code.&lt;br&gt;&lt;br&gt;
(Remember to replace &lt;code&gt;&amp;lt;Account ID&amp;gt;&lt;/code&gt; with your actual AWS account ID.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;botocore.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize S3 client
&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signature_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3v4&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:us-east-1:&amp;lt;Account ID&amp;gt;:accesspoint/vpc-bound-access-point&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sampledata.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3.3: Test from org-vpc
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dgwq0gwfhfhos2zig20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dgwq0gwfhfhos2zig20.png" alt=" " width="562" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to save your code changes.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Test&lt;/strong&gt; to configure a test event. Use the default "Hello World" template and give it a name.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Test&lt;/strong&gt; to run the function.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The execution should succeed. The file contents will appear in the function's logs because the Lambda function runs inside the allowed VPC.  &lt;/p&gt;

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




&lt;h3&gt;
  
  
  Step 3.4: Test from Default VPC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the Lambda function, go to the &lt;strong&gt;Configuration&lt;/strong&gt; tab and select the &lt;strong&gt;VPC&lt;/strong&gt; section.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Switch the VPC to the &lt;strong&gt;default VPC&lt;/strong&gt; and select two of its subnets.
&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;default security group.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Wait for the network changes to apply, then click &lt;strong&gt;Test&lt;/strong&gt; again to run the function.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The function execution will now fail with an error like &lt;strong&gt;AccessDenied&lt;/strong&gt; or &lt;strong&gt;403 Forbidden.&lt;/strong&gt; No data is retrieved because the Access Point policy correctly restricts access to only the &lt;code&gt;org-vpc&lt;/code&gt;.  &lt;/p&gt;




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

&lt;p&gt;Amazon S3 Access Points provide a powerful mechanism for implementing fine-grained access control to your S3 data. By binding access points to specific VPCs, you can enforce network-level security that complements traditional IAM policies. This approach is particularly valuable in multi-tenant environments, compliance scenarios, or when you need to isolate data access to specific network segments.  &lt;/p&gt;

&lt;p&gt;This hands-on exercise demonstrated how to:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a secure S3 bucket with sensitive data.
&lt;/li&gt;
&lt;li&gt;Configure a VPC-bound access point with appropriate policies.
&lt;/li&gt;
&lt;li&gt;Test access patterns from both allowed and restricted networks.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This knowledge empowers you to design more secure and manageable data access patterns in your AWS environments, ensuring that your sensitive data remains protected while still being accessible to authorized services and applications.  &lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Connecting Multi-VPC Applications Using AWS Transit Gateway</title>
      <dc:creator>harsh patel</dc:creator>
      <pubDate>Sun, 16 Feb 2025 19:38:00 +0000</pubDate>
      <link>https://forem.com/harshhp/connecting-multi-vpc-applications-using-aws-transit-gateway-30go</link>
      <guid>https://forem.com/harshhp/connecting-multi-vpc-applications-using-aws-transit-gateway-30go</guid>
      <description>&lt;p&gt;Deploying a React App Across Multiple VPCs Using AWS Transit Gateway&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're working with AWS and need to connect multiple VPCs efficiently, AWS Transit Gateway is your best bet! It acts as a centralized hub, making it easier to route traffic between multiple VPCs without the complexity of VPC peering.&lt;/p&gt;

&lt;p&gt;In this guide, we'll deploy a React application where the frontend and backend live in separate VPCs. These VPCs will be connected using AWS Transit Gateway, allowing smooth communication between services. Let’s dive in! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with admin access&lt;/li&gt;
&lt;li&gt;Basic knowledge of AWS Networking (VPCs, Subnets, Route Tables)&lt;/li&gt;
&lt;li&gt;Familiarity with React and MySQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Architecture Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mpsae348j6vacp5w9ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mpsae348j6vacp5w9ma.png" alt=" " width="800" height="643"&gt;&lt;/a&gt;&lt;br&gt;
Here’s what we’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend VPC → Hosts the React application&lt;/li&gt;
&lt;li&gt;Backend VPC → Runs a MySQL database&lt;/li&gt;
&lt;li&gt;AWS Transit Gateway → Connects both VPCs&lt;/li&gt;
&lt;li&gt;Transit Gateway Attachments → Link each VPC to the Transit Gateway&lt;/li&gt;
&lt;li&gt;Routing Tables → Manage traffic flow between VPCs&lt;/li&gt;
&lt;li&gt;Security Groups → Control access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create Two VPCs&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to AWS VPC Console.&lt;/li&gt;
&lt;li&gt;Click Create VPC and name it FrontendVPC (CIDR: 10.0.0.0/16).&lt;/li&gt;
&lt;li&gt;Create BackendVPC (CIDR: 10.1.0.0/16).&lt;/li&gt;
&lt;li&gt;Add public and private subnets in both VPCs:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;FrontendVPC Public: 10.0.1.0/24&lt;br&gt;
FrontendVPC Private: 10.0.2.0/24&lt;br&gt;
BackendVPC Public: 10.1.1.0/24&lt;br&gt;
BackendVPC Private: 10.1.2.0/24&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Set Up AWS Transit Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to AWS Transit Gateway Console.&lt;/li&gt;
&lt;li&gt;Click Create Transit Gateway, name it, and enable DNS support.&lt;/li&gt;
&lt;li&gt;Once created, note the Transit Gateway ID.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Attach VPCs to Transit Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Transit Gateway Attachments, create:&lt;/li&gt;
&lt;li&gt;Attachment for FrontendVPC&lt;/li&gt;
&lt;li&gt;Attachment for BackendVPC&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Configure Route Tables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.Modify each VPC’s route table:&lt;br&gt;
2.Associate these routes with the correct subnets.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 5: Deploy the Frontend Application&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch an EC2 instance in FrontendVPC public subnet.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Node.js and React:&lt;br&gt;
&lt;code&gt;sudo yum install -y mysql-server&lt;br&gt;
sudo systemctl start mysqld&lt;br&gt;
sudo mysql_secure_installation&lt;br&gt;
mysql -u root -p -e "CREATE DATABASE app_db;"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allow inbound HTTP traffic (port 3000) via security groups.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Deploy the Backend and MySQL Database&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch an EC2 instance in BackendVPC private subnet.&lt;/li&gt;
&lt;li&gt;Install MySQL and set up a database:
&lt;code&gt;sudo yum install -y mysql-server
sudo systemctl start mysqld
sudo mysql_secure_installation
mysql -u root -p -e "CREATE DATABASE app_db;"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set up a backend API using Express.js:
&lt;code&gt;npm install express mysql
node server.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Allow MySQL traffic (port 3306) from FrontendVPC in security groups.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Open and Test the Application&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the Public IP Address of the frontend EC2 instance.&lt;/li&gt;
&lt;li&gt;Open a browser and go to:
&lt;code&gt;ping &amp;lt;Backend-EC2-Private-IP&amp;gt;
curl http://&amp;lt;Backend-EC2-Private-IP&amp;gt;:&amp;lt;Backend-Port&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test frontend-backend connectivity:&lt;br&gt;
&lt;code&gt;sudo yum install -y mysql-server&lt;br&gt;
sudo systemctl start mysqld&lt;br&gt;
sudo mysql_secure_installation&lt;br&gt;
mysql -u root -p -e "CREATE DATABASE app_db;"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If something fails, check:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Route Tables for correct routing.&lt;/li&gt;
&lt;li&gt;Security Groups for inbound/outbound traffic.&lt;/li&gt;
&lt;li&gt;Transit Gateway Attachments for proper linking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture allows for &lt;strong&gt;scalability, security&lt;/strong&gt;, and &lt;strong&gt;efficient communication&lt;/strong&gt; between VPCs.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>vpc</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
