diff --git a/README.md b/README.md index 6a35a16..9d754d0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,55 @@ Organization-level GitHub configuration for Sea Haven Industries. **`scripts/rollout-review-workflow.sh`** — One-time script to push the thin PR review wrapper workflow to all org repos via the GitHub API. Creates a branch and PR on each repo. +### AWS deploy roles & IAM (`oidc-deploy-roles.yaml`) + +**`oidc-deploy-roles.yaml`** is a **bootstrap CloudFormation stack** (`github-oidc-deploy-roles`, us-east-1, account 328440206208) that owns the IAM the CI/CD workflows assume. It contains: + +- The GitHub Actions **OIDC provider** (conditional — already exists in the account). +- One **OIDC deploy role per repo** (`githubdeploy-`), assumed by that repo's `deploy.yaml` via OIDC and passed in as `AWS_DEPLOY_ROLE_ARN`. CDK repos use these to assume the `cdk-hnb659fds-*` bootstrap roles; SAM repos use these to run `sam deploy`. +- The shared **SAM CloudFormation execution role** `github-cfn-execution-role` (`SamCfnExecutionRole`) — passed as `cfn-role-arn` by every SAM `deploy.yaml` (see §5). CloudFormation assumes it to provision the SAM stacks' resources. +- The **`seahaven-lambda-execution-boundary`** managed policy. + +> ⚠️ **This stack has no CD pipeline — it is deployed manually.** (It defines the very roles the pipelines use, so it can't deploy itself.) + +```bash +# Review IAM changes FIRST (IAM changes also require the cross-family review per the handbook): +aws cloudformation deploy \ + --region us-east-1 \ + --stack-name github-oidc-deploy-roles \ + --template-file oidc-deploy-roles.yaml \ + --capabilities CAPABILITY_NAMED_IAM \ + --s3-bucket cdk-hnb659fds-assets-328440206208-us-east-1 \ + --no-execute-changeset +# inspect the printed change-set, then drop --no-execute-changeset to apply. +``` + +`--s3-bucket` is **required** — the template is larger than the 51,200-byte inline limit. + +#### `github-cfn-execution-role` is scoped (no `*FullAccess`) + +The execution role carries **no blanket `*FullAccess`/`IAMFullAccess`** — only per-service inline policies. Its `iam:CreateRole` / `iam:AttachRolePolicy` / `iam:PutRolePolicy` are conditioned on `iam:PermissionsBoundary == seahaven-lambda-execution-boundary`, so it can only create roles that carry the boundary (it cannot mint an unconstrained admin role). **Adding a new AWS service to a SAM stack means adding that service's provisioning actions to this role**, or the deploy fails. + +#### `seahaven-lambda-execution-boundary` is the Lambda runtime ceiling + +Every SAM-created Lambda execution role gets this boundary attached — SAM stacks set it on `Globals.Function`: + +```yaml +Globals: + Function: + PermissionsBoundary: arn:aws:iam::328440206208:policy/seahaven-lambda-execution-boundary +``` + +A function's effective permissions are the **intersection** of its own role policy and this boundary. **A new runtime permission must also be added to the boundary, or it is silently denied at runtime** (the deploy still succeeds — the failure only shows when the function runs). SAM does **not** support a custom `Path` on auto-generated function roles, so the boundary *condition* (not a role path) is the escalation guard. + +#### Order of operations when changing the exec role or boundary + +1. Deploy the boundary change first. +2. Redeploy the SAM stacks so their roles pick it up (while the exec role still permits it). +3. *Then* tighten the exec role. + +Wrong order breaks every SAM deploy. (History: INFRA-103 established the boundary, INFRA-97 scoped the role.) CDK repos are unaffected — they deploy via `cdk-hnb659fds-*` roles, not this execution role. + ## Setup ### 1. Create a GitHub App @@ -143,6 +192,8 @@ jobs: deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} ``` +> The `cfn-role-arn` (`github-cfn-execution-role`) is scoped and boundary-gated — adding a new AWS service or a new Lambda runtime permission to a SAM stack may require updating that role and/or `seahaven-lambda-execution-boundary` first. See [AWS deploy roles & IAM](#aws-deploy-roles--iam-oidc-deploy-rolesyaml). + **TypeScript CDK repo** (e.g., seahaven-door-unlock-api): ```yaml