diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index e70cfd5..b537091 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -50,3 +50,12 @@ jobs: stack-name: "seahaven-dev-baseline" secrets: deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN_DEV }} + + deploy-prod: + uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@3cde673b9d05c0e68aac4d997d582f2543853d20 # main + with: + node-version: "24" + stacks: "prod-baseline" + stack-name: "seahaven-prod-baseline" + secrets: + deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN_PROD }} diff --git a/README.md b/README.md index 8c406c4..38fb4f5 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,11 @@ Stacks (deployed by the CD workflow — one job per target account): | `seahaven-regional-baseline-us-east-2` | 328440206208 | us-east-2 | Bedrock invocation logging + AWS Config recorder + Security Hub (INFRA-91 / INFRA-16) | | `seahaven-backup` | 328440206208 | us-east-1 | Primary AWS Backup vault + plan + role (C-7) | | `seahaven-backup-offsite` | 328440206208 | us-west-2 | Governance-locked offsite copy vault (C-7) | +| `seahaven-org-governance` | 328440206208 | us-east-1 | AWS Organizations OU tree + SCPs (incl. the cdk-imported external-dev guardrails) | | `seahaven-external-dev-baseline` | 396287094661 | us-east-1 | Member-account baseline: Config, GuardDuty, Security Hub (FSBP + CIS v3.0), Access Analyzer, flow logs, budget | | `seahaven-security-baseline` | 001520130573 | us-east-1 | Member-account baseline for the delegated security-admin account (same construct set) | | `seahaven-dev-baseline` | 710827005802 | us-east-1 | Member-account baseline for internal dev/staging (org-managed detection — no local GuardDuty/SecurityHub) | +| `seahaven-prod-baseline` | 011934824531 | us-east-1 | Member-account baseline for production workloads (org-managed detection; mgmt account frozen for new workloads) | ## CDK app @@ -43,12 +45,12 @@ the TypeScript source — no separate compile step needed for `cdk synth` / | Path | Role | |---|---| | `cdk.json` | CDK config: `app` synth command, `watch` includes/excludes, `context` feature flags | -| `bin/app.ts` | App entry point — instantiates every stack with an explicit kebab-case `stackName` and its target `env` (account `328440206208`, per-region) | +| `bin/app.ts` | App entry point — instantiates every stack with an explicit kebab-case `stackName` and its target `env` (five accounts, per-account/per-region) | | `lib/*-stack.ts` | Stack definitions (one class per stack; larger stacks compose the constructs in `lib/*.ts`) | | `tsconfig.json` | TypeScript compiler options (`outDir: cdk.out`) | | `package.json` | Pinned `aws-cdk-lib`, CDK CLI, and the `build` / `synth` / `diff` / `deploy` npm scripts | -`bin/app.ts` synthesizes nine stacks across three regions and four accounts: +`bin/app.ts` synthesizes eleven stacks across three regions and five accounts: | Construct id | Stack name | Account | Region | Source | |---|---|---|---|---| @@ -58,9 +60,11 @@ the TypeScript source — no separate compile step needed for `cdk synth` / | `regional-baseline-us-east-2` | `seahaven-regional-baseline-us-east-2` | 328440206208 | us-east-2 | `lib/regional-baseline-stack.ts` | | `backup-offsite` | `seahaven-backup-offsite` | 328440206208 | us-west-2 | `lib/backup-offsite-stack.ts` | | `backup` | `seahaven-backup` | 328440206208 | us-east-1 | `lib/backup-stack.ts` | +| `org-governance` | `seahaven-org-governance` | 328440206208 | us-east-1 | `lib/org-governance-stack.ts` | | `external-dev-baseline` | `seahaven-external-dev-baseline` | 396287094661 | us-east-1 | `lib/member-baseline-stack.ts` | | `security-baseline` | `seahaven-security-baseline` | 001520130573 | us-east-1 | `lib/member-baseline-stack.ts` | | `dev-baseline` | `seahaven-dev-baseline` | 710827005802 | us-east-1 | `lib/member-baseline-stack.ts` (orgManagedDetection) | +| `prod-baseline` | `seahaven-prod-baseline` | 011934824531 | us-east-1 | `lib/member-baseline-stack.ts` (orgManagedDetection) | Member-account stacks deploy with per-account credentials — the CD workflow runs one job per account, each assuming that account's OIDC deploy role. Local @@ -71,6 +75,7 @@ deploys/diffs assume `OrganizationAccountAccessRole` in the target account. | 396287094661 (external-dev) | `githubdeploy-seahaven-external-dev-baseline` | `AWS_DEPLOY_ROLE_ARN_EXTDEV` | | 001520130573 (security) | `githubdeploy-seahaven-org-baseline` | `AWS_DEPLOY_ROLE_ARN_SECURITY` | | 710827005802 (dev) | `githubdeploy-seahaven-org-baseline` | `AWS_DEPLOY_ROLE_ARN_DEV` | +| 011934824531 (prod) | `githubdeploy-seahaven-org-baseline` | `AWS_DEPLOY_ROLE_ARN_PROD` | Shared constructs (`DetectiveControls`, `FlowLogs`, `GovernanceToggles`) are prefix-parameterized — construct ids and physical names must stay @@ -236,7 +241,11 @@ recording is never interrupted. ### CLI-applied governance toggles (no CloudFormation resource) These account toggles have no native CloudFormation resource, so they are applied -via CLI and recorded here. Applied 2026-06-01. +via CLI and recorded here — **per account** (they are account-scoped; a new +member account has NONE of them until applied). Applied: 328440206208 +(2026-06-01); 001520130573, 710827005802, 011934824531 (2026-07-14 — EBS +encryption-by-default + password policy, verified per account; Inspector2 via +delegated admin; cost-allocation tags are org-level). ```bash # M-3 EBS encryption-by-default (new volumes; existing 5 plaintext volumes are H-19-adjacent) diff --git a/bin/app.ts b/bin/app.ts index 014f969..945180a 100644 --- a/bin/app.ts +++ b/bin/app.ts @@ -13,6 +13,7 @@ const ACCOUNT = "328440206208"; const EXTERNAL_DEV_ACCOUNT = "396287094661"; const SECURITY_ACCOUNT = "001520130573"; const DEV_ACCOUNT = "710827005802"; +const PROD_ACCOUNT = "011934824531"; // All 5 VPCs in 328440206208 / us-east-1 (4 custom + default), audit Agent 7. // Index-derived logical IDs — append only, never reorder. @@ -105,8 +106,9 @@ new MemberBaselineStack(app, "security-baseline", { // Internal dev/staging workloads (NOT the external-dev engagement account). // Created 2026-07-14 AFTER org delegation went live: GuardDuty detector + // Security Hub hub are org-managed — enrolled via delegated-admin -// create-members and verified Enabled (the AUTOMATIC new-account sweep -// remains unexercised; do not rely on it without verifying). Standards and +// create-members and verified Enabled (the AUTOMATIC sweep was later proven +// on seahaven-prod, ~2min; still verify enrollment before any org-managed +// stack's first deploy). Standards and // the account analyzer stay CFN-owned (SH-DEV-001/SH-DEVBASE-002). Same // lifecycle rule as the other new accounts: root-harden at org ROOT, then // move-account into the nonprod OU (ou-nbuj-zpt5ka98) — NO WORKLOADS until @@ -128,6 +130,31 @@ new MemberBaselineStack(app, "dev-baseline", { orgManagedDetection: true, }); +// ── Member-account baseline: seahaven-prod (Phase 5) ──────────────────────── +// Target for ALL new production stacks (mgmt 328440206208 is frozen for new +// workloads). First tenant: proposal-system redeploy. Detection is org-managed +// (AUTO-enrolled by the sweep in 124s — first proven exercise, 2026-07-14 — +// and verified Enabled before this stack's first deploy); standards + account +// analyzer are CFN-owned per the Phase-4 review. Default VPC DELETED (prod +// workloads use purpose-built VPCs). Same lifecycle rule: root-harden at org +// ROOT, then move-account into the prod OU (ou-nbuj-5lc2wp6h) — NO WORKLOADS +// until the account is inside the OU. Budget starts at $100 and is resized as +// tenants land; AWS Backup vaults are added with the first stateful tenant +// (cross-account restore test = definition of done for that change). +new MemberBaselineStack(app, "prod-baseline", { + stackName: "seahaven-prod-baseline", + env: { account: PROD_ACCOUNT, region: "us-east-1" }, + namePrefix: "seahaven-prod", + monthlyBudgetUsd: 100, + budgetAlertEmail: "aws@seahaven.com", + ownerEmail: "adam@seahaven.com", + // Append-only, never reorder (index-derived logical IDs). Empty: no VPCs + // exist yet; append ids via PR as purpose-built VPCs land. + flowLogVpcIds: [], + managedByTag: "seahaven-org-baseline", + orgManagedDetection: true, +}); + // ── Shared DynamoDB CMK (INFRA-95 / M-3) ───────────────────────────────────── // Dedicated, standalone stack so the customer-managed key for sensitive // finance/PII DynamoDB tables is an independent shared dependency for the owning diff --git a/lib/member-baseline-stack.ts b/lib/member-baseline-stack.ts index 0ef7608..3080896 100644 --- a/lib/member-baseline-stack.ts +++ b/lib/member-baseline-stack.ts @@ -22,9 +22,10 @@ export interface MemberBaselineStackProps extends cdk.StackProps { /** Value for the ManagedBy tag on every resource in the stack. */ readonly managedByTag: string; /** - * TRUE for accounts created after org delegation (2026-07-14): GuardDuty / - * Security Hub / analyzer are org-managed (auto-enrolled), so the stack must - * not create local duplicates. Default FALSE (pre-delegation accounts). + * TRUE for accounts created after org delegation (2026-07-14): the GuardDuty + * detector and Security Hub hub are org-managed (auto-enrolled), so the + * stack must not create local duplicates. Standards and the account analyzer + * remain CFN-owned either way. Default FALSE (pre-delegation accounts). */ readonly orgManagedDetection?: boolean; }