mirror of
https://github.com/Sea-Haven-Industries/seahaven-account-baseline.git
synced 2026-08-04 16:56:14 +00:00
Adopt external-dev OU and its 3 SCPs via resource import (#45)
cdk import by Id (non-mutating), content byte-exact from describe-policy, targetIds = exact live attachments. Post-import drift detection: IN_SYNC, 0 drifted. All four Retain — the full org guardrail set is now drift-checked IaC.
This commit is contained in:
parent
22b04c4e75
commit
10e66c92c0
4 changed files with 147 additions and 0 deletions
|
|
@ -1,7 +1,15 @@
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as cdk from "aws-cdk-lib";
|
||||
import * as organizations from "aws-cdk-lib/aws-organizations";
|
||||
import { Construct } from "constructs";
|
||||
|
||||
/** Byte-exact live SCP content (lib/scp/*.json) — see import block below. */
|
||||
const scpContent = (name: string): Record<string, unknown> =>
|
||||
JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, "scp", `${name}.json`), "utf8")
|
||||
);
|
||||
|
||||
/**
|
||||
* AWS Organizations structure for org o-9kufuzz6b4: OU skeleton + generalized
|
||||
* service-control policies (multi-account segregation plan Phase 2,
|
||||
|
|
@ -226,6 +234,51 @@ export class OrgGovernanceStack extends cdk.Stack {
|
|||
});
|
||||
retain(denyRootUser);
|
||||
|
||||
// ── Adopted (cdk-imported) external-dev OU + its 3 SCPs ─────────────────
|
||||
// Imported 2026-07-14 by Id (ou-nbuj-q34yz3ql, p-i59g24mz, p-8yty5mnd,
|
||||
// p-ivmwtipw). Properties are byte-exact to the live resources at import
|
||||
// time (content JSON in lib/scp/, descriptions/targets verified via
|
||||
// describe-policy). RULES: content stays a JSON object (string form kills
|
||||
// drift detection); targetIds is the exact live attachment set — any edit
|
||||
// here detaches/attaches a LIVE guardrail on the isolated contractor
|
||||
// account and requires the mandatory review gates; never rename these
|
||||
// logical ids (rename = delete+create; Retain would orphan, not detach,
|
||||
// but the stack would lose the resource).
|
||||
const externalDevOu = new organizations.CfnOrganizationalUnit(this, "ExternalDevOu", {
|
||||
name: "external-dev",
|
||||
parentId: ROOT_ID,
|
||||
});
|
||||
retain(externalDevOu);
|
||||
|
||||
const externalDevRegionLock = new organizations.CfnPolicy(this, "ExternalDevRegionLock", {
|
||||
name: "external-dev-region-lock",
|
||||
type: "SERVICE_CONTROL_POLICY",
|
||||
description: "external-dev OU guardrail: external-dev-region-lock",
|
||||
targetIds: ["ou-nbuj-q34yz3ql"],
|
||||
content: scpContent("external-dev-region-lock"),
|
||||
});
|
||||
retain(externalDevRegionLock);
|
||||
|
||||
const externalDevIamGuardrails = new organizations.CfnPolicy(this, "ExternalDevIamGuardrails", {
|
||||
name: "external-dev-iam-guardrails",
|
||||
type: "SERVICE_CONTROL_POLICY",
|
||||
description: "external-dev OU guardrail: external-dev-iam-guardrails",
|
||||
targetIds: ["ou-nbuj-q34yz3ql"],
|
||||
content: scpContent("external-dev-iam-guardrails"),
|
||||
});
|
||||
retain(externalDevIamGuardrails);
|
||||
|
||||
const externalDevProtectSecurity = new organizations.CfnPolicy(this, "ExternalDevProtectSecurity", {
|
||||
name: "external-dev-protect-security",
|
||||
type: "SERVICE_CONTROL_POLICY",
|
||||
description: "external-dev OU guardrail: external-dev-protect-security",
|
||||
targetIds: ["ou-nbuj-q34yz3ql"],
|
||||
content: scpContent("external-dev-protect-security"),
|
||||
});
|
||||
retain(externalDevProtectSecurity);
|
||||
|
||||
new cdk.CfnOutput(this, "ExternalDevOuId", { value: externalDevOu.attrId });
|
||||
|
||||
new cdk.CfnOutput(this, "WorkloadsOuId", { value: workloadsOu.attrId });
|
||||
new cdk.CfnOutput(this, "ProdOuId", { value: prodOu.attrId });
|
||||
new cdk.CfnOutput(this, "NonprodOuId", { value: nonprodOu.attrId });
|
||||
|
|
|
|||
50
lib/scp/external-dev-iam-guardrails.json
Normal file
50
lib/scp/external-dev-iam-guardrails.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "RequireBoundaryOnRoleAndUserCreate",
|
||||
"Effect": "Deny",
|
||||
"Action": ["iam:CreateRole", "iam:CreateUser"],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringNotEquals": { "iam:PermissionsBoundary": "arn:aws:iam::396287094661:policy/external-dev-execution-boundary" },
|
||||
"ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*", "arn:aws:iam::396287094661:role/githubdeploy-seahaven-external-dev-baseline"] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "ProtectBoundaryPolicyFromEdits",
|
||||
"Effect": "Deny",
|
||||
"Action": ["iam:CreatePolicyVersion", "iam:SetDefaultPolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion"],
|
||||
"Resource": "arn:aws:iam::396287094661:policy/external-dev-execution-boundary"
|
||||
},
|
||||
{
|
||||
"Sid": "DenyAlteringPermissionsBoundaries",
|
||||
"Effect": "Deny",
|
||||
"Action": ["iam:DeleteRolePermissionsBoundary", "iam:DeleteUserPermissionsBoundary", "iam:PutRolePermissionsBoundary", "iam:PutUserPermissionsBoundary"],
|
||||
"Resource": "*",
|
||||
"Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] } }
|
||||
},
|
||||
{
|
||||
"Sid": "DenyIamUserAndAccessKeyCreation",
|
||||
"Effect": "Deny",
|
||||
"Action": ["iam:CreateUser", "iam:CreateAccessKey", "iam:CreateLoginProfile"],
|
||||
"Resource": "*",
|
||||
"Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole"] } }
|
||||
},
|
||||
{
|
||||
"Sid": "ProtectPrivilegedRoles",
|
||||
"Effect": "Deny",
|
||||
"Action": ["iam:UpdateAssumeRolePolicy", "iam:AttachRolePolicy", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:DeleteRolePolicy", "iam:DeleteRole", "iam:UpdateRole", "iam:TagRole", "iam:UntagRole"],
|
||||
"Resource": [
|
||||
"arn:aws:iam::396287094661:role/OrganizationAccountAccessRole",
|
||||
"arn:aws:iam::396287094661:role/cdk-hnb659fds-*",
|
||||
"arn:aws:iam::396287094661:role/githubdeploy-*",
|
||||
"arn:aws:iam::396287094661:role/seahaven-extdev-config-recorder-role",
|
||||
"arn:aws:iam::396287094661:role/seahaven-extdev-config-custom-resource-role",
|
||||
"arn:aws:iam::396287094661:role/aws-service-role/*"
|
||||
],
|
||||
"Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] } }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
26
lib/scp/external-dev-protect-security.json
Normal file
26
lib/scp/external-dev-protect-security.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "DenyDisablingSecurityServices",
|
||||
"Effect": "Deny",
|
||||
"Action": [
|
||||
"cloudtrail:StopLogging", "cloudtrail:DeleteTrail", "cloudtrail:UpdateTrail",
|
||||
"guardduty:DeleteDetector", "guardduty:UpdateDetector", "guardduty:DisassociateFromMasterAccount",
|
||||
"config:StopConfigurationRecorder", "config:DeleteConfigurationRecorder", "config:DeleteDeliveryChannel",
|
||||
"securityhub:DisableSecurityHub", "securityhub:BatchDisableStandards",
|
||||
"accessanalyzer:DeleteAnalyzer", "inspector2:Disable"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"ArnNotLike": { "aws:PrincipalArn": [
|
||||
"arn:aws:iam::396287094661:role/OrganizationAccountAccessRole",
|
||||
"arn:aws:iam::396287094661:role/cdk-hnb659fds-*",
|
||||
"arn:aws:iam::396287094661:role/seahaven-extdev-config-custom-resource-role"
|
||||
]}
|
||||
}
|
||||
},
|
||||
{ "Sid": "DenyLeavingOrganization", "Effect": "Deny", "Action": ["organizations:LeaveOrganization"], "Resource": "*" }
|
||||
]
|
||||
}
|
||||
|
||||
18
lib/scp/external-dev-region-lock.json
Normal file
18
lib/scp/external-dev-region-lock.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "DenyRegionsOutsideUsEast1",
|
||||
"Effect": "Deny",
|
||||
"NotAction": [
|
||||
"iam:*", "organizations:*", "account:*", "sts:*", "route53:*", "route53domains:*",
|
||||
"cloudfront:*", "waf:*", "shield:*", "globalaccelerator:*", "budgets:*", "ce:*",
|
||||
"cur:*", "health:*", "support:*", "supportplans:*", "trustedadvisor:*", "artifact:*",
|
||||
"aws-portal:*"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": { "StringNotEquals": { "aws:RequestedRegion": "us-east-1" } }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue