Skip to content

atoumbre/cloud_resume_challenge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cloud Resume Challenge

Production-style cloud portfolio project showing how I build and operate a small serverless application with Terraform, GitHub Actions, OIDC, Astro, and AWS.

Live site: atoumbre.me

Cloud Resume landing page preview

What This Repository Demonstrates

  • Infrastructure as Code with reusable Terraform modules
  • Serverless backend design with Lambda, API Gateway, and DynamoDB
  • Edge delivery with S3, CloudFront, and Cloudflare-managed DNS
  • GitHub Actions deployment using OIDC instead of long-lived AWS keys
  • A static Astro frontend that consumes a live backend API at build/runtime boundaries

Architecture

flowchart LR
    User["Visitor Browser"] --> DNS["Cloudflare DNS"]
    DNS --> CDN["AWS CloudFront"]
    CDN --> S3["S3 Static Site Bucket"]
    User --> API["API Gateway HTTP API"]
    API --> Lambda["Python Lambda"]
    Lambda --> DDB["DynamoDB Visitor Counter"]
    GHA["GitHub Actions"] --> OIDC["AWS OIDC Deploy Role"]
    OIDC --> TF["Terraform Apply"]
    TF --> CDN
    TF --> API
    TF --> Lambda
    TF --> DDB
Loading

Repository Structure

cloud_resume_challenge/
├── infra-bootstrap/             # First-run local Terraform root (OIDC + GitHub repo vars)
├── frontend/                    # Astro frontend
├── backend/                     # Lambda handler and backend tests
├── infra/                       # Main application infrastructure root
│   ├── main.tf                  # Root Terraform composition
│   ├── variables.tf             # Root input variables
│   ├── outputs.tf               # Deployment outputs
│   └── modules/
│       ├── backend_api/         # Lambda, HTTP API, and DynamoDB resources
│       └── s3_cloudfront/       # S3 origin, CloudFront distribution, ACM, DNS
├── infra-bootstrap/modules/
│   └── oidc/                    # OIDC provider and GitHub Actions deploy role
└── deploy_local.py              # Local deploy helper

Deployment

Run the one-time bootstrap root from a local machine before relying on GitHub Actions:

export GITHUB_TOKEN="YOUR_GITHUB_TOKEN"
terraform -chdir=infra-bootstrap init
terraform -chdir=infra-bootstrap apply

That bootstrap step creates the GitHub OIDC deploy role and writes the repository variables used by the deploy workflow, including AWS_ROLE_ARN.

Pull requests are validated by .github/workflows/ci.yml. Deployments happen through .github/workflows/deploy.yml on pushes to main. Shared validation and build logic is centralized in reusable workflows under .github/workflows/.

CI/CD flow

  1. Pull requests run Terraform formatting and validation, backend tests, and the Astro production build.
  2. A one-time local apply from infra-bootstrap/ creates the OIDC deploy role and repository variables for GitHub Actions.
  3. GitHub Actions assumes an AWS role using OIDC only for the deploy workflow on main.
  4. Terraform applies infrastructure from infra/.
  5. The frontend builds with PUBLIC_API_URL set from Terraform outputs.
  6. The generated frontend/dist/ assets are synced to S3 and CloudFront is invalidated.

local deploy helper

deploy_local.py is an helper for manual deployment. It follows the same high-level flow as CI: Terraform apply, Astro build, S3 sync, CloudFront invalidation.

Run it from the repo root:

python3 deploy_local.py

Local Setup

Prerequisites

  • AWS CLI
  • Terraform >= 1.5
  • Node.js >= 24.0.0
  • Python >= 3.12

Terraform variables

This repository commits both infra/terraform.tfvars and infra-bootstrap/terraform.tfvars because they contain stable, non-secret project configuration. Keep only the Cloudflare API token out of source control.

export TF_VAR_cloudflare_api_token="YOUR_CLOUDFLARE_API_TOKEN"
export GITHUB_TOKEN="YOUR_GITHUB_TOKEN"

GITHUB_TOKEN is only needed when running the bootstrap root locally.

GitHub Actions configuration

Deploys require this repository secret:

  • CLOUDFLARE_API_TOKEN

The bootstrap root manages the non-secret repository variables used by deploys, including AWS_ROLE_ARN and AWS_REGION.

Testing

Current automated checks in this repository are lightweight but real:

  • Pull request validation for Terraform formatting and validation
  • Backend unit tests with pytest and moto
  • Production frontend build with Astro
  • Deployment verification through Terraform outputs and the live site

Run the main checks locally:

(cd backend && python3 -m pip install -r requirements-dev.txt && pytest test_app.py)
(cd frontend && npm ci && npm run build)
(cd infra-bootstrap && terraform init)
(cd infra && terraform fmt -check -recursive && terraform init -backend=false && terraform validate)

Key Engineering Decisions

  • Use OIDC for GitHub Actions to avoid storing long-lived AWS credentials in GitHub secrets.
  • Keep the frontend static and let only the visitor counter use serverless compute.
  • Provision the visitor counter table inside the backend_api Terraform module because the Lambda, API, and DynamoDB resources are tightly coupled.
  • Use CloudFront in front of S3 rather than direct bucket hosting so the site can use a proper CDN, TLS, and controlled origin access.

Security And Delivery Notes

  • AWS access for CI is federated through the IAM role created from infra-bootstrap/.
  • The S3 bucket is private and exposed through CloudFront origin access control.
  • Cloudflare handles DNS while AWS serves the site and API.
  • Terraform remains the source of truth for infrastructure state.

Future Improvements

  • Add frontend smoke tests for the counter behavior against a deployed preview or local mock API.
  • Narrow the GitHub Actions deploy role permissions further as the infrastructure stabilizes.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors