mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-09-30 09:13:17 +00:00
SAM repos migrating off the frozen management account need the shared deploy plumbing (permissions boundary + github-cfn-execution-role) in their target account; none of it existed outside mgmt, so there was no OIDC SAM deploy path into seahaven-prod or seahaven-dev at all. Adds a templated, per-account substrate stack so onboarding a future account is one bin/app.ts instance plus one CD job, not a hand-rolled copy. Per-repo githubdeploy-* roles stay out by design: they are provisioned per repo at migration time so an account never accumulates trust for repos that do not deploy to it. The template is a verbatim extraction of the reviewed mgmt substrate, with deliberate, documented divergences — notably the removal of iam:DeleteRolePermissionsBoundary plus explicit Deny backstops, which closes a confirmed privilege-escalation path (see PR body).
64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
import * as cdk from "aws-cdk-lib";
|
|
import * as cfninc from "aws-cdk-lib/cloudformation-include";
|
|
import * as path from "path";
|
|
import { Construct } from "constructs";
|
|
|
|
export interface DeploySubstrateStackProps extends cdk.StackProps {
|
|
/**
|
|
* Create the GitHub OIDC identity provider in this account. Leave false
|
|
* when the provider already exists (seahaven-prod and seahaven-dev both
|
|
* have it from their githubdeploy-* role provisioning) - an account can
|
|
* only hold ONE provider per URL, so creating a duplicate fails the deploy.
|
|
* Set true only for a brand-new account with no OIDC provider yet.
|
|
*/
|
|
createOidcProvider?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Per-account GitHub Actions deploy substrate: the shared account-level
|
|
* resources every SAM deploy pipeline needs -
|
|
* - GitHub OIDC identity provider (conditional, see props),
|
|
* - `seahaven-lambda-execution-boundary` permissions boundary (the ceiling
|
|
* applied to every SAM-generated Lambda execution role),
|
|
* - `github-cfn-execution-role` (the shared CloudFormation execution role
|
|
* that cd-sam callers pass as cfn-role-arn).
|
|
*
|
|
* Deliberately NOT here: per-repo githubdeploy-* roles. Those are provisioned
|
|
* per repo at migration/onboarding time (deploy-role-first playbook) so an
|
|
* account never accumulates trust relationships for repos that do not deploy
|
|
* to it.
|
|
*
|
|
* The resources come verbatim from the management account's reviewed
|
|
* oidc-deploy-roles.yaml substrate section via cloudformation-include, so the
|
|
* policy JSON that passed cross-review and security review deploys unchanged.
|
|
* See lib/deploy-substrate/deploy-substrate.template.yaml for the provenance
|
|
* and drift warning (mgmt's copy stays source of truth for 328440206208 until
|
|
* its stacks finish migrating out).
|
|
*
|
|
* Deploy-order note: the boundary and the execution role live in the SAME
|
|
* stack, and the role carries an explicit DependsOn on the boundary (the
|
|
* role only names the boundary ARN inside Condition strings, so CFN would
|
|
* otherwise infer no creation edge). App stacks (payments-dashboard,
|
|
* front-integrations, sh-openswe-traces, ...) can only target this account
|
|
* AFTER this stack is deployed there.
|
|
*/
|
|
export class DeploySubstrateStack extends cdk.Stack {
|
|
constructor(scope: Construct, id: string, props?: DeploySubstrateStackProps) {
|
|
super(scope, id, props);
|
|
|
|
new cfninc.CfnInclude(this, "Substrate", {
|
|
templateFile: path.join(
|
|
__dirname,
|
|
"deploy-substrate",
|
|
"deploy-substrate.template.yaml",
|
|
),
|
|
parameters: {
|
|
CreateOIDCProvider: props?.createOidcProvider ? "true" : "false",
|
|
},
|
|
});
|
|
|
|
cdk.Tags.of(this).add("Project", "account-baseline");
|
|
cdk.Tags.of(this).add("Owner", "adam@seahavenind.com");
|
|
cdk.Tags.of(this).add("ManagedBy", "cdk");
|
|
}
|
|
}
|