Skip to content

GP3 — GCS bucket + dedicated write-only publish SA (no host cluster) #1403

Description

@njhensley

Parent: #1400 · Labels: enhancement, area/infra (auto, infra/**) · Size: M · Depends on: none

Goal. Light infra: the source-keyed GCS bucket and a dedicated least-privilege write identity via the existing WIF federation — and explicitly no GKE host cluster (GitHub Pages is the host).

Scope.

  • New Terraform under infra/evidence-dashboard/ (sibling of infra/uat-gcp-account/, reusing its backend.tf/providers.tf/variables.tf conventions and the eidosx project default).
  • Bucket (data) with hardening: public-access-prevention, uniform bucket-level access, object versioning, soft-delete, access logging. The bucket stays locked/non-public — the public surface is GitHub Pages, not the bucket. (Optionally a staging bucket; no four-bucket worker model is needed since there are no workers.)
  • Dedicated write-only publish SA. A NEW SA (e.g. evidence-publish@eidosx) bound to only roles/storage.objectCreator on the data bucket, impersonated through the existing github-actions-pool provider (uat-gcp.yaml:53). Do not reuse or scope down the shared github-actions@eidosx SA — it holds project-wide objectAdmin/objectViewer and more (infra/uat-gcp-account/iam.tf:19-23); the publish SA's compromise must not reach any of that. No new federation beyond the reused pool; no static keys.
  • Read SA (objectViewer) for the build CI that pulls all CTRFs to generate the site (GP4/GP5) — or have the build job impersonate a read-only SA; least-privilege either way.
  • Per-SA WIF subject/attribute condition. Bind the publish SA's roles/iam.workloadIdentityUser member to a condition admitting only the GP2 ingest workflow/job (decide push-event vs workflow_run up front — it changes the OIDC sub/event_name claim). The github-actions-pool provider is owned by infra/demo-api-server; do not tighten/loosen the shared provider — scope per-SA, or stand up a separate provider under infra/evidence-dashboard/ if a provider-level condition is unavoidable. Confirm no demo-api-server regression.
  • Explicitly no GKE host cluster — document in the Terraform README that the public surface is GitHub Pages and the only standing cost is negligible GCS storage (a deliberate divergence from Epic: TG — Deploy & operate the AICR TestGrid instance #1263 TG1).

Out of scope. The ingest job (GP2); the generator (GP4); Pages publish (GP5). Any worker/API/UI compute.

Key files. New infra/evidence-dashboard/*.tf (+ README); reference infra/uat-gcp-account/variables.tf:15-18 (eidosx default), infra/uat-gcp-account/iam.tf:17-23 (shared-SA caveat), backend.tf; WIF provider/SA uat-gcp.yaml:53-54. .github/labeler.yml:51-53 (infra/**area/infra, no change needed).

Tests. terraform validate + terraform plan (dry-run, no apply); tflint/checkov if wired for infra/. Assert: data bucket has public-access-prevention + uniform bucket-level access; the publish SA is a new SA whose only binding is objectCreator (a policy test rejecting any objectViewer/objectAdmin/compute binding and asserting it is not github-actions@eidosx); the per-SA subject condition admits only the GP2 context; no static-key resources; no GKE cluster resource is declared.

Acceptance. infra/evidence-dashboard/ plans cleanly against eidosx; the data bucket is hardened and locked (non-public); a dedicated write-only objectCreator publish SA + a read-only SA are bound least-privilege via the existing github-actions-pool federation with a per-SA subject condition scoped to the GP2 ingest workflow (no shared-provider regression); no host cluster is provisioned.


Child of #1400 · staged from docs/design/013-interim-evidence-dashboard.md (GP3).

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions