Skip to main content

CI/CD Enablement

Corpus provisions the shared infrastructure that enables continuous delivery across the platform — keyless authentication for pipelines, a central registry for built artifacts, and encrypted remote state storage for OpenTofu.

  • GitHub Actions service accounts: Workload identity federation allows GitHub Actions workflows to authenticate to GCP without long-lived credentials
  • Artifact Registry: A central registry for container images and packages, scoped per team and consumed by workloads running on GKE
  • State buckets: Encrypted GCS buckets backed by Cloud KMS, with a dedicated bucket per repository per environment, used as the OpenTofu remote backend
Architecture Decision Records

This page includes Architecture Decision Records documenting the key design decisions.

Components

ComponentDescription
service-accountA GCP service account created per team for GitHub Actions workloads; individual repository access is granted via IAM bindings
workload-identity-poolA Workload Identity Federation pool that maps GitHub OIDC tokens to GCP service accounts — no static credentials
workload-identity-providerAn OIDC provider within the pool, scoped to the GitHub org via repository_owner_id; repository-level access is enforced at the IAM binding level
artifact-registryA three-tier registry per team: a shared Docker Hub remote proxy, a per-team standard repository for team images, and a per-team virtual repository that chains both
state-bucketAn encrypted GCS bucket per repository per environment used as the OpenTofu remote backend, protected by a per-environment KMS key

Core Invariant

GitHub Actions authenticates via Workload Identity Federation — no static credentials exist.

Architecture Decision Records

Keyless Authentication via Workload Identity Federation

StatusDateDeciders
Accepted ✅April 2026Corpus

Context and Problem Statement

GitHub Actions workflows need to authenticate to GCP to deploy infrastructure, push container images to Artifact Registry, and read and write OpenTofu state in GCS. The conventional approach is to create a service account key, store it as a GitHub Actions secret, and pass it to the workflow. Service account keys are long-lived credentials — they do not expire, cannot be scoped to a single job, and represent a persistent attack surface if leaked.

The platform manages repositories across three environments. Each repository needs its own identity for least-privilege enforcement. Storing and rotating service account keys at that scale is operationally unsustainable and creates significant credential leak risk.

Decision

Use Workload Identity Federation to allow GitHub Actions workflows to authenticate to GCP using short-lived OIDC tokens — no service account keys are created, stored, or rotated.

Each repository and environment gets a dedicated GCP service account. GitHub Actions exchanges a per-job OIDC token (minted by GitHub, scoped to the repository and workflow ref) for a short-lived GCP access token via a Workload Identity Pool. The token expires automatically when the job ends.

Environment-separated identity pools mean a token issued for sandbox cannot be used in production, even if intercepted.

Alternatives Considered

  • Service account keys stored as GitHub secrets — Rejected. Long-lived credentials that cannot be automatically scoped, do not expire, and require manual rotation. Any leak is a persistent breach.
  • Shared service account across repositories — Rejected. Violates least-privilege. A compromise in one repository would grant access to all environments.
  • Self-hosted runners with attached service accounts — Rejected. Adds infrastructure to manage, increases attack surface, and provides no meaningful security improvement over Workload Identity Federation on GitHub-hosted runners.

Consequences

  • No static credentials exist anywhere in the platform
  • Token scope is limited to a single job, repository, and environment
  • Compromise of a GitHub Actions secret does not grant GCP access
  • Adding a new repository requires provisioning a new service account and Workload Identity binding in Corpus — this is automated via pt-logos team definitions