diff --git a/CLAUDE.md b/CLAUDE.md index f42a26d..935df18 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -315,7 +315,7 @@ Team group OWNERs are admin-managed and never removed by the sync; non-@java.no | 0a | AWS Discovery | **Done** | | 0b | Bootstrap State Backend | **Done** — S3 backend live | | 0c | Organizations + Permission Boundary | **Done** — org enabled, boundary deployed, SCP deferred | -| 1 | Identity (Google + Identity Center + Cognito) | **Deployed** — GCP SA with domain-wide delegation, Identity Center with ABAC + 3 permission sets in `terraform/org/`. Google Workspace SAML IdP for SSO (auto-provisions users, groups synced via CI/team-provisioner). Cognito pool TF exists but not yet applied (needs Google OAuth client). | +| 1 | Identity (Google + Identity Center + Cognito) | **Deployed** — GCP SA with domain-wide delegation, Identity Center with ABAC + 3 permission sets in `terraform/org/`. Google Workspace SAML IdP for SSO (auto-provisions users, groups synced via CI/team-provisioner). Cognito pools deployed; the internal pool signs in with the Terraform-managed Google OIDC IdP. | | 2a | Networking | **Deployed** — VPC, subnets, NAT | | 2b | Ingress | **Deployed** — ALB + ACM cert | | 2c | IAM / OIDC | **Deployed** — 6 CI roles (infra, infra-plan, per-app, deploy, override-approver, registry), team-prefixed naming + permission boundary | @@ -334,7 +334,7 @@ Team group OWNERs are admin-managed and never removed by the sync; non-@java.no ### Known Issues - **ECS deploy stabilization**: platform-test-app task registers but service fails health check -- **Cognito**: pools deployed; internal pool's `GoogleSAML` IdP was created outside Terraform. It is replaced by the Terraform-managed Google OIDC IdP at cutover (docs/cognito-google-setup.md), then deleted +- **Cognito**: pools deployed; the internal pool has been cut over to the Terraform-managed Google OIDC IdP (`internal_identity_providers` defaults to `["Google"]`). The old `GoogleSAML` IdP, created outside Terraform, is still in the pool but offered on no app client until it is deleted (docs/cognito-google-setup.md, "Decommission GoogleSAML") - **Google SCIM provisions only direct members** of `drift@`, `styret@` and `javabin-developer@java.no` to Identity Center; it does not expand nested groups. Nobody gets an Identity Center user (and so no AWS access, team role included) unless they are a direct member of one of those. The team provisioner adds team members and (via `flatten: true` in the registry's `groups/access.yaml`) kodesmia members to `javabin-developer@` one by one; SCIM creates the user later, and the 3-hourly `sync_access_members` run adds them to their Identity Center groups. Don't create Identity Center users through the API: they'd have no link to Google (see `docs/lambda-functions.md`). - **SSO sessions carry no `team` tag**: the Identity Center ABAC attribute (`${path:enterprise.team}`) is never set on users, so `${aws:PrincipalTag/team}` is empty for humans. Per-team permission sets (`javabin-team-{team}`) therefore use `javabin-team-{team}-guardrails` (the developer boundary rendered with the team name) as their permissions boundary instead. It must stay a boundary: its baseline `Allow *` attached as a policy grants everything its Denies miss (every untagged resource). A team with no guardrails policy (`platform`, or a new team before platform CI) gets read-only access only. The ABAC-based `javabin-developer` permission set in `terraform/org` cannot reach team resources - **App databases share one network path** (fixed by `app-network`): service-rds now allows ingress only from the app's own `{team}-{app}-tasks` SG; each app moves off the shared ECS tasks SG on its next pipeline run diff --git a/docs/platform-modules.md b/docs/platform-modules.md index 2a1fc21..9f9fa02 100644 --- a/docs/platform-modules.md +++ b/docs/platform-modules.md @@ -57,7 +57,8 @@ GitHub OIDC provider (data source), CI roles, permission boundary, ECS execution | `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, `main` only | Team provisioning dispatch | -| `javabin-ecs-execution` | ECS tasks | Pull images, write logs, read secrets | +| `javabin-ecs-exec-{team}` | ECS tasks | Pull images, write logs, read the team's own secrets (`/javabin/apps/{team}/*`). One per registry team | +| `javabin-ecs-execution` | ECS tasks | Deprecated shared role: image pull and logs only, no secrets. Teams can no longer pass it | **Key design:** `job_workflow_ref` condition prevents app repos from writing rogue workflows. @@ -118,5 +119,4 @@ Team SSO roles' `CredentialAccess:IAMUser/AnomalousBehavior` on `ssm:GetParamete ## identity -**Not yet implemented.** Will contain IAM Identity Center + Cognito user pools. -Blocked on Google Admin access for SAML federation. +Cognito user pools (internal + external) and the `auth-claims` trigger. The internal pool signs in through Google OIDC (provider `Google`, from the `internal_identity_providers` variable); the hand-made `GoogleSAML` provider is still in the pool but no longer offered on app clients. See [cognito-google-setup.md](cognito-google-setup.md). IAM Identity Center is in `terraform/org/`, not here. diff --git a/docs/reusable-modules.md b/docs/reusable-modules.md index aa19f0f..b51d16d 100644 --- a/docs/reusable-modules.md +++ b/docs/reusable-modules.md @@ -16,7 +16,7 @@ source = "git::https://github.com/javaBin/platform.git//terraform/modules/{name} | Security group | `javabin-ecs-tasks-sg` | | ALB | `javabin-alb` | | ECS cluster | `javabin-platform` | -| Execution role | `javabin-ecs-execution` | +| Execution role | `javabin-ecs-exec-{team}` (from the `team` input; reads only that team's secrets) | | Route53 zones | `javazone.no` (`route53_zone_id`); `javazone.no`, `java.no`, `javabin.no` (`route53_zone_ids` map) | **Key outputs:** `vpc_id`, `private_subnet_ids`, `ecs_cluster_id`, `https_listener_arn`, `execution_role_arn`, `route53_zone_id`, `route53_zone_ids` diff --git a/terraform/modules/cognito-app-client/main.tf b/terraform/modules/cognito-app-client/main.tf index 06e7e45..9249ce2 100644 --- a/terraform/modules/cognito-app-client/main.tf +++ b/terraform/modules/cognito-app-client/main.tf @@ -18,7 +18,8 @@ # # Those parameters are owned by the Lambda, not by this Terraform. Their ARNs # are deterministic, so the ECS task definition can reference them up front; -# the shared execution role reads //apps/* at task launch. +# the team's execution role (-ecs-exec-, which can read only +# //apps//*) resolves them at task launch. # # With `slot` set (e.g. "login-1", used by service-routing for ALB sign-in), # everything moves one level down — //apps////auth — diff --git a/terraform/org/identity-center.tf b/terraform/org/identity-center.tf index fe0fc0f..49ac4e4 100644 --- a/terraform/org/identity-center.tf +++ b/terraform/org/identity-center.tf @@ -7,9 +7,14 @@ # Prerequisite: Google Workspace SAML sync must be configured first so that # Identity Center groups (infra@, heroes@, board@, pkom@) exist. # -# ABAC: The "team" attribute flows from Google group membership through -# SAML assertion → Identity Center → STS session tag. This lets a single -# JavabinDeveloper permission set work for all teams. +# ABAC: The "team" attribute was meant to flow from Google group membership +# through SAML assertion → Identity Center → STS session tag, so a single +# JavabinDeveloper permission set would work for all teams. +# +# NOTE: the "team" attribute is never populated on Identity Center users, so +# SSO sessions carry no team tag and javabin-developer gets no access to team +# resources. Developers use the per-team permission sets (javabin-team-{team}) +# created by the team-provisioner Lambda instead (see CLAUDE.md, Known Issues). ################################################################################ data "aws_ssoadmin_instances" "this" {} @@ -20,6 +25,7 @@ locals { ################################################################################ # Access Control Attributes (ABAC) — map "team" from SAML assertion +# (the source attribute is never set today; see the ABAC note above) ################################################################################ resource "aws_ssoadmin_instance_access_control_attributes" "this" { diff --git a/terraform/platform/iam/main.tf b/terraform/platform/iam/main.tf index 2466fb6..2e997ac 100644 --- a/terraform/platform/iam/main.tf +++ b/terraform/platform/iam/main.tf @@ -998,10 +998,10 @@ resource "aws_iam_role_policy" "ci_apply_gate" { } ################################################################################ -# ECS Execution Role — pulls images, writes logs, reads secrets +# ECS Execution Role (shared, deprecated) — pulls images, writes logs # -# This is the shared execution role for all ECS tasks on the platform. -# Individual task roles are created per-app via the service-role module. +# Tasks now use the per-team execution roles below. Individual task roles are +# created per-app via the service-role module. ################################################################################ # Deprecated shared execution role. Kept (image pull + logs only, no secrets)