Add seahaven-dev member baseline with org-managed detection

Account 710827005802 (internal dev/staging) is the first account born
after delegation: GuardDuty/Security Hub enroll it via the org admin,
so DetectiveControls gains a localDetectiveServices flag (default true
— zero diff on the three deployed consumers, verified) and the dev
instance sets orgManagedDetection to skip the colliding local
detector/hub/analyzer. Default VPC kept and flow-logged (dev runs real
workloads). Enrollment verified Enabled in both services before this
commit.
This commit is contained in:
Adam Moussa 2026-07-14 16:12:24 -04:00
parent 2d3ba94140
commit 0ec8a5ca3c
No known key found for this signature in database
5 changed files with 57 additions and 5 deletions

View file

@ -41,3 +41,12 @@ jobs:
stack-name: "seahaven-security-baseline"
secrets:
deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN_SECURITY }}
deploy-dev:
uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@3cde673b9d05c0e68aac4d997d582f2543853d20 # main
with:
node-version: "24"
stacks: "dev-baseline"
stack-name: "seahaven-dev-baseline"
secrets:
deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN_DEV }}

View file

@ -30,6 +30,7 @@ Stacks (deployed by the CD workflow — one job per target account):
| `seahaven-backup-offsite` | 328440206208 | us-west-2 | Governance-locked offsite copy vault (C-7) |
| `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) |
## CDK app
@ -59,6 +60,7 @@ the TypeScript source — no separate compile step needed for `cdk synth` /
| `backup` | `seahaven-backup` | 328440206208 | us-east-1 | `lib/backup-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) |
The member-account stack (`external-dev-baseline`) deploys with credentials for
**396287094661** — the CD workflow runs it as a separate job assuming that

View file

@ -12,6 +12,7 @@ import { OrgGovernanceStack } from "../lib/org-governance-stack";
const ACCOUNT = "328440206208";
const EXTERNAL_DEV_ACCOUNT = "396287094661";
const SECURITY_ACCOUNT = "001520130573";
const DEV_ACCOUNT = "710827005802";
// All 5 VPCs in 328440206208 / us-east-1 (4 custom + default), audit Agent 7.
// Index-derived logical IDs — append only, never reorder.
@ -100,6 +101,26 @@ new MemberBaselineStack(app, "security-baseline", {
managedByTag: "seahaven-org-baseline",
});
// ── Member-account baseline: seahaven-dev (Phase 4) ─────────────────────────
// Internal dev/staging workloads (NOT the external-dev engagement account).
// Created 2026-07-14 AFTER org delegation went live, so GuardDuty/SecurityHub/
// analyzer are org-managed (auto-enrollment verified) — orgManagedDetection
// keeps this stack from creating colliding local duplicates. Same lifecycle
// rule as the other new accounts: root-harden at org ROOT, then move-account
// into the nonprod OU (ou-nbuj-zpt5ka98).
new MemberBaselineStack(app, "dev-baseline", {
stackName: "seahaven-dev-baseline",
env: { account: DEV_ACCOUNT, region: "us-east-1" },
namePrefix: "seahaven-dev",
monthlyBudgetUsd: 150,
budgetAlertEmail: "aws@seahaven.com",
ownerEmail: "adam@seahaven.com",
// Default VPC kept (dev runs real workloads) — logged from day one.
flowLogVpcIds: ["vpc-08f07dc5edeea621f"],
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

View file

@ -31,6 +31,16 @@ export interface DetectiveControlsProps {
* custom resources; keep it stable per account.
*/
readonly namePrefix: string;
/**
* Create the account-local GuardDuty detector / Security Hub hub + standards /
* account Access Analyzer. Default TRUE (pre-delegation accounts own these).
* Set FALSE for accounts created AFTER org delegation went live (2026-07-14):
* GuardDuty/Security Hub auto-enroll new members and CREATE these resources
* themselves — a CFN-owned duplicate fails (one detector/hub per account),
* and the org analyzer supersedes the account analyzer. The Config recorder
* is always created: recorders stay per-account, delegation never makes one.
*/
readonly localDetectiveServices?: boolean;
}
export class DetectiveControls extends Construct {
@ -297,12 +307,14 @@ export class DetectiveControls extends Construct {
});
// ──────────────────────────────────────────────────────────────────────
// H-3 GuardDuty
// H-3 GuardDuty, H-4 Security Hub, M-5 Access Analyzer — skipped when the
// org delegated admin owns them (localDetectiveServices: false).
// ──────────────────────────────────────────────────────────────────────
new guardduty.CfnDetector(this, "GuardDutyDetector", {
enable: true,
findingPublishingFrequency: "FIFTEEN_MINUTES",
});
if (props.localDetectiveServices ?? true) {
new guardduty.CfnDetector(this, "GuardDutyDetector", {
enable: true,
findingPublishingFrequency: "FIFTEEN_MINUTES",
});
// ──────────────────────────────────────────────────────────────────────
// H-4 Security Hub (FSBP + CIS v3.0)
@ -354,6 +366,7 @@ export class DetectiveControls extends Construct {
analyzerName: `${prefix}-account-analyzer`,
type: "ACCOUNT",
});
}
new cdk.CfnOutput(this, "ConfigBucketName", {
value: configBucket.bucketName,

View file

@ -21,6 +21,12 @@ export interface MemberBaselineStackProps extends cdk.StackProps {
readonly flowLogVpcIds: string[];
/** 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).
*/
readonly orgManagedDetection?: boolean;
}
/**
@ -47,6 +53,7 @@ export class MemberBaselineStack extends cdk.Stack {
new DetectiveControls(this, "DetectiveControls", {
namePrefix: props.namePrefix,
localDetectiveServices: !(props.orgManagedDetection ?? false),
});
new FlowLogs(this, "FlowLogs", {