The Cloud Resume Challenge: CI/CD, Python, and Surviving a Security Scare

Published: (March 13, 2026 at 07:11 PM EDT)
4 min read
Source: Dev.to

Source: Dev.to

Introduction

Theoretical knowledge is foundational, but engineering competency is built through implementation.

I realized that understanding the theory of services like S3, Lambda, and DynamoDB wasn’t enough—I wanted to demonstrate that I could orchestrate them into a secure, automated, production‑grade application.

The Cloud Resume Challenge (created by Forrest Brazeal) was the perfect framework to bridge the gap between architectural concepts and real‑world DevOps implementation.

Challenge Accepted

Here is how I built a serverless resume website, automated the deployment with GitHub Actions, and solved the engineering hurdles along the way.

The Architecture

The project requirement is simple: “Host a resume online.”
The architecture I implemented is pure Cloud Engineering:

LayerTechnology
FrontendHTML/CSS hosted on S3, accelerated by CloudFront (HTTPS) for global caching
BackendAWS Lambda (Python) handling API requests
DatabaseDynamoDB (NoSQL) for storing the visitor count
InfrastructureFully automated CI/CD pipelines using GitHub Actions

Level 1: The Frontend Glue (JavaScript)

The website itself is static HTML/CSS, but making it dynamic required JavaScript. I wrote a script to fetch the visitor count from my API Gateway trigger.

The biggest hurdle was CORS (Cross‑Origin Resource Sharing). My JavaScript running on aminetraibi.com was trying to talk to an AWS Lambda URL, and the browser blocked it for security reasons.

Fix: Configure the Python Lambda function to return the header Access-Control-Allow-Origin: * so the browser accepts the response.

// Fetching the view count
fetch(apiUrl)
  .then(response => response.json())
  .then(data => {
    document.getElementById('counter').innerText = data.views;
  });

Level 2: The Backend Logic (Python & DynamoDB)

I needed an atomic counter that increments every time the page loads. I wrote a Python script using boto3 to talk to DynamoDB.

A specific challenge was handling DynamoDB reserved words. Since views is a reserved keyword, I used ExpressionAttributeNames to map it correctly.

# Atomic update using UpdateExpression
response = table.update_item(
    Key={'id': 'page_view'},
    UpdateExpression='SET #v = #v + :val',
    ExpressionAttributeNames={'#v': 'views'},
    ExpressionAttributeValues={':val': 1},
    ReturnValues='UPDATED_NEW'
)

Level 3: The Security Lesson 🚨

This was the most critical part of my learning journey.

I learned a hard lesson about secrets management. Early in the build I accidentally committed credentials to the repository.

Sweating

I immediately identified the risk, revoked the keys in IAM, and migrated to GitHub Secrets.

Key takeaways

  • Use a dedicated IAM user with least‑privilege permissions.
  • Inject keys only at runtime via the CI/CD pipeline.
  • Never store secrets in source control.

Level 4: Automated Testing & Mocking

The challenge requires Python unit tests, which turned out to be one of the hardest parts.

When I ran tests locally, boto3 tried to connect to the real DynamoDB. In the CI/CD environment I didn’t want my tests to depend on an internet connection or live database permissions.

The Solution: Mocking

I used the unittest.mock library to simulate AWS services. By mocking the DynamoDB table resource, I could test the function logic without making any actual API calls.

Hackerman

# Using MagicMock to fake the database response
mock_table = MagicMock()
mock_table.update_item.return_value = {'Attributes': {'views': 123}}
lambda_function.table = mock_table

This keeps the pipeline fast, robust, and free of AWS costs during testing.

Level 5: CI/CD (The “Green Checkmark”)

The ultimate goal was to move away from the AWS Console (“ClickOps”) and adopt proper DevOps practices.

I built two separate GitHub Actions workflows:

WorkflowTriggerActions
Frontend PipelineChanges in HTML/CSSSync to S3, invalidate CloudFront cache
Backend PipelineChanges in Python codeRun unit tests, zip code, update Lambda function

Now a simple git push to main updates the entire application automatically.

Success

Conclusion & Next Steps

This project forced me to touch every part of the stack: Networking (DNS/Route53), Security (IAM), Compute (Lambda), Database (DynamoDB), and Frontend logic (JavaScript).

My next milestone is to continue building on this foundation—specifically diving deeper into Infrastructure as Code with Terraform and exploring containerization with Docker/ECS.

If you are looking for a Cloud Engineer who learns by doing, breaks things, and fixes them—let’s connect!

Live Site: https://aminetraibi.com
GitHub Repository: https://github.com/AmineTra/cloud-resume-challenge

Success

0 views
Back to Blog

Related posts

Read more »

Travigo

Travel as fast as you speak with Gemini! Where live agents meet immersive storytelling & 3D navigation. This project was created for entering the Gemini Live Ag...

Micro games

Hey Gamers! 👾 As part of the Rapid Games Prototyping module, we are tasked with reviewing a peer's game. The challenge is to analyse a prototype built in just...