Secrets & Identity Management
This page describes the design of secret management and identity/access control across the Shokunin Platform. It covers how secrets are stored, who can access them, how they flow to the places that need them, and how new developers are onboarded.Three Core Principles
Every decision in this design follows three rules:-
GCP Secret Manager is the single source of truth. No secret has an authoritative home anywhere else. GitHub Actions secrets, Vercel environment variables, and local
.envfiles are all derived copies populated from Secret Manager. -
Terraform is the pipe, not the vault. Terraform reads values from Secret Manager (or from
TF_VAR_*environment variables during bootstrapping) and distributes them outward. It never invents secret values. - A human manually sets a secret exactly once. After initial creation, all distribution and rotation is automated.
Secret Namespaces
All secrets live in GCP Secret Manager in projectshokunin-480309. They are organised into two namespaces by naming convention and access scope.
Platform namespace
Naming pattern:shokunin-{env}-{component}
These secrets are shared across the team and consumed by CI/CD, Vercel runtime, and Cloud Run services.
shokunin-dev-dolt-db-password and shokunin-dev-beads-api-key are created by the staging and production Terraform environments, not dev-shared. The dev-shared environment does not deploy a Dolt VM or Beads API Cloud Run service.required = "true" label drives monitoring alerts — any required secret with zero active versions triggers an alert.
Tenant namespace
Naming pattern:shokunin-{env}-{tenant_id}-{component}
Tenant-scoped secrets are provisioned per tenant by the tenant Terraform module. They are isolated from platform secrets and from each other.
Identity Map
The table below describes every actor in the system, how it authenticates, and what it can access.Service accounts
Every service account is managed in Terraform underplatform/environments/foundation/ (project-level SAs) or platform/modules/iam/ (environment-level SAs).
Secret Flow Pipeline
GCP Secret Manager is the authoritative store. Terraform reads values from it and distributes them to every consumer. The local.env is populated by a developer script (scripts/env-sync) that reads from the same source.
Bootstrap exceptions
Two secrets cannot be stored in Secret Manager because accessing Secret Manager itself requires a credential — a circular dependency. These are the only intentional exceptions to Principle 1:
These are set by the operator before running
terraform apply and are never committed or persisted:
Workload Identity Federation (WIF)
GitHub Actions authenticates to GCP without any stored credentials using Workload Identity Federation. The GitHub OIDC token is exchanged for a short-lived GCP access token at runtime.terraform/platform/environments/foundation/wif.tf. The pool is scoped to the Horizon-AI-dev GitHub organisation — tokens from other organisations are rejected.
WIF covers GitHub Actions → GCP only. Deployments from GitHub Actions to Vercel still require a
VERCEL_TOKEN in GitHub secrets — Vercel does not currently support OIDC federation for inbound API authentication.Terraform Modules
Secret and IAM management is split across four Terraform modules:SA key lifecycle
Two service account keys are managed entirely by Terraform — no manualgcloud iam service-accounts keys create steps:
vercel-caller-sakey — created iniammodule, stored inshokunin-dev-vercel-caller-sa-key, pushed to Vercel asGOOGLE_SERVICE_ACCOUNT_KEYby thevercel-envmodule.firebase-admin-sakey — created iniammodule, stored inshokunin-dev-firebase-admin-key, pushed to Vercel asGOOGLE_FIREBASE_ADMIN_KEYby thevercel-envmodule.
terraform apply. Terraform replaces the google_service_account_key resource, updates Secret Manager, and re-pushes to Vercel in a single operation.
Developer Onboarding
Adding a new developer is a two-step process split between an admin and the developer.Step 1 — Admin: grant bootstrap access
Create the developer’s identity file and grant them the permission needed to run their own sandbox terraform.serviceAccountTokenCreator on shokunin-dev-platform-sa to the developer’s Google account. This is the bootstrap permission that allows ./scripts/dev-setup to apply the developer’s own sandbox — without it, SA impersonation fails and dev-setup exits immediately.
serviceAccountTokenCreator lives in foundation (not in dev/main.tf) to break a circular dependency: dev/main.tf is applied via scripts/tf, which requires this very permission to impersonate the platform SA.Step 2 — Developer: one-command local setup
dev-setup handles everything in order:
- Verifies prerequisites (
gcloud,terraform,bun) and that gcloud is authenticated - Creates
config/developers/alice.tfvarsif it does not already exist - Runs
./scripts/tf dev alice apply— creates the developer’s Firestore database and grants Secret Manager read access - Calls
scripts/env-syncto populate.envfrom Secret Manager - Runs a health check to verify the environment is working
scripts/env-sync
env-sync is the developer’s tool for keeping their local .env in sync with Secret Manager. It:
- Authenticates using the developer’s own GCP user account (no SA key required)
- Reads all secrets from the
shokunin-dev-*platform namespace - Writes values to
.env, skipping any that are already set - Prints a summary: what was updated, what was skipped, what is missing a version
Secret Monitoring
A Cloud Monitoring dashboard deployed via Terraform provides visibility into the state of all secrets:- All platform secrets are listed with their version count and last rotation date
- Required secrets (
required = "true"label) with zero active versions trigger an alert - Expiring secrets — any secret version with an
expire_timeset triggers an alert 30 days before expiry
dev-shared apply. Developers can access it directly in the GCP Console under Monitoring → Dashboards.
Runbooks
Adding a new shared secret
- Create the Secret Manager container in
platform/modules/secret-manager/main.tf - Add the appropriate label (
required,consumer,purpose) - Add a
vercel_project_environment_variableresource inplatform/modules/vercel-env/main.tfif the secret is consumed by Vercel - Run
./terraform/scripts/tf dev-shared apply - Set the initial value:
gcloud secrets versions add shokunin-dev-<name> --data-file=-
Rotating a secret
For secrets whose values are managed externally (not SA keys):vercel-caller-sa-key, firebase-admin-key): simply run terraform apply — Terraform recreates the key, updates Secret Manager, and re-pushes to Vercel.
Removing a developer’s access
Delete or remove the IAM binding in their developer.tfvars and re-apply. The developer’s GCP user account will lose secretmanager.secretAccessor on the platform namespace immediately.