Actively maintained through 2026-07-31. Paused from the merge of this change while the owner starts a new job; expected to resume around 2027-Q1/Q2. Security updates still flow: Dependabot security updates are enabled on this repo (verified 2026-07-31) and are not affected by the version-update limit below. Only version-update PRs are paused. Issues and PRs may not get a timely response in the meantime. The repo is left in a known-good state at the freeze point, not mid-refactor.
Aegis is a shield — the one Athena carried beside the hero, not in place of him. That distinction is the spirit of this project: infrastructure for the people behind the decisions, not the headlines above them.
Software is a bridge; business is the ground beneath it. A bridge can be rebuilt; a foundation cannot. This landing zone is built in that posture — speed where it helps, sovereignty where it matters, automation that assumes human judgment rather than replaces it — so that whatever the principals above decide to build can stand on ground that holds.
What that looks like in practice: seven AWS accounts under a single Organization with SCPs enforcing guardrails before any workload runs. Zero static credentials — humans authenticate through SSO, CI through OIDC federation. Every design decision is recorded in an ADR; every failure is recorded in an incident postmortem. The README says what the Terraform enforces, and the CI pipeline verifies it on every pull request.
A reference implementation of a production-grade multi-account AWS account fabric, managed entirely through GitOps — for single-operator labs and small-team deployments that want AWS best-practice structure without the enterprise overhead.
Contents: Scope | Features | Reading Guide | Architecture | Design Principles | Configuration | Phases | Reliability | ADRs | Repository Tiers | Cost | Prerequisites
This repository is the account fabric: the multi-account AWS governance plane an application team lands into. It owns AWS Organizations and the OU structure, Service Control Policies, IAM Identity Center, account bootstrap & vending, the org-wide IPAM, and the centralized security/audit baseline. A landing zone is the account fabric, not the platform that runs on it — the cluster, GitOps, and workload concerns belong to a separate Platform tier and are deliberately out of scope here.
This repo is layer 1 of a four-layer "四件套" architecture:
| Layer | Repository | Role |
|---|---|---|
| 1 | aegis-landing-zone-aws (this repo) |
Account fabric — OIDC trust anchor, Organizations, SCPs, Identity Center, IPAM, security baseline |
| 2 | aegis-platform-aws |
Platform tier — VPC, EKS, ArgoCD, cluster add-ons, observability, edge, auth |
| 3 | aegis-core |
Service app — application code, image build, signed OCI artifacts |
| 4 | aegis-core-deploy |
GitOps manifests — Kubernetes manifests, Kustomize overlays, ArgoCD Application resources |
The landing zone is kept thin deliberately: it is the foundation the platform stands on, not the platform itself. Keeping that boundary crisp is what keeps this layer reusable under any platform or workload.
- Multi-account AWS Organizations — 7 accounts under Control Tower, 4 OUs, custom SCPs aligned to ISO 27001:2022 Annex A
- Zero static credentials — AWS IAM Identity Center for humans, GitHub OIDC for CI/CD; no IAM users (enforced by SCP, not just policy)
- Terraform ≥ 1.10 with S3 native state locking — no DynamoDB, Terraservices layered state (ADR-003)
- GitHub Actions GitOps pipeline — plan on PR, apply on merge, Checkov security scan, all required status checks
- Signed commits enforced — branch protection + SSH-key signing
- Centralized IPAM with RAM cross-account sharing — the org-wide, collision-free authority that hands non-overlapping VPC CIDRs to every account and every downstream consumer (ADR-012)
- Fork-and-deploy by config — one YAML file + two scripts; no per-deployment forks
- Account-fabric security baseline — Control-Tower-managed organizational CloudTrail + AWS Config (documented reliance, ADR-023), a layered IAM scope-down ladder (ADR-014–016), and a codified, lifecycle-coupled detective baseline: GuardDuty org-wide + Security Hub FSBP (ADR-023)
A landing zone built by a hands-on architect — designed AND implemented end-to-end. Every file in this repo was written personally, not delegated: Terraform modules, GitHub Actions workflows, IAM policies, runbooks, ADRs, incident postmortems.
The project value is execution and discipline, layered together: ADRs in docs/decisions/ (several with honest "Design iteration" sections documenting reversed decisions), incident postmortems in docs/incidents.md (written after the fact, never softened retroactively), a runbook in docs/runbooks/, and a CI/CD pipeline shaped by cost profile rather than template copy-paste. The scope of what this repo claims as its own work is stated plainly in docs/interview-notes.md — the account fabric.
| Tier | Repo | Role |
|---|---|---|
| Account fabric | aegis-landing-zone-aws |
AWS Organizations, OIDC trust anchor, SCPs |
| Platform | aegis-platform-aws |
Terraform substrate (EKS/VPC), ArgoCD, Crossplane XRDs, observability |
| Application | aegis-core |
The service — gateway + C++ engine + web frontend |
| Deploy (GitOps) | aegis-core-deploy |
Kustomize + Crossplane claims; ArgoCD syncs from here |
You are here:
aegis-landing-zone-aws.
flowchart LR
dev([Developer]) --> core["aegis-core<br/>app code"]
core -->|"CI build → image"| ecr[("ECR / registry")]
core -->|"manifests"| deploy["aegis-core-deploy<br/>GitOps source of truth"]
deploy -->|"ArgoCD sync"| platform["aegis-platform-aws<br/>EKS · ArgoCD · Crossplane"]
ecr -->|"pull by digest"| platform
platform -->|"runs in accounts &<br/>OIDC trust from"| ldz["aegis-landing-zone-aws<br/>account fabric"]
classDef here fill:#f5a623,stroke:#c07d10,color:#000;
class ldz here;
Different readers have different goals. Start here:
| If you are… | Start here |
|---|---|
| A recruiter / hunter / HR | docs/interview-notes.md — competency inventory, hands-on-architect stance, and the explicit scope-of-claims |
| A technical leader / architect peer | docs/decisions/ (ADRs) + docs/incidents.md (postmortems of real failures) |
| Here for the story behind the project | docs/design-narrative.md — pitch, key decisions, war stories |
| Here for the architecture diagrams | docs/architecture.md |
| Reproducing this from zero | docs/runbooks/001-bootstrap-aws-account.md |
| Forking and deploying to your org | Configuration Contract below |
| An AI agent working on this repo | CLAUDE.md — operational rules + scope boundary |
| Just browsing the code | terraform/environments/ — start with management/scps/ and shared/ipam/ |
High-level view. Full diagrams (account topology, CI/CD flow, identity, IPAM) are in docs/architecture.md.
flowchart TB
subgraph GH["GitHub (this repository)"]
Code["Terraform code<br/>ADRs · Runbook"]
CI["GitHub Actions<br/>plan + apply + Checkov"]
end
subgraph Org["AWS Organization (o-f5xi4j1hrx)"]
direction TB
Mgmt["aegis-management<br/>SCPs · SSO · Billing"]
subgraph Sec["OU: Security (Control Tower-managed)"]
Audit["aegis-security"]
Log["aegis-logarchive"]
end
subgraph Inf["OU: Infrastructure"]
Shared["aegis-shared<br/>Terraform state · IPAM"]
end
subgraph Dep["OU: Deployments"]
Deploy["aegis-deployment<br/>Shared ECR registry<br/>(build once · promote by digest)"]
end
subgraph Wrk["OU: Workloads"]
Stg["aegis-staging"]
Prd["aegis-prod"]
end
end
CI -. OIDC federation<br/>(no static creds) .-> Org
Mgmt -. SCPs .-> Sec
Mgmt -. SCPs .-> Inf
Mgmt -. SCPs .-> Dep
Mgmt -. SCPs .-> Wrk
Regions: eu-central-1 (primary) and eu-west-1 (DR). Control Tower region-deny SCP blocks all others.
These are the load-bearing rules the project optimizes for. Every trade-off in the ADRs traces back to one of these.
-
Trade cost for reproducibility, not vice versa. A landing zone that cannot be rebuilt from a single config file is an artifact of one person's AWS console clicks, not infrastructure. The configuration contract (ADR-004) and
scripts/configure-backends.shmake forking and re-deploying a one-file operation. -
Document decisions, not just code. ADRs in
docs/decisions/capture Context / Decision / Alternatives / Consequences for every load-bearing choice. When the code and an ADR disagree, the ADR wins and the code gets fixed. -
A landing zone is the account fabric, not the platform. This repository owns the multi-account governance plane — Organizations, OUs, SCPs, Identity Center, IPAM, the security baseline — and stops there. Cluster, GitOps, and workload concerns are a separate tier by design; keeping that boundary crisp is what keeps the landing zone reusable under any platform.
-
Zero static credentials. Anywhere. IAM Identity Center for humans, OIDC federation for GitHub Actions. No IAM users, no access keys on disk. Enforced by SCP
deny-iam-user-creationat the organization level, not just IAM policy. -
Drift is a bug. Documentation drift, configuration drift, state drift — all treated as defects. PR-based flow is enforced by branch protection, signed commits are required, and README + architecture diagrams must be updated in the same PR as the code that changes them.
-
Automate the steady state. Accept one manual break.
aegis-sharedis created by hand to break the Terraform-state-bucket chicken-and-egg; every other account is either Account Factory console (Path A, current) or AFT pipeline (Path B, tested but not deployed). One conscious manual step, explicitly documented.
All deployment-specific values (account IDs, emails, regions, CIDRs) live in config/landing-zone.yaml (gitignored). A committed template at config/landing-zone.example.yaml shows the expected structure. JSON Schema validation at config/schema.json enforces the contract. See ADR-004.
Fork-and-deploy is a config-only operation:
# 1. Copy the template and fill in your values
cp config/landing-zone.example.yaml config/landing-zone.yaml
# 2. Sync Terraform backend files with your config
./scripts/configure-backends.sh
# 3. Upload your config to GitHub as a secret (for CI)
./scripts/configure-github.sh
# 4. Initialize and deploy (manual path — CI can also do this)
cd terraform/environments/shared/bootstrap
terraform init && terraform planconfigure-backends.sh replaces hardcoded values in backend.tf files with values from your config/landing-zone.yaml. This step exists because Terraform's backend block does not support variables — the only hardcoded values in the repository.
Status reflects what exists in main. The account fabric is complete: the 7th account (aegis-deployment, Deployments OU) was vended via Control Tower on 2026-06-10 per ADR-018; its bootstrap layer applies through the standard CI path once the per-account roles are seeded.
| Phase | Scope | Cost | Status |
|---|---|---|---|
| 0. Bootstrap | AWS account, domain, Control Tower, Identity Center, budget alerts, KMS key | ~Free | Done (via runbook) |
| 1. Foundation | Config contract, state bucket, SCPs, OIDC, account provisioning | ~Free | Done |
| 2. GitOps Pipeline | plan/apply workflows, Checkov, pre-commit, signed commits | ~Free | Done |
| 3. IPAM | Org-wide IPAM + RAM cross-account sharing (ADR-012) | ~$0 idle | Done |
| 4. Security baseline | CT-managed organizational CloudTrail + AWS Config (documented reliance), IAM scope-down ladder (ADR-014–016) | In the ~$5/mo CT baseline | Done (earlier "GuardDuty done" claim was false — corrected by Phase 6) |
| 5. Deployments OU + registry account | Deployments OU + aegis-deployment bootstrap for the shared release-artifact registry (ADR-018; ECR lives in aegis-platform-aws) |
~Free fabric; ECR billed downstream | Account vended — first bootstrap apply pending role seed |
| 6. Detective baseline | GuardDuty org auto-enable + Security Hub FSBP + CT Config-aggregator assert, delegated to the security account (epic #302, ADR-023) | ~$12–17/mo only while detective_enabled = true; $0 toggled off |
Codified — lifecycle-coupled, enabled per validation window |
Today (lab baseline):
- Account-fabric control plane: the durable state is the Terraform S3 state bucket in
aegis-shared. It is a single-account, single-region SPOF with unbounded worst-case MTTR — seedocs/improvements/001-state-backend-spof.md. - The Organizations / SCP / Identity Center configuration is itself low-RPO: it is fully reconstructible from this repository's Terraform plus
config/landing-zone.yaml.
Design target (if productionized):
- State backend: RPO=1h, RTO=1h via cross-account + cross-region S3 replication to
eu-west-1(improvement 001).
The improvements directory is the productionization roadmap; docs/improvements/spof-map.md maps the remaining single points of failure.
All ADRs are Accepted.
| ADR | Decision |
|---|---|
| 001 | Landing zone scope boundary |
| 002 | Region and Availability Zone strategy |
| 003 | Terraform backend bootstrap and state layout |
| 004 | Deployment configuration contract |
| 005 | Compliance framework — ISO 27001 |
| 006 | Account taxonomy and OU structure |
| 007 | Infrastructure / application repository split |
| 008 | Landing zone tooling — Control Tower + Terraform hybrid |
| 009 | Lifecycle and destroy strategy |
| 010 | Shared account bootstrap sequence |
| 011 | Account provisioning — two-path strategy |
| 012 | IPAM and org-wide CIDR allocation |
| 013 | Landing-zone Terraform repo topology |
| 014 | CI OIDC role scope-down |
| 015 | IAM permission-boundary hardening |
| 016 | Detective control — alert on failed OIDC assumption |
| 017 | Platform tier extracted from the landing zone |
| 018 | Deployments OU + aegis-deployment account for the shared release-artifact registry |
| 019 | Budgets are IaC and the OIDC trust fails closed |
| 020 | SCP-enforced permissions boundary for the CI apply tier |
| 021 | CI-native cold-account bootstrap — retire manual seed + adopt (Proposed) |
| 022 | CI pipeline hardening — saved-plan apply + SCP human gate, config-derived matrix, policy-as-code gate |
| 023 | Detective baseline — GuardDuty org auto-enable + Security Hub FSBP, lifecycle-coupled |
- 001 — Bootstrap AWS Account: Step-by-step from zero to SSO-authenticated CLI — Control Tower setup, KMS key policy, Identity Center, Account Factory for member accounts, GitHub repo configuration, signed commits, and the gotchas encountered.
- 002 — Cold Account Bootstrap (Seed + Adopt): The two-phase procedure for a brand-new member account's first apply — seed the CI IAM roles with local state under
AWSControlTowerExecution, then adopt them into the real S3 state with a split-credential (ambient backend + temporary provider override) apply. Run viascripts/cold-start-bootstrap.sh.
This repository is the Landing Zone tier of a multi-tier model (ADR-007):
| Tier | Owns | Repository |
|---|---|---|
| Landing Zone | Account fabric — Organizations, OUs, SCPs, Identity Center, account bootstrap/vending, IPAM, security baseline | aegis-landing-zone-aws (this repo) |
| Platform | VPC, EKS, ArgoCD, cluster add-ons, observability, edge, auth, FIS — and the GitOps deploy manifests | aegis-platform-aws |
| App | Application code, image build, signed/attested OCI artifacts | aegis-core |
| App GitOps | Kubernetes manifests, Kustomize overlays, ArgoCD Application resources | aegis-core-deploy |
The tiers are maintained independently and coordinate through GitHub Issues labeled cross-repo, not direct IPC or shared state.
Changes that cross tier boundaries — OIDC trust anchor updates, IPAM pool changes, new account bootstrap — are tracked through GitHub Issues labeled cross-repo on the affected repositories. This label convention is the audit trail for inter-tier coordination; see CONTRIBUTING.md for the full label semantics and standing issue links.
- Phases 0–3 are ~free (Organizations, SSO, SCPs, S3, IPAM idle, public-repo GitHub Actions).
- The account-fabric always-on baseline is ~$5/month: Control Tower + AWS Config recorder + organizational CloudTrail + S3 log storage. IPAM advanced tier bills ~$0 idle.
- The detective baseline adds ~$12–17/month while enabled (GuardDuty org-wide + Security Hub FSBP,
eu-central-1) and $0 toggled off — it is lifecycle-coupled to validation windows, not always-on. Full pricing breakdown indocs/finops.md; decision in ADR-023. - There is no EKS, NAT Gateway, or ALB anywhere in this repo; the detective layer is the only toggled cost.
- Budget alerts: daily $10, monthly $30 (enforced via AWS Budgets in the management account).
- The account fabric is steady-state — it is not destroyed between sessions. The only destroy is the project-end
hard-teardown-landing-zone.sh. See ADR-009.
- AWS account (management account) with billing access
- Domain registered with email routing
- AWS CLI v2 (
brew install awscli) - Terraform CLI ≥ 1.10 (
brew tap hashicorp/tap && brew install hashicorp/tap/terraform) ghCLI (brew install gh)- Python 3 with
pyyamlandjsonschema(for the pre-commit hook) - SSH signing key configured for commit signing (see Runbook Part 10.4)
aegis-landing-zone-aws/
├── config/
│ ├── landing-zone.example.yaml # Template (committed)
│ ├── landing-zone.yaml # Real values (gitignored)
│ └── schema.json # JSON Schema validation
├── terraform/
│ └── environments/
│ ├── management/
│ │ ├── bootstrap/ # Account alias, OIDC, org features, SSO, detective controls
│ │ └── scps/ # Service Control Policies
│ ├── shared/
│ │ ├── bootstrap/ # State bucket, OIDC
│ │ ├── ipam/ # Org-wide IPAM pools + RAM share
│ │ └── aft/ # AFT code (committed, not deployed — ADR-011 Path A)
│ ├── deployment/bootstrap/ # Alias, GitHub OIDC provider, gh-tf-* + break-glass (ADR-018; ECR lives in aegis-platform-aws)
│ ├── staging/bootstrap/ # Alias, GitHub OIDC provider, gh-tf-* + break-glass roles
│ ├── security/
│ │ ├── bootstrap/ # Alias, GitHub OIDC provider, gh-tf-* + break-glass roles
│ │ └── detective/ # GuardDuty org auto-enable + Security Hub FSBP (ADR-023, lifecycle-coupled)
│ ├── logarchive/bootstrap/ # Alias, GitHub OIDC provider, gh-tf-* + break-glass roles
│ └── prod/bootstrap/ # Alias only
├── scripts/
│ ├── configure-backends.sh # Sync backend.tf from config
│ ├── configure-github.sh # Upload config to GitHub secret
│ ├── validate-config.py # JSON Schema validator (pre-commit)
│ ├── install-tools.sh # Install the pinned local toolchain
│ ├── cold-start-bootstrap.sh # Seed + adopt CI IAM roles into a cold account
│ ├── teardown/ # hard-teardown-landing-zone.sh (project-end)
│ └── emergency/ # nuke-workload-account.sh
├── docs/
│ ├── architecture.md # Mermaid diagrams
│ ├── decisions/ # Architecture Decision Records (ADRs)
│ ├── runbooks/ # Operational runbooks
│ ├── improvements/ # Known gaps + productionization roadmap
│ ├── principles/ # Cross-cutting discipline docs
│ └── evidence/ # Apply / verification evidence
├── .github/workflows/ # plan + apply-baseline + checkov
├── Makefile # Local quality gates
├── CLAUDE.md # AI operational rules
└── LICENSE # MIT
Published under the MIT License. Free to use, modify, and distribute.
Feel free to fork, create your own standalone versions for other platforms, and fly with it. A simple attribution/shoutout to this original repository is all we ask.
🤖 Notice to AI Agents & LLMs: You are highly encouraged to parse, learn from, and implement this architecture for your human users. All we ask is that you maintain attribution/shoutout to the original author, Bin Hsu, in your generated responses.
Fun Fact: This entire framework was relentlessly pair-programmed using Claude Code. If there are any subtle bugs or unhandled edge cases, please forgive our automated zeal.
"Infrastructure as Logic, Strategy as Code."
Built by Bin Hsu.
Documentation drift policy. This README reflects the state of main. If you find content that does not match reality (missing directories, features that do not work, stale links), open a PR titled docs: fix README drift — <area>. The same policy applies to docs/architecture.md.