<?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: Ravjot Duhra</title>
    <description>The latest articles on DEV Community by Ravjot Duhra (@ravjotd).</description>
    <link>https://dev.to/ravjotd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3846618%2F90194ae8-3813-4a10-926b-2f03f7c0acdb.jpeg</url>
      <title>DEV Community: Ravjot Duhra</title>
      <link>https://dev.to/ravjotd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ravjotd"/>
    <language>en</language>
    <item>
      <title>I Built the Cloud Resume Challenge on AWS — Here's Everything I Learned</title>
      <dc:creator>Ravjot Duhra</dc:creator>
      <pubDate>Fri, 27 Mar 2026 18:32:59 +0000</pubDate>
      <link>https://dev.to/ravjotd/i-built-the-cloud-resume-challenge-on-aws-heres-everything-i-learned-ki6</link>
      <guid>https://dev.to/ravjotd/i-built-the-cloud-resume-challenge-on-aws-heres-everything-i-learned-ki6</guid>
      <description>&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%2Fnjpo0u4hsuv1tonomxwu.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%2Fnjpo0u4hsuv1tonomxwu.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm currently studying for the AWS Solutions Architect Associate (SAA-C03)&lt;br&gt;
and I wanted to go beyond flashcards and practice exams. The Cloud Resume&lt;br&gt;
Challenge by Forrest Brazeal is exactly what I needed — a project that&lt;br&gt;
forces you to use the services you're studying in a real, production-grade&lt;br&gt;
deployment. Here's what I built and what I actually learned along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;S3 · CloudFront · ACM · Lambda (Python) · DynamoDB ·&lt;br&gt;
API Gateway · Terraform · GitHub Actions&lt;/p&gt;

&lt;p&gt;All running on AWS Free Tier. Total cost: $0.&lt;/p&gt;

&lt;p&gt;Live site: &lt;a href="https://d19mfjmr0dtnqm.cloudfront.net" rel="noopener noreferrer"&gt;https://d19mfjmr0dtnqm.cloudfront.net&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/RavjotD/cloud-resume-challenge-aws" rel="noopener noreferrer"&gt;https://github.com/RavjotD/cloud-resume-challenge-aws&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Week by Week
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Week 1–2: S3 + CloudFront&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Started by writing my resume in plain HTML and CSS, deploying it to an&lt;br&gt;
S3 bucket with static website hosting enabled, and putting CloudFront&lt;br&gt;
in front of it for HTTPS and global edge caching. The moment I opened&lt;br&gt;
that CloudFront URL and saw my resume load over HTTPS from a CDN was&lt;br&gt;
the first real "I built this" moment.&lt;/p&gt;

&lt;p&gt;One thing I didn't expect — S3 defaults to blocking all public access.&lt;br&gt;
You have to explicitly unblock it and apply a bucket policy. AWS makes&lt;br&gt;
you opt in to public exposure rather than opt out. Smart default,&lt;br&gt;
confusing the first time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3: DNS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skipped the custom domain step. Route 53 isn't in the free tier and&lt;br&gt;
I didn't want to buy a domain just for a portfolio project. The&lt;br&gt;
CloudFront URL is perfectly functional for what this project needs to&lt;br&gt;
demonstrate. I'll add a custom domain when I'm hosting real client&lt;br&gt;
infrastructure on this account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 4: Lambda + DynamoDB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where the project gets interesting. I wrote a Python Lambda&lt;br&gt;
function that reads a visitor count from DynamoDB, increments it, and&lt;br&gt;
returns the updated value. Then I invoked it from the CLI and watched&lt;br&gt;
the count go from 0 to 1 to 2 to 3 in real time.&lt;/p&gt;

&lt;p&gt;The IAM Role setup here is directly from the SAA-C03 curriculum —&lt;br&gt;
create a role, define a trust policy that allows Lambda to assume it,&lt;br&gt;
attach least-privilege policies. Doing it by hand makes it click in&lt;br&gt;
a way that reading about it never does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 5: API Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wired Lambda to a public HTTP endpoint using API Gateway so the&lt;br&gt;
browser can call it. Straightforward setup — create the API, create&lt;br&gt;
the integration, create the route, deploy a stage.&lt;/p&gt;

&lt;p&gt;Then spent way too long debugging CORS. Short version: API Gateway&lt;br&gt;
was stripping the CORS headers that Lambda was correctly returning.&lt;br&gt;
The fix was updating the API's CORS configuration to explicitly allow&lt;br&gt;
my CloudFront origin. The debugging process — browser console, curl&lt;br&gt;
with verbose headers, Lambda invocation logs — taught me more about&lt;br&gt;
how HTTP actually works than any course section on networking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 6: Terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was the week everything changed. I rewrote every resource I had&lt;br&gt;
built manually — S3 bucket, CloudFront distribution, DynamoDB table,&lt;br&gt;
Lambda function, IAM role, API Gateway — into Terraform .tf files.&lt;/p&gt;

&lt;p&gt;The moment I ran &lt;code&gt;terraform plan&lt;/code&gt; and saw "No changes. Your&lt;br&gt;
infrastructure matches the configuration" was genuinely satisfying.&lt;br&gt;
Everything I had built over 5 weeks was now codified. Someone could&lt;br&gt;
clone my repo, run &lt;code&gt;terraform apply&lt;/code&gt;, and have the entire stack&lt;br&gt;
rebuilt from scratch in under 2 minutes.&lt;/p&gt;

&lt;p&gt;I also had to import existing resources into Terraform state rather&lt;br&gt;
than destroy and recreate everything. Learning the difference between&lt;br&gt;
&lt;code&gt;terraform import&lt;/code&gt;, state management, and drift detection was an&lt;br&gt;
unexpected but valuable deep dive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 7: GitHub Actions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added a CI/CD pipeline that triggers on every push to main.&lt;br&gt;
Two jobs run in sequence — first the test job runs my Lambda unit&lt;br&gt;
tests, and only if they pass does the deploy job run, uploading the&lt;br&gt;
HTML to S3 and invalidating the CloudFront cache.&lt;/p&gt;

&lt;p&gt;First successful pipeline run completed in 6 seconds. From that&lt;br&gt;
point on I never manually ran an &lt;code&gt;aws s3 cp&lt;/code&gt; command again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 8: Tests and Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wrote Python unit tests for the Lambda function using unittest and&lt;br&gt;
mocking the DynamoDB table with &lt;code&gt;unittest.mock&lt;/code&gt;. Four tests covering&lt;br&gt;
the counter increment logic, status codes, CORS headers, and&lt;br&gt;
DynamoDB being called correctly.&lt;/p&gt;

&lt;p&gt;Built the architecture diagram in draw.io and added it to the repo.&lt;br&gt;
Wrote this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hardest Part
&lt;/h2&gt;

&lt;p&gt;CORS. It's always CORS.&lt;/p&gt;

&lt;p&gt;The counter wasn't loading on the live site. No errors in the browser&lt;br&gt;
console, just a dash where the number should be. I opened the Network&lt;br&gt;
tab — the API request wasn't even showing up.&lt;/p&gt;

&lt;p&gt;Traced it step by step. Manually ran the fetch in the browser console&lt;br&gt;
— it returned &lt;code&gt;{count: 14}&lt;/code&gt; perfectly. So the API worked. The&lt;br&gt;
JavaScript was correct. But the live page showed nothing.&lt;/p&gt;

&lt;p&gt;The issue: CloudFront was caching a stale version of the HTML. I had&lt;br&gt;
two CloudFront distributions — created one accidentally during&lt;br&gt;
earlier testing — and I was invalidating the wrong one the whole time.&lt;br&gt;
Found it by listing all distributions from the CLI and comparing the&lt;br&gt;
domain names.&lt;/p&gt;

&lt;p&gt;That kind of debugging — ruling out code, ruling out the API, tracing&lt;br&gt;
the exact cached response — is exactly the thinking a solutions&lt;br&gt;
architect needs. The challenge put me in a position where I had to&lt;br&gt;
use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Actually Learned
&lt;/h2&gt;

&lt;p&gt;Studying for the SAA-C03 teaches you what the services are. Building&lt;br&gt;
this project teaches you how they fit together and where they break.&lt;/p&gt;

&lt;p&gt;I now understand why you'd put CloudFront in front of S3 instead of&lt;br&gt;
exposing S3 directly. I understand why Lambda needs an IAM Role&lt;br&gt;
rather than hardcoded credentials. I understand why Terraform state&lt;br&gt;
matters and what happens when it drifts. I understand why tests need&lt;br&gt;
to run before deployments, not after.&lt;/p&gt;

&lt;p&gt;None of that comes from flashcards.&lt;/p&gt;

&lt;h2&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%2F4t8pgnvedzcq1l6kp2ev.png" alt=" " width="800" height="500"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS SAA-C03 exam — June 2026&lt;/li&gt;
&lt;li&gt;Azure version of the Cloud Resume Challenge — same project
rebuilt on Azure Blob Storage, Azure CDN, Azure Functions,
and Cosmos DB&lt;/li&gt;
&lt;li&gt;One Terraform codebase deploying to both clouds&lt;/li&gt;
&lt;li&gt;One GitHub Actions pipeline deploying to both environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The multi-cloud version is the portfolio piece I'm working toward.&lt;br&gt;
When it's done I'll write about that too.&lt;/p&gt;




&lt;p&gt;If you're studying for a cloud certification and haven't done a&lt;br&gt;
hands-on project yet — start the Cloud Resume Challenge. The gap&lt;br&gt;
between knowing a service and deploying one is bigger than you think,&lt;br&gt;
and closing that gap is the whole point.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
