Forms DB Access — Paths & Break-Glass Procedure¶
Classification: CONFIDENTIAL — Internal Use Only Document:
infrastructure/runbooks/forms-db-access.md· v1.0 · 2026-06-12 · GPUS-IT
Access paths to Cloud SQL instance gpus-forms-db (PostgreSQL 15,
private IP 10.34.0.3 on gpus-vpc, IAM database authentication, no
password auth). Covers the canonical service paths and the
break-glass human path used when an operator must reach the
database directly from a workstation.
Canonical access paths (standing)¶
| Principal | IAM DB user | Path | Purpose |
|---|---|---|---|
gpus-forms-backend@gpus-infra.iam.gserviceaccount.com |
gpus-forms-backend@gpus-infra.iam |
Cloud Run → VPC connector gpus-vpc-connector → private IP |
Application runtime (holds forms_app role) |
clamav-worker@gpus-infra.iam.gserviceaccount.com |
clamav-worker@gpus-infra.iam |
Cloud Run → VPC connector → private IP | α ClamAV verdict + audit writes (scanner RLS policies) |
maple-agent@gpus-infra.iam.gserviceaccount.com |
maple-agent@gpus-infra.iam |
MAPLE VM → VPC peering → private IP | Daily backup export; 2.5(c) routing worker (Gate 4) |
rajesh.chhetry@greenpeace.us |
rajesh.chhetry@greenpeace.us (CLOUD_IAM_USER) |
Break-glass only (below) | Operator |
There is no public IP and no password-authenticated user in active
use. Humans have no standing connection path: workstations are not on
gpus-vpc, and that is deliberate.
Break-glass path: laptop tunnel via MAPLE + SA impersonation¶
Not a standing convenience
This is a grant → use → revoke procedure, time-boxed to a
single work session. The roles/iam.serviceAccountTokenCreator
grant exists only while the session is open and is revoked —
and the revocation verified — before the session is considered
closed. Leaving the grant in place defeats the access model
(CIS 5.2 / NIST AC-6 least privilege). Used most recently for the
forms 2.5(c) Gate-3 end-to-end test (2026-06-10/11); revocation
verified 2026-06-12.
Use this path when work requires direct psql against gpus-forms-db
with an application role's privileges (e.g. forms_app row-level
security context) — schema verification, e2e checks, incident
forensics. For plain read access under your own identity, the same
tunnel works with your own CLOUD_IAM_USER and no grant is needed
(skip steps 1 and 4; your DB user carries only its own privileges, not
forms_app).
Prerequisites: SSH reachability to MAPLE (172.16.0.12) over the
established VPN path (IAP is not currently a working fallback —
see priority T3, IAP-to-MAPLE 4003 host-level), and
roles/cloudsql.instanceUser on your account (already held by
rajesh.chhetry@greenpeace.us).
1 — Grant (time-boxed)¶
Grant yourself token-creator on the service account whose database
privileges the work requires — normally
gpus-forms-backend@gpus-infra.iam.gserviceaccount.com (holds
forms_app):
gcloud iam service-accounts add-iam-policy-binding \
gpus-forms-backend@gpus-infra.iam.gserviceaccount.com \
--member="user:rajesh.chhetry@greenpeace.us" \
--role="roles/iam.serviceAccountTokenCreator" \
--project=gpus-infra
Record the grant (timestamp + reason) in the work log for the change
that needed it. The grant itself is captured in Cloud Audit Logs
(SetIamPolicy on the SA).
2 — Use¶
Terminal 1 — tunnel a local port through MAPLE to the Cloud SQL private IP:
Terminal 2 — IAM-auth psql as the impersonated service account
(access tokens expire after ~60 minutes; re-run the PGPASSWORD
mint as needed):
PGPASSWORD="$(gcloud auth print-access-token \
--impersonate-service-account=gpus-forms-backend@gpus-infra.iam.gserviceaccount.com)" \
psql "host=127.0.0.1 port=15432 \
user=gpus-forms-backend@gpus-infra.iam \
dbname=gpus_forms sslmode=require"
For your own-identity variant: user=rajesh.chhetry@greenpeace.us and
drop the --impersonate-service-account flag.
3 — Revoke (same session, not "later")¶
gcloud iam service-accounts remove-iam-policy-binding \
gpus-forms-backend@gpus-infra.iam.gserviceaccount.com \
--member="user:rajesh.chhetry@greenpeace.us" \
--role="roles/iam.serviceAccountTokenCreator" \
--project=gpus-infra
4 — Verify the revocation (evidence, not assertion)¶
gcloud iam service-accounts get-iam-policy \
gpus-forms-backend@gpus-infra.iam.gserviceaccount.com \
--project=gpus-infra --format=json
Expected: no user: member under any role. The only standing
bindings across the forms-portal service accounts are
roles/iam.serviceAccountUser for
gpus-cloudbuild@gpus-infra.iam.gserviceaccount.com (deploy-time
actor) and — on clamav-worker only —
roles/iam.serviceAccountTokenCreator for the Pub/Sub service agent
service-1056766133984@gcp-sa-pubsub.iam.gserviceaccount.com (mints
OIDC tokens for the push subscription; do not remove it).
Close the tunnel (Ctrl-C in Terminal 1) and note the revocation in the same work log entry as the grant.
GRANT-class migrations — who can apply them (documented fact, 2026-06-12)¶
Discovered applying migration 013: IAM DB users (including
rajesh.chhetry@greenpeace.us) hold only cloudsqliamuser — no
CREATEROLE, no admin option on forms_app — so GRANT <role> TO …
migrations fail with must have admin option on role. ALTER TYPE
migrations (011/012 style) work under your own IAM user because the
type owner check passes; role-membership grants do not.
The only identity that can apply GRANT-class migrations is the
postgres built-in (member of cloudsqlsuperuser, which holds
CREATEROLE; it is also the effective grantor of record for both
forms_app memberships). Its password is deliberately not stored
anywhere — Step 5 never set one and no secret exists. Procedure
(transient-credential analog of the break-glass grant→use→revoke):
# 1. Set a one-time random password (requires project owner):
PW="$(openssl rand -base64 24)"
gcloud sql users set-password postgres --instance=gpus-forms-db \
--project=gpus-infra --password="$PW"
# 2. Apply over the MAPLE tunnel (§ above) as postgres:
PGPASSWORD="$PW" psql "host=127.0.0.1 port=15432 user=postgres \
dbname=gpus_forms sslmode=require" -f <migration.sql>
# 3. Immediately rotate to a NEW random that is discarded — never
# leave a known root credential behind:
gcloud sql users set-password postgres --instance=gpus-forms-db \
--project=gpus-infra --password="$(openssl rand -base64 24)"
Record which identity applied each migration in its commit message.
Related¶
- Backup & Restore —
maple-agentCloud SQL export auth path - Forms Portal — architecture and controls overview
forms-backend/RUNBOOK-CLAUDE-CODE.mdStep 6 — original schema-apply procedure (Cloud SQL Auth Proxy variant; the proxy needs direct network reach to the instance, so from a workstation the SSH-tunnel form above is the working path)