Samuel Tillman
  • About Me
  • Skills
  • Projects
  • Posts
  • Categories

Building an AWS Multi-Account EKS Platform in Public

Kicking off a weekly series building a complete, forkable AWS organization and Kubernetes based platform in the open with zero stored AWS credentials, everything as code, and an ADR behind every decision.

July 20, 2026

Most public AWS examples are fragments. One account, one purpose, and, if you read closely, a quiet dependency on a stored credential or some prerequisite a human built by hand and never wrote down. They teach you the shape of a resource, not the shape of a system.

I wanted the other thing. So I’ve been building a complete AWS organization in the open: multiple accounts, an internal developer platform on Kubernetes, and a realistic demo workload, a fictional fishing-charter booking SaaS, because “hello world” doesn’t have a database, a queue, and async jobs. It’s MIT-licensed, it lives on GitHub, and the whole point is that you can fork it, set your variables, and stand up your own.

This post is the map. It covers the principles the project is built on and walks the six-layer roadmap end to end. Starting next week, each layer gets its own deep dive, including the deployment gotchas that cost me real hours and that no tutorial warns you about. Those war stories are coming; this is the orientation.

The rules I gave myself

Five principles, and they’re load-bearing. Every one of them has said “no” to a shortcut at some point, which is how I know they’re real.

Zero stored AWS credentials. Ever. There is not a single IAM user or access key anywhere in this organization. Humans authenticate through IAM Identity Center (SSO). CI authenticates through GitHub Actions OIDC federation. Workloads use IAM roles. No access credential outlives a session. Application secrets are a different category and they do exist: they live in AWS Secrets Manager, generated at random, never in git, never baked into an image, and reachable only by a role-based identity. What doesn’t exist is a credential to reach them. This isn’t a nice-to-have bolted on later; it’s a constraint I designed around from the first commit, and it changes the architecture in ways the later posts will show.

Everything is code. The only manual steps are the genuinely unavoidable bootstrap that creates the organization itself, the chicken-and-egg problem where something has to exist before Terraform can run. I documented every one of those ClickOps steps honestly rather than pretending they don’t exist. Everything after the bootstrap is Terraform.

Forkable by design. Account IDs, domains, org-specific values: all variables. A Control Tower landing zone can’t be forked; a Terraform org module can. That drove a lot of the design.

Costs stay capped. Spot capacity, scale-to-zero, and a documented destroy-and-rebuild flow. Every paid org service sits behind an enable_* flag so the platform can be stood down to near-zero and rebuilt from code. My rule: if it can’t be rebuilt from this repo, it doesn’t belong in this repo.

Decisions get documented. Every significant choice becomes an Architecture Decision Record, a short note capturing what I chose, the situation that forced it, and what I traded away. When a decision changes, I don’t delete the old one; I supersede it, so the reasoning history stays intact. Reading how the thinking evolved is the whole value.

The six layers

I’m building this thing one layer at a time, and each layer has to be production-grade, publicly reviewable, and rebuildable before the next one starts. Here’s the whole roadmap. If you’d rather see it than read it, there’s a visual architecture reference with a diagram for every layer, plus a live roadmap page that always shows what’s actually shipped, which will stay current long after this post goes stale.

Layer 0: org bootstrap. The foundation everything else assumes: the AWS Organization itself, the OU structure, service control policies, the Terraform state backend, and GitHub OIDC. It’s a deliberately small, deliberately boring five-account layout: management, a security account, shared services, and dev/prod workload accounts. This is where “zero stored credentials” and “everything as code” get their first real test, because you have to bootstrap a credential-free system without any credentials to start from. Done.

Layer 1: landing zone. The organization-wide services that make the platform safe to build on: identity through Identity Center, centralized and tamper-resistant logging, org-wide security tooling, plus the CI/CD pipeline and the network. The network is the piece I’m proudest of, a hub-and-spoke design with a Transit Gateway and centralized egress, so workload accounts share one NAT tier instead of paying for NAT per VPC. This layer is also where I learned that Terraform quietly does not do several things the AWS console does for you. That’s a whole post on its own. Done.

Layer 2: EKS platform. The internal developer platform itself, on Kubernetes. The core is now shipped: the EKS cluster, ArgoCD for GitOps delivery, Karpenter for autoscaling, Prometheus and OpenTelemetry for observability, Kyverno for policy enforcement, passwordless dashboard access, and External Secrets for platform secrets. Still to come: Cilium, a service mesh, and Backstage as the developer portal. This is the layer most people actually come for. Core complete.

Layer 3: GPU/AI serving. The interesting workload tier: the NVIDIA GPU Operator, MIG for slicing GPUs into shareable units, and vLLM for serving models efficiently. This is where the cost discipline from Layer 0 earns its keep, because GPUs are exactly the kind of resource that quietly bankrupts a side project if you can’t scale it to zero and rebuild it on demand. Planned.

Layer 4: sample workload. The platform finally earns its keep by running something real: the fishing-charter booking SaaS from the top of this post, deployed onto the EKS platform, plus the data pipeline behind it (ingest to embeddings to vector store) and a Bedrock RAG service on top. This is the layer that proves the whole stack is a place you can actually ship an application, not just an empty control plane. It’s application code, not landing zone, which is exactly why it lives up here and isn’t folded into Layer 1. Planned.

Layer 5: architecture docs. The reflective layer: the full ADR log read as a single narrative, a threat model for the whole platform, and a FinOps dashboard that makes the cost story concrete rather than aspirational. A reference platform that doesn’t explain its own reasoning is just someone else’s Terraform. Planned.

Where this goes from here

That’s the shape of it: Layer 0 and Layer 1 done, giving an organization with identity, an audit backbone, org-wide security services, per-account OIDC deploy roles, and a real hub-and-spoke network, all with zero stored credentials and an ADR behind every decision.

This post kicks off a weekly series. Each week I’ll take one layer and go deep: the design choices, the trade-offs, and the deployment gotchas I hit along the way, the AWS Organizations service-enablement traps, the “it looks like eventual consistency but it’s actually a config error” diagnoses, the partial applies that are just normal here. The stuff the tutorials leave out.

Next week: Layer 0, the org bootstrap, and how you build a credential-free system when you have no credentials to start with.

The repo is public and MIT-licensed. Fork it, set your variables, and the whole thing is yours: github.com/samueltillman/aws-eks-reference-platform . If you want the executive version first, the value map lays out what each layer actually demonstrates and why it’s there.

More layers coming.

Enjoyed this? I write about AWS, DevOps, SRE, and building platforms in public. New posts most weeks.

Subscribe to Highly Available
  • AWS
  • EKS
  • Kubernetes
  • Terraform
  • DevOps
  • SRE
  • Platform Engineering
Share:
☕ Enjoyed this? Buy me a coffee

Comments

© Samuel Tillman 2026