AWS Lesson 122 of 123

Real-World AWS Portfolio Projects: From a Static Site to a Multi-Account Landing Zone

In a nutshell

Level: Advanced · Time: ~40 min · You’ll need: an AWS account (Free Tier is fine), the AWS CLI v2, Terraform, Git, and a GitHub account.

Think of AWS certifications as a driving licence and this portfolio as a dashcam reel of you actually driving. The licence proves you passed a test on a good day; the reel proves you can merge onto a motorway in the rain. Employers hire the reel. This lesson hands you six such reels — six real AWS projects, arranged easiest-to-hardest — plus the exact way to film and caption them so a busy reviewer believes you built them. If you want the designs behind these builds first, the architecture ladder lesson teaches the shapes; here you build and present them.

A “portfolio” here is nothing mystical: it is a set of public GitHub repositories, each holding a small but complete AWS system you built, defined as code, with a README that explains what it does, a diagram, the cost, and the decisions you made. Each project on the ladder proves one more capability than the last — first that you can automate deployments, then that you can write backends, then that you understand networking, events, operations, and finally whole-organisation governance. The rungs compound: what you learn on rung one you reuse on every rung above it.

You do not need all six to get hired. Three finished, well-documented ones will land an associate role; the higher rungs unlock more senior conversations. The single biggest mistake beginners make is chasing quantity — six half-built tutorials — when three finished, torn-down, and clearly written projects win every time. Read the ladder table below, pick the rungs that match the job you want, and build those to the presentation standard in this lesson.

Two candidates apply for the same mid-level AWS role. Both list the same five certifications. The first attaches a CV that says “experienced with EC2, S3, Lambda, and IAM.” The second attaches a GitHub profile with six pinned repositories — a static site with a real CI/CD pipeline, a serverless API with tests, a containerised three-tier app behind a load balancer, an event-driven pipeline, an observability stack with dashboards and SLOs, and a multi-account landing zone built entirely in Terraform — each with a tidy README, an architecture diagram, a cost note, and a teardown script. As the hiring manager, you have read perhaps forty CVs that morning. Which of these two do you phone first? The answer is not close, and it is the entire reason this lesson exists.

Certifications prove you can recognise the right answer in a multiple-choice question. A portfolio proves you can build the thing. Those are different skills, and interviewers know it. A certification is a filter that gets your CV past the first screen; a portfolio is the evidence that survives the technical interview, because the questions stop being “what does CloudFront do?” and become “walk me through your CloudFront setup — why Origin Access Control and not the old OAI? how does your cache invalidate on deploy? what did it cost?” You can only answer those crisply if you have actually shipped it. This article gives you six projects, deliberately arranged as a hiring ladder — each one a rung harder, each one mapping to a tier of AWS roles and certifications — so that by the time you finish the sixth you are not “studying AWS,” you are demonstrably an AWS engineer.

The ladder is designed so the projects compound. Project 1 teaches you Infrastructure as Code and CI/CD on the gentlest possible surface. Project 2 adds application logic and a managed database. Project 3 introduces containers, networking, and stateful tiers. Project 4 is the asynchronous, decoupled architecture every real system grows into. Project 5 makes all of it observable and operable — the difference between a demo and production. Project 6 is the platform-engineering capstone that puts everything inside a governed, multi-account organisation, which is where senior and staff roles live. You do not have to build all six to get hired — three good ones will land you an associate-level role — but the higher you climb, the more senior the conversations you can hold.

Learning objectives

By the end of this lesson you will be able to:

Prerequisites

You should be comfortable with the AWS fundamentals, the IAM model, and basic VPC networking — the earlier rungs of this course cover all three. You will need an AWS account (the Free Tier is enough for projects 1–5; project 6 needs a fresh management account and the ability to create a small number of member accounts), the AWS CLI v2, Terraform (or AWS CDK/SAM where noted), Git, and a GitHub account. A little familiarity with one programming language — Python or TypeScript/Node.js are the most portable choices for Lambda — will carry you through projects 2, 4, and 5. None of the projects require paid third-party tooling; everything here uses the free tiers of AWS and GitHub.

This lesson sits in the Career module of the AWS Zero-to-Hero course, immediately after the architecture ladder (which teaches the designs); here you build and present them. It pairs naturally with the certification prep kit that follows it and with the capstone, which takes project 6 to full production depth.

The portfolio ladder: how the six projects map to roles and certs

Before the projects themselves, internalise the shape of the ladder. Each rung adds a capability that an interviewer at the next seniority tier expects you to have touched. The table below is the map; treat the “Hiring signal” column as the sentence a reviewer says to themselves when they see the repo.

# Project Core new capability Targets role Maps to cert Hiring signal
1 Static site + CI/CD IaC + automated deploys Junior / Cloud Support CLF-C02, SAA-C03 “Knows IaC, doesn’t click in the console”
2 Serverless REST API App logic + managed NoSQL + tests Associate Developer DVA-C02, SAA-C03 “Can build a real serverless backend”
3 Containerised 3-tier on Fargate Containers, ALB, VPC, RDS Associate / DevOps SAA-C03, DOP-C02 “Comfortable with networking and stateful tiers”
4 Event-driven pipeline Asynchronous, decoupled design Associate / Developer DVA-C02, SAA-C03 “Thinks in events and queues, not just request/response”
5 Observability / SRE Operability, SLOs, alarms, tracing DevOps / SRE DOP-C02, SOA-C02 “Operates systems, not just deploys them”
6 Multi-account landing zone Governance, org-scale identity, platform IaC Senior / Platform / Architect SAP-C02, DOP-C02 “Can build the foundation other teams land on”

A useful rule of thumb: build the rung that matches the role you want, plus the one below it. Targeting an associate developer role? Projects 1, 2, and 4 tell the strongest story. Targeting DevOps/SRE? Projects 3, 5, and 6. Targeting a solutions-architect or platform role? Projects 3, 5, and 6 again, with 1 as the polished “I know the fundamentals cold” showpiece. Quality beats quantity every time — three excellent, well-documented repos outshine six abandoned ones.

A word on cost discipline, because it is itself a hiring signal: every project below stays on or near the Free Tier, and every one ships with a teardown path (terraform destroy or a documented cleanup). Leaving a NAT gateway or an RDS instance running for a month is exactly the mistake a cost-conscious employer is screening for. Build, screenshot, document, tear down.

Make it yours: escaping the tutorial trap

The fastest way to make a portfolio worthless is to follow a popular tutorial line-for-line. Reviewers have seen the same “serverless URL shortener from that one video” a hundred times; an identical repo proves only that you can copy, not that you can solve. The projects above are deliberately written as briefs, not walkthroughs — a specification to hit, with the how left to you. Your job is to add a twist: one deliberate constraint, feature, domain, or engineered-and-fixed failure that is genuinely yours. The twist is the part you actually talk about in the interview, because it is the part you had to think through — and it is why “add your own twist” is the single instruction that turns a follow-along into evidence of judgement.

A twist does not need to be large. Pick one axis and turn it:

Axis A tutorial does… Your twist does…
Domain A generic “todo API” A backend for something you actually do — climbing logs, recipe ratings, a D&D initiative tracker
Constraint Whatever the video used “No NAT gateway — VPC endpoints only,” or “cold-start under 200 ms,” or “under ₹800/month”
Feature The happy path only Add pagination, optimistic locking, a rate limiter, or a multi-region read replica
Failure Ignores failure entirely Deliberately break something (kill an AZ, poison a queue) and show the recovery in the README
Data Fake foo/bar rows A realistic (synthetic) dataset, plus a note on why you modelled it that way

Then write the README in your own voice — especially the “Key decisions / trade-offs” section. Paraphrased tutorial prose is as obvious to a reviewer as copied code. When you can say “I chose X over Y because Z, and here is the latency or cost number that proves it,” you have escaped the trap. The twist is also insurance against the follow-up question every interviewer asks — “what would you change?” — because you have already been forced to reason about one real constraint instead of none.


Project 1 — Static site with a CI/CD pipeline

The brief. Host a static website (a portfolio page, a blog, or a single-page app build) on AWS so that it is globally fast, served only over HTTPS, and deployed automatically from a Git push — no console clicking, no manual S3 uploads. The whole thing must be defined as code and destroyable with one command. This is the gentlest possible surface on which to prove the two skills every modern cloud role assumes: Infrastructure as Code and CI/CD.

The AWS services.

Service Role in this project
Amazon S3 Private origin bucket holding the built site (no public bucket access)
Amazon CloudFront Global CDN, HTTPS termination, caching, custom domain
Origin Access Control (OAC) Lets only CloudFront read the bucket; keeps the bucket private
AWS Certificate Manager (ACM) Free TLS certificate for the custom domain (must be in us-east-1 for CloudFront)
Amazon Route 53 DNS for the custom domain (optional but recommended)
GitHub Actions CI/CD: build the site, sync to S3, invalidate the CloudFront cache
Terraform Defines every resource above as code

Build outline.

  1. Write the Terraform: a private S3 bucket, a CloudFront distribution with an OAC (not the deprecated Origin Access Identity), a bucket policy that allows only that distribution to s3:GetObject, an ACM certificate in us-east-1, and (optionally) a Route 53 record. Enable Block Public Access on the bucket and confirm the site is reachable only through CloudFront.
  2. Add a CloudFront default root object (index.html) and a custom error response mapping 403/404 to your SPA’s index.html if it is a single-page app.
  3. Put your site source in the same repo. Build it (or just use plain HTML for a first pass).
  4. Write a GitHub Actions workflow that, on push to main, authenticates to AWS via an OIDC role (no long-lived access keys in secrets — this is the modern, secure pattern), runs the build, aws s3 syncs the output to the bucket, and issues a cloudfront create-invalidation so visitors see the new version immediately.
  5. Document the architecture, capture a screenshot of a green pipeline run, and add a terraform destroy note.

The GitHub deliverable. A repo containing infra/ (Terraform), the site source, .github/workflows/deploy.yml, an architecture diagram, and a README that explains the OAC-keeps-the-bucket-private decision, the OIDC-not-access-keys decision, and the cache-invalidation step. Pin it.

Copy-paste résumé bullet.

Built and deployed a globally distributed static site on AWS (S3 + CloudFront with Origin Access Control, ACM TLS) defined entirely in Terraform, with a GitHub Actions CI/CD pipeline that authenticates via OIDC (zero long-lived credentials) and ships every commit to production in under 3 minutes with automatic cache invalidation, cutting page-load latency ~60% versus single-region hosting.


Project 2 — Serverless REST API

The brief. Build a working REST API — a URL shortener, a notes/todo service, or a simple bookmarking backend — with no servers to manage. It must persist data, validate input, return proper HTTP status codes, be defined as code, and have automated tests. This proves you can build application logic on AWS, not just wire up infrastructure.

The AWS services.

Service Role in this project
Amazon API Gateway HTTP API front door, routing, request validation, throttling
AWS Lambda The function(s) implementing each endpoint (Python or Node.js)
Amazon DynamoDB Serverless NoSQL persistence (on-demand capacity for Free Tier friendliness)
AWS IAM Least-privilege execution role per function
Amazon CloudWatch Logs, metrics, and a basic alarm on errors
AWS SAM or Terraform IaC for the whole stack

Build outline.

  1. Model the data for DynamoDB first — partition key and, if needed, a sort key or a global secondary index for your main access pattern (e.g. PK = shortCode for a URL shortener). Design for the query, not the entity.
  2. Write Lambda handlers for the CRUD operations. Keep handlers thin; validate input and return correct status codes (201 on create, 404 on miss, 400 on bad input).
  3. Define an API Gateway HTTP API with routes mapped to the functions; enable request validation and a sensible throttling limit so a runaway client cannot drive your bill up.
  4. Give each function a least-privilege IAM role — dynamodb:GetItem/PutItem on exactly your table ARN, nothing wildcard.
  5. Add unit tests for the handlers (mock the AWS SDK) and at least one integration test that hits the deployed endpoint. Wire the tests into a GitHub Actions workflow.
  6. Add a CloudWatch alarm on the function error metric. Document the data model and the access patterns.

The GitHub deliverable. A repo with src/ (handlers), tests/, the IaC (template.yaml for SAM or infra/ for Terraform), a CI workflow that runs tests then deploys, an OpenAPI sketch or a curl examples section in the README, and an architecture diagram. The README should justify the DynamoDB key design and show example requests/responses.

Copy-paste résumé bullet.

Designed and shipped a serverless REST API on AWS (API Gateway + Lambda + DynamoDB) with a single-table data model tuned to the primary access pattern, per-function least-privilege IAM roles, request validation, and CloudWatch error alarms; covered by unit and integration tests in a GitHub Actions pipeline, sustaining sub-50 ms median latency at effectively zero idle cost.


Project 3 — Containerised three-tier app on ECS Fargate

The brief. Take a containerised web application (a small CRUD app — Flask, Express, or similar — with a database) and run it as a production-shaped three-tier architecture: a load balancer in public subnets, the app on serverless containers in private subnets, and a managed relational database in isolated subnets. This is the project that proves you understand VPC networking, load balancing, and stateful tiers — the things serverless lets you skip.

The AWS services.

Service Role in this project
Amazon VPC Public / private / isolated subnets across two Availability Zones
Application Load Balancer (ALB) Public entry point, health checks, HTTPS
Amazon ECS on AWS Fargate Serverless containers running the app (no EC2 to patch)
Amazon ECR Private registry for the container image
Amazon RDS (PostgreSQL/MySQL) Managed database, Multi-AZ for the resilience story
AWS Secrets Manager The DB credentials — never in env files or the image
NAT Gateway / VPC endpoints Outbound access for tasks (or endpoints to avoid NAT cost)
Terraform IaC for the network, cluster, service, and database

Build outline.

  1. Build the VPC: two AZs, with public subnets (ALB), private subnets (Fargate tasks), and isolated subnets (RDS). Add either a NAT gateway or — to save cost and show awareness — VPC interface endpoints for ECR/Secrets Manager/CloudWatch so tasks need no NAT.
  2. Containerise the app, push to ECR. Define an ECS task definition and a service running ≥2 tasks across the two AZs behind the ALB.
  3. Stand up RDS in the isolated subnets; store the credentials in Secrets Manager and inject them into the task via the task definition’s secrets block (so they never appear in plaintext).
  4. Lock down security groups as a chain: ALB SG allows 443 from the internet; task SG allows the app port only from the ALB SG; RDS SG allows the DB port only from the task SG. This security-group-referencing pattern is a classic interview talking point.
  5. Configure ALB health checks and ECS service auto scaling on CPU or request count.
  6. Document the three-tier diagram, the security-group chain, and the Secrets Manager flow. Note the cost of NAT vs endpoints. Provide terraform destroy.

The GitHub deliverable. A repo with the app, a Dockerfile, infra/ (Terraform for VPC, ECS, ALB, RDS, Secrets Manager), a CI workflow that builds and pushes the image and updates the service, an architecture diagram showing all three tiers and the SG chain, and a README explaining the subnet tiers, the SG-referencing pattern, and the Multi-AZ resilience story.

Copy-paste résumé bullet.

Deployed a production-shaped three-tier application on AWS — ALB → ECS Fargate (2 AZs, auto-scaling) → RDS Multi-AZ — inside a custom VPC with public/private/isolated subnet tiers, security-group-referenced traffic chaining, and database credentials managed in Secrets Manager; fully defined in Terraform and self-healing across an Availability Zone failure with zero single points of failure.


Project 4 — Event-driven data pipeline

The brief. Build an asynchronous, decoupled pipeline: a file lands in S3 (an image, a CSV, a log), and that event triggers a processing chain that does real work — resize the image and write a thumbnail, parse the CSV and store rows, enrich a record — with the processing decoupled via a queue, a dead-letter queue for poison messages, and notifications on completion or failure. This proves you think in events and queues, not just request/response — the mental shift that separates associate-level engineers from juniors.

The AWS services.

Service Role in this project
Amazon S3 The event source (object-created notifications)
Amazon EventBridge Routes the S3 event to targets; the central event bus
AWS Lambda The processing function(s)
Amazon SQS Buffers work between stages; absorbs spikes; enables retries
Amazon SNS Fan-out notifications (e.g. email/Slack on completion or failure)
SQS Dead-Letter Queue Captures messages that fail repeatedly for inspection
Amazon DynamoDB Stores processing results / job state

Build outline.

  1. Configure S3 → EventBridge (enable EventBridge notifications on the bucket) and write an EventBridge rule that matches Object Created events and routes them onward.
  2. Put an SQS queue in front of the processing Lambda so work is buffered and retried independently of the producer; attach a dead-letter queue with a sensible maxReceiveCount (e.g. 3).
  3. Implement the processing Lambda idempotently — the same S3 object may be delivered more than once, so use a deterministic key (e.g. the object key + ETag) in DynamoDB to detect duplicates. Idempotency is the question every interviewer asks about event pipelines.
  4. On success, write results to DynamoDB and publish to an SNS topic; subscribe an email endpoint. On exhaustion, the DLQ holds the failed message and a CloudWatch alarm fires.
  5. Add a tiny producer (or just upload a file) and demonstrate the end-to-end flow, including a deliberately malformed file landing in the DLQ.
  6. Document the event flow, the at-least-once-delivery / idempotency reasoning, and the DLQ replay procedure.

The GitHub deliverable. A repo with the function(s), the IaC (S3, EventBridge rule, SQS + DLQ, SNS, DynamoDB, alarms), a CI workflow, an architecture diagram showing the event flow and the DLQ branch, and a README that explains idempotency, at-least-once delivery, and how to replay the DLQ. Include a screenshot of a message in the DLQ and a successful SNS notification.

Copy-paste résumé bullet.

Built a serverless event-driven pipeline on AWS (S3 → EventBridge → SQS → Lambda → DynamoDB + SNS) with idempotent processing keyed on object ETag, a dead-letter queue with automated alarming for poison messages, and fan-out notifications; the queue-decoupled design absorbed 10x ingestion bursts without loss and isolated producer failures from consumers.


Project 5 — Observability and SRE

The brief. Take one of the earlier applications (project 2, 3, or 4 is ideal) and make it observable and operable: structured logs, custom metrics, dashboards, actionable alarms, distributed tracing, and a defined SLO with an error budget. The deliverable is the difference between “I deployed an app” and “I operate a service” — exactly the gap DevOps and SRE interviews probe.

The AWS services.

Service Role in this project
Amazon CloudWatch Logs Centralised, structured (JSON) logs
CloudWatch Logs Insights Querying logs for diagnostics
CloudWatch Metrics + Dashboards The four golden signals on one screen
CloudWatch Alarms Actionable, multi-datapoint alarms (not noisy single-spike ones)
Amazon SNS Alarm notification delivery (email/Slack)
AWS X-Ray Distributed tracing across API Gateway → Lambda → DynamoDB
CloudWatch Synthetics (canary) Outside-in availability check against the SLO

