Gate. Forecast. Failover.

A tested EKS platform, not just a diagram of one. Terraform and GitOps run an EKS cluster with cost-aware autoscaling and policy enforcement out of the box. On top of that baseline: a blocking DevSecOps CI gate, a proactive autoscaler that scales ahead of predictable traffic, and a disaster-recovery path with a measured recovery time.

Git repo Terraform + GitOps Argo CD app of apps EKS cluster Karpenter reactive nodes Kyverno admission policy httpbin 2 replicas, pod anti-affinity + KEDA proactive scaler (POC) ALB public / private ingress DR path (POC): DynamoDB Global Tables + Lambda + Route 53

Solid boxes: deployed and tested. Dashed: proof-of-concept, off by default.

What it is

An EKS platform built the way a small platform team actually runs one: infrastructure as code, GitOps delivery, cost-aware autoscaling, and policy enforcement as the tested baseline — then three additions on top, each scoped and labeled honestly as either production-grade or a proof-of-concept.

InfrastructureTerraform, modular, per-environment statetested
DeliveryArgo CD, GitOps, app-of-apps patterntested
Node scalingKarpenter — bin-packing, spot-awaretested
PolicyKyverno admission controltested
CI securitygitleaks · Semgrep · Checkov · npm auditpoc
App scalingKEDA, forecast-driven, ahead of loadpoc
ResilienceDynamoDB Global Tables + Route 53 failoverpoc
[ screenshot ] Argo CD UI showing all four apps Synced and Healthy, plus a Grafana panel with live cluster metrics — from the Phase 1 baseline verification.

Architecture

Git is the only source of truth. Terraform provisions the cluster and everything that needs AWS IAM (IRSA roles, Karpenter's NodePool, the load balancer controller); Argo CD reconciles everything else — the app, the observability stack, Kyverno's policies, and the two proof-of-concept additions — straight from this repository. Nothing is applied by hand.

A CI gate that actually blocks poc

Four scanners, each independent so one failure never hides another. The build fails on any finding by default — a soft-fail toggle exists only to demo a green run on purpose.

secrets

gitleaks scans the whole repository, not just the Terraform, on every push and PR.

sast

Semgrep, scoped to this repo's actual custom logic — the app itself is a prebuilt image, so the surface is small by design and the README says so.

sca

npm audit, conditional — it only runs if a package.json actually exists, instead of faking one to tick a box.

iac

Checkov against the Terraform, with a no-blanket-suppression policy: every skip needs a written reason and a documented production fix.

[ screenshot ] A failed Actions run showing a deliberately planted secret caught by gitleaks — the Phase 2 checkpoint that proves the gate actually blocks something.

Scaling ahead of the load, not after it poc

A CronJob reads recent ALB request-rate history from CloudWatch, blends in a same-time-yesterday signal, and publishes a forecasted replica count as a custom metric. KEDA scales the app off that forecast instead of live load — the one thing a reactive HPA structurally can't do. It's classical time-series smoothing, not a trained model, and the README says that plainly too.

[ chart or GIF ] Two Grafana screenshots of pod count over time, same synthetic traffic ramp: one under a plain reactive HPA, one under the KEDA forecast — side by side.

A failover with a number attached poc

DynamoDB Global Tables replicate one small table across two regions. A Lambda-backed endpoint — not a fork of the app image — is deployed identically to both. Route 53 health checks drive the failover; a short TTL keeps DNS propagation from dominating the measured recovery time.

RTOtime from health-check failure to Route 53 failing traffic over
RPOnear-zero, not zero — Global Tables replicate asynchronously
[ screenshot or log ] The actual failover test: health check flipping to Unhealthy, the DNS record switching, and the measured RTO written down — not just quoted from a config file.

Build log

Every project accretes — this one absorbed a security-gate design from an earlier, separate pipeline project rather than merging two competing delivery systems into one. The full reasoning is in the repo's changelog; here's the shape of it.

0

Repo consolidation

Absorbed the security-gate concept from a separate CI/CD project — not its CodePipeline stack, which would have competed with Argo CD.

1

Baseline verification

Confirmed the existing platform still deploys clean end to end before adding anything.

2

DevSecOps gate

Added the four-scanner CI gate, proven with a deliberately planted secret.

3

Predictive scaling

KEDA + a forecasting CronJob, measured against a reactive-HPA baseline.

4

Disaster recovery

Cross-region failover, tested once, torn back down.

5

Documentation

This page, the README, and a study guide written phase by phase.