docs: document github-oidc-deploy-roles stack + permissions boundary (#47)

The bootstrap IAM stack (oidc-deploy-roles.yaml) had no README coverage:
how to deploy it manually (no CD pipeline; >51KB needs --s3-bucket), the
scoped github-cfn-execution-role contract, and the
seahaven-lambda-execution-boundary ceiling for SAM Lambda roles.

Documents the INFRA-97 / INFRA-103 work.
This commit is contained in:
Adam Moussa 2026-06-10 15:03:34 -04:00 • committed by GitHub
parent 385f00d97a
commit b4d9c32a9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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-<repo>`), 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