Build outline.

  1. Make the app emit structured JSON logs with a correlation/request ID so you can trace a single request across components in Logs Insights.
  2. Publish custom metrics (e.g. business events, or use Embedded Metric Format) and build a CloudWatch dashboard showing the four golden signals — latency, traffic, errors, saturation — on one screen.
  3. Enable X-Ray tracing and capture a service map showing the call path and where latency accumulates.
  4. Define a concrete SLO (e.g. “99.5% of requests succeed and return in <300 ms over 30 days”), compute the error budget, and create a CloudWatch alarm with multiple datapoints / anomaly detection so it fires on real degradation, not single blips. Route it to SNS.
  5. Add a CloudWatch Synthetics canary that exercises the endpoint from outside and feeds the availability SLI.
  6. Write a one-page runbook: what each alarm means and the first three diagnostic steps. Document the SLO, the dashboard, and a sample Logs Insights query.

The GitHub deliverable. A repo (or a folder added to an existing project) with the dashboard and alarm definitions as IaC (dashboards-as-code is a strong signal), the canary script, the runbook, a screenshot of the dashboard under load, an X-Ray service-map screenshot, and a README stating the SLO and error budget. Treating monitoring as code, not click-ops, is the thing that impresses here.

Copy-paste résumé bullet.

Instrumented a production AWS workload for SRE — structured JSON logging with request correlation, a four-golden-signals CloudWatch dashboard, X-Ray distributed tracing, and multi-datapoint alarms wired to SNS — defined a 99.5%/300 ms SLO with an error budget and a Synthetics canary, all as code, cutting mean-time-to-diagnose from guesswork to a single Logs Insights query.


Project 6 — Multi-account landing zone

The brief. Build the governed foundation that real organisations run on: a multi-account AWS environment with a security/log-archive separation, a sane organisational-unit structure, centralised single-sign-on with permission sets, preventive guardrails, and a baseline of org-wide logging and detection — provisioned and version-controlled with Terraform. This is the platform-engineering capstone; it is where senior, platform, and architect roles live, because it demonstrates you can build the thing other teams land on rather than a single app.

The AWS services.

Service Role in this project
AWS Organizations The account hierarchy and OUs; the root of governance
AWS Control Tower Orchestrates the landing zone, baseline guardrails, account factory
AWS IAM Identity Center Centralised SSO, permission sets, account assignments
Service Control Policies (SCPs) Preventive, org-wide guardrails (e.g. deny region/​root-action)
AWS CloudTrail (org trail) Org-wide, tamper-resistant audit log to a central account
AWS Config + GuardDuty Org-wide configuration recording and threat detection
AWS KMS / Secrets Manager Central encryption keys and secrets baseline
Terraform Codifies OUs, SCPs, Identity Center assignments, baselines

Build outline.

  1. Start from a fresh management account. Enable AWS Organizations, then set up a Control Tower landing zone (it creates the log-archive and audit accounts and a baseline). Understand what Control Tower provisions before you add to it.
  2. Design an OU structure — at minimum a Security OU, an Infrastructure OU, and a Workloads OU (often split Prod/Non-Prod). Keep it shallow; OUs are for applying policy, not org-charting.
  3. Author Service Control Policies as code and attach them to OUs — e.g. deny disabling CloudTrail/GuardDuty, deny use of non-approved regions, restrict root-user actions. SCPs set the maximum permissions; they do not grant.
  4. Configure IAM Identity Center: define permission sets (e.g. AdministratorAccess, ReadOnly, a scoped Developer) and assign groups to accounts. This replaces per-account IAM users — a key talking point.
  5. Ensure the org CloudTrail lands in the central log-archive account, and that Config and GuardDuty are enabled org-wide with findings centralised.
  6. Vend at least one member account through the account factory to demonstrate the workflow end to end. Document the OU/SCP design and the identity model. (Mind the cost: Control Tower itself is free, but enabled services and any running resources are not — tear down what you can.)

The GitHub deliverable. A repo with terraform/ defining OUs, SCP documents, Identity Center permission sets and assignments, and the logging/detection baseline; an architecture diagram of the account/OU topology and the identity flow; and a README that explains the blast-radius-as-account principle, why SCPs are guardrails not grants, and how access flows through Identity Center. This is the most senior-signalling repo you can pin.

Copy-paste résumé bullet.

Architected a governed multi-account AWS landing zone with Control Tower and Organizations — a Security/Infrastructure/Workloads OU hierarchy, preventive Service Control Policies as code, centralised access via IAM Identity Center permission sets, and org-wide CloudTrail, Config, and GuardDuty into a dedicated log-archive account — all in Terraform, giving new teams a compliant, audit-ready account in minutes instead of weeks.


AWS portfolio projects ladder

The diagram above shows the six projects as ascending rungs, each annotated with its headline AWS services, the role tier it targets, and the certification it maps to — so you can see at a glance how capability and seniority compound as you climb.

The GitHub presentation standard

A brilliant project hidden in a messy repo is a wasted project. Reviewers spend seconds, not minutes, on each repo; presentation is not vanity, it is the medium through which your work is read. Apply this standard to every project above.

The repository. Give it a clear, descriptive name (aws-serverless-url-shortener, not project2). Pin your best three-to-six repos on your GitHub profile so they appear first. Add topics/tags (aws, terraform, serverless) so the repo is discoverable. Include a permissive licence (MIT is fine) — its absence quietly signals “not really finished.” Ensure the default branch is clean and the repo has no committed secrets (more on this below).

The README is the product. It is the first — often only — thing read. Structure it: a one-line description and an architecture diagram at the very top; then What it does, Architecture (the diagram plus a paragraph), How to deploy (the exact commands), How to tear down (terraform destroy or cleanup steps), Cost (a Free-Tier note or rough monthly estimate), and Key decisions / trade-offs (this section is what wins technical interviews — explain why OAC, why DynamoDB, why the SG chain). A reviewer who reads only the README should understand the whole project.

Architecture diagrams. Every repo gets one, embedded in the README. Use a consistent tool (draw.io/diagrams.net, Excalidraw, or the official AWS architecture icons) and commit the source so it is editable. A clear diagram instantly communicates seniority; its absence reads as “I can’t see the whole system.”

Commit history. Make commits atomic and meaningfully messaged (“Add CloudFront OAC and bucket policy,” not “stuff” or “fix”). A clean history shows how you work and is itself reviewed. Avoid one giant “initial commit” dump where possible — incremental, descriptive commits read as professional.

Infrastructure as Code, always. Every project is defined in Terraform/CDK/SAM and destroyable with one command. Console click-ops in a portfolio reads as junior; reproducible IaC reads as production-ready. Bonus signals: a CI badge in the README, a Makefile or task runner for common commands, and a short CONTRIBUTING/architecture-decision note.

The table below is the at-a-glance checklist to run against each repo before you pin it.

Element The standard Why a reviewer cares
Repo name Descriptive, hyphenated Signals intent at a glance
Pinned Best 3–6 on profile Controls first impression
README top One-liner + diagram Whole project understood in seconds
Deploy/teardown Exact commands, both ways Proves it actually runs — and that you clean up
Cost note Free-Tier / estimate Cost-awareness is a hiring signal
Key decisions Why each choice Wins the technical interview
Diagram Embedded, source committed Communicates system thinking
Commits Atomic, well-messaged Shows how you work
IaC One-command create/destroy Reads as production-ready
Secrets None committed; OIDC/Secrets Manager Screens out a common security failure

A README skeleton reviewers respond to

The presentation standard above is the checklist; this is the concrete shape to paste into every repo’s README.md and fill in. A reviewer who reads only this should understand the whole project — which is the entire point of the exercise. Commands are shown inline so the whole skeleton stays one copyable block:

# <project-name>

One line: what this is and the headline result
(e.g. "Serverless URL shortener — sub-50 ms median, ~₹0/month idle").

![architecture](docs/architecture.svg)

## What it does
Two or three sentences, plain language, no jargon.

## Architecture
The diagram, then a short paragraph naming each service and *why* it is there.

## Deploy
Run: `cd infra && terraform init && terraform apply`

## Tear down
Run: `terraform destroy`  — cost after teardown: ₹0

## Cost
Free-Tier note or a rough monthly estimate, and the one line item to watch.

## Key decisions / trade-offs
- Why OAC over a public bucket / DynamoDB over RDS / endpoints over NAT.
- One honest limitation and what I would change next.

## Tests
How to run them and what they cover.

Three lines do most of the work: the one-liner + result at the very top (a recruiter reads only this before deciding to keep going), the architecture diagram (system-thinking communicated in a single glance), and Key decisions / trade-offs (the section that actually wins the technical interview). If you polish nothing else, polish those three — they are the parts a busy reviewer is guaranteed to reach.

One more habit that pays off across the whole ladder: keep a tiny docs/ folder in each repo holding the diagram source (draw.io/Excalidraw file) and a one-page architecture-decision note. It costs ten minutes, and it is the difference between “I drew a diagram” and “I can regenerate and defend every box on it.”

Hands-on lab: ship Project 1 and pin it

This lab gets the first rung done end to end on the Free Tier, so you finish with a real, pinned repository.

Step 1 — scaffold the repo. Create a GitHub repo aws-static-site-cicd, clone it, and add a minimal index.html. Create an infra/ directory for Terraform.

Step 2 — write the Terraform. In infra/, define a private S3 bucket with Block Public Access on, a CloudFront distribution with an Origin Access Control, a bucket policy granting s3:GetObject only to that distribution (condition on the AWS:SourceArn of the distribution), and a default root object of index.html. Run:

cd infra
terraform init
terraform apply

Expected: Terraform prints the CloudFront domain name as an output (e.g. dxxxx.cloudfront.net).

Step 3 — first manual deploy (to validate). Sync the site and confirm it serves only through CloudFront:

aws s3 sync .. s3://<your-bucket> --exclude "infra/*" --exclude ".git/*"
curl -I https://<cloudfront-domain>/

Expected: HTTP/2 200 from CloudFront. Validation: try the bucket’s direct REST endpoint — curl -I https://<bucket>.s3.amazonaws.com/index.html should return 403 AccessDenied, proving the origin is private and only reachable via CloudFront.

Step 4 — wire CI/CD with OIDC (no static keys). Create an IAM OIDC identity provider for GitHub Actions and a role that trusts your repo (scoped to the main branch), with permissions to s3:sync to the bucket and create CloudFront invalidations. Add .github/workflows/deploy.yml that, on push to main, assumes the role via aws-actions/configure-aws-credentials (OIDC), syncs to S3, and runs aws cloudfront create-invalidation --paths "/*".

Step 5 — prove the pipeline. Edit index.html, commit, and push to main. Watch the Actions run go green; refresh the CloudFront URL and confirm the change is live. Screenshot the green run for your README.

Step 6 — document and pin. Write the README to the presentation standard above (diagram, deploy, teardown, cost, key decisions). Pin the repo on your profile.

Cleanup / cost note. Run terraform destroy to remove the distribution and bucket. Everything here is Free-Tier eligible (S3 storage of a few MB, CloudFront’s perpetual free allotment, ACM is free, Route 53 is the only paid item at about ₹45/USD 0.50 per hosted zone per month if you add a custom domain). Leaving it running costs effectively nothing, but destroy it if you used a hosted zone you do not need.

Going deeper

The six briefs tell you what to build. This section is the advanced layer that separates a portfolio that gets a callback from one that gets scrolled past: the signals that read as production rather than demo, the concrete artifacts reviewers actually open, the cost story you must be able to defend, and how to narrate all of it in ninety seconds. Read it once now, and again after you have built your first rung.

Demo vs. production-shaped: the signals that separate them

Anyone can terraform apply a happy path. Seniority shows in the parts a tutorial skips. Each of these signals maps to a pillar of the AWS Well-Architected Framework, and naming that mapping in your README is itself a hiring signal — it says you know the vocabulary reviewers grade against.

Signal A demo does… Production-shaped does… WA pillar
Identity One admin role, Action: "*" One least-privilege role per function, scoped to specific ARNs Security
Secrets Password in an env var or the image Secrets Manager / SSM Parameter Store, injected at run time Security
Failure Single instance, single AZ ≥2 AZs, health checks, auto-scaling, self-healing Reliability
Observability print() to stdout Structured logs, metrics, alarms, tracing, an SLO Operational Excellence
Cost Left running; no visibility Free-Tier-aware, a Budget alarm, terraform destroy Cost Optimisation
Efficiency Over-provisioned “to be safe” Right-sized, serverless/Graviton where it fits Performance Efficiency

You do not need all six pillars perfect on every project — that is what the ladder is for (Project 3 carries Reliability, Project 5 carries Operational Excellence, Project 6 carries Security and governance). But every repo should consciously nail at least Security and Cost, because those are the two a reviewer checks first and the two that most cheaply betray a junior. The capstone lesson takes a single build through all six pillars in depth if you want the reference.

Show the artifact, not just the claim

The lesson’s briefs describe the modern patterns; a strong repo shows them. Below are the four artifacts reviewers most want to see actually written down. All account IDs are placeholders.

