From 5bd068724319ad89272a578f41ef744d8122878c Mon Sep 17 00:00:00 2001 From: Alexanderamiri Date: Sat, 24 Oct 2026 15:37:50 +0200 Subject: [PATCH 1/2] fix(iam): pin javabin-ci-infra to platform-ci.yml on main The production-environment OIDC sub carries no branch, so any branch that declared the environment could assume the apply role. Require job_workflow_ref = platform-ci.yml@refs/heads/main, and move the drift job to the read-only plan role so apply is the only ci-infra user. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/platform-ci.yml | 2 +- docs/ci-workflow.md | 2 ++ docs/platform-modules.md | 4 ++-- terraform/platform/iam/main.tf | 13 +++++++++---- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/platform-ci.yml b/.github/workflows/platform-ci.yml index 763efe2..a3dd575 100644 --- a/.github/workflows/platform-ci.yml +++ b/.github/workflows/platform-ci.yml @@ -269,7 +269,7 @@ jobs: - uses: aws-actions/configure-aws-credentials@v6 with: - role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/javabin-ci-infra + role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/javabin-ci-infra-plan aws-region: ${{ env.AWS_REGION }} role-session-name: ${{ env.SESSION_NAME }} diff --git a/docs/ci-workflow.md b/docs/ci-workflow.md index 8c99945..8fe8220 100644 --- a/docs/ci-workflow.md +++ b/docs/ci-workflow.md @@ -32,9 +32,11 @@ Monday 08:00 ──► securityhub-summary Lambda ──► #javabin-infra-ale - Downloads plan from S3, verifies SHA256 integrity - `terraform apply -auto-approve tfplan` - Uses `environment: production` (GitHub environment protection) +- OIDC → `javabin-ci-infra`. The role's trust also pins `job_workflow_ref` to `platform-ci.yml@refs/heads/main`, because the environment-based `sub` claim carries no branch. A workflow on another branch that declares `environment: production` cannot assume it. ### drift - Weekly schedule (Monday 06:00 UTC) +- OIDC → `javabin-ci-infra-plan` (read-only; drift never applies) - Runs `terraform plan -detailed-exitcode` - If drift detected, posts to Slack with plan output diff --git a/docs/platform-modules.md b/docs/platform-modules.md index 0c18eaf..1fb657a 100644 --- a/docs/platform-modules.md +++ b/docs/platform-modules.md @@ -47,8 +47,8 @@ GitHub OIDC provider (data source), CI roles, permission boundary, ECS execution | Role | Trust | Purpose | |------|-------|---------| -| `javabin-ci-infra` | platform repo, main branch | Apply platform TF | -| `javabin-ci-infra-plan` | platform repo, main branch + PRs | Read-only plan + review for platform TF | +| `javabin-ci-infra` | platform repo, pinned to `platform-ci.yml@refs/heads/main` | Apply platform TF (apply job only) | +| `javabin-ci-infra-plan` | platform repo, main branch + PRs | Read-only plan + review + weekly drift check for platform TF | | `javabin-ci-app-{repo}` | Per-app, pinned to `tf-plan.yml` | App TF plan + apply | | `javabin-ci-deploy-{repo}` | Per-app, pinned to `tf-apply.yml` | ECR push, ECS deploy | | `javabin-ci-override-approver` | Board members, pinned to `approve-override.yml` | SSM override tokens | diff --git a/terraform/platform/iam/main.tf b/terraform/platform/iam/main.tf index e35ae8f..de8eb0d 100644 --- a/terraform/platform/iam/main.tf +++ b/terraform/platform/iam/main.tf @@ -149,7 +149,7 @@ resource "aws_iam_role_policy" "ci_infra_plan_extras" { ################################################################################ # 1b. javabin-ci-infra — Platform repo apply only # -# Trust: GitHub OIDC, ONLY main branch (not PRs). +# Trust: GitHub OIDC, ONLY platform-ci.yml on main (job_workflow_ref pin). # Permissions: Allow *:* with permission boundary + explicit deny on operations # that should never happen via CI (organizations, IAM users, destructive security ops). ################################################################################ @@ -172,13 +172,18 @@ resource "aws_iam_role" "ci_infra" { "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" } StringLike = { - # Main branch OR production environment — the apply job uses - # `environment: production`, which changes the OIDC sub claim - # from ref-based to environment-based. + # The apply job uses `environment: production`, which changes the + # OIDC sub claim from ref-based to environment-based. That sub + # carries no branch, so on its own any branch that declares the + # environment would match. "token.actions.githubusercontent.com:sub" = [ "repo:${var.github_org}/platform:ref:refs/heads/main", "repo:${var.github_org}/platform:environment:production", ] + # The job_workflow_ref pin is what ties this role to main: only + # platform-ci.yml as committed on main can assume it, whatever + # the environment's branch policy says. + "token.actions.githubusercontent.com:job_workflow_ref" = "${var.github_org}/platform/.github/workflows/platform-ci.yml@refs/heads/main" } } } From db4cb43f9d4554db5c4f00171a53083a77aca527 Mon Sep 17 00:00:00 2001 From: Alexanderamiri Date: Sat, 24 Oct 2026 16:02:39 +0200 Subject: [PATCH 2/2] docs(iam): correct CI role trust in the platform-modules role table Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/platform-modules.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/platform-modules.md b/docs/platform-modules.md index 1fb657a..2af7bfc 100644 --- a/docs/platform-modules.md +++ b/docs/platform-modules.md @@ -48,9 +48,10 @@ GitHub OIDC provider (data source), CI roles, permission boundary, ECS execution | Role | Trust | Purpose | |------|-------|---------| | `javabin-ci-infra` | platform repo, pinned to `platform-ci.yml@refs/heads/main` | Apply platform TF (apply job only) | -| `javabin-ci-infra-plan` | platform repo, main branch + PRs | Read-only plan + review + weekly drift check for platform TF | -| `javabin-ci-app-{repo}` | Per-app, pinned to `tf-plan.yml` | App TF plan + apply | -| `javabin-ci-deploy-{repo}` | Per-app, pinned to `tf-apply.yml` | ECR push, ECS deploy | +| `javabin-ci-infra-plan` | platform repo, any branch / PR (`repo:javaBin/platform:*`) | Read-only plan + review + weekly drift check for platform TF | +| `javabin-ci-app-broker` | Any org repo, pinned to the platform's reusable workflows on `main` | Invoke the CI broker Lambda only | +| `javabin-ci-team-{team}` | CI broker and apply gate Lambdas (not OIDC) | Team TF plan + apply, scoped to the team by the developer boundary | +| `javabin-ci-deploy-{team}` | CI broker Lambda (not OIDC) | ECR push, ECS deploy | | `javabin-ci-override-approver` | Board members, pinned to `approve-override.yml` | SSM override tokens | | `javabin-ci-registry` | Registry repo | Team provisioning dispatch | | `javabin-ecs-execution` | ECS tasks | Pull images, write logs, read secrets |