Frank Idugboe
Menu
← Back to Projects

Platform Engineering · Cloud & DevOps

Production AWS Portfolio Platform

This website is itself an engineering project. It runs on AWS as a secure static site with a serverless contact backend, defined entirely in Terraform and deployed automatically through GitHub Actions using short-lived OIDC credentials — no stored AWS keys.

AWSTerraformGitHub ActionsOIDCCloudFrontS3WAFAPI GatewayLambdaSESRoute 53DNSSECACMCloudWatchAstro

Goal

A portfolio that proves the skills it describes.

The objective was not simply to publish a website, but to run it the way production infrastructure should be run: reproducible from code, secured by default, observable, automatically deployed, and free of long-lived credentials. The site therefore doubles as a working reference for the cloud and DevOps practices described across the rest of this portfolio.

Architecture

Static delivery, a serverless API, and a single edge.

Visitors are served through CloudFront over HTTPS. The static site lives in a private S3 bucket reachable only through CloudFront via Origin Access Control. The same distribution routes/api/*to the contact backend, so the whole site sits behind one WAF and one certificate.

Internet

↓

Route 53 (DNSSEC signed)

↓

CloudFront + ACM TLS + WAF + Security Headers

↓ ┌───────────────┐

Static site ← private S3 (OAC / SigV4)

/api/* → API Gateway → Lambda → SES → private inbox

Delivery

Everything ships through an automated, credential-free pipeline.

All infrastructure is defined in modular Terraform with remote state in S3 using native state locking. GitHub Actions authenticates to AWS through OpenID Connect, assuming short-lived roles — a read-only role for pull-request plans and a separate deploy role scoped to the production environment. There are no static AWS access keys.

Pull request

↓ terraform fmt · module & composition tests · validate

↓ plan (OIDC) · TFLint · Checkov · Trivy

Merge to main

↓ production environment (manual approval)

↓ terraform apply (OIDC)

↓ Astro build → S3 sync → CloudFront invalidation

↓ HTTPS + contact-API smoke test

The deploy role holds no IAM self-modification permissions; the Lambda execution role and OIDC roles are provisioned separately in a security plane. UI-only changes skip the Terraform apply step to avoid unnecessary control-plane activity.

Security

Secure by default at every layer.

The S3 origin blocks all public access and is reachable only through CloudFront. TLS is enforced (1.2+), with AWS-managed security response headers including HSTS.

A CloudFront-scoped WAF applies the AWS managed common rule set, the Known Bad Inputs set (covering Log4j), and an IP rate-based rule in front of both the site and the contact API.

The contact Lambda validates input, uses a honeypot field to drop bots, applies rate limiting, and sends through SES from a verified domain identity — the destination inbox is never exposed publicly.

DNS is signed with DNSSEC (a KMS-backed key-signing key), and the delegation-signer record is published at the registrar, so the chain of trust validates end to end.

Infrastructure-as-code security scanning (TFLint, Checkov, Trivy) runs on every change, and each finding is classified as implemented, accepted risk, or documented false positive in a written security policy.

Observability

Logs, alarms, and a cost guardrail.

CloudFront access logs, S3 server access logs, WAF logs, and Route 53 query logs are delivered to a governed, private log destination. A CloudWatch alarm watches the contact Lambda for errors, notifications are delivered through SNS, and a monthly AWS Budget provides an early cost-overrun signal.

Results

A reproducible, self-operating site.

The entire platform is reproducible from code and deploys on merge with a single manual approval gate. Frontend quality checks, Terraform validation and tests, and IaC security scans are required before any change reaches production.

Each deploy verifies itself: the pipeline confirms the homepage returns HTTP 200 with the expected security headers and that the contact API correctly rejects invalid input — without sending a real email.

Lessons

Small platform decisions compound.

OIDC federation removes an entire class of credential-management risk compared with stored access keys.

Keeping IAM changes out of the deploy role's permissions preserves a clear separation between the delivery pipeline and the security plane.

Security scanners are most useful when their findings are decided deliberately and documented, rather than chased blindly toward a green badge.

Treating routing, caching, and per-object cache headers explicitly keeps a static site both fast and always up to date after deploys.

Technologies

AWSTerraformGitHub ActionsOIDCCloudFrontS3WAFAPI GatewayLambdaSESRoute 53DNSSECACMCloudWatchAstro