1. The OIDC trust policy (Project 1’s CI/CD). The single most-praised “I know the modern way” signal is GitHub Actions assuming a role via OIDC instead of storing access keys. First create the identity provider once per account, then the role’s trust policy scopes who may assume it — down to your repo and branch:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
      "StringLike":   { "token.actions.githubusercontent.com:sub": "repo:my-org/aws-static-site-cicd:ref:refs/heads/main" }
    }
  }]
}

The workflow side needs one permission block most people forget — without id-token: write the token is never minted:

permissions:
  id-token: write   # REQUIRED for OIDC; the #1 "why won't it auth?" gotcha
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
          aws-region: us-east-1
      - run: aws s3 sync ./site s3://my-site-bucket --delete
      - run: aws cloudfront create-invalidation --distribution-id E123EXAMPLE --paths "/*"

2. A least-privilege function role (Project 2). “Least privilege” in a README is a claim; this is proof. Grant exactly the three actions on exactly one table ARN — no dynamodb:*, no Resource: "*":

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "TableRW",
    "Effect": "Allow",
    "Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query"],
    "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/links"
  }]
}

Attach the AWS-managed AWSLambdaBasicExecutionRole alongside it for CloudWatch Logs, and you have a role a security reviewer nods at instead of flagging.

3. The security-group chain as references, not CIDRs (Project 3). This is the classic interview artifact. On the current aws Terraform provider (v5+), the recommended form is the per-rule resource aws_vpc_security_group_ingress_rule — the old inline ingress {} blocks still work but are deprecated. The key field is referenced_security_group_id:

resource "aws_security_group" "alb"  { name = "alb-sg"  vpc_id = aws_vpc.main.id }
resource "aws_security_group" "task" { name = "task-sg" vpc_id = aws_vpc.main.id }
resource "aws_security_group" "db"   { name = "db-sg"   vpc_id = aws_vpc.main.id }

# ALB: HTTPS from the whole internet
resource "aws_vpc_security_group_ingress_rule" "alb_https" {
  security_group_id = aws_security_group.alb.id
  cidr_ipv4         = "0.0.0.0/0"
  from_port         = 443
  to_port           = 443
  ip_protocol       = "tcp"
}

# Tasks: app port ONLY from the ALB's SG (a reference, not an IP range)
resource "aws_vpc_security_group_ingress_rule" "task_from_alb" {
  security_group_id            = aws_security_group.task.id
  referenced_security_group_id = aws_security_group.alb.id
  from_port                    = 8080
  to_port                      = 8080
  ip_protocol                  = "tcp"
}

# Database: 5432 ONLY from the task SG
resource "aws_vpc_security_group_ingress_rule" "db_from_task" {
  security_group_id            = aws_security_group.db.id
  referenced_security_group_id = aws_security_group.task.id
  from_port                    = 5432
  to_port                      = 5432
  ip_protocol                  = "tcp"
}

Referencing SGs rather than IP ranges means the rules stay correct as tasks scale and their IPs churn — the whole point, and the sentence you say out loud in the interview.

4. The single-table data model (Project 2). Reviewers of a DynamoDB project look for one thing: did you design around access patterns or did you bring a relational habit? Put the access-pattern table in your README. For a link-shortener with click history, one table serves everything:

Access pattern PK SK How
Create / read a short link LINK#<code> LINK#<code> GetItem / PutItem
Record a click LINK#<code> CLICK#<iso-timestamp> PutItem
List recent clicks for a link LINK#<code> CLICK#… Query PK, SK begins_with "CLICK#"

Everything is a single-partition Query — no scans, no joins. The full technique (overloaded keys, GSIs for secondary access patterns) is in the DynamoDB single-table design lesson.

Engineer the cost story

Cost is not an afterthought here — it is a graded pillar, and “I left a NAT gateway running for a month” is the single most common way a beginner’s portfolio costs them money and a callback at once. Do three things on every project.

Estimate before you build. Sketch the monthly cost in the AWS Pricing Calculator (or a back-of-envelope in the README) before terraform apply. Reviewers love a “Cost” section that shows you predicted it, not just measured it.

Wire a backstop budget. A ten-dollar budget that emails you at 80% turns a runaway from a surprise invoice into a Tuesday-morning email. It is a few lines of Terraform:

resource "aws_budgets_budget" "monthly" {
  name         = "portfolio-monthly"
  budget_type  = "COST"
  limit_amount = "10"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["you@example.com"]
  }
}

AWS Cost Anomaly Detection (aws_ce_anomaly_monitor + aws_ce_anomaly_subscription) is free and catches the shape of a spend spike even under the budget cap — worth a second mention in the README.

Know the expensive parts by heart. The two line items that quietly drain a hobby account are the NAT gateway and an always-on RDS instance. Representative us-east-1 figures: a NAT gateway is roughly $0.045/hour ≈ $32/month before the $0.045/GB processing charge, whereas a VPC interface endpoint is about $0.01/hour per endpoint per AZ plus $0.01/GB. For the low traffic of a portfolio, three or four interface endpoints beat one NAT gateway on cost and score you a Security/Cost point for keeping tasks off the public internet. Then the discipline that makes all of it safe: build, screenshot, terraform destroy. A repo with a teardown script and a “cost after destroy: ₹0” note reads as more senior than a repo with a live URL and a mounting bill.

Tell the story: STAR and the trade-off narrative

Building the project is half the work; being able to narrate it in under ninety seconds is the other half, and it is the half most candidates neglect. Use STAR — Situation, Task, Action, Result — so the story has a spine. A worked example for Project 3:

Then volunteer the trade-off before you are asked: “If I did it again I’d put the NAT-versus-endpoints choice behind a Terraform variable and add ECS Service Connect for service discovery.” Naming what you’d change is not weakness — it is the exact signal of an engineer who reflects, and it pre-empts the interviewer’s favourite follow-up. Rehearse one STAR paragraph per pinned project, out loud, timed.

Build in public

The projects compound faster when they are visible. After you ship a rung, write it up — a short blog post (dev.to, Hashnode, LinkedIn, or your own site), with the architecture diagram and one hard bug you fought. Three things happen. First, the write-up is your interview answer, drafted and rehearsed. Second, it is searchable — recruiters and future teammates find it. Third, a stream of small “build log” commits and posts reads as momentum, which is itself a hiring signal: this person ships, and keeps shipping. You are not performing; you are documenting. The documentation habit — README, diagram, cost note, write-up — is the throughline of every rung on this ladder, and it is what makes six repositories read as one deliberate, growing body of work rather than six disconnected experiments.

Common mistakes & troubleshooting

Symptom Likely cause Fix
CloudFront returns 403 for every path Bucket policy doesn’t grant the distribution, or OAC not attached to the origin Attach OAC to the origin and set a bucket policy allowing the distribution’s AWS:SourceArn
ACM certificate won’t attach to CloudFront Certificate created in the wrong region CloudFront requires the cert in us-east-1; recreate it there
GitHub Actions can’t authenticate to AWS Long-lived keys leaked/rotated, or OIDC trust policy doesn’t match the repo/branch Use OIDC; set the role trust sub condition to repo:owner/name:ref:refs/heads/main
RDS in project 3 is unreachable from tasks Security-group chain wrong, or DB in a public subnet RDS SG should allow the DB port only from the task SG; keep RDS in isolated subnets
Event pipeline processes the same file twice No idempotency; at-least-once delivery Use a deterministic dedupe key (object key + ETag) in DynamoDB
Alarms fire constantly (alert fatigue) Single-datapoint alarm on a noisy metric Require multiple datapoints / use anomaly detection; alarm on the SLI, not raw spikes
Surprise bill after a project NAT gateway, RDS, or a forgotten resource left running terraform destroy; prefer VPC endpoints over NAT; set an AWS Budget alert
Secrets committed to the repo Credentials in env files or the image Use Secrets Manager / OIDC; run git-secrets or gitleaks in CI; rotate anything exposed

Common beginner mistakes

The troubleshooting table above fixes symptoms. These are the misconceptions — the wrong mental models that quietly sink a portfolio before a reviewer ever runs your code.

Best practices

Security notes

A portfolio is also a security exhibit — reviewers notice both good and bad habits.

Interview & exam questions

Q1. Why use Origin Access Control instead of making the S3 bucket public? A public bucket exposes objects directly, bypasses CloudFront’s caching/TLS/WAF, and is a top cause of breaches. OAC lets only the CloudFront distribution read the bucket (via a signed request and a bucket policy scoped to the distribution’s ARN), keeping the origin private while serving globally. OAC supersedes the older Origin Access Identity (OAI) and supports SSE-KMS.

Q2. In your CI/CD pipeline, why OIDC instead of storing AWS access keys in GitHub secrets? Long-lived access keys are a standing liability — if leaked they grant persistent access. OIDC lets GitHub Actions exchange a short-lived token for temporary AWS credentials by assuming a role whose trust policy is scoped to your specific repo and branch. No secret to leak, automatic expiry, and least-privilege by branch.

Q3. In the three-tier project, how do the security groups enforce the tiers? As a chain of references, not IP ranges: the ALB SG allows 443 from the internet; the Fargate task SG allows the app port only from the ALB SG; the RDS SG allows the DB port only from the task SG. Referencing SGs rather than CIDRs means the rules stay correct as instances/tasks scale and IPs change.

Q4. Why put an SQS queue between S3/EventBridge and the processing Lambda? To decouple producer from consumer: the queue absorbs bursts (the producer never waits on the consumer), provides independent retries, and — with a dead-letter queue — isolates poison messages for inspection instead of blocking the pipeline. It turns a brittle synchronous chain into a resilient asynchronous one.

Q5. Your event pipeline must handle the same S3 event being delivered twice. How? Make processing idempotent. EventBridge/SQS guarantee at-least-once delivery, so design for duplicates: derive a deterministic key (e.g. object key + ETag) and record it in DynamoDB with a conditional write; if the key already exists, skip. The operation’s effect is then the same no matter how many times it runs.

Q6. What is an SLO, an SLI, and an error budget, and how did you implement them? An SLI is the measured indicator (e.g. % of successful requests under 300 ms); the SLO is the target for it (e.g. 99.5% over 30 days); the error budget is the allowed shortfall (0.5%). I implemented the SLI as a CloudWatch metric/Synthetics canary, alarmed on multi-datapoint breaches via SNS, and tracked the budget on a dashboard — so alerts fire on real degradation, not single spikes.

Q7. What does Control Tower give you that raw AWS Organizations does not? Organizations provides accounts, OUs, and SCPs. Control Tower orchestrates a best-practice landing zone on top: it provisions the log-archive and audit accounts, applies baseline guardrails, sets up Identity Center, and gives you an account factory for governed account vending — turning a blank org into a compliant foundation.

Q8. SCPs — do they grant permissions? No. SCPs are guardrails: they define the maximum permissions available to accounts in an OU but grant nothing themselves. Effective permissions are the intersection of SCPs and the identity’s IAM policies. A common use is denying disabling of CloudTrail/GuardDuty or use of non-approved regions org-wide.

Q9. Why DynamoDB rather than RDS for the serverless API project? DynamoDB is serverless (no instance to manage or pay for at idle), scales seamlessly, and with on-demand capacity is Free-Tier friendly and effectively zero-cost when quiet. The trade-off is data-modelling discipline — you design tables around access patterns (single-table design, GSIs), not normalised relations. For a known-access-pattern API it is the right fit.

Q10. A reviewer opens your repo. What are the first three things you want them to see, and why? (1) The README’s one-line description and architecture diagram at the top — instant comprehension of what and how. (2) A clear deploy and teardown section — proof it actually runs and that I clean up. (3) A “Key decisions / trade-offs” section — evidence I made reasoned choices, which is what the technical interview probes.

Q11. How do you keep these projects from costing money? Stay on the Free Tier (DynamoDB on-demand, Lambda/API Gateway free allotments, CloudFront’s free tier), prefer VPC endpoints over NAT gateways, avoid leaving RDS/NAT running, define everything in IaC so I can terraform destroy after capturing screenshots, and set an AWS Budgets alert as a backstop.

Q12. Which of these projects would you build first for a DevOps/SRE role, and why? Project 5 (observability) layered on project 3 (containerised three-tier), then project 6 (landing zone). DevOps/SRE roles care most about operating systems — dashboards, SLOs, alarms, tracing — and about platform-scale governance and IaC, which those three projects evidence directly.

Practice challenges

Six graded exercises, beginner to advanced. Do them against a real repo — most produce an artifact you can commit. Reveal each solution only after you have attempted it.

1. (Beginner) Audit a repo against the presentation standard. Take any project repo (yours or a classmate’s) and score it against the ten-row checklist in “The GitHub presentation standard.” List what is missing.

<details> <summary>Solution</summary>

Walk the checklist rows in order: descriptive hyphenated name; pinned; README opens with a one-liner and an embedded diagram; deploy and teardown commands; a cost note; a “Key decisions / trade-offs” section; diagram source committed; atomic, well-messaged commits; one-command IaC create/destroy; zero committed secrets. A typical first-pass repo is missing the diagram, the teardown section, the cost note, and the decisions section — fix those four first.

Why: presentation is the medium through which your work is read; a reviewer scores these in seconds, so missing rows cost you before your code is ever run. </details>

2. (Beginner) Scope an OIDC trust policy to one repo and branch. Write the Condition block that lets only GitHub Actions runs from my-org/aws-notes-api on branch main assume the deploy role.

<details> <summary>Solution</summary>

"Condition": {
  "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
  "StringLike":   { "token.actions.githubusercontent.com:sub": "repo:my-org/aws-notes-api:ref:refs/heads/main" }
}

Remember the workflow also needs permissions: id-token: write, or no token is minted.

Why: scoping the sub to repo and branch is exactly what makes OIDC safe — a leaked workflow file on another branch or repo cannot assume the role. </details>

3. (Intermediate) Write a least-privilege role for a notes API. A Lambda must only read and write one DynamoDB table named notes. Write the IAM policy — no wildcards.

<details> <summary>Solution</summary>

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "NotesTableRW",
    "Effect": "Allow",
    "Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:DeleteItem"],
    "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/notes"
  }]
}

Attach AWSLambdaBasicExecutionRole as well so the function can write CloudWatch Logs.

Why: least privilege is the skill the project exists to demonstrate; a scoped ARN and explicit action list is the difference between a green tick and a flagged review. </details>

4. (Intermediate) Chain a database security group by reference. In Terraform (provider v5), write the ingress rule so the DB security group accepts Postgres (5432) only from the task security group — not a CIDR.

<details> <summary>Solution</summary>

resource "aws_vpc_security_group_ingress_rule" "db_from_task" {
  security_group_id            = aws_security_group.db.id
  referenced_security_group_id = aws_security_group.task.id
  from_port                    = 5432
  to_port                      = 5432
  ip_protocol                  = "tcp"
}

Why: referencing the source SG instead of an IP range keeps the rule correct as Fargate tasks scale and their IPs change — the exact point interviewers probe. </details>

5. (Advanced) Turn a project into a bullet and a 90-second STAR. Pick one built project. Write its quantified résumé bullet and a Situation-Task-Action-Result narration you can say aloud in under ninety seconds, ending with one trade-off you would change.

<details> <summary>Solution</summary>

Bullet (Project 2 example): “Shipped a serverless REST API (API Gateway + Lambda + DynamoDB) with a single-table model, per-function least-privilege IAM, and unit/integration tests in CI, sustaining sub-50 ms median latency at effectively zero idle cost.” STAR: S — “I wanted to prove I could build backend logic, not just wire infra.” T — “A notes API with validation, tests, and least privilege.” A — “Single-table DynamoDB, thin Lambda handlers returning correct status codes, scoped IAM, tests in GitHub Actions.” R — “Sub-50 ms median, zero idle cost, one-command teardown.” Trade-off: “I’d add a GSI for a second access pattern and put throttling limits behind a variable.”

Why: an interview-ready rung is one you can build, present, quantify, and narrate; rehearsing the STAR out loud is what converts a repo into a callback. </details>

6. (Advanced) Add a cost backstop and name the cheaper NAT alternative. Write the Terraform for a $10 monthly budget that emails you at 80%, and state the cheaper alternative to a NAT gateway for private-subnet outbound to AWS services.

<details> <summary>Solution</summary>

resource "aws_budgets_budget" "monthly" {
  name         = "portfolio-monthly"
  budget_type  = "COST"
  limit_amount = "10"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["you@example.com"]
  }
}

The cheaper alternative: VPC interface endpoints (PrivateLink) for ECR, Secrets Manager, and CloudWatch — about $0.01/hour each versus a NAT gateway’s ~$0.045/hour plus per-GB processing, and they keep traffic off the public internet.

Why: cost discipline is itself a hiring signal, and knowing endpoints-vs-NAT is the most common cost question asked about the three-tier project. </details>

Quick check

  1. What replaces the deprecated Origin Access Identity for keeping an S3 origin private behind CloudFront?
  2. In which region must an ACM certificate live to be used by CloudFront?
  3. What delivery guarantee do EventBridge and SQS provide, and what application property must you therefore design for?
  4. Do Service Control Policies grant permissions?
  5. Name the three subnet tiers in the project-3 architecture and which component lives in each.

Answers

  1. Origin Access Control (OAC) — attached to the CloudFront origin, with a bucket policy scoped to the distribution’s ARN.
  2. us-east-1 (N. Virginia) — CloudFront only reads ACM certificates from there.
  3. At-least-once delivery; therefore your processing must be idempotent (e.g. dedupe on object key + ETag).
  4. No. SCPs are guardrails that cap the maximum permissions; effective access is the intersection of SCPs and IAM grants.
  5. Public subnets (the ALB), private subnets (the ECS Fargate tasks), isolated subnets (the RDS database).

Exercise

Pick the two rungs that match the role you are currently targeting (use the ladder table) and take them to the full GitHub presentation standard: descriptive repo name, README with diagram/deploy/teardown/cost/key-decisions, IaC with a one-command destroy, atomic commits, a secrets scan in CI, and the repo pinned to your profile. Then write the quantified résumé bullet for each, adapting the templates above with your own numbers (latency, cost, burst factor, deploy time). Finally, draft a two-sentence answer to the question “walk me through this project” for each — out loud, timed to under 90 seconds. If you can build it, present it, quantify it, and narrate it, that rung is interview-ready.

Certification mapping

This lesson is portfolio evidence across the AWS certification ladder rather than mapped to a single exam:

Build the projects that match the certifications you are pursuing; the portfolio and the exam reinforce each other.

Glossary

Next steps

You now have a build plan and a presentation standard for a portfolio that gets you hired. Next, sharpen the exam side of the story with the AWS Certification Prep Kit: CLF, SAA, SOA, DVA, SAP & DOP — checklists, scenario practice questions, and cheat sheets that pair with these projects. Then take the most senior rung all the way to production depth in the AWS Capstone: Build a Well-Architected Multi-Account Landing Zone + 3-Tier App, which turns projects 3 and 6 into a single, pillar-by-pillar reference build. Together, the portfolio, the certifications, and the capstone make the complete case: you can recognise the right answer, and you can build it.

AWSPortfolioCareerTerraformResumeProjects
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments