mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-10-03 22:23:12 +00:00
refactor(iam): fold seahaven-site roles into seahaven-hcptf (#175)
Prod HCP exec roles for seahaven-site now live in the same stack as payments-dashboard so role ownership is one stack.
This commit is contained in:
parent
c6de4e0c7f
commit
031e1d1a3b
8 changed files with 97 additions and 50 deletions
8
.github/workflows/deploy.yaml
vendored
8
.github/workflows/deploy.yaml
vendored
|
|
@ -58,10 +58,10 @@ jobs:
|
|||
uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@e5691d8a7f96ac4d5a841a82975ff0a4354d53ac # v1.0.7
|
||||
with:
|
||||
node-version: "24"
|
||||
# seahaven-site-hcptf was imported after the roles left terraform-substrate.
|
||||
# seahaven-hcptf was imported. The deploy creates the three managed
|
||||
# policies and removes the inline policies. Do not create the roles.
|
||||
stacks: "prod-baseline dynamodb-cmk-prod alarm-topic-prod deploy-substrate-prod app-web-acl-prod seahaven-site-hcptf seahaven-hcptf"
|
||||
# seahaven-hcptf was imported. It owns payments-dashboard and the
|
||||
# seahaven-site exec roles. Do not create the roles. Deleting the
|
||||
# retired seahaven-site-hcptf stack is a separate prod step.
|
||||
stacks: "prod-baseline dynamodb-cmk-prod alarm-topic-prod deploy-substrate-prod app-web-acl-prod seahaven-hcptf"
|
||||
stack-name: "seahaven-prod-baseline"
|
||||
secrets:
|
||||
deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN_PROD }}
|
||||
|
|
|
|||
19
README.md
19
README.md
|
|
@ -33,8 +33,7 @@ are noted):
|
|||
| `seahaven-engineering-access` | 328440206208 | us-east-1 | Identity Center group `engineering`. `EngineeringProd` reads payments-dashboard configuration and seahaven-site in 011934824531. `EngineeringDev` has no allow (PLAT-235, PLAT-236). |
|
||||
| `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-terraform-substrate` | 011934824531, 710827005802 | us-east-1 | Removed from the CDK app and from CD (PLAT-147). Live stacks remain until `scripts/delete-terraform-substrate-prod-dev.sh`. The six imported prod pairs are already forgotten. |
|
||||
| `seahaven-site-hcptf` | 011934824531 | us-east-1 | Imported `hcptf-seahaven-site` apply and plan roles (PLAT-225). Policies are managed at `/tf-managed/`. On the prod deploy job. Do not create the roles. |
|
||||
| `seahaven-hcptf` | 011934824531, 710827005802 | us-east-1 | payments-dashboard HCP apply and plan roles, scoped policies, and the Lambda boundary. Trust is pinned to `payments-dashboard-prod` in project `seahaven-prod`, and to `payments-dashboard-dev` in project `seahaven-dev`. Roles and boundary are imported. On the dev and prod deploy jobs. |
|
||||
| `seahaven-hcptf` | 011934824531, 710827005802 | us-east-1 | payments-dashboard HCP apply and plan roles, scoped policies, and the Lambda boundary in prod and dev. Prod also owns the imported `hcptf-seahaven-site` apply and plan roles (PLAT-225), with policies at `/tf-managed/`. Trust is pinned per workspace. On the dev and prod deploy jobs. Do not create the roles. |
|
||||
| `seahaven-terraform-substrate` | 396287094661 | us-east-1 | Staged manually for SHOC backend/frontend adoption; exact HCP roles and deploy boundaries referencing the existing OIDC provider. Stays (PLAT-148). |
|
||||
| `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) |
|
||||
|
|
@ -78,7 +77,6 @@ the TypeScript source — no separate compile step needed for `cdk synth` /
|
|||
| `dynamodb-cmk-prod` | `seahaven-dynamodb-cmk` | 011934824531 | us-east-1 | `lib/dynamodb-cmk-stack.ts` |
|
||||
| `alarm-topic-prod` | `seahaven-alarm-topic` | 011934824531 | us-east-1 | `lib/alarm-topic-stack.ts` |
|
||||
| `app-web-acl-prod` | `seahaven-app-web-acl` | 011934824531 | us-east-1 | `lib/app-web-acl-stack.ts` |
|
||||
| `seahaven-site-hcptf` | `seahaven-site-hcptf` | 011934824531 | us-east-1 | `lib/seahaven-site-hcptf-stack.ts` |
|
||||
| `seahaven-hcptf` | `seahaven-hcptf` | 011934824531 | us-east-1 | `lib/seahaven-hcptf-stack.ts` |
|
||||
| `seahaven-hcptf-dev` | `seahaven-hcptf` | 710827005802 | us-east-1 | `lib/seahaven-hcptf-stack.ts` |
|
||||
|
||||
|
|
@ -240,12 +238,13 @@ Console / one-shot CLI owns only:
|
|||
Do not manage prod/dev workload IAM (`hcptf-<stack>` pairs, Lambda exec
|
||||
roles, `policy/tf-managed/<stack>` ceilings) in the console. Do not append
|
||||
new prod/dev `hcptf-<stack>` pairs to this template. New prod/dev HCP stacks
|
||||
do not need an org-baseline IAM PR. payments-dashboard HCP roles and
|
||||
the Lambda boundary are stack `seahaven-hcptf` in prod and dev. Both copies
|
||||
are imported and are on the deploy jobs. The deploy creates
|
||||
do not need an org-baseline IAM PR. Prod HCP exec roles for
|
||||
payments-dashboard and seahaven-site both live in `seahaven-hcptf`.
|
||||
Dev `seahaven-hcptf` is payments-dashboard only. Both account copies
|
||||
are imported and are on the deploy jobs. The payments deploy creates
|
||||
`payments-dashboard-hcptf-iam`, `payments-dashboard-hcptf-services`, and
|
||||
`payments-dashboard-hcptf-plan`, and removes the inline policies. Do not
|
||||
create the roles or the boundary.
|
||||
create the roles, the boundary, or the seahaven-site roles.
|
||||
|
||||
**External-dev IAM stays in this repo (PLAT-148).** SHOC backend/frontend HCP
|
||||
roles, SHOC deploy/runtime boundaries, `shoc-frontend-resources.ts`, and
|
||||
|
|
@ -267,7 +266,7 @@ Until the delete script runs, the live stacks still hold:
|
|||
`seahaven-lambda-execution-boundary-*` allow-list; frozen, do not append).
|
||||
|
||||
The six imported prod pairs are Retain-removed. `seahaven-site` is
|
||||
`seahaven-site-hcptf`. `sh-openswe-traces` is gone.
|
||||
`seahaven-hcptf`. `sh-openswe-traces` is gone.
|
||||
|
||||
External-dev still carries:
|
||||
|
||||
|
|
@ -314,7 +313,7 @@ and nonprod (PLAT-145), covering `hcptf-bootstrap*` plus the break-glass /
|
|||
CDK / `githubdeploy-*` set already on the security OU.
|
||||
|
||||
The six live prod pairs are imported into the owning app, not recreated, then
|
||||
Retain-removed from this template. `seahaven-site` is `seahaven-site-hcptf`.
|
||||
Retain-removed from this template. `seahaven-site` is `seahaven-hcptf`.
|
||||
`sh-openswe-traces` is not imported. The prod/dev stacks are deleted after
|
||||
that forget. See the first-apply and import runbooks below.
|
||||
|
||||
|
|
@ -611,7 +610,7 @@ wildcards. Do not enumerate provider Get* APIs.
|
|||
state: `afi-backup-monitor`, `front-integrations`, `paychex-integrations`,
|
||||
`procurement-ingest`, `meal-order-manager`, `seahaven-door-unlock-api`.
|
||||
`sh-openswe-traces` was decommissioned (PLAT-196) and is not imported.
|
||||
`seahaven-site` is stack `seahaven-site-hcptf` (PLAT-225), not this template.
|
||||
`seahaven-site` is stack `seahaven-hcptf` (PLAT-225), not this template.
|
||||
|
||||
Repos that do not change: SHOC (`shoc-backend`, `shoc-frontend-new`),
|
||||
remaining SAM / unmigrated stacks.
|
||||
|
|
|
|||
18
bin/app.ts
18
bin/app.ts
|
|
@ -11,7 +11,6 @@ import { TerraformSubstrateStack } from "../lib/terraform-substrate-stack";
|
|||
import { DynamoDbCmkStack } from "../lib/dynamodb-cmk-stack";
|
||||
import { AppWebAclStack } from "../lib/app-web-acl-stack";
|
||||
import { SeahavenHcptfStack } from "../lib/seahaven-hcptf-stack";
|
||||
import { SeahavenSiteHcptfStack } from "../lib/seahaven-site-hcptf-stack";
|
||||
import { MemberBaselineStack } from "../lib/member-baseline-stack";
|
||||
import { OrgGovernanceStack } from "../lib/org-governance-stack";
|
||||
import { PlatformAccessStack } from "../lib/platform-access-stack";
|
||||
|
|
@ -231,19 +230,12 @@ new AppWebAclStack(app, "app-web-acl-prod", {
|
|||
env: { account: PROD_ACCOUNT, region: "us-east-1" },
|
||||
});
|
||||
|
||||
// seahaven-site exec roles (PLAT-225). Not part of terraform-substrate.
|
||||
// Imported. On the prod deploy job. A create fails because the roles already exist.
|
||||
// Inline policies are managed policies at /tf-managed/. Do not recreate the roles.
|
||||
new SeahavenSiteHcptfStack(app, "seahaven-site-hcptf", {
|
||||
stackName: "seahaven-site-hcptf",
|
||||
env: { account: PROD_ACCOUNT, region: "us-east-1" },
|
||||
});
|
||||
|
||||
// payments-dashboard HCP roles, scoped policies, and the Lambda boundary.
|
||||
// The same three names already exist in prod and dev. Import them with
|
||||
// `-c hcptfPaymentsImport=true`. A create fails. Neither stack is on a
|
||||
// deploy job until that import succeeds. Trust is pinned per workspace.
|
||||
// Prod also includes the imported seahaven-site apply and plan roles
|
||||
// (PLAT-225). A create fails. Import site with `-c hcptfSiteImport=true`.
|
||||
// Trust is pinned per workspace.
|
||||
const hcptfPaymentsImport = contextBoolean("hcptfPaymentsImport");
|
||||
const hcptfSiteImport = contextBoolean("hcptfSiteImport");
|
||||
const paymentsSecrets = (
|
||||
account: string,
|
||||
suffixes: readonly string[],
|
||||
|
|
@ -269,6 +261,8 @@ new SeahavenHcptfStack(app, "seahaven-hcptf", {
|
|||
"expense-slack-signing-secret-lbb78J",
|
||||
]),
|
||||
importExisting: hcptfPaymentsImport,
|
||||
includeSeahavenSite: true,
|
||||
siteImportExisting: hcptfSiteImport,
|
||||
});
|
||||
|
||||
new SeahavenHcptfStack(app, "seahaven-hcptf-dev", {
|
||||
|
|
|
|||
17
import-maps/seahaven-site-into-hcptf-prod.json
Normal file
17
import-maps/seahaven-site-into-hcptf-prod.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"SeahavenSiteApplyRoleE31E1F61": {
|
||||
"RoleName": "hcptf-seahaven-site"
|
||||
},
|
||||
"SeahavenSitePlanRoleF0DFA964": {
|
||||
"RoleName": "hcptf-seahaven-site-plan"
|
||||
},
|
||||
"SeahavenSiteIamPolicy1032B47C": {
|
||||
"PolicyArn": "arn:aws:iam::011934824531:policy/tf-managed/seahaven-site-hcptf-iam"
|
||||
},
|
||||
"SeahavenSiteServicesPolicy1E92BC24": {
|
||||
"PolicyArn": "arn:aws:iam::011934824531:policy/tf-managed/seahaven-site-hcptf-services"
|
||||
},
|
||||
"SeahavenSitePlanPolicyC4736E1F": {
|
||||
"PolicyArn": "arn:aws:iam::011934824531:policy/tf-managed/seahaven-site-hcptf-plan"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,8 @@ const MAX_POLICY_CHARS = 6144;
|
|||
/**
|
||||
* Fails synth when an HCP stack's managed policy document reaches the IAM
|
||||
* size quota, or when a role in that stack carries an inline policy.
|
||||
* Register it on seahaven-hcptf and seahaven-site-hcptf only.
|
||||
* Register it on seahaven-hcptf only. That stack owns payments-dashboard
|
||||
* in prod and dev, and seahaven-site in prod.
|
||||
*
|
||||
* `allowInlinePolicies` is only for the one-time `cdk import` template.
|
||||
* That template has to name the live inline policies so the following
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@ import * as cdk from "aws-cdk-lib";
|
|||
import * as iam from "aws-cdk-lib/aws-iam";
|
||||
import { Construct } from "constructs";
|
||||
import { HcptfPolicyAspect } from "./hcptf-policy-aspect";
|
||||
import { SeahavenSiteRoles } from "./seahaven-site-hcptf-stack";
|
||||
|
||||
/**
|
||||
* payments-dashboard HCP exec roles. One stack per account. Prod is
|
||||
* 011934824531, workspace payments-dashboard-prod, project seahaven-prod.
|
||||
* Dev is 710827005802, workspace payments-dashboard-dev, project seahaven-dev.
|
||||
* HCP exec roles. One stack per account. Prod is 011934824531 and also
|
||||
* hosts the seahaven-site apply and plan roles. Dev is 710827005802 and
|
||||
* stays payments-dashboard only.
|
||||
*
|
||||
* payments-dashboard: workspace payments-dashboard-prod, project
|
||||
* seahaven-prod, or workspace payments-dashboard-dev, project seahaven-dev.
|
||||
*
|
||||
* hcptf-payments-dashboard, hcptf-payments-dashboard-plan, and
|
||||
* payments-dashboard-lambda-boundary already existed in both accounts and
|
||||
|
|
@ -37,12 +41,27 @@ export interface SeahavenHcptfStackProps extends cdk.StackProps {
|
|||
* Default is the managed-policy template.
|
||||
*/
|
||||
importExisting?: boolean;
|
||||
/** Prod only. Fold seahaven-site exec roles into this stack. */
|
||||
includeSeahavenSite?: boolean;
|
||||
/**
|
||||
* Synthesize the seahaven-site import template. Set from
|
||||
* `-c hcptfSiteImport=true`. Omits site role tags and site outputs.
|
||||
*/
|
||||
siteImportExisting?: boolean;
|
||||
}
|
||||
|
||||
export class SeahavenHcptfStack extends cdk.Stack {
|
||||
constructor(scope: Construct, id: string, props: SeahavenHcptfStackProps) {
|
||||
super(scope, id, props);
|
||||
if (props.importExisting && props.siteImportExisting) {
|
||||
throw new Error("hcptfPaymentsImport and hcptfSiteImport cannot both be set");
|
||||
}
|
||||
paymentsDashboard(this, props);
|
||||
if (props.includeSeahavenSite) {
|
||||
new SeahavenSiteRoles(this, "SeahavenSite", {
|
||||
importExisting: props.siteImportExisting === true,
|
||||
});
|
||||
}
|
||||
cdk.Aspects.of(this).add(new HcptfPolicyAspect(props.importExisting === true));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,43 @@
|
|||
import * as cdk from "aws-cdk-lib";
|
||||
import * as iam from "aws-cdk-lib/aws-iam";
|
||||
import { Construct } from "constructs";
|
||||
import { HcptfPolicyAspect } from "./hcptf-policy-aspect";
|
||||
|
||||
/**
|
||||
* Prod exec roles for the seahaven-site HCP workspace (PLAT-225).
|
||||
*
|
||||
* These roles already exist and were imported into this stack. Do not
|
||||
* create them. A plain create fails because the roles already exist.
|
||||
* The stack is on the prod deploy job.
|
||||
* Nested in the prod seahaven-hcptf stack. These roles already exist.
|
||||
* Do not create them. A plain create fails because the roles already exist.
|
||||
*
|
||||
* Import identifiers were the role names `hcptf-seahaven-site` and
|
||||
* `hcptf-seahaven-site-plan`. Construct ids stay ApplyRole and PlanRole.
|
||||
* Import identifiers are the role names `hcptf-seahaven-site` and
|
||||
* `hcptf-seahaven-site-plan`, plus the three /tf-managed/ policy ARNs.
|
||||
* Construct ids stay ApplyRole and PlanRole under SeahavenSite.
|
||||
* Inline policies are managed policies at /tf-managed/. Do not rename
|
||||
* the roles.
|
||||
*
|
||||
* `importExisting` is the `-c hcptfSiteImport=true` template. It omits
|
||||
* role tags and the role ARN outputs. CloudFormation rejects both on an
|
||||
* IAM role import. The steady-state template adds them back.
|
||||
*/
|
||||
export class SeahavenSiteHcptfStack extends cdk.Stack {
|
||||
constructor(scope: Construct, id: string, props: cdk.StackProps) {
|
||||
super(scope, id, props);
|
||||
export interface SeahavenSiteRolesProps {
|
||||
/** Omit role tags and outputs. Set from `-c hcptfSiteImport=true`. */
|
||||
importExisting?: boolean;
|
||||
}
|
||||
|
||||
const account = this.account;
|
||||
export class SeahavenSiteRoles extends Construct {
|
||||
constructor(scope: Construct, id: string, props: SeahavenSiteRolesProps = {}) {
|
||||
super(scope, id);
|
||||
|
||||
const importing = props.importExisting === true;
|
||||
// Overrides the parent stack's Project=payments-dashboard tag.
|
||||
cdk.Tags.of(this).add("Project", "seahaven-site", { priority: 200 });
|
||||
if (importing) {
|
||||
const roleOnly = { priority: 300, includeResourceTypes: ["AWS::IAM::Role"] };
|
||||
cdk.Tags.of(this).remove("Project", roleOnly);
|
||||
cdk.Tags.of(this).remove("Owner", roleOnly);
|
||||
cdk.Tags.of(this).remove("ManagedBy", roleOnly);
|
||||
}
|
||||
|
||||
const account = cdk.Stack.of(this).account;
|
||||
const deployRole = `arn:aws:iam::${account}:role/tf-managed/githubdeploy-seahaven-site`;
|
||||
const boundary = `arn:aws:iam::${account}:policy/tf-managed/seahaven-site-githubdeploy-boundary`;
|
||||
const bucket = "arn:aws:s3:::seahaven-site-prod";
|
||||
|
|
@ -62,7 +80,7 @@ export class SeahavenSiteHcptfStack extends cdk.Stack {
|
|||
maxSessionDuration: 3600,
|
||||
assumeRolePolicyDocument: trust(hcpOidc, "apply"),
|
||||
managedPolicyArns: [iamPolicy.ref, services.ref],
|
||||
tags: roleTags(),
|
||||
...(importing ? {} : { tags: roleTags() }),
|
||||
});
|
||||
retain(apply);
|
||||
|
||||
|
|
@ -74,17 +92,16 @@ export class SeahavenSiteHcptfStack extends cdk.Stack {
|
|||
"arn:aws:iam::aws:policy/job-function/ViewOnlyAccess",
|
||||
planRefresh.ref,
|
||||
],
|
||||
tags: roleTags(),
|
||||
...(importing ? {} : { tags: roleTags() }),
|
||||
});
|
||||
retain(plan);
|
||||
|
||||
new cdk.CfnOutput(this, "ApplyRoleArn", { value: apply.attrArn });
|
||||
new cdk.CfnOutput(this, "PlanRoleArn", { value: plan.attrArn });
|
||||
|
||||
cdk.Tags.of(this).add("Project", "seahaven-site");
|
||||
cdk.Tags.of(this).add("Owner", "adam@seahavenind.com");
|
||||
cdk.Tags.of(this).add("ManagedBy", "cdk");
|
||||
cdk.Aspects.of(this).add(new HcptfPolicyAspect());
|
||||
if (!importing) {
|
||||
const applyArn = new cdk.CfnOutput(this, "ApplyRoleArn", { value: apply.attrArn });
|
||||
const planArn = new cdk.CfnOutput(this, "PlanRoleArn", { value: plan.attrArn });
|
||||
applyArn.overrideLogicalId("SeahavenSiteApplyRoleArn");
|
||||
planArn.overrideLogicalId("SeahavenSitePlanRoleArn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ Description: >-
|
|||
# those roles (PLAT-144/PLAT-146). The six imported prod pairs are removed
|
||||
# here. Their previous DeletionPolicy is Retain, so CloudFormation forgets
|
||||
# them (PLAT-147). hcptf-sh-openswe-traces was already forgotten.
|
||||
# seahaven-site lives in seahaven-site-hcptf. External-dev
|
||||
# seahaven-site lives in seahaven-hcptf. External-dev
|
||||
# SHOC roles below remain in this template (PLAT-148). All remaining subs are
|
||||
# exact StringEquals (never StringLike, never a wildcarded run_phase).
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue