<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hyelngtil Isaac</title>
    <description>The latest articles on DEV Community by Hyelngtil Isaac (@maven_h).</description>
    <link>https://dev.to/maven_h</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3049759%2Fab7e9cca-d5f4-4692-975c-9a09a05fdf42.png</url>
      <title>DEV Community: Hyelngtil Isaac</title>
      <link>https://dev.to/maven_h</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maven_h"/>
    <language>en</language>
    <item>
      <title>Automated End-to-End CI/CD Pipeline via AWS CodePipeline</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Wed, 26 Aug 2026 10:24:06 +0000</pubDate>
      <link>https://dev.to/maven_h/automated-end-to-end-cicd-pipeline-via-aws-codepipeline-48d</link>
      <guid>https://dev.to/maven_h/automated-end-to-end-cicd-pipeline-via-aws-codepipeline-48d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Project Scope:&lt;/strong&gt; A comprehensive implementation guide for building a fully automated continuous integration and continuous deployment (CI/CD) pipeline using AWS developer tools and GitHub: AWS CodeArtifact, AWS CodeBuild, and AWS CodeDeploy via AWS CodePipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Executive Summary &amp;amp; Project Reflection
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Overview:&lt;/strong&gt; &lt;br&gt;
This runbook details the end-to-end architecture and deployment of an automated CI/CD pipeline. The project is broken down into six distinct phases: provisioning a cloud-based development environment, integrating source control, securing package dependencies, configuring continuous integration, defining continuous deployment, and finally, orchestrating the entire workflow via an event-driven pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Tools and Concepts:&lt;/strong&gt; &lt;br&gt;
Services utilized include Amazon EC2, AWS IAM, GitHub, AWS CodeArtifact, Amazon S3, AWS CodeBuild, AWS CloudFormation, AWS CodeDeploy, and AWS CodePipeline. Key concepts mastered include Infrastructure as Code (IaC), event-driven triggers, immutable artifact transitions, least-privilege IAM enforcement, and disaster recovery via automated rollbacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Reflection:&lt;/strong&gt; &lt;br&gt;
This architecture requires approximately 3 hours to provision from scratch across all phases. The most challenging aspect was architecting fine-grained, cross-service IAM policies to enforce least-privilege access across pipeline stages. The most rewarding milestone was successfully troubleshooting permission errors, watching event-driven GitHub trigger automated runs, and seeing the entire end-to-end CI/CD workflow execute and deploy to the target EC2 fleet with zero manual intervention.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Prerequisites &amp;amp; Baseline Requirements
&lt;/h2&gt;

&lt;p&gt;Before initializing the pipeline, the following baseline configurations must be established:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;AWS Account:&lt;/strong&gt; Active AWS account with IAM Admin privileges (avoid using the Root user).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Local IDE:&lt;/strong&gt; Antigravity IDE or VS Code installed locally with the "Remote - SSH" extension enabled.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;GitHub Account:&lt;/strong&gt; Active GitHub account for source control integration.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Part 1: Set Up a Web App in the Cloud
&lt;/h2&gt;

&lt;p&gt;To ensure a consistent and isolated development environment, the project begins by provisioning a cloud-based IDE host to write and compile the application code.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.1 Development EC2 Instance Provisioning
&lt;/h3&gt;

&lt;p&gt;The development environment is hosted on an Amazon EC2 instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Instance Setup:&lt;/strong&gt; Provisioned an Amazon Linux 2023 EC2 instance (&lt;code&gt;t2.micro or t3.micro&lt;/code&gt;) depending on the Region.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security &amp;amp; Access:&lt;/strong&gt; Generated a new RSA &lt;code&gt;.pem&lt;/code&gt; key pair (&lt;code&gt;keypair.pem&lt;/code&gt;) for secure SSH access. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Network Inbound Rules:&lt;/strong&gt; Restricted the Security Group inbound rules to allow SSH (Port 22) traffic &lt;em&gt;strictly&lt;/em&gt; from the developer's local IP address (appending &lt;code&gt;/32&lt;/code&gt; for CIDR notation).&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frj7dh7fk9ygzskfa079b.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frj7dh7fk9ygzskfa079b.png" alt=" " width="799" height="379"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1.2 Remote SSH &amp;amp; Environment Bootstrapping
&lt;/h3&gt;

&lt;p&gt;To interact with the EC2 instance securely, we configure an SSH tunnel from the local Antigravity IDE environment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Secure the Key Pair:&lt;/strong&gt; Locally stored the &lt;code&gt;.pem&lt;/code&gt; file in a dedicated &lt;code&gt;DevOps&lt;/code&gt; directory and restricted file permissions to enforce read-only access for the current user.
    *   &lt;em&gt;Mac/Linux:&lt;/em&gt; &lt;code&gt;chmod 400 keypair.pem&lt;/code&gt;
    *   &lt;em&gt;Windows (PowerShell):&lt;/em&gt; &lt;code&gt;icacls "keypair.pem" /inheritance:r /grant:r "$($env:USERNAME):R"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSH Tunneling:&lt;/strong&gt; Utilized the Antigravity IDE Remote - SSH extension to connect to the instance using the command:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; keypair.pem ec2-user@&amp;lt;YOUR_EC2_PUBLIC_IPV4_DNS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  1.3 Toolchain Installation &amp;amp; Application Scaffolding
&lt;/h3&gt;

&lt;p&gt;Once tunneled into the EC2 instance, the environment requires specific tools to build Java applications.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Java &amp;amp; Maven:&lt;/strong&gt; &lt;br&gt;
Bootstrapped the instance by installing &lt;strong&gt;Java 8 (Amazon Corretto)&lt;/strong&gt; and &lt;strong&gt;Apache Maven 3.5.2&lt;/strong&gt; via the terminal. Export the &lt;code&gt;$JAVA_HOME&lt;/code&gt; and &lt;code&gt;$PATH&lt;/code&gt; environment variables within &lt;code&gt;~/.bashrc&lt;/code&gt; to ensure persistence across sessions.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Maven&lt;/span&gt;
wget https://archive.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz
&lt;span class="nb"&gt;sudo tar &lt;/span&gt;xzf apache-maven-3.5.2-bin.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /opt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH=/opt/apache-maven-3.5.2/bin:$PATH'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc

&lt;span class="c"&gt;#Java&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; java-1.8.0-amazon-corretto-devel
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/jvm/java-1.8.0-amazon-corretto.x86_64
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$JAVA_HOME&lt;/span&gt;/jre/bin/:&lt;span class="nv"&gt;$PATH&lt;/span&gt;

&lt;span class="c"&gt;# Verification Commands&lt;/span&gt;
java &lt;span class="nt"&gt;-version&lt;/span&gt;
mvn &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate the Web App:&lt;/strong&gt; &lt;br&gt;
Utilized Maven's &lt;code&gt;archetype:generate&lt;/code&gt; command to scaffold a standard Java web application directory structure.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn archetype:generate &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.hye.app &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hye-web-app &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-DarchetypeArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-archetype-webapp &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-DinteractiveMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Part 2: Connect a GitHub Repo with AWS
&lt;/h2&gt;

&lt;p&gt;Version control is the foundation of any CI/CD pipeline. This phase establishes the upstream repository, ensuring the web application's codebase is securely tracked and centralized before being consumed by downstream CI/CD services.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 Git Initialization &amp;amp; Upstream Connection
&lt;/h3&gt;

&lt;p&gt;To bridge the local development environment on the EC2 instance with GitHub, we initialize a local repository and establish the remote origin.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Local Git Setup:&lt;/strong&gt; &lt;br&gt;
Within the Antigravity IDE terminal (connected to the EC2 instance via SSH), navigate to the root of the newly scaffolded Maven project (&lt;code&gt;hye-web-app&lt;/code&gt;). Initialize the repository and stage the files:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;hye-web-app
git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub Repository Creation:&lt;/strong&gt; &lt;br&gt;
Navigate to GitHub and create a new private repository (e.g., &lt;code&gt;hye-web-app&lt;/code&gt;). This acts as the central source of truth for the CI/CD pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Push to Upstream:&lt;/strong&gt; &lt;br&gt;
Link the local EC2 directory to the GitHub repository and push the &lt;code&gt;master&lt;/code&gt; branch using your secure GitHub credentials (Personal Access Token):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin &lt;span class="o"&gt;[&lt;/span&gt;https://github.com/]&lt;span class="o"&gt;(&lt;/span&gt;https://github.com/&lt;span class="o"&gt;)&lt;/span&gt;&amp;lt;your-username&amp;gt;/hye-web-app.git
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; master
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;


&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcm8fb791lvifjfqc8vbf.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcm8fb791lvifjfqc8vbf.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 3: Secure Packages with CodeArtifact
&lt;/h2&gt;

&lt;p&gt;To maintain software supply chain security and ensure deterministic builds, external Maven dependencies must be proxied and cached through a secure, private repository rather than downloading them directly from the public internet during every build.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.1 CodeArtifact Repository Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Provisioning:&lt;/strong&gt; In the AWS Console, navigate to AWS CodeArtifact and create a new domain (e.g., &lt;code&gt;hye-cicd-domain&lt;/code&gt;) and a repository (e.g., &lt;code&gt;hye-cicd-codeartifact-repo&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Upstream Configuration:&lt;/strong&gt; Ensure the repository is configured with &lt;code&gt;maven-central-store&lt;/code&gt; as its upstream connection so it can successfully proxy public Java packages.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  3.2 IAM Role &amp;amp; Policy Configuration
&lt;/h3&gt;

&lt;p&gt;The EC2 instance requires explicit permissions to authenticate with CodeArtifact. We enforce least-privilege access using AWS IAM.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create IAM Policy:&lt;/strong&gt; Create a custom JSON policy (&lt;code&gt;hye-codeartifact-access-policy&lt;/code&gt;) granting token retrieval and read access:&lt;br&gt;
&lt;/p&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;"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;"codeartifact:GetAuthorizationToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"codeartifact:GetRepositoryEndpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"codeartifact:ReadFromRepository"&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;"*"&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;"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;"sts:GetServiceBearerToken"&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="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;"sts:AWSServiceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"codeartifact.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="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;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Attach to EC2:&lt;/strong&gt; Create an IAM Role (&lt;code&gt;Hye-DevOps-Instance-CodeArtifact-Role&lt;/code&gt;) with EC2 as the trusted entity, attach the policy above, and map this role to the running development EC2 instance via the EC2 console (Actions &amp;gt; Security &amp;gt; Modify IAM role).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  3.3 Maven Authentication &amp;amp; Configuration
&lt;/h3&gt;

&lt;p&gt;With IAM permissions in place, Maven must be configured to route package requests through the CodeArtifact endpoint.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate Auth Token:&lt;/strong&gt; &lt;br&gt;
In the Antigravity IDE terminal (EC2 instance), use the AWS CLI to extract a temporary CodeArtifact authorization token and export it as an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CODEARTIFACT_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;aws codeartifact get-authorization-token &lt;span class="nt"&gt;--domain&lt;/span&gt; hye-cicd-domain &lt;span class="nt"&gt;--domain-owner&lt;/span&gt; &amp;lt;YOUR_ACCOUNT_ID&amp;gt; &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;YOUR_REGION&amp;gt; &lt;span class="nt"&gt;--query&lt;/span&gt; authorizationToken &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure &lt;code&gt;settings.xml&lt;/code&gt;:&lt;/strong&gt; &lt;br&gt;
In the root of your project (&lt;code&gt;hye-web-app&lt;/code&gt;), create a &lt;code&gt;settings.xml&lt;/code&gt; file. Populate it with the CodeArtifact connection instructions (provided in the CodeArtifact console), ensuring the &lt;code&gt;&amp;lt;password&amp;gt;&lt;/code&gt; tag references the environment variable: &lt;code&gt;${env.CODEARTIFACT_AUTH_TOKEN}&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compile &amp;amp; Verify:&lt;/strong&gt; &lt;br&gt;
Execute a Maven compile command pointing to the custom settings file to force the application to download dependencies via the private CodeArtifact repository:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn compile &lt;span class="nt"&gt;-s&lt;/span&gt; settings.xml
&lt;/code&gt;&lt;/pre&gt;


&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxak2sh250h6070xywa0x.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxak2sh250h6070xywa0x.png" alt=" " width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 4: Continuous Integration with CodeBuild
&lt;/h2&gt;

&lt;p&gt;This phase automates the compilation, testing, and packaging of the web application into an immutable artifact. By utilizing AWS CodeBuild, we provision an isolated, stateless Linux container that pulls the source code, resolves dependencies securely via CodeArtifact, and compiles a deployable target.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 S3 Artifact Store Provisioning
&lt;/h3&gt;

&lt;p&gt;Before creating the build project, we need a centralized staging area to store the compiled output.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Provision S3 Bucket:&lt;/strong&gt; Navigate to the Amazon S3 console and create a new bucket (e.g., &lt;code&gt;hye-codebuild-artifact-store&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Configuration:&lt;/strong&gt; Leave all settings as default (Block all public access enabled). This bucket will serve as the secure artifact transition mechanism between the Build and Deploy stages of the pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  4.2 CodeBuild Project Initialization
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Project:&lt;/strong&gt; Navigate to AWS CodeBuild and create a new build project named &lt;code&gt;hye-cicd-codebuild-project&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Source Control Integration:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  Set the &lt;strong&gt;Source provider&lt;/strong&gt; to &lt;strong&gt;GitHub&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  Connect CodeBuild to your GitHub account using the GitHub App connection.&lt;/li&gt;
&lt;li&gt;  Select the private repository you created in Part 2 (&lt;code&gt;hye-web-app&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ytmwosv6qi5r4pyh03z.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ytmwosv6qi5r4pyh03z.png" alt=" " width="799" height="206"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98a1s7udv2c2aklvaxe8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98a1s7udv2c2aklvaxe8.png" alt=" " width="800" height="769"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F169d371chjhh6wii1epr.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F169d371chjhh6wii1epr.png" alt=" " width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Environment Settings:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  Environment image: &lt;strong&gt;Managed image&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Operating system: &lt;strong&gt;Amazon Linux&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Runtime: &lt;strong&gt;Standard&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Image: Select the latest &lt;code&gt;aws/codebuild/amazonlinux2-x86_64-standard:corretto8&lt;/code&gt; image.&lt;/li&gt;
&lt;li&gt;  Service role: Select &lt;strong&gt;New service role&lt;/strong&gt; (CodeBuild will automatically generate a least-privilege IAM role for this project).&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyupfy2rjfixo81p7flu.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyupfy2rjfixo81p7flu.png" alt=" " width="799" height="392"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fasdupitezllrv9bzeea5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fasdupitezllrv9bzeea5.png" alt=" " width="799" height="397"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2rk00r9dkadbjvh2wku.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2rk00r9dkadbjvh2wku.png" alt=" " width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4.3 IAM Role Modification (CodeArtifact Authorization)
&lt;/h3&gt;

&lt;p&gt;The CodeBuild container must securely pull Maven dependencies from our private CodeArtifact repository. We must explicitly grant CodeBuild's newly created IAM service role access to CodeArtifact.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Locate Service Role:&lt;/strong&gt; In the IAM Console, find the role automatically generated by CodeBuild (e.g., &lt;code&gt;Hye-cicd-CodeBuild-Project-Role&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Attach Policy:&lt;/strong&gt; Attach the &lt;code&gt;hye-codeartifact-access-policy&lt;/code&gt; (created in Part 3) to this role. This ensures the build container has the exact same least-privilege token retrieval permissions as our development EC2 instance.
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi17ccjxfhn4x0wis0osq.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi17ccjxfhn4x0wis0osq.png" alt=" " width="799" height="214"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4.4 Define Build Directives (&lt;code&gt;buildspec.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;AWS CodeBuild requires a declarative YAML file to execute build phases. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Buildspec:&lt;/strong&gt; In your local Antigravity IDE terminal, create a &lt;code&gt;buildspec.yml&lt;/code&gt; file in the root directory of your project.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Author Directives:&lt;/strong&gt; Define the installation, pre-build (CodeArtifact authentication), build (Maven compile), and post-build (Artifact packaging) phases:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;

&lt;span class="na"&gt;phases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runtime-versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;java&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;corretto8&lt;/span&gt;
  &lt;span class="na"&gt;pre_build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo Logging in to AWS CodeArtifact...&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain hye-cicd-domain --domain-owner &amp;lt;YOUR_ACCOUNT_ID&amp;gt; --region &amp;lt;YOUR_REGION&amp;gt; --query authorizationToken --output text`&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export CODEARTIFACT_AUTH_TOKEN&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo Build started on `date`&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mvn clean install -s settings.xml&lt;/span&gt;
  &lt;span class="na"&gt;post_build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo Build completed on `date`&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo Packaging artifacts...&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mvn package -s settings.xml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x scripts/*.sh&lt;/span&gt;
&lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;target/*.war&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;scripts/**/*&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;appspec.yml&lt;/span&gt;
  &lt;span class="na"&gt;discard-paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commit &amp;amp; Push:&lt;/strong&gt; Add, commit, and push the &lt;code&gt;buildspec.yml&lt;/code&gt; file to the GitHub &lt;code&gt;master&lt;/code&gt; branch so CodeBuild can read the execution instructions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  4.5 Build Execution &amp;amp; Artifact Verification
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Trigger Build:&lt;/strong&gt; In the AWS CodeBuild console, manually click &lt;strong&gt;Start build&lt;/strong&gt; to validate the configuration.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Monitor Logs:&lt;/strong&gt; CodeBuild will provision the container, download the source from GitHub, authenticate with CodeArtifact, and execute the Maven build. Monitor the real-time Phase Details for success.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Artifact Output:&lt;/strong&gt; Upon a successful build phase, CodeBuild extracts the compiled &lt;code&gt;.war&lt;/code&gt; file (defined in the artifacts block of the buildspec) and prepares it for downstream deployment.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgee6a9ps87svzaka4wj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgee6a9ps87svzaka4wj.png" alt=" " width="799" height="392"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 5: Deploy a Web App with CodeDeploy
&lt;/h2&gt;

&lt;p&gt;This phase provisions the live production infrastructure and automates the continuous delivery process. Instead of manually copying files and restarting services, AWS CodeDeploy will orchestrate the deployment of our compiled &lt;code&gt;.war&lt;/code&gt; artifact directly to the target web servers with zero downtime.&lt;/p&gt;
&lt;h3&gt;
  
  
  5.1 Infrastructure as Code (CloudFormation)
&lt;/h3&gt;

&lt;p&gt;To ensure our production environment is reproducible and isolated from our development environment, we will provision the target EC2 fleet using Infrastructure as Code (IaC).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Navigate to CloudFormation:&lt;/strong&gt; Open the AWS CloudFormation console and click &lt;strong&gt;Create stack&lt;/strong&gt; &amp;gt; &lt;strong&gt;With new resources (standard)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Upload Template:&lt;/strong&gt; Select &lt;strong&gt;Upload a template file&lt;/strong&gt; and upload your declarative YAML configuration file &lt;a href="https://drive.google.com/file/d/118A9SpSBxqNxu2bIJIOypJxMifUGh33V/view?usp=sharing" rel="noopener noreferrer"&gt;hye-web-app.yaml&lt;/a&gt;. This template is pre-configured to:

&lt;ul&gt;
&lt;li&gt;  Provision a production-ready Amazon Linux EC2 instance.&lt;/li&gt;
&lt;li&gt;  Automatically install the AWS CodeDeploy Agent via user data scripts.&lt;/li&gt;
&lt;li&gt;  Attach the necessary IAM Instance Profile allowing S3 read access (to fetch the artifact).&lt;/li&gt;
&lt;li&gt;  Configure Security Groups to allow inbound HTTP (Port 80) and SSH (Port 22) traffic.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Configure Stack Details:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Stack name:&lt;/strong&gt; &lt;code&gt;hye-cicd-ec2-server-stack&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;MyIP:&lt;/strong&gt; Enter your local IP address appended with &lt;code&gt;/32&lt;/code&gt; (e.g., &lt;code&gt;192.168.1.1/32&lt;/code&gt;) to secure SSH access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Execute Deployment:&lt;/strong&gt; Acknowledge the IAM resource creation capabilities and click &lt;strong&gt;Submit&lt;/strong&gt;. Wait for the stack status to reach &lt;code&gt;CREATE_COMPLETE&lt;/code&gt;.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6zd0spa8dnr3hjwpgbgg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6zd0spa8dnr3hjwpgbgg.png" alt=" " width="800" height="372"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxtub7ou7973om5cm5lni.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxtub7ou7973om5cm5lni.png" alt=" " width="800" height="297"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ufcync5hmum087zllxl.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ufcync5hmum087zllxl.png" alt=" " width="799" height="261"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5.2 CodeDeploy Orchestration Setup
&lt;/h3&gt;

&lt;p&gt;With the infrastructure running, we must configure CodeDeploy to target the new instances.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Application:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  Navigate to AWS CodeDeploy &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;Create application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Application name:&lt;/strong&gt; &lt;code&gt;hye-cicd-codedeploy-application&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Compute platform:&lt;/strong&gt; &lt;code&gt;EC2/On-premises&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftm59mekvd21xaiz035yx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftm59mekvd21xaiz035yx.png" alt=" " width="799" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Deployment Group:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  Inside the application, click &lt;strong&gt;Create deployment group&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Deployment group name:&lt;/strong&gt; &lt;code&gt;hye-cicd-codedeploy-deployment-group&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Service role:&lt;/strong&gt; Select the IAM role granting CodeDeploy access to read target instances (e.g., &lt;code&gt;Hye-cicd-CodeDeploy-Role&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F43rtkwtyv5x0k2r53gr2.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F43rtkwtyv5x0k2r53gr2.png" alt=" " width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   **Environment configuration:** Select **Amazon EC2 instances**. Use Tag keys to target the instance provisioned by CloudFormation (e.g., Key: `role`, Value: `webserver`).
*   **Agent configuration:** Select `Never` (the CloudFormation template already installed the CodeDeploy agent).
*   **Load balancer:** Uncheck 'Enable load balancing' (we are using a single instance for this architecture).
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiy0dsavphfwnohz7fcak.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiy0dsavphfwnohz7fcak.png" alt=" " width="799" height="282"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5.3 Define Deployment Directives (&lt;code&gt;appspec.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;AWS CodeDeploy relies on an AppSpec file to understand exactly where to place files and which lifecycle scripts to run during the deployment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create &lt;code&gt;appspec.yml&lt;/code&gt;:&lt;/strong&gt; In your local Antigravity IDE terminal, create an &lt;code&gt;appspec.yml&lt;/code&gt; file at the absolute root of your project directory.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Author Directives:&lt;/strong&gt; Define the OS, files destination, and the lifecycle hooks.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/target/hye-web-app.war&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/share/tomcat/webapps/&lt;/span&gt;
&lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;BeforeInstall&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scripts/stop_server.sh&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;runas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
  &lt;span class="na"&gt;ApplicationStart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scripts/start_server.sh&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;runas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Lifecycle Scripts:&lt;/strong&gt; Create a &lt;code&gt;scripts&lt;/code&gt; folder and add the referenced bash files (&lt;code&gt;stop_server.sh&lt;/code&gt; and &lt;code&gt;start_server.sh&lt;/code&gt;). These scripts instruct the target instance to stop the Tomcat web server, clear the old cache, and start it back up once the new &lt;code&gt;.war&lt;/code&gt; file is unpacked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commit &amp;amp; Push:&lt;/strong&gt; Add, commit, and push the &lt;code&gt;appspec.yml&lt;/code&gt; and &lt;code&gt;scripts/&lt;/code&gt; directory to the GitHub &lt;code&gt;master&lt;/code&gt; branch. &lt;/p&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsgw6hcud91wpv2yvbe0x.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsgw6hcud91wpv2yvbe0x.png" alt=" " width="797" height="148"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F322el0nx493xmcnxukiy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F322el0nx493xmcnxukiy.png" alt=" " width="800" height="70"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzok7qntjldbj8vdtk73o.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzok7qntjldbj8vdtk73o.png" alt=" " width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5.4 Manual Deployment Verification
&lt;/h3&gt;

&lt;p&gt;Before automating the workflow, we must verify that CodeDeploy can successfully execute the AppSpec directives using the latest S3 artifact.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Deployment:&lt;/strong&gt; In the CodeDeploy console, navigate to your deployment group and click &lt;strong&gt;Create deployment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Revision Type:&lt;/strong&gt; Select &lt;strong&gt;My application is stored in Amazon S3&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Revision Location:&lt;/strong&gt; Paste the S3 URI of the latest &lt;code&gt;.zip&lt;/code&gt; artifact compiled by CodeBuild in Part 4.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pqdcp8vov00sml66xo4.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pqdcp8vov00sml66xo4.png" alt=" " width="799" height="387"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl09q2ah79z4s0ngcfn8g.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl09q2ah79z4s0ngcfn8g.png" alt=" " width="799" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Deploy:&lt;/strong&gt; Click &lt;strong&gt;Create deployment&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Monitor Lifecycle Events:&lt;/strong&gt; CodeDeploy will execute the AppSpec hooks. Monitor the stages (&lt;code&gt;DownloadBundle&lt;/code&gt;, &lt;code&gt;BeforeInstall&lt;/code&gt;, &lt;code&gt;Install&lt;/code&gt;, &lt;code&gt;ApplicationStart&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Verify Live App:&lt;/strong&gt; Once successful, navigate to the production EC2 instance's Public IPv4 DNS in your browser. You should see the Java web application rendering live.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbgromoxc3u298uk4q762.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbgromoxc3u298uk4q762.png" alt=" " width="800" height="385"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1evll7dkj9mdzvblp4wm.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1evll7dkj9mdzvblp4wm.png" alt=" " width="800" height="377"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fapl4wv30qlbd55wz7fhb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fapl4wv30qlbd55wz7fhb.png" alt=" " width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 6: Build a CI/CD Pipeline with AWS
&lt;/h2&gt;

&lt;p&gt;The final phase unites all previously configured components (GitHub, CodeArtifact, CodeBuild, CodeDeploy) into a single, fully automated, event-driven orchestration engine using AWS CodePipeline. &lt;/p&gt;
&lt;h3&gt;
  
  
  6.1 Pipeline Initialization &amp;amp; State Management
&lt;/h3&gt;

&lt;p&gt;When creating the pipeline, specific execution and authentication parameters must be set to ensure deployment consistency and security.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create Pipeline:&lt;/strong&gt; Navigate to AWS CodePipeline and select &lt;strong&gt;Create pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Pipeline Settings:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pipeline category:&lt;/strong&gt; &lt;code&gt;Buid custom pipeline&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frsm6r0slbs0n30bvh930.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frsm6r0slbs0n30bvh930.png" alt=" " width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   **Pipeline name:** `hye-cicd-codepipeline`
*   **Execution mode:** `Superseded`. This mode ensures that newer pipeline executions automatically cancel and override in-flight runs, guaranteeing only the absolute latest commit is deployed.
*   **Service role:** Select **New service role** to generate least-privilege IAM permissions.
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj5n39otq2xqm6ujdzl6w.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj5n39otq2xqm6ujdzl6w.png" alt=" " width="799" height="376"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  6.2 Stage 1: Source Control Integration
&lt;/h3&gt;

&lt;p&gt;The Source stage defines the trigger mechanism, monitoring the specified Git branch for commit events via webhooks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Source Provider:&lt;/strong&gt; Select &lt;strong&gt;GitHub (Version 2)&lt;/strong&gt; and authorize the AWS Connector for GitHub.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Repository &amp;amp; Branch:&lt;/strong&gt; Select the &lt;code&gt;hye-web-app&lt;/code&gt; repository and the &lt;code&gt;master&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Output Artifact:&lt;/strong&gt; Set the output artifact format to CodePipeline default (&lt;code&gt;SourceArtifact&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Webhook events:&lt;/strong&gt; Enable the &lt;code&gt;Start your pipeline on push and pull request events&lt;/code&gt; check-box.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ew21w2yeqstn0v76126.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ew21w2yeqstn0v76126.png" alt=" " width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  6.3 Stage 2: Continuous Integration (Build)
&lt;/h3&gt;

&lt;p&gt;The Build stage is responsible for transforming raw source code into a deployable package.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Build Provider:&lt;/strong&gt; Select &lt;strong&gt;AWS CodeBuild&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Region &amp;amp; Project:&lt;/strong&gt; Select your region and the &lt;code&gt;hye-cicd-codebuild-project&lt;/code&gt; CodeBuild project created in Part 4.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Input &amp;amp; Output:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Input artifacts:&lt;/strong&gt; Map to &lt;code&gt;SourceArtifact&lt;/code&gt; (the ZIP file generated by Stage 1).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output artifacts:&lt;/strong&gt; Define a new namespace, &lt;code&gt;BuildArtifact&lt;/code&gt; (this represents the compiled &lt;code&gt;.war&lt;/code&gt; file).&lt;/li&gt;
&lt;/ul&gt;
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo1ybnvnb5vuxiqdig2h.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo1ybnvnb5vuxiqdig2h.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  6.4 Stage 3: Continuous Deployment (Deploy)
&lt;/h3&gt;

&lt;p&gt;The final stage provisions the compiled application artifact to the live EC2 infrastructure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Deploy Provider:&lt;/strong&gt; Select &lt;strong&gt;AWS CodeDeploy&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Application &amp;amp; Group:&lt;/strong&gt; Select the &lt;code&gt;hye-cicd-codedeploy-application&lt;/code&gt; application and the &lt;code&gt;hye-cicd-codedeploy-deployment-group&lt;/code&gt; deployment group created in Part 5.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Input Artifact:&lt;/strong&gt; Map to &lt;code&gt;BuildArtifact&lt;/code&gt; (the compiled package generated by Stage 2).&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ypc90e234vnjaareiuw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ypc90e234vnjaareiuw.png" alt=" " width="799" height="371"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Execution, Testing, &amp;amp; Validation
&lt;/h2&gt;

&lt;p&gt;To prove the pipeline's end-to-end automation, a live code change must be pushed to the upstream repository.&lt;/p&gt;
&lt;h3&gt;
  
  
  7.1 Triggering the Pipeline via Code Change
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Open the application source code in your local Antigravity IDE terminal.&lt;/li&gt;
&lt;li&gt; Navigate to the primary web page file: &lt;code&gt;src/main/webapp/index.jsp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inject a visible UI change, for example:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If you see this lines, that means your latest changes are automatically deployed into production by CodePipeline!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If you see this lines, that means your latest changes are automatically deployed into production by CodePipeline for the second time!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;That's how easy it can get.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commit and push the code to the tracked branch:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Update index.jsp to verify automated CI/CD deployment."&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  7.2 Monitoring Automated Orchestration
&lt;/h3&gt;

&lt;p&gt;Immediately upon pushing the code, navigate to the AWS CodePipeline console. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The GitHub webhook will have dispatched a payload, initiating a new execution graph.&lt;/li&gt;
&lt;li&gt;  The commit message under the Source stage will reflect your recent &lt;code&gt;git commit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Monitor cross-stage transitions as CodeBuild compiles the WAR package and CodeDeploy initiates the in-place deployment to the EC2 fleet.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3a4wk2kq032nkesgjpqw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3a4wk2kq032nkesgjpqw.png" alt=" " width="799" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Live Production Verification
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Locate the Public IPv4 DNS of your production EC2 instance.&lt;/li&gt;
&lt;li&gt; Navigate to this address in a standard web browser. &lt;/li&gt;
&lt;li&gt; The updated application revision (featuring the newly added HTML paragraph tag) will render live, validating zero-touch, zero-downtime release orchestration.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7x6a7uieiwb47lmoge77.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7x6a7uieiwb47lmoge77.png" alt=" " width="798" height="148"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Disaster Recovery: Automated Rollback Validation
&lt;/h2&gt;

&lt;p&gt;A critical component of a robust CI/CD pipeline is the ability to recover from bad deployments instantly. To validate disaster recovery protocols, a manual rollback is initiated to simulate an emergency reversion.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.1 Executing the Rollback
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; In the CodePipeline console, locate the &lt;strong&gt;Deploy&lt;/strong&gt; stage.&lt;/li&gt;
&lt;li&gt; Click the options menu (three dots) on the Deploy stage card and select &lt;strong&gt;Start rollback&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Select the previous stable execution ID from the dropdown menu and confirm the rollback.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzr2p59bpu3vqw6q7axzg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzr2p59bpu3vqw6q7axzg.png" alt=" " width="799" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8.2 Validating State Isolation and Recovery
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Result:&lt;/strong&gt; CodeDeploy successfully restores the last known good deployment artifact to the EC2 instance. Navigating to the EC2 instance's Public IPv4 DNS confirms the web page displays the previous version (the test paragraph tag is removed).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;State Isolation Proof:&lt;/strong&gt; The &lt;strong&gt;Source&lt;/strong&gt; and &lt;strong&gt;Build&lt;/strong&gt; stages are entirely unaffected. They retain the latest Git commit SHA and message, while &lt;em&gt;only&lt;/em&gt; the &lt;strong&gt;Deploy&lt;/strong&gt; stage reverts its execution state to the previous stable revision. This proves that CodeDeploy rollback actions are isolated to the deployment environment and do not destructively invalidate S3 build artifacts or overwrite the upstream GitHub repository state.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jfg0kba9nypo1p53mrs.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jfg0kba9nypo1p53mrs.png" alt=" " width="799" height="275"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0vyo6cnbh0q808vt3up.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0vyo6cnbh0q808vt3up.png" alt=" " width="800" height="252"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91th40o86eh4p3fethr1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91th40o86eh4p3fethr1.png" alt=" " width="800" height="108"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Congratulations! You now have a fully functional end-to-end CI/CD pipeline for a Java web application hosted on AWS!
&lt;/h1&gt;

</description>
      <category>cicd</category>
      <category>github</category>
      <category>aws</category>
      <category>automation</category>
    </item>
    <item>
      <title>Deploy Backend with Kubernetes</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Sun, 02 Aug 2026 14:32:05 +0000</pubDate>
      <link>https://dev.to/maven_h/deploy-backend-with-kubernetes-155g</link>
      <guid>https://dev.to/maven_h/deploy-backend-with-kubernetes-155g</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;In this project, I will deploy a containerized backend application to an Amazon EKS cluster because it provides a highly scalable, managed orchestration environment. This involves building a Docker image, pushing it to Amazon ECR, and defining the infrastructure state using Kubernetes Deployment and Service manifests applied via &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools and concepts
&lt;/h3&gt;

&lt;p&gt;Key tools utilized include &lt;code&gt;eksctl&lt;/code&gt; for Amazon EKS cluster provisioning, Docker for containerization, Amazon ECR for secure image storage, and &lt;code&gt;kubectl&lt;/code&gt; for resource management. Core concepts demonstrated are Kubernetes orchestration, declarative state management via YAML manifests (Deployments and Services), immutable container deployments, and internal cluster networking using NodePort configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project reflection
&lt;/h3&gt;

&lt;p&gt;This project took me approximately 90 minutes to complete. My favourite part was executing the kubectl apply commands to orchestrate the immutable backend container and establish NodePort routing across the distributed EKS worker nodes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Set Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kubernetes cluster
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;To set up today's project, I launched a Kubernetes cluster&lt;/strong&gt; using the &lt;code&gt;eksctl&lt;/code&gt; CLI on a provisioned EC2 instance. &lt;strong&gt;The cluster's role in this deployment is&lt;/strong&gt; to serve as a managed orchestration control plane via Amazon EKS, automating the scheduling, scaling, and networking of the containerized backend across a 3-node &lt;code&gt;t3.micro&lt;/code&gt; compute group.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdllyeqkuayj6stlvc1sl.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdllyeqkuayj6stlvc1sl.png" alt=" " width="800" height="345"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error above showing `eksctl` not installed.
To install it, I ran; 
`curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/eksctl /usr/local/bin
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Backend code
&lt;/h3&gt;

&lt;p&gt;I retrieved backend code by executing a &lt;code&gt;git clone&lt;/code&gt; command on the provisioned EC2 instance to pull the remote &lt;code&gt;nextwork-flask-backend&lt;/code&gt; repository. Pulling code is essential to this deployment because the repository contains the Python application source files and the &lt;code&gt;Dockerfile&lt;/code&gt; required to compile the standardized, immutable container image that Kubernetes will orchestrate.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwugpcukbmbp97fim62dy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwugpcukbmbp97fim62dy.png" alt=" " width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Container image
&lt;/h3&gt;

&lt;p&gt;Once I cloned the backend code, I built a container image because it creates a standardized, immutable package containing the application source and all necessary dependencies. Without an image, it would be difficult for Kubernetes to reliably provision identical, scalable container replicas across the cluster nodes, as the orchestrator requires a centralized, consistent artifact for deployment.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbx2votimbz6dtgpx39f9.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbx2votimbz6dtgpx39f9.png" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also pushed the container image to a container registry, which is Amazon Elastic Container Registry (ECR), a fully managed, secure AWS repository for container artifacts. ECR facilitates scaling for my deployment because its native IAM integration with Amazon EKS enables the Kubernetes control plane to rapidly authenticate and pull immutable image replicas across distributed worker nodes on demand.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6rzaww5155qm49n3i4c.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6rzaww5155qm49n3i4c.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Manifest files
&lt;/h2&gt;

&lt;p&gt;Kubernetes manifests are declarative YAML configuration files that define the desired state of cluster resources, specifying parameters such as container images, replica counts, and resource allocations. Manifests are helpful because they automate application orchestration, enabling reproducible, consistent deployments while eliminating the operational overhead and error-prone nature of manual container configuration.&lt;/p&gt;

&lt;p&gt;A Deployment manifest manages the desired state of application replicas by automating the creation, scaling, and rolling updates of container groups across the cluster. The container image URL in my Deployment manifest tells Kubernetes the exact Amazon ECR registry location to authenticate against and pull the immutable Docker artifact from when provisioning new pods.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw7bhfo96ksddtvr967vd.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw7bhfo96ksddtvr967vd.png" alt=" " width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Service resource exposes deployed applications to network traffic by establishing stable routing rules across dynamic pod replicas. My Service manifest sets up a NodePort configuration, instructing the Kubernetes control plane to map external node port requests to internal target port 8080 on pods bearing the &lt;code&gt;app:nextwork-flask-backend&lt;/code&gt; label.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjwf2vlqz4nu8vi2ss0pg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjwf2vlqz4nu8vi2ss0pg.png" alt=" " width="799" height="275"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Backend Deployment!
&lt;/h2&gt;

&lt;p&gt;To deploy my backend application, I updated the local kubeconfig using the AWS CLI to authenticate with the Amazon EKS control plane. Next, I executed the &lt;code&gt;kubectl apply&lt;/code&gt; command on the Deployment and Service YAML manifests to schedule the container replicas and establish NodePort routing rules across the cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  kubectl
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;kubectl&lt;/code&gt; is the primary command-line interface for interacting with the Kubernetes control plane. I need this tool to authenticate with the EKS cluster and apply the declarative YAML manifests that orchestrate the application deployment. I can't use &lt;code&gt;eksctl&lt;/code&gt; for the job because it is specifically designed for provisioning and managing the underlying EKS infrastructure, not for scheduling workloads or managing internal Kubernetes resources.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-eks4_6cfb382f2" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-eks4_6cfb382f2" alt="Image" width="1919" height="512"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying Deployment
&lt;/h2&gt;

&lt;p&gt;My extension for this project is to use the EKS console to verify the deployment status, inspect the provisioned node groups, and confirm that the backend pods are running successfully. I had to set up IAM access policies because AWS IAM permissions do not automatically grant authorization within the internal Kubernetes RBAC system. I set up access by executing the &lt;code&gt;eksctl create iamidentitymapping&lt;/code&gt; command to map my IAM User ARN to the Kubernetes &lt;code&gt;system:masters&lt;/code&gt; group.&lt;/p&gt;

&lt;p&gt;Once I gained access into my cluster's nodes, I discovered pods running inside each node. Pods are the smallest deployable units in Kubernetes, designed to bundle one or more containers together to function as a cohesive workload. Containers in a pod share the same network address space and underlying storage resources, which enables efficient inter-process communication and localized data synchronization.&lt;/p&gt;

&lt;p&gt;The EKS console shows you the events for each pod, where I could see the control plane's sequence of operations, including internal IP assignment, image retrieval from Amazon ECR, and container initialization. This validated that the backend application was successfully provisioned, actively running, and accessible within the internal cluster network.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-eks4_3b391f873" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-eks4_3b391f873" alt="Image" width="1919" height="917"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 Thank you for reading thus far. Next project will be a DevOps Challenge.
&lt;/h2&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>backend</category>
      <category>docker</category>
    </item>
    <item>
      <title>Build a Three-Tier Web App</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Fri, 24 Jul 2026 14:41:44 +0000</pubDate>
      <link>https://dev.to/maven_h/build-a-three-tier-web-app-1bjd</link>
      <guid>https://dev.to/maven_h/build-a-three-tier-web-app-1bjd</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;In this project, I will demonstrate how to architect and deploy a serverless three-tier application by hosting static web assets in Amazon S3 delivered globally via Amazon CloudFront, executing business logic using AWS Lambda routed through Amazon API Gateway, and managing persistence with Amazon DynamoDB.&lt;/p&gt;

&lt;p&gt;I'm doing this project to demonstrate end-to-end integration of serverless AWS components, cross-origin resource sharing (CORS) configurations, least-privilege IAM policies, and cloud troubleshooting practices.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqtccgi3gauw3mtsaxjy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqtccgi3gauw3mtsaxjy.png" alt=" " width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools and concepts
&lt;/h3&gt;

&lt;p&gt;Services I used were Amazon S3, Amazon CloudFront, AWS Lambda, Amazon API Gateway, and Amazon DynamoDB. Key concepts I learnt include Lambda functions, serverless three-tier architecture, API REST routing, Cross-Origin Resource Sharing (CORS) configurations, Origin Access Control (OAC), and NoSQL partition key database management.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project reflection
&lt;/h3&gt;

&lt;p&gt;This project took me approximately 150 minutes. The most challenging part was debugging the Cross-Origin Resource Sharing (CORS) restrictions between the CloudFront distribution and the API Gateway. It was most rewarding to successfully deploy a decoupled, serverless three-tier architecture while enforcing secure HTTP routing and least-privilege IAM policies.&lt;/p&gt;

&lt;p&gt;I chose to do this project today because validating secure, decoupled serverless architectures and enforcing strict IAM policies perfectly aligns with my core focus on cloud engineering and cybersecurity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Presentation tier
&lt;/h2&gt;

&lt;p&gt;For the presentation tier, I will set up an Amazon S3 bucket to store static frontend assets (&lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;style.css&lt;/code&gt;, &lt;code&gt;script.js&lt;/code&gt;) and an Amazon CloudFront CDN distribution configured with Origin Access Control (OAC) because this provides scalable, low-latency global web content delivery while securely restricting direct public access to the underlying storage bucket.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj1brwj06934ep6nsm48p.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj1brwj06934ep6nsm48p.png" alt=" " width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I accessed my delivered website by requesting the domain name assigned to the CloudFront distribution via HTTPS, which securely retrieved and served the cached static frontend files from edge locations using Origin Access Control permissions to query the origin S3 bucket.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_3a4b5c6d" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_3a4b5c6d" alt="Image" width="1919" height="1004"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Logic tier
&lt;/h2&gt;

&lt;p&gt;For the logic tier, I will set up AWS Lambda functions and an Amazon API Gateway REST API because API Gateway acts as the secure entry point for HTTP requests from the frontend, routing them to Lambda to execute serverless backend business logic and process application data without managing underlying server infrastructure.&lt;/p&gt;

&lt;p&gt;The Lambda function retrieves data by parsing the &lt;code&gt;userId&lt;/code&gt; query parameter from the incoming HTTP request event and using the AWS SDK DynamoDB Document Client (&lt;code&gt;GetCommand&lt;/code&gt;) to execute a read request against the target DynamoDB table (&lt;code&gt;UserData&lt;/code&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7k0tu97jph8xlw5444xh.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7k0tu97jph8xlw5444xh.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Data tier
&lt;/h2&gt;

&lt;p&gt;For the data tier, I will set up an Amazon DynamoDB NoSQL table named &lt;code&gt;UserData&lt;/code&gt; with a primary partition key of &lt;code&gt;userId&lt;/code&gt; because it provides a fully managed, high-performance, and schemaless storage layer for persistent application data that scales seamlessly without server management overhead.&lt;/p&gt;

&lt;p&gt;The partition key for my DynamoDB table is &lt;code&gt;userId&lt;/code&gt;, which means DynamoDB uses this unique attribute value to hash and route data items across underlying physical partitions, enabling efficient, single-digit millisecond key-value lookups and persistent storage for application user records.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_u1v2w3x4" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_u1v2w3x4" alt="Image" width="1919" height="922"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Logic and Data tier
&lt;/h2&gt;

&lt;p&gt;Once all three layers of my three-tier architecture are set up, the next step is to integrate the presentation layer with the logic tier by updating &lt;code&gt;script.js&lt;/code&gt; to target the API Gateway Invoke URL because this establishes end-to-end communication, allowing the frontend to trigger Lambda functions and retrieve DynamoDB data.&lt;/p&gt;

&lt;p&gt;To test my API, I appended the &lt;code&gt;/users?userId=1&lt;/code&gt; path and query string parameter directly to the API Gateway prod stage Invoke URL and executed the HTTP GET request in a web browser. The results were successful, returning a 200 OK HTTP response containing the JSON payload from the DynamoDB table.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_a112c3d5" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_a112c3d5" alt="Image" width="1919" height="991"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Console Errors
&lt;/h2&gt;

&lt;p&gt;The error in my distributed site was because the frontend &lt;code&gt;script.js&lt;/code&gt; file contained an unresolved placeholder (&lt;code&gt;[YOUR-PROD-API-URL]&lt;/code&gt;) instead of the active Amazon API Gateway Invoke URL, preventing the client browser from successfully routing HTTP requests to the backend logic tier.&lt;/p&gt;

&lt;p&gt;To resolve the error, I updated script.js by replacing the &lt;code&gt;[YOUR-PROD-API-URL]&lt;/code&gt; placeholder with the active API Gateway prod stage Invoke URL. I then reuploaded it into S3 because CloudFront caches and serves frontend assets from this origin bucket, and this update ensures client browsers receive the correct endpoint to properly route HTTP requests to the backend logic tier.&lt;/p&gt;

&lt;p&gt;I ran into a second error after updating script.js. This was an error with Cross-Origin Resource Sharing (CORS) because the Amazon API Gateway was not configured to explicitly allow HTTP requests from the CloudFront distribution domain, causing the client browser to block the cross-origin request.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_a1b2c3d5" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_a1b2c3d5" alt="Image" width="1919" height="1016"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Resolving CORS Errors
&lt;/h2&gt;

&lt;p&gt;To resolve the CORS error, I first enabled CORS on the Amazon API Gateway by selecting both &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;OPTIONS&lt;/code&gt; under &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt;. Next, I set the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; value to my specific CloudFront distribution domain name. Finally, I redeployed the REST API to the production stage to ensure the new security configuration took effect.&lt;/p&gt;

&lt;p&gt;I also updated my Lambda function because the Amazon API Gateway uses Lambda Proxy Integration, requiring the backend function itself to explicitly construct and return the full HTTP response, including security headers. The changes I made were injecting the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header configured with the CloudFront distribution domain into the JSON response objects across all status codes to securely permit cross-origin browser requests.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_1qthryj2" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_1qthryj2" alt="Image" width="1918" height="917"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Fixed Solution
&lt;/h2&gt;

&lt;p&gt;I verified the fixed connection between API Gateway and CloudFront by reloading the CloudFront distribution domain in the client browser and validating that the frontend successfully executed the cross-origin HTTP GET request to retrieve and render the JSON payload from the DynamoDB table.&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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_2b3c4d5e" 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/http%3A%2F%2Fnextwork.ai%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-compute-threetier_2b3c4d5e" alt="Image" width="1919" height="956"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🤝This is the only project in the series on &lt;strong&gt;Three tier Web App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next series will be on &lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>aws</category>
      <category>serverless</category>
      <category>dynamodb</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Build a Security Monitoring System</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Thu, 11 Jun 2026 14:27:33 +0000</pubDate>
      <link>https://dev.to/maven_h/build-a-security-monitoring-system-ei6</link>
      <guid>https://dev.to/maven_h/build-a-security-monitoring-system-ei6</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;In this project, I am building an AWS Security Monitoring System to demonstrate how cloud-native tools can be configured to detect, alert, and respond to threats. My goal is to show how services like CloudWatch, GuardDuty, and Security Hub can strengthen visibility and resilience in a cloud environment. I am also doing this project to demonstrate hands-on experience in cloud security, reflecting on my strengths and weaknesses, and investing in my personal growth.&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%2Fht4ucm4o59hiirtv8est.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%2Fht4ucm4o59hiirtv8est.png" alt=" " width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools and concepts
&lt;/h3&gt;

&lt;p&gt;Services I used were &lt;strong&gt;AWS Secrets Manager, CloudTrail, CloudWatch Logs, CloudWatch Metrics &amp;amp; Alarms, and SNS&lt;/strong&gt;. Key concepts I learnt include how &lt;strong&gt;CloudTrail records API activity for auditing&lt;/strong&gt;, how &lt;strong&gt;CloudWatch Logs and Metrics enable monitoring and alerting&lt;/strong&gt;, the role of &lt;strong&gt;thresholds in alarms&lt;/strong&gt; to trigger notifications, the importance of &lt;strong&gt;SNS topics and confirmed subscriptions&lt;/strong&gt; for reliable message delivery, and how these services integrate to create a &lt;strong&gt;security monitoring pipeline&lt;/strong&gt; that detects, logs, and alerts on secret access events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project reflection
&lt;/h3&gt;

&lt;p&gt;This project took me approximately &lt;strong&gt;two hours&lt;/strong&gt;. The most challenging part was &lt;strong&gt;tuning the CloudWatch alarm threshold&lt;/strong&gt; setting it to &lt;strong&gt;1&lt;/strong&gt; didn’t reliably detect a single secret access, so I adjusted it to &lt;strong&gt;0.01&lt;/strong&gt; to trigger as expected. It was most rewarding to see the full pipeline work end‑to‑end: &lt;strong&gt;CloudTrail&lt;/strong&gt; logged the access, &lt;strong&gt;CloudWatch&lt;/strong&gt; recorded the metric and fired the alarm, and &lt;strong&gt;SNS&lt;/strong&gt; delivered the email notification.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a Secret
&lt;/h2&gt;

&lt;p&gt;Secrets Manager is an AWS cloud service that securely stores and manages sensitive data like passwords, API keys, and database credentials, enabling applications to access them safely at runtime with encryption, access control, and automatic rotation instead of hardcoding secrets in code.&lt;/p&gt;

&lt;p&gt;To set up for my project, I created a secret called &lt;strong&gt;&lt;code&gt;TopSecretInfo&lt;/code&gt;&lt;/strong&gt; that contains the the key and value needed by my AWS security monitoring system.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_o5p6q7r8" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_o5p6q7r8" alt="Image" width="1919" height="935"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Set Up CloudTrail
&lt;/h2&gt;

&lt;p&gt;CloudTrail is an AWS service that records and monitors all API calls and account activity, providing visibility into actions taken by users, roles, and services for auditing and security purposes. I set up a trail to &lt;strong&gt;capture these events and deliver them to a designated S3 bucket&lt;/strong&gt;, ensuring that logs are securely stored, easily accessible for analysis, and available for compliance or incident investigation.&lt;/p&gt;

&lt;p&gt;CloudTrail events include &lt;strong&gt;management events&lt;/strong&gt; that log control‑plane actions like creating users or modifying security groups, &lt;strong&gt;data events&lt;/strong&gt; that capture resource‑level activity such as reading or writing S3 objects or invoking Lambda functions, &lt;strong&gt;network activity events&lt;/strong&gt; that track API calls through VPC endpoints, and &lt;strong&gt;insights events&lt;/strong&gt; that detect anomalies or unusual patterns, together providing full visibility into AWS account activity for auditing and security monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read vs Write Activity
&lt;/h3&gt;

&lt;p&gt;Read API activity involves retrieving or viewing information without making changes, such as listing users, describing resources, or getting object data, while Write API activity involves creating, modifying, or deleting resources, such as launching instances, updating configurations, or deleting objects. For this project, we need to capture both Read and Write activities to ensure complete visibility into account actions, since monitoring only one type would leave gaps in detecting potential security issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying CloudTrail
&lt;/h2&gt;

&lt;p&gt;I retrieved the secret in two ways: first through the &lt;strong&gt;AWS Management Console&lt;/strong&gt;, where I opened the secret directly to view its stored values, and second using the &lt;strong&gt;AWS CLI&lt;/strong&gt;, where I ran a command to programmatically fetch the secret, ensuring both manual and automated access methods were tested for logging and monitoring.&lt;/p&gt;

&lt;p&gt;To analyze my CloudTrail events, I visited the &lt;strong&gt;CloudTrail console&lt;/strong&gt; and reviewed the event history; I found entries showing both the retrieval of my secret from Secrets Manager and the corresponding API activity recorded with details like the user identity, time, and access method; this tells me that CloudTrail is successfully capturing and logging sensitive operations, providing the visibility and accountability needed for auditing and security monitoring.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_s8t9u0v1" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_s8t9u0v1" alt="Image" width="1919" height="927"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  CloudWatch Metrics
&lt;/h2&gt;

&lt;p&gt;CloudWatch Logs is an AWS service that collects, stores, and manages log data from resources and applications, making it possible to monitor activity in real time. It’s important for monitoring because it centralizes logs, enables the creation of metrics and alarms, and provides visibility into system behavior, which helps detect issues, track security events, and ensure compliance.&lt;/p&gt;

&lt;p&gt;CloudTrail’s Event History is useful for quickly viewing recent account activity and auditing specific API calls, while CloudWatch Logs are better for continuous monitoring and analysis because they store detailed log data, allow you to create metrics and alarms, and provide real‑time visibility into patterns or anomalies across your AWS environment.&lt;/p&gt;

&lt;p&gt;A CloudWatch metric is a measurement that tracks specific activity or performance in your AWS environment. When setting up a metric, the &lt;strong&gt;metric value&lt;/strong&gt; represents the actual data point being recorded, such as the number of times a secret was accessed. The &lt;strong&gt;default value&lt;/strong&gt; is used when no data is reported for a given period, ensuring the metric still has a baseline reading so alerts or dashboards remain consistent even if no events occur.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_a9b0c1d2" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_a9b0c1d2" alt="Image" width="1919" height="923"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  CloudWatch Alarm
&lt;/h2&gt;

&lt;p&gt;A CloudWatch alarm is a monitoring tool that watches a specific metric and triggers an action when the metric crosses a defined threshold. I set my CloudWatch alarm threshold to &lt;strong&gt;1&lt;/strong&gt; on the &lt;code&gt;SecretIsAccessed&lt;/code&gt; metric so the alarm will trigger whenever a secret is accessed at least once, ensuring I immediately receive a notification through SNS whenever sensitive data is retrieved.&lt;/p&gt;

&lt;p&gt;I created an SNS topic along the way. An SNS topic is a &lt;strong&gt;communication channel that groups multiple subscribers together so messages can be delivered to all of them at once&lt;/strong&gt;. My SNS topic is set up to send notifications whenever the CloudWatch alarm detects secret access, and since I subscribed my email address to it, I’ll immediately receive an alert in my inbox whenever the alarm is triggered.&lt;/p&gt;

&lt;p&gt;AWS requires email confirmation for SNS subscriptions because it ensures that the recipient explicitly agrees to receive notifications, preventing accidental or unauthorized subscriptions. This helps prevent spam, protects users from unwanted messages, and guarantees that alerts only go to verified and consenting email addresses.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_fsdghstt" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_fsdghstt" alt="Image" width="1916" height="961"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting Notification Errors
&lt;/h2&gt;

&lt;p&gt;To test my monitoring system, I deliberately retrieved the secret value again to trigger the CloudWatch alarm. The results were mixed, while the event was successfully logged in CloudTrail, I didn’t receive the expected notification in my inbox. This showed that the alarm was firing but the SNS subscription or email delivery wasn’t configured correctly. The test highlighted the importance of end-to-end validation, ensuring not just that events are captured but also that alerts reach the intended recipients.&lt;/p&gt;

&lt;p&gt;When troubleshooting the notification issues I checked five areas: first, I verified that the CloudWatch alarm was actually firing when the secret was retrieved. Second, I confirmed that the alarm was correctly linked to the SNS topic. Third, I checked that my email subscription to the SNS topic was active and confirmed. Fourth, I reviewed IAM permissions to ensure CloudWatch and SNS could publish and deliver messages. Finally, I inspected spam filters and delivery settings to rule out blocked or misrouted emails.&lt;/p&gt;

&lt;p&gt;I initially didn't receive an email because the alarm used &lt;strong&gt;Average&lt;/strong&gt; (and a long period), so a single &lt;code&gt;1&lt;/code&gt; was diluted or treated as missing; metric/dimension mismatch or an unconfirmed SNS subscription can also block alerts.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Key solution:&lt;/strong&gt; switch the alarm to &lt;strong&gt;Sum&lt;/strong&gt; or &lt;strong&gt;Maximum&lt;/strong&gt;, use a short period (e.g., 60s) with &lt;strong&gt;EvaluationPeriods=1&lt;/strong&gt;, verify metric/dimensions, set missing‑data handling, and confirm the SNS email subscription.&lt;/p&gt;




&lt;h2&gt;
  
  
  Success!
&lt;/h2&gt;

&lt;p&gt;To validate my monitoring system, I checked the &lt;strong&gt;CloudWatch alarm&lt;/strong&gt; tied to the &lt;code&gt;SecretIsAccessed&lt;/code&gt; metric after retrieving a secret, and I confirmed that the alarm was triggered. I then verified that the &lt;strong&gt;SNS topic&lt;/strong&gt; delivered an email notification to my subscribed address. I received the alert exactly as expected, which tells me that the monitoring pipeline from CloudTrail logging to CloudWatch metrics and alarms, through to SNS notifications is working correctly and will reliably inform me of secret access events.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_ageraergearge" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_ageraergearge" alt="Image" width="1835" height="950"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparing CloudWatch with CloudTrail Notifications
&lt;/h2&gt;

&lt;p&gt;I updated my CloudTrail configurations because I needed to capture additional management events across all regions, ensure logs were encrypted with KMS keys, and integrate with CloudWatch for real-time alerts. This allowed me to enhance security monitoring, meet compliance standards, and reduce blind spots in activity tracking.&lt;/p&gt;

&lt;p&gt;After enabling CloudTrail SNS notifications, my inbox quickly filled with hundreds of event emails per day. In terms of usefulness, I thought the notifications were initially helpful for confirming that logging was working, but the sheer volume made them impractical for daily monitoring. Instead, I realized it was better to route these events into CloudWatch or a centralized logging system, where I could filter, aggregate, and set alerts for only the truly critical activities.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_d7e8f9g0" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-monitoring_d7e8f9g0" alt="Image" width="1919" height="957"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End-to-End Validation is Crucial:&lt;/strong&gt; Building a security pipeline isn't just about turning services on. Testing the flow from the initial event (accessing the secret) all the way to the final alert (receiving the email) is the only way to guarantee your system works when a real threat occurs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signal vs. Noise matters:&lt;/strong&gt; Raw CloudTrail notifications can quickly overwhelm your inbox with hundreds of events. Routing these logs through CloudWatch allows you to filter, aggregate, and set alarms only for critical activity, saving you from alert fatigue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics Require Tuning:&lt;/strong&gt; Default configurations don't always catch single events. Changing metric math from Average to Sum or Maximum, shortening the evaluation period, and properly handling missing data are essential steps to ensure single occurrences (like reading a secret) trigger an immediate alarm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete Visibility Requires Both Read and Write Logging:&lt;/strong&gt; Monitoring only "Write" activities leaves massive security gaps. Capturing "Read" events is equally critical, especially when protecting sensitive data like passwords and API keys stored in Secrets Manager.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security is a Pipeline:&lt;/strong&gt; No single AWS tool provides complete security on its own. It requires a layered integration: CloudTrail for auditing, CloudWatch for monitoring and alerting, and SNS for reliable delivery to the right people.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🤝This is the end of the series on Security.&lt;/p&gt;

&lt;p&gt;Next series will be &lt;strong&gt;Three-Tier Architecture&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>security</category>
      <category>aws</category>
    </item>
    <item>
      <title>Secure Secrets with Secrets Manager</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Fri, 29 May 2026 07:46:07 +0000</pubDate>
      <link>https://dev.to/maven_h/secure-secrets-with-secrets-manager-2mcg</link>
      <guid>https://dev.to/maven_h/secure-secrets-with-secrets-manager-2mcg</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;In this project, I will demonstrate how to identify and remove hard‑coded credentials from a configuration file, create and store those credentials in &lt;strong&gt;AWS Secrets Manager&lt;/strong&gt;, update the application to fetch secrets at runtime, configure least‑privilege &lt;strong&gt;IAM&lt;/strong&gt; access so the app can retrieve the secret, and rotate the secret while verifying the application continues to authenticate; I’m doing this project to show practical Secrets Manager workflows, secure secret handling that prevents committing credentials to source control, how to design minimal IAM policies, and how to test secret rotation and deployment changes so I can confidently deploy applications without exposing sensitive data.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_r7s8t9u0" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_r7s8t9u0" alt="Image" width="1919" height="1079"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Tools and concepts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Services I used were&lt;/strong&gt; AWS Secrets Manager, AWS IAM, Amazon S3, the &lt;code&gt;boto3&lt;/code&gt; AWS SDK for Python, GitHub (with secret scanning), Git (interactive rebase and history rewrite), and Python tooling (virtualenv, FastAPI, uvicorn, &lt;code&gt;requirements.txt&lt;/code&gt;); &lt;strong&gt;Key concepts demonstrated are:&lt;/strong&gt; never hardcode secrets, use a managed secrets store to centralize and encrypt credentials, apply least‑privilege IAM policies, automating secret rotation, practice Git hygiene and removing secrets from history when leaks occur, fetch secrets at runtime instead of storing them in config files, and follow local‑dev best practices to isolate dependencies and keep sensitive data out of source control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project reflection
&lt;/h3&gt;

&lt;p&gt;This project took me approximately an hour. The most challenging part was safely removing hardcoded credentials from the repository history and configuring Secrets Manager and IAM so the app could retrieve secrets at runtime. It was most rewarding to replace insecure config files with a managed secrets workflow and verify the app could access S3 using least‑privilege credentials.&lt;/p&gt;

&lt;p&gt;I chose to do this project today because I wanted to demonstrate practical skills in securing application credentials and show I can move a demo app from insecure config files to a managed‑secrets workflow; something that would make learning with NextWork even better is more hands‑on, bite‑sized labs with step‑by‑step remediation (including sample IAM policies, Secrets Manager rotation examples, and CI/CD checks) plus instant feedback or badges to validate each completed task.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hardcoding credentials
&lt;/h2&gt;

&lt;p&gt;In this project, a sample web app is exposing AWS credentials and other secrets directly in source files &lt;code&gt;config.py&lt;/code&gt;. Hardcoding credentials is unsafe because anyone with repo access or attackers who find the repo can steal keys to impersonate the app, access or delete data, run costly resources, or escalate privileges; secrets also persist in Git history. Use a managed secrets store, least‑privilege IAM, and rotate/revoke compromised keys.&lt;/p&gt;

&lt;p&gt;I put placeholder credentials and config values into &lt;code&gt;config.py&lt;/code&gt; to simulate an insecure app for the exercise: example &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;, an AWS_REGION, a database connection string stub (e.g., &lt;code&gt;DB_HOST&lt;/code&gt;, &lt;code&gt;DB_USER&lt;/code&gt;, &lt;code&gt;DB_PASS&lt;/code&gt;), and a &lt;code&gt;DEBUG=True&lt;/code&gt; flag. These are &lt;strong&gt;fake/example values&lt;/strong&gt; so you can reproduce the risk of hard‑coding without exposing real secrets; the goal is to demonstrate detection, removal, and replacement with a secure store (Secrets Manager), then rotate and revoke any real keys if they were used.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_j2k3l4m5" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_j2k3l4m5" alt="Image" width="1919" height="1079"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Using my own AWS credentials
&lt;/h2&gt;

&lt;p&gt;As an extension for this project, I also decided to install &lt;code&gt;fastapi==0.115.8&lt;/code&gt; to build a lightweight and efficient web API, &lt;code&gt;uvicorn==0.34.0&lt;/code&gt; as the ASGI server to run FastAPI applications, &lt;code&gt;boto3==1.36.20&lt;/code&gt; to interact with AWS services like Secrets Manager, and &lt;code&gt;python-multipart==0.0.5&lt;/code&gt; to handle file uploads in API requests—all essential for securely managing secrets while building and deploying the application.&lt;/p&gt;

&lt;p&gt;When I first ran the app, I ran into an error because the AWS Access Key ID I provided was invalid, meaning it didn’t match any credentials in AWS’s records. This happens when the key is mistyped, deleted, or not properly configured, and it prevents the app from authenticating to AWS to list the S3 buckets.&lt;/p&gt;

&lt;p&gt;To resolve the &lt;code&gt;InvalidAccessKeyId&lt;/code&gt; error, I updated the &lt;code&gt;config.py&lt;/code&gt; file to include the correct AWS credentials. It now contains the proper &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;, &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;, and &lt;code&gt;AWS_REGION&lt;/code&gt; values, ensuring the app can authenticate with AWS and successfully list the S3 buckets.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_wghjteykut" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_wghjteykut" alt="Image" width="1919" height="1010"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Pushing Insecure Code to GitHub
&lt;/h2&gt;

&lt;p&gt;Once I updated the web app code with credentials, I forked the repository because I wanted my own independent copy under my GitHub account where I could make changes without affecting the original project. A fork is different from a clone because a fork stays linked to the original repository on GitHub, allowing me to propose changes back through pull requests, while a clone is just a local copy on my machine with no direct connection to the original.&lt;/p&gt;

&lt;p&gt;To connect my local repository to the forked one, I first realized &lt;code&gt;git add&lt;/code&gt; was pointing to the original repo I didn’t have permission to write to because I initially cloned directly to my IDE. So I used &lt;code&gt;git remote set-url origin https://github.com/hyelngtil/nextwork-security-secretsmanager.git&lt;/code&gt; to update the remote to my fork. Then I ran &lt;code&gt;git remote -v&lt;/code&gt; to confirm the change, followed by &lt;code&gt;git add&lt;/code&gt; and &lt;code&gt;git commit&lt;/code&gt; to stage and save my updates locally. Finally, &lt;code&gt;git push&lt;/code&gt; to upload those commits to my forked repository on GitHub.&lt;/p&gt;

&lt;p&gt;GitHub blocked my push because there were hardcoded secrets in my &lt;code&gt;config.py&lt;/code&gt; file, which triggered its secret scanning protection. This is a good security feature because it prevents sensitive credentials from being exposed publicly, protecting both my AWS account and anyone who might accidentally use those leaked keys.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_o2p3q4r5" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_o2p3q4r5" alt="Image" width="1919" height="1079"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Secrets Manager
&lt;/h2&gt;

&lt;p&gt;Secrets Manager is an AWS service designed to securely store, manage, and automatically rotate sensitive information like credentials, API keys, and database passwords. I'm using it to store my AWS access keys so they aren’t hardcoded in my application files, which keeps them protected and retrievable only when needed. Other common use cases include managing database connection strings, third‑party API tokens, and encryption keys, all while ensuring secrets remain encrypted and access is tightly controlled.&lt;/p&gt;

&lt;p&gt;Another feature in Secrets Manager is &lt;strong&gt;secret rotation&lt;/strong&gt;, which means the service can automatically update and replace stored credentials (like AWS keys or database passwords) on a schedule without manual intervention. It's useful in situations where long‑lived credentials could become a security risk, such as database connections or API tokens, because rotation reduces exposure time and ensures that applications always use fresh, valid secrets.&lt;/p&gt;

&lt;p&gt;Secrets Manager provides sample code in various languages, like Python, Java, and JavaScript, to show developers how to retrieve secrets directly from their applications. This is helpful because it makes integration straightforward, reduces the risk of exposing credentials in code, and ensures that applications can securely access secrets without manual handling.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_h2i3j4k5" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_h2i3j4k5" alt="Image" width="1919" height="938"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Updating the web app code
&lt;/h2&gt;

&lt;p&gt;I updated the &lt;code&gt;config.py&lt;/code&gt; file to retrieve credentials directly from AWS Secrets Manager instead of hardcoding them. The &lt;code&gt;get_secret()&lt;/code&gt; function will connect to Secrets Manager, fetch the stored secret containing my AWS access keys, and return those values securely at runtime. This way, the application uses credentials managed by AWS rather than exposing them in the source code.&lt;/p&gt;

&lt;p&gt;I also added code to &lt;code&gt;config.py&lt;/code&gt; to extract the individual values—like &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;, &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;, and &lt;code&gt;AWS_REGION&lt;/code&gt; from the JSON secret retrieved by &lt;code&gt;get_secret()&lt;/code&gt;. This is important because the application needs those specific fields to authenticate with AWS services, and by parsing them out of the secret object, the app can use them securely at runtime without ever exposing the raw credentials in the source code.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_v0w1x2y3" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_v0w1x2y3" alt="Image" width="1915" height="1079"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Resetting the repository
&lt;/h2&gt;

&lt;p&gt;Git reset is a Git command that lets you move your current branch pointer to a different commit and optionally change the state of your working directory and staging area. I used it to roll back the repository to a clean state before the commit that contained my hardcoded secrets. This was necessary because those secrets had already been staged and committed, and I needed to remove them from the commit history so they wouldn’t be pushed to GitHub or exposed publicly.&lt;/p&gt;

&lt;p&gt;A merge conflict occurred during rebasing because rewriting the branch history left the working tree and the new base out of sync and both versions modified the same lines in &lt;code&gt;config.py&lt;/code&gt;. I resolved it by checking &lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git diff&lt;/code&gt;, manually editing &lt;code&gt;config.py&lt;/code&gt; to keep the Secrets Manager changes and remove the hardcoded keys, staging and committing the fix, and then updating the remote so the exposed credentials were removed.&lt;/p&gt;

&lt;p&gt;Once the merge conflict was resolved, I verified that my hardcoded credentials were out of sight in the repository by checking the files with &lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git diff&lt;/code&gt; to confirm no sensitive lines remained, reviewing the commit history with &lt;code&gt;git log&lt;/code&gt; to ensure the secrets were removed from past commits, and inspecting the remote repository on GitHub to confirm that only the updated &lt;code&gt;config.py&lt;/code&gt; with Secrets Manager integration was present.&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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_t5u6v7w8" 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/http%3A%2F%2Flearn.nextwork.org%2Fsincere_amber_glamorous_sphinx%2Fuploads%2Faws-security-secretsmanager_t5u6v7w8" alt="Image" width="1919" height="1079"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Zero-Trust Secret Handling: Refactored a FastAPI web application to remediate architectural vulnerabilities caused by hard-coded credentials in config.py. Implemented dynamic, runtime retrieval of AWS access keys and database strings via AWS Secrets Manager, mitigating the risk of source control credential leaks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Git History Sanitization: Utilized git reset and interactive rebasing to purge compromised commits from the Git metadata. Successfully resolved merge conflicts to establish strict Git hygiene and bypass GitHub Secret Scanning blockers during remote pushes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Least-Privilege &amp;amp; Automation: Designed minimal AWS IAM policies to grant the application restrictive access to secrets, while successfully configuring and validating automated secret rotation loops.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤝Next in the series builds on this, which will be &lt;strong&gt;Build a Security Monitoring System&lt;/strong&gt;
&lt;/h2&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Threat Detection with GuardDuty</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Thu, 02 Apr 2026 07:46:22 +0000</pubDate>
      <link>https://dev.to/maven_h/threat-detection-with-guardduty-1odj</link>
      <guid>https://dev.to/maven_h/threat-detection-with-guardduty-1odj</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;I built a hands-on project where I wore two hats; attacker and defender, to demonstrate how SQL injection and command injection can escalate into a full cloud credential breach, and how AWS GuardDuty surfaces those behaviors in near real-time.&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%2F0e9n8pla2v4ghnt3j9v4.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%2F0e9n8pla2v4ghnt3j9v4.png" alt=" " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools &amp;amp; Concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Services used:&lt;/strong&gt; Amazon GuardDuty, Amazon EC2, Amazon S3, AWS CloudFormation, AWS CloudShell, IAM Roles, Amazon CloudFront, VPC and networking components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key concepts:&lt;/strong&gt; Threat detection with GuardDuty, SQL injection, command injection, Instance Metadata Service (IMDS) and credential exfiltration, simulating attacker behavior with CloudShell, S3 Malware Protection, and incident investigation workflows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This project took approximately 1 hour. The most challenging part was tuning GuardDuty detections and IAM role permissions. The most rewarding moment was watching real threat findings surface during testing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;I deployed a &lt;strong&gt;CloudFormation template&lt;/strong&gt; that provisions three functional pillars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web App Infrastructure&lt;/strong&gt; — an Amazon EC2 instance inside a dedicated VPC (not the default), with its own Subnet, Internet Gateway, and Elastic Load Balancer for isolated networking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Storage&lt;/strong&gt; — a bucket containing a protected &lt;code&gt;important-information.txt&lt;/code&gt; file that the EC2 instance is authorized to access, simulating sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GuardDuty Monitoring&lt;/strong&gt; — automatically enabled as a security sentinel to monitor resources and detect threats.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The web app deployed is &lt;strong&gt;OWASP Juice Shop&lt;/strong&gt;, a deliberately vulnerable application. My objective as the simulated attacker: gain access to the EC2 web server and read the sensitive file in S3.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is GuardDuty?
&lt;/h3&gt;

&lt;p&gt;GuardDuty is an &lt;strong&gt;intelligent threat detection service&lt;/strong&gt; that continuously monitors AWS accounts and workloads for malicious activity. In this project, it analyzes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC Flow Logs&lt;/li&gt;
&lt;li&gt;CloudTrail management events&lt;/li&gt;
&lt;li&gt;S3 data events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It uses machine learning and integrated threat intelligence to detect indicators of compromise — credential exfiltration, communication with known malicious IPs, and more. Findings trigger an automated remediation workflow via &lt;strong&gt;Amazon EventBridge&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%2Fxy3n721sxf7zbx10v3if.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%2Fxy3n721sxf7zbx10v3if.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Attack Phase 1: SQL Injection
&lt;/h2&gt;

&lt;p&gt;SQL injection involves injecting malicious SQL code into an input field to manipulate backend database queries. It's dangerous because it allows attackers to bypass authentication and access sensitive data without authorization.&lt;/p&gt;

&lt;p&gt;I entered the following into the email field of the Juice Shop login page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="s1"&gt;' or 1=1;--
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1=1&lt;/code&gt; is always true, so the database validates the login regardless of the password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--&lt;/code&gt; comments out the rest of the original query, neutralizing the intended security check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: administrative access to the OWASP Juice Shop portal — no password required.&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%2Fioby4bkpekfy3kgxn7sc.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%2Fioby4bkpekfy3kgxn7sc.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Attack Phase 2: Command Injection
&lt;/h2&gt;

&lt;p&gt;Command injection is a vulnerability where an attacker executes arbitrary OS commands via a vulnerable application. Juice Shop is vulnerable because it fails to sanitize user input before passing it to a system shell.&lt;/p&gt;

&lt;p&gt;I exploited the search field by injecting a &lt;strong&gt;Node.js payload&lt;/strong&gt; that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Queried the &lt;strong&gt;Instance Metadata Service (IMDSv2)&lt;/strong&gt; to retrieve a session token.&lt;/li&gt;
&lt;li&gt;Identified the &lt;strong&gt;IAM Role&lt;/strong&gt; attached to the EC2 instance.&lt;/li&gt;
&lt;li&gt;Fetched temporary security credentials — &lt;code&gt;AccessKeyId&lt;/code&gt;, &lt;code&gt;SecretAccessKey&lt;/code&gt;, and &lt;code&gt;SessionToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Piped the JSON output to a publicly accessible path:
&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="err"&gt;/frontend/dist/frontend/assets/public/credentials.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple application flaw became a significant cloud infrastructure breach.&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%2F7etli677751zp3kzrhi0.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%2F7etli677751zp3kzrhi0.png" alt=" " width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Attack Verification
&lt;/h2&gt;

&lt;p&gt;I navigated to the public URL at &lt;code&gt;/assets/public/credentials.json&lt;/code&gt; and confirmed the exfiltrated credentials — a structured JSON object containing the stolen IAM temporary credentials tied to the EC2 instance's role.&lt;/p&gt;

&lt;p&gt;This proved the attacker now had everything needed to authenticate as a legitimate internal service and begin compromising additional AWS resources, including the S3 bucket.&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%2F8m1szajsoaodcmrd204c.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%2F8m1szajsoaodcmrd204c.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Using CloudShell to Escalate the Attack
&lt;/h2&gt;

&lt;p&gt;CloudShell provided a pre-authenticated environment with the AWS CLI pre-installed — perfect for simulating an attacker operating from an external machine using stolen credentials.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download the exfiltrated credentials file&lt;/span&gt;
wget &amp;lt;public-url&amp;gt;/assets/public/credentials.json

&lt;span class="c"&gt;# Extract the credential values&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;credentials.json | jq &lt;span class="s1"&gt;'.AccessKeyId, .SecretAccessKey, .SessionToken'&lt;/span&gt;

&lt;span class="c"&gt;# Configure a new AWS CLI profile called "stolen"&lt;/span&gt;
aws configure &lt;span class="nt"&gt;--profile&lt;/span&gt; stolen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;stolen&lt;/code&gt; profile isolated the "hacker" identity from the default CloudShell credentials. I could now simulate unauthorized S3 access — the exact behavior GuardDuty would flag as anomalous.&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%2F3xudoc1l7ujbu5ane6vn.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%2F3xudoc1l7ujbu5ane6vn.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  GuardDuty's Findings
&lt;/h2&gt;

&lt;p&gt;Within &lt;strong&gt;15 minutes&lt;/strong&gt; of executing the attack, GuardDuty generated a finding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS
Severity: HIGH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this means:&lt;/strong&gt; GuardDuty detected that IAM credentials were exfiltrated and then used &lt;em&gt;inside&lt;/em&gt; the AWS environment — indicating a likely credential compromise and unauthorized lateral movement within the account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it detected it:&lt;/strong&gt;&lt;br&gt;
GuardDuty models normal AWS behavior and flags deviations. It correlates telemetry from CloudTrail, VPC Flow Logs, and DNS logs to spot unusual patterns — atypical API calls, credential use from unexpected sources, sudden internal data access, or reconnaissance activity.&lt;/p&gt;

&lt;p&gt;The detailed finding reported that credentials for the EC2 instance role were used from a &lt;strong&gt;remote AWS account&lt;/strong&gt;, confirming the simulated exfiltration scenario.&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%2F6j38j8w47c86pl6zq64t.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%2F6j38j8w47c86pl6zq64t.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  S3 Malware Protection
&lt;/h2&gt;

&lt;p&gt;To test GuardDuty's Malware Protection for S3, I uploaded the standard &lt;strong&gt;EICAR anti-malware test file&lt;/strong&gt; — a harmless string that antivirus products are configured to recognize as a test signature.&lt;/p&gt;

&lt;p&gt;GuardDuty instantly triggered a security alert, confirming that Malware Protection detected the uploaded object and generated a finding indicating potential malware.&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%2Fhwrx57h76v0iknbx1qut.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%2Fhwrx57h76v0iknbx1qut.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A single unsanitized input field can escalate from a login bypass to full cloud credential theft.&lt;/li&gt;
&lt;li&gt;IMDS is a high-value target; restricting it with &lt;strong&gt;IMDSv2&lt;/strong&gt; and tight IAM policies is critical.&lt;/li&gt;
&lt;li&gt;GuardDuty's anomaly detection is effective, it flagged the credential misuse within 15 minutes with no manual configuration beyond enabling the service.&lt;/li&gt;
&lt;li&gt;Simulating attacks in a controlled lab environment is one of the best ways to build intuition for both offensive techniques and defensive tooling.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🤝Next in the series builds on this, which will be "Secure Secrets with Secrets Manager"&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloudnative</category>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>Encrypt Data with AWS KMS</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Sun, 15 Mar 2026 11:17:31 +0000</pubDate>
      <link>https://dev.to/maven_h/encrypt-data-with-aws-kms-4fdb</link>
      <guid>https://dev.to/maven_h/encrypt-data-with-aws-kms-4fdb</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;p&gt;In this project, I will demonstrate how to create AWS KMS encryption keys, use them to encrypt a DynamoDB table, add and retrieve data to verify the encryption, observe how AWS blocks unauthorized access, and grant a user the necessary encryption permission. The goal is to show end‑to‑end data protection in AWS by provisioning keys, applying encryption to a live database, validating that only authorized principals can read or write the data, and confirming that key policies and &lt;code&gt;IAM controls&lt;/code&gt; effectively prevent unauthorized access.&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%2Faw7k9q31cm1gka4uj5qq.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%2Faw7k9q31cm1gka4uj5qq.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools and concepts
&lt;/h2&gt;

&lt;p&gt;I used AWS KMS to create and manage a customer‑managed key, Amazon DynamoDB to store and encrypt table data, and IAM to create a test user and attach scoped policies. I worked in the AWS console to edit key policies, add key users, and verify access from an incognito session.&lt;/p&gt;

&lt;p&gt;I learned about encryption at rest, that KMS key policies are the ultimate authority, and how to enforce least privilege by separating DynamoDB permissions from KMS decrypt permissions. I practiced using grants for temporary access, testing permissions, and documenting changes for auditability and rollback.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project reflection
&lt;/h2&gt;

&lt;p&gt;This project took me less an hour to complete, including setup, testing, and documentation. It was rewarding to see least‑privilege controls work in practice: the test user initially received access denied errors, then, after a narrowly scoped policy change, could decrypt the DynamoDB items, and I captured the steps and evidence for an auditable, repeatable workflow.&lt;/p&gt;

&lt;p&gt;I chose to do this project today because I wanted hands‑on experience with real AWS security controls, creating a customer‑managed KMS key, attaching it to a DynamoDB table, and testing least‑privilege in practice. Working through the console and verifying access as a restricted test user helped me connect theory to operational tasks I’ll face as a junior cloud engineer and gave me confidence in key policy mechanics and auditable workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Encryption and KMS
&lt;/h2&gt;

&lt;p&gt;Encryption is the process of converting plaintext into an unreadable format (ciphertext) using mathematical algorithms so that unauthorized parties cannot understand the data. &lt;/p&gt;

&lt;p&gt;Companies and developers do this to protect sensitive data at rest and in transit, prevent data breaches, satisfy legal and regulatory obligations, and preserve customer trust by ensuring confidentiality and integrity. &lt;/p&gt;

&lt;p&gt;Encryption keys are secret values used by encryption algorithms to lock (encrypt) and unlock (decrypt) data; proper key management (storage, rotation, access control, and auditing) is essential because weak key handling defeats encryption. &lt;/p&gt;

&lt;p&gt;AWS KMS is a fully managed AWS service that creates, stores, and controls cryptographic keys, enforces key policies, integrates with other AWS services, and logs key usage for auditing; key management systems are important because they protect the secrets that secure your data, enforce least‑privilege access, provide auditable trails for compliance, simplify key rotation and lifecycle operations, and reduce the operational risk and complexity of managing encryption securely.&lt;/p&gt;

&lt;p&gt;Encryption keys are broadly categorized as &lt;code&gt;symmetric&lt;/code&gt; (one secret used for both encryption and decryption) and &lt;code&gt;asymmetric&lt;/code&gt; (a public/private key pair where the public key encrypts and the private key decrypts); I set up a symmetric key because symmetric keys are the recommended and most efficient choice for encrypting data at rest in AWS services like DynamoDB, they offer better performance for bulk data operations, integrate seamlessly with AWS KMS and service‑side encryption, simplify access control and key lifecycle management, and keep the sensitive key material protected inside KMS while still allowing authorized AWS principals to read and write encrypted table data.&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%2Fl78i9303m5fz0bjk2fti.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%2Fl78i9303m5fz0bjk2fti.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Encrypting Data
&lt;/h2&gt;

&lt;p&gt;My encryption key will safeguard data in DynamoDB, which is a fully managed, serverless NoSQL database that stores items as key‑value or document records, delivers single‑digit millisecond performance at scale, supports transactions and global replication, and integrates with AWS KMS for server‑side encryption; by attaching a customer‑managed symmetric KMS key to the table, storage and backups are encrypted at rest, access is controlled through key policies and IAM permissions, and every use of the key is logged for auditability so only authorized principals can decrypt and read the plaintext.&lt;/p&gt;

&lt;p&gt;The different encryption options in DynamoDB include &lt;code&gt;AWS owned keys&lt;/code&gt; (fully managed by AWS with no customer control), &lt;code&gt;AWS managed KMS keys&lt;/code&gt; (service‑managed CMKs that AWS creates and rotates but still surface usage in CloudTrail), and &lt;code&gt;customer‑managed KMS keys&lt;/code&gt; (CMKs you create and control in AWS KMS).&lt;br&gt;
Their differences are based on who controls the key material and lifecycle, how much policy and access control you can enforce, the granularity of audit and rotation capabilities, and how quickly you can revoke or disable access.&lt;br&gt;
I selected a &lt;code&gt;customer‑managed symmetric KMS key&lt;/code&gt; because it gives me full policy control, immediate revocation and rotation options, detailed auditability, and the performance and seamless integration needed for encrypting DynamoDB table data.&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%2Fyq9k7gj9xn8zh7k0pppn.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%2Fyq9k7gj9xn8zh7k0pppn.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Visibility
&lt;/h2&gt;

&lt;p&gt;Rather than controlling who has access to the key, KMS manages user permissions by requiring explicit, key‑level authorization through a key policy (the primary control), and by evaluating IAM policies, grants, and any explicit denies before allowing cryptographic operations such as Encrypt, Decrypt, ReEncrypt, GenerateDataKey, or DescribeKey. This means no principal has any KMS key permissions unless the key policy or an allowed IAM policy/grant gives them those permissions.&lt;/p&gt;

&lt;p&gt;Despite encrypting my DynamoDB table, I could still see the table’s items because DynamoDB’s server‑side encryption with KMS is transparent to authorized clients: AWS encrypts data at rest and stores ciphertext, but when an IAM principal or service with the necessary permissions reads an item, DynamoDB requests KMS to decrypt the data and returns plaintext to the caller, so applications and users who hold the right IAM/KMS permissions see normal, readable items; this protects storage, snapshots, and backups from anyone who cannot obtain KMS decrypt rights, while if you need ciphertext visible to clients you must use client‑side encryption (where the application holds the keys) rather than KMS server‑side encryption.&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%2F03og7f7tf2ww7hqub7wl.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%2F03og7f7tf2ww7hqub7wl.png" alt=" " width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Denying Access
&lt;/h2&gt;

&lt;p&gt;I configured a new IAM user named &lt;code&gt;nextwork-kms-user&lt;/code&gt; to act as a test account for DynamoDB work; I attached the &lt;code&gt;AmazonDynamoDBFullAccess&lt;/code&gt; managed policy so the user can fully interact with DynamoDB and saved the login credentials from the Retrieve password page, but I did not grant any permissions to my KMS key (no KMS actions or key policy access), ensuring the user cannot manage or decrypt encrypted data.&lt;/p&gt;

&lt;p&gt;After accessing the DynamoDB table as the test user, I encountered an error when attempting to view the encrypted item attributes because the test user lacked permissions to use the KMS key (the console returned an access denied / missing &lt;code&gt;kms:Decrypt&lt;/code&gt; message). This confirmed that attaching AmazonDynamoDBFullAccess alone does not permit reading encrypted data and that explicit KMS key permissions are required to decrypt and view those items, validating the principle of least privilege.&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%2Frmm81yn0bonmg43ta8za.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%2Frmm81yn0bonmg43ta8za.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Granting Access
&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%2Ft5rujd1nyodxyvvbx78v.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%2Ft5rujd1nyodxyvvbx78v.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To let my test user use the encryption key, I added maven-kms-user as a key user in the KMS console so the principal can perform cryptographic operations; my key's policy was updated in the policy view to include a narrowly scoped statement granting that user &lt;code&gt;Encrypt&lt;/code&gt;, &lt;code&gt;Decrypt&lt;/code&gt;, &lt;code&gt;ReEncrypt&lt;/code&gt;, &lt;code&gt;GenerateDataKey&lt;/code&gt;, and &lt;code&gt;DescribeKey&lt;/code&gt; on the key (targeted to the user’s ARN) while explicitly omitting any key‑management actions so the user can decrypt and encrypt data but cannot manage or change the key.&lt;br&gt;
Using the test user, I retried accessing the DynamoDB table and refreshed the Items view; I observed the previously encrypted attributes now displayed in plaintext and successful &lt;code&gt;GetItem&lt;/code&gt;/&lt;code&gt;Scan&lt;/code&gt; operations without any KMS access‑denied errors, which confirmed that adding the user to the key policy (granting &lt;code&gt;kms:Decrypt&lt;/code&gt; and related use actions) allowed the test user to decrypt and view the encrypted data while still not granting key management permissions.&lt;/p&gt;

&lt;p&gt;Encryption protects data by making it unreadable without keys, while access control restricts who can request or retrieve that data; use encryption when you need protection against compromised storage or cross‑boundary exposure, and combine it with access controls, IAM, network controls, and logging to enforce defense in depth&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%2Flviywarg0g6zm6vugjnw.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%2Flviywarg0g6zm6vugjnw.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🤝Next in the series builds on this, which will be "Threat Detection with Amazon GuardDuty"&lt;/p&gt;




</description>
      <category>security</category>
      <category>aws</category>
      <category>database</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Query Data with DynamoDB</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Thu, 05 Mar 2026 17:02:13 +0000</pubDate>
      <link>https://dev.to/maven_h/query-data-with-dynamodb-33ci</link>
      <guid>https://dev.to/maven_h/query-data-with-dynamodb-33ci</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Amazon DynamoDB?
&lt;/h3&gt;

&lt;p&gt;Amazon DynamoDB is a fully managed, serverless NoSQL database service from AWS that provides fast, predictable performance and scales automatically. It is useful because it eliminates the need to manage servers, supports both key‑value and document data models, and ensures single‑digit millisecond response times even at massive scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I used Amazon DynamoDB in this project
&lt;/h3&gt;

&lt;p&gt;In today’s project, I used Amazon DynamoDB to practice querying and updating data across tables in a way that keeps everything consistent. I started by running &lt;code&gt;get-item&lt;/code&gt; commands to retrieve specific records using partition keys and projection expressions, which allowed me to pull back only the attributes I needed. Then I explored how related tables can be updated together by running a transaction with &lt;code&gt;transact-write-items&lt;/code&gt;, which let me insert a new comment into one table while simultaneously updating a counter in another. This showed me how DynamoDB ensures atomicity, both operations succeed or fail together making it really useful for handling connected data across multiple tables without risking mismatched updates.&lt;/p&gt;

&lt;p&gt;One thing I didn’t expect in this project is how seamlessly DynamoDB handled transactions across multiple tables. I thought working with related data in separate tables would require a lot of manual coordination, but using &lt;code&gt;transact-write-items&lt;/code&gt; made it surprisingly straightforward to insert a new record in one table while simultaneously updating another. It was eye‑opening to see how DynamoDB guarantees atomicity, either both operations succeed or neither does which really simplifies keeping related data consistent. This step showed me that DynamoDB isn’t just about speed and scalability, but also about reliability when managing complex relationships.&lt;/p&gt;

&lt;p&gt;This project took me through the full cycle of working with DynamoDB from retrieving specific items with "get-item" and "projection expressions", to exploring how tables can be related, and finally running a transaction that updated two tables at once. It wasn’t just about learning commands; it was about seeing how DynamoDB ensures consistency and reliability when handling connected data&lt;/p&gt;




&lt;h3&gt;
  
  
  Querying DynamoDB Tables
&lt;/h3&gt;

&lt;p&gt;A partition key is the primary attribute DynamoDB uses to distribute and retrieve data across its storage partitions. Every item in a DynamoDB table must include a partition key, and items with the same partition key value are grouped together. This key determines where the data is stored internally and is essential for efficient queries, since DynamoDB can quickly locate items based on that key rather than scanning the entire table.&lt;br&gt;
A sort key is the secondary attribute in a DynamoDB table’s primary key schema that works alongside the partition key to uniquely identify items. While the partition key determines which partition the data belongs to, the sort key organizes items within that partition. This means multiple items can share the same partition key but be distinguished by different sort key values. Sort keys also enable powerful query patterns, such as retrieving items in a range (e.g., all comments after a certain date) or ordering results by the sort 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%2Fmhje6zf9yzbvbunfevly.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%2Fmhje6zf9yzbvbunfevly.png" alt=" " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Limits of Using DynamoDB
&lt;/h3&gt;

&lt;p&gt;I ran into an error when I queried for items in the Comment table without providing a value for the partition key Id. This was because DynamoDB requires the partition key filter to be specified in every query, without it, the system doesn’t know which partition to look in, so the console flagged the input as invalid. In other words, the query failed because the partition key field was left empty, and DynamoDB cannot execute a query unless the full key schema is respected.&lt;br&gt;
Insights we could extract from our Comment table include the ability to see which posts attract the most engagement, track how often specific users contribute comments, and identify time-based activity patterns such as peak commenting hours or days. We can also observe relationships between posts and their associated comments, giving us a clear picture of community interaction at a structural level.&lt;/p&gt;

&lt;p&gt;Insights we can’t easily extract from the Comment table include deeper qualitative analysis, such as the sentiment or tone of comments, trending topics across multiple posts, or demographic-based engagement patterns. DynamoDB stores structured attributes but doesn’t analyze meaning or allow complex joins across tables, so extracting these kinds of insights would require additional tools or data sources.&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%2Fww7djla08q9jj8y31nbr.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%2Fww7djla08q9jj8y31nbr.png" alt=" " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Running Queries with CLI
&lt;/h3&gt;

&lt;p&gt;A query I ran in CloudShell was &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;aws dynamodb get-item \&lt;br&gt;
    --table-name ContentCatalog \&lt;br&gt;
    --key '{"Id":{"N":"202"}}' \&lt;br&gt;
    --projection-expression "Title, ContentType, Services" \&lt;br&gt;
    --return-consumed-capacity TOTAL&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This query will fetch the item in the ContentCatalog table with the partition key Id equal to 202, but instead of returning the entire record, DynamoDB will only return the attributes I specified in the projection expression — Title, ContentType, and Services. Alongside those values, the response will also include a Consumed-Capacity block that shows how many read capacity units (RCUs) were used, giving me both the filtered item data and a usage report in one result.&lt;/p&gt;

&lt;p&gt;Query options I could add to my query affect how DynamoDB returns the data and what additional information I get back. Specifically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;--consistent-read&lt;br&gt;
Ensures I always get the most up-to-date version of the item, rather than a possibly stale copy from a replicated node.&lt;/p&gt;

&lt;p&gt;--projection-expression&lt;br&gt;
Lets me specify which attributes to return, so instead of the full record I only get the fields I care about (Title, ContentType, and Services).&lt;/p&gt;

&lt;p&gt;--return-consumed-capacity TOTAL&lt;br&gt;
Adds a usage report to the response, showing how many read capacity units were consumed by the query.&lt;/p&gt;
&lt;/blockquote&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%2Fq8hgnldisxm4mem3v9i2.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%2Fq8hgnldisxm4mem3v9i2.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Transactions
&lt;/h3&gt;

&lt;p&gt;A transaction is a coordinated set of operations in DynamoDB that are executed together so they either all succeed or all fail. Based on the surrounding page content, the idea is that when you need to update related data across multiple tables or items, you can group those changes into a single transaction. DynamoDB then guarantees atomicity: if one part of the transaction cannot be completed, none of the changes are applied. This ensures consistency and prevents situations where one table is updated but another is left behind, keeping your data reliable and synchronized across different parts of your application.&lt;/p&gt;

&lt;p&gt;I ran a transaction using the &lt;code&gt;aws dynamodb transact-write-items&lt;/code&gt; command with a client request token called &lt;code&gt;TRANSACTION1&lt;/code&gt;. This transaction did two things: first, it added a new item into the "Comment" table with details such as the event name, the date and time of the comment, the comment text, and the user who posted it. Second, it updated the "Forum" table by incrementing the &lt;code&gt;Comments&lt;/code&gt; attribute for the &lt;code&gt;Events&lt;/code&gt; item. By grouping these two operations together in a single transaction, DynamoDB ensured that both changes either succeeded or failed as one unit, keeping the data consistent across the related tables.&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%2Fh0n8nnbzed4i9xpcbifj.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%2Fh0n8nnbzed4i9xpcbifj.png" alt=" " width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🤝This is the end of this Series.&lt;br&gt;
Next Series will be &lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>nosql</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Load Data into a DynamoDB Table</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Mon, 02 Feb 2026 22:20:35 +0000</pubDate>
      <link>https://dev.to/maven_h/load-data-into-adynamodb-table-ko0</link>
      <guid>https://dev.to/maven_h/load-data-into-adynamodb-table-ko0</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Amazon DynamoDB?
&lt;/h3&gt;

&lt;p&gt;DynamoDB is useful because it combines fast performance, flexible data modeling, and effortless scaling, making it a strong choice for modern applications that need to handle large amounts of varied data reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I used Amazon DynamoDB in this project
&lt;/h3&gt;

&lt;p&gt;In today's project, I used Amazon DynamoDB to create tables, load diverse data like projects and videos into the ContentCatalog, and then view and update those items, because DynamoDB’s flexible schema allowed me to store different&lt;br&gt;
types of content side by side while still retrieving them quickly with partition keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  One thing I didn't expect in this project was...
&lt;/h3&gt;

&lt;p&gt;One thing I didn't expect in this project is how straightforward it was to set up and run DynamoDB compared to relational databases like RDS or Aurora, because DynamoDB doesn’t require configuring servers, managing connections,&lt;br&gt;
or defining rigid schemas, it just lets you create a table and start loading items right away.&lt;/p&gt;

&lt;p&gt;This project took me about an hour, taking me through the full cycle of working with Amazon DynamoDB, creating tables, loading diverse data like projects and videos, and then viewing and updating items, because it was designed to show&lt;br&gt;
how DynamoDB’s flexibility and speed make it easier to manage different types of content compared to traditional relational databases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a DynamoDB table
&lt;/h2&gt;

&lt;p&gt;DynamoDB tables organize data using items, which are records made up of &lt;strong&gt;attributes&lt;/strong&gt; that describe details about each item; unlike relational databases, items don’t need to share the same attributes, giving DynamoDB a flexible way to store varied information in one table.&lt;/p&gt;

&lt;p&gt;An attribute is a single piece of data that describes an item in DynamoDB, for example, if the item is a student record, attributes could include the student’s name, age, or number of projects completed. Unlike traditional relational databases where every row must share the same set of columns, DynamoDB&lt;br&gt;
items can each have different attributes, giving you flexibility to store varied information within the same table.&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%2Fnyz6r441grfx73qitay4.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%2Fnyz6r441grfx73qitay4.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Read and Write Capacity
&lt;/h3&gt;

&lt;p&gt;Read Capacity Units (RCUs) and Write Capacity Units (WCUs) are DynamoDB’s measures of throughput, where RCUs define how many reads per second a table can handle and WCUs define how many writes per second it can handle.&lt;/p&gt;

&lt;p&gt;Amazon DynamoDB’s Free Tier provides 25 GB of storage, along with 25 Read Capacity Units (RCUs) and 25 Write Capacity Units (WCUs), which together allow upto 200million of requests per month at no cost. I turned off auto scaling because while it can automatically increase capacity in production to handle&lt;br&gt;
spikes in demand, it could push usage beyond the Free Tier limits and lead to unexpected charges, so disabling it ensures my table stays within the free allowance while I safely experiment.&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%2Fb7y24tp9kse86ppc6fve.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%2Fb7y24tp9kse86ppc6fve.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Using CLI and CloudShell
&lt;/h3&gt;

&lt;p&gt;AWS CloudShell is a browser‑based command line environment provided by Amazon Web Services that let's you securely manage, explore, and interact with your AWS resources without needing to install or configure tools locally. It comes pre‑authenticated with your AWS account and includes popular developer tools, making it easy to run commands, scripts, and manage services like DynamoDB directly from your web browser.&lt;/p&gt;

&lt;p&gt;AWS CLI is a command-line interface tool that lets you manage and interact with AWS services by typing commands instead of using the web console. It provides a unified way to automate tasks, run scripts, and control resources like DynamoDB, S3, or EC2 directly from your terminal, making it especially useful for developers and administrators who want efficiency and repeatability in managing their cloud infrastructure.&lt;/p&gt;

&lt;p&gt;I ran a CLI command in AWS CloudShell that created a new &lt;br&gt;
DynamoDB table, because CloudShell provides a ready‑to‑use, browser‑based terminal that’s already authenticated with my AWS account, making it simple to execute AWS CLI commands without installing or configuring anything locally. This step is part of learning how to provision DynamoDB resources directly from the command line, reinforcing the idea that you can manage AWS services not only through the console but also programmatically&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%2Fra7d64vvktcnzk6zwrro.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%2Fra7d64vvktcnzk6zwrro.png" alt=" " width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Loading Data with CLI
&lt;/h3&gt;

&lt;p&gt;I ran a CLI command in AWS CloudShell that created new DynamoDB tables, because CloudShell comes pre‑installed with the AWS CLI and is already authenticated with my AWS account, making it easy to provision resources directly from the browser without needing any local setup. This step shows how DynamoDB tables can be defined programmatically, reinforcing the flexibility of managing cloud databases through commands instead of the console.&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%2F6rtyr03w7z0uufkus52v.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%2F6rtyr03w7z0uufkus52v.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Observing Item Attributes
&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%2Ffotngoycls82q8p15egd.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%2Ffotngoycls82q8p15egd.png" alt=" " width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I checked a ContentCatalog item, which had the following attributes: &lt;br&gt;
Id (partition key, number), Title (string), URL (string), Authors (list), Price (number), Difficulty (string), Published (boolean), ProjectCategory (string), and ContentType (string).&lt;br&gt;
I checked another ContentCatalog item, which had a different set of attributes:&lt;br&gt;
Id (partition key, number), Title (string), URL (string), VideoType (string), Price (number), Services (list, sometimes included), and ContentType (string).&lt;/p&gt;




&lt;h3&gt;
  
  
  Benefits of DynamoDB
&lt;/h3&gt;

&lt;p&gt;A benefit of DynamoDB over relational databases is flexibility, because it doesn’t require a fixed schema, items in the same table can have different sets of attributes and data types. This means you can store diverse records (like projects and videos in your ContentCatalog) side by side without redesigning the table, whereas relational databases enforce rigid column structures that must be consistent across all rows. This flexibility makes DynamoDB especially useful for applications where data models evolve quickly or vary widely.&lt;/p&gt;

&lt;p&gt;Another benefit over relational databases is speed, because DynamoDB is designed for high‑performance at scale, using SSD storage and a distributed architecture that allows single‑digit millisecond response times. Unlike relational databases, which often need complex joins and indexing across rigid schemas, DynamoDB retrieves items directly by their keys, making lookups and writes much faster. This speed is especially valuable for applications like gaming, e‑commerce, or real‑time analytics, where quick responses are critical.&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%2Fh8iagge0qx9cum0azoxf.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%2Fh8iagge0qx9cum0azoxf.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🤝Next in the series builds on this, which is "Query Data with DynamoDB"&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>nosql</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Connect a Web App to Amazon Aurora</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Tue, 13 Jan 2026 11:51:33 +0000</pubDate>
      <link>https://dev.to/maven_h/connect-a-web-app-toamazon-aurora-367h</link>
      <guid>https://dev.to/maven_h/connect-a-web-app-toamazon-aurora-367h</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Amazon Aurora?
&lt;/h3&gt;

&lt;p&gt;Amazon Aurora is a fully managed relational database service from AWS that is compatible with MySQL. It is useful because it combines the familiarity of MySQL with the scalability, speed, and reliability of a cloud‑native service. Aurora&lt;br&gt;
automatically handles tasks like backups, replication, and failover, which makes it easier to build web apps that need secure, high‑performance data storage without managing complex infrastructure yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I used Amazon Aurora in this project
&lt;/h3&gt;

&lt;p&gt;In today’s project, I used Amazon Aurora to store and manage the data from my web app. By connecting my EC2‑hosted application to Aurora, I was able to capture user input through the web interface and save it securely in a relational&lt;br&gt;
database. Aurora’s compatibility with MySQL made it easy to query and verify the data using the MySQL CLI, while its scalability and reliability ensured that the app could handle future growth without me having to manage complex infrastructure.&lt;/p&gt;

&lt;p&gt;One thing I didn’t expect in this project was how quickly Amazon Aurora connected with my EC2 instance once the configuration details were set. I thought it might take longer or require a more complex setup, but the compatibility with MySQL and the php‑mysqli extension made the process smoother than I anticipated.&lt;br&gt;
This showed me that cloud services can simplify tasks that would normally be more complicated to manage on my own.&lt;/p&gt;




&lt;h3&gt;
  
  
  Creating a Web App
&lt;/h3&gt;

&lt;p&gt;To connect to my EC2 instance, I used SSH with my .pem key file because this provides secure, authenticated access to the server. By running the "ssh -i MavenAuroraApp.pem ec2-user@" command, I was able to log in remotely, and I'm ready to begin installing and configuring my web application.&lt;br&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%2F04yzyy29byc7i5krlela.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%2F04yzyy29byc7i5krlela.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To help me create my web app, I first connected to my EC2 instance through SSH and installed the necessary software, Apache, PHP, and the php‑mysqli extension, because these tools turn the EC2 instance into a functioning web server capable of running a dynamic application and communicating with my Aurora database.&lt;/p&gt;




&lt;h3&gt;
  
  
  Connecting my Web App to Aurora
&lt;/h3&gt;

&lt;p&gt;I set up my EC2 instance's connection details to my database.&lt;br&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%2Fpm39lecopehr82t6b2dz.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%2Fpm39lecopehr82t6b2dz.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  My Web App Upgrade
&lt;/h3&gt;

&lt;p&gt;Next, I upgraded my web app by adding a new PHP script that connects to my Aurora database and displays a more user‑friendly web page. This upgrade allowed the app to move beyond a simple static page and start handling dynamic data, capturing user input, sending queries to Aurora, and showing results directly in the browser.&lt;br&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%2F8ckvges8cmx1j1rb3c12.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%2F8ckvges8cmx1j1rb3c12.png" alt=" " width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Testing my Web App
&lt;/h3&gt;

&lt;p&gt;To make sure my web app was working correctly, I tested it in the browser by submitting data through the web page and then used the MySQL CLI on my EC2 instance to query the Aurora database. By checking that the new entries appeared in the database, I confirmed that the app was successfully sending and storing data in Aurora.&lt;br&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%2Fqxilh0zakgxz5bgwnevw.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%2Fqxilh0zakgxz5bgwnevw.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;br&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%2Fim3325phbq9b6dezyv27.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%2Fim3325phbq9b6dezyv27.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🤝&lt;strong&gt;&lt;em&gt;Next in the series builds on this, which is "Load Data into DynamoDB"&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>awschallenge</category>
      <category>database</category>
      <category>cloudnative</category>
      <category>aws</category>
    </item>
    <item>
      <title>Aurora Database with EC2</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Mon, 05 Jan 2026 10:18:09 +0000</pubDate>
      <link>https://dev.to/maven_h/aurora-database-with-ec2-380d</link>
      <guid>https://dev.to/maven_h/aurora-database-with-ec2-380d</guid>
      <description>&lt;h3&gt;
  
  
  Connect a Web App to Amazon Aurora
&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%2F5aaj7w11gkdz9gqi3d8a.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%2F5aaj7w11gkdz9gqi3d8a.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Today's Project!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Amazon Aurora?
&lt;/h3&gt;

&lt;p&gt;Amazon Aurora is a high‑performance, fully managed database engine that combines the speed and reliability of commercial databases with the simplicity and cost‑effectiveness of open‑source ones. It’s useful because it scales automatically, stays highly available, and integrates smoothly with your AWS environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I used Amazon Aurora in this project
&lt;/h3&gt;

&lt;p&gt;In today’s project, I used Amazon Aurora to set up a highly available relational database that integrates seamlessly with my EC2 instance. Aurora provided the database endpoint I needed to connect my application, while automatically handling scalability, replication, and fault tolerance. This allowed me to focus on building and testing my app without worrying about manual database management.&lt;/p&gt;

&lt;h3&gt;
  
  
  One thing I didn't expect in this project
&lt;/h3&gt;

&lt;p&gt;One thing I didn’t expect in this project was how straightforward the setup turned out to be. I thought it would be much of a hassle to configure the database and connect it to my EC2 instance, but the AWS steps made the process surprisingly simple.&lt;/p&gt;

&lt;p&gt;I completed the Aurora Database with EC2 project in about an hour, which was faster than I expected. The guided AWS setup made connecting my EC2 instance to Aurora straightforward and efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  In the first part of my project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Creating an Aurora Cluster&lt;/strong&gt;&lt;br&gt;
A relational database is one in which data are organized into tables, which are collections of rows and columns. It's called  "relational" because the rows relate to the columns and vice versa.&lt;br&gt;
Aurora is a good choice when we need something large-scale, with peak performance and uptime. This is because Aurora databases use clusters. Ordinary relational databases, like MySQL and Oracle, are more generic and cost-effective. They suit smaller databases and less demanding workloads.&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%2F3qphgm22rfyymk0u1d2v.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%2F3qphgm22rfyymk0u1d2v.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Halfway through I stopped!
&lt;/h3&gt;

&lt;p&gt;I stopped creating my Aurora database because I am trying to connect a web app server to my Aurora database. That is why I needed to set up an EC2 instance to serve as the web app server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features of my EC2 instance
&lt;/h3&gt;

&lt;p&gt;I created a new key pair for my EC2 instance, because I need keys to access my EC2 instance if I want to add, change, or update how my EC2 instance is running.&lt;br&gt;
When I created my EC2 instance, I took particular note of the "Public IPv4 DNS" and the "Key pair name." The Public IPv4 DNS is essentially the address of my EC2 instance on the internet, while the Key pair is a set of cryptographic keys (public and private) used to securely access the instance. The Key pair name identifies which keys are associated with 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%2Ft8f4naazng9nw7cnaekf.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%2Ft8f4naazng9nw7cnaekf.png" alt=" " width="598" height="779"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Then I could finish setting up my database
&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%2Fqafrzr4oupbfi4xndko2.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%2Fqafrzr4oupbfi4xndko2.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aurora Database uses clusters because they work together, so your data is always available. Aurora is really good for the big jobs because of these clusters.&lt;br&gt;
Each cluster consists of a primary instance (where all write operations occur) and multiple read replicas as back-ups. If your database's primary instance fails, one of the replicas can be promoted to primary automatically.&lt;/p&gt;

&lt;p&gt;🤝&lt;strong&gt;&lt;em&gt;Next in the series builds on this, which is "Connect a Web App with Aurora"&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>database</category>
      <category>cloudnative</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>AWS Databases!</title>
      <dc:creator>Hyelngtil Isaac</dc:creator>
      <pubDate>Sat, 03 Jan 2026 09:54:53 +0000</pubDate>
      <link>https://dev.to/maven_h/aws-databases-1nlh</link>
      <guid>https://dev.to/maven_h/aws-databases-1nlh</guid>
      <description>&lt;h2&gt;
  
  
  I'm exploring AWS Databases!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I'm building database solutions on AWS&lt;/strong&gt;&lt;br&gt;
In this AWS Databases series, I'm learning about AWS databases (Relational and NoSQL databases). By the end of these projects, I will have known how to Connect an Aurora Database to EC2, connect a Web App to Amazon Aurora, Load Data into a DynamoDB Table, Visualize a Relational Database, and Query Data with DynamoDB. I'm learning about cloud databases because I want to know how it works and then use it create impactful solutions.&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%2Fj1706djr0hnxc5tc279d.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%2Fj1706djr0hnxc5tc279d.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I am excited to share my progress - explore AWS databases with me!&lt;/strong&gt;&lt;br&gt;
I will set aside few hours daily to work on these database projects. I will keep myself accountable by tracking my daily progress and sharing updates to stay consistent. My reward for completing this AWS Databases series will be more ability to manage cloud databases effectively and confidently in real projects, and the satisfaction of mastering practical cloud database skills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are databases?&lt;/strong&gt;&lt;br&gt;
Databases are organized systems for storing and managing information digitally. They allow data such as customer records, product details, and transactions to be kept in one central place, making it easy to access, update, and share securely across teams. Cloud engineers use databases to store, organize, and manage application data securely in the cloud. They rely on databases to connect applications to data, run queries for insights, ensure scalability, and maintain high availability across different services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do database professionals do?&lt;/strong&gt;&lt;br&gt;
Database professionals are responsible for setting up databases, modelling data, writing queries, and ensuring database security. They also handle performance tuning, backups, and connecting databases to applications. The most interesting part of their job is using queries to turn raw data into meaningful insights that support decision‑making.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>database</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
