---
title: "GCP Naming Conventions"
slug: gcp-naming-conventions
section: GCP Infrastructure
status: stable
description: "The binding standard is `docs/naming-conventions.md` in `alliance-gcp-infra`."
last-updated: 2026-10-07
---

# GCP Naming Conventions

## The standard

The binding standard is `docs/naming-conventions.md` in `alliance-gcp-infra`. It replaces the archived `00000_iac_*` standard, whose full-word environment suffixes needed "legacy exceptions" almost at once because of the 30-character service-account `account_id` limit. The universal pattern is:

```
<system>-<component>-<env>
```

All lowercase, hyphen-separated. `env` is always abbreviated to `dev`, `qa` or `prod`. The words `development`, `quality-assurance` and `production` do not belong in a new resource name. For example, `applicant-portal-runtime-development` is 37 characters and cannot be a service account id, while `applicant-portal-runtime-dev` is 28.

There is no `staging` environment, so no name may use that word. The promotion path is dev, then QA, then prod (see `/docs/git-branching-release-model` and `/docs/dev-only-deployment-policy`).

## Rules per resource type

| Resource | Pattern | Example from the standard | Notes |
|---|---|---|---|
| Service account | `<system>-<component>-<env>` | `n8n-runtime-qa` | No `-sa` suffix. Capped at 30 characters; shorten `component`, never `system` or `env`. One dedicated service account per workload. |
| Cloud SQL instance | `<system>-db-<env>` | `n8n-db-qa` | Instance names are immutable, so fixing one is a data migration, not an edit. |
| Secret | `<system>-<component>-<env>-<key>`, or `<system>-<env>-<key>` when the system has one component | `n8n-qa-api-key` | Do not invent a third variant. The module manages the secret container and IAM bindings only, never the value. |
| Cloud Run service | `<system>-<component>-<env>`, with no env suffix for genuinely shared services | `wildpacks-api-qa`; `cloudbuild-teams-notifier` (shared) | The MCP services are one shared instance, never per environment. |
| GKE cluster | `<system>-cluster-<env>` | `globus-cluster-qa` | |
| GKE namespace | `<system>-<env>` | `globus-qa`, `host-portal-qa` | `n8n` is the one documented exception. |
| Static IP and load balancer | `<system>-<purpose>-<env>` | `shared-ingress-qa` | The standard mandates one shared external IP per environment because the static address quota in QA was already at 75%. |
| Container image | `<region>-docker.pkg.dev/<project>/<repo>/<image>:<semver>@sha256:<digest>` | n/a | Never `:latest`. Terraform pins the digest; the semver tag is for humans. |
| DNS record | `<env>.<name>.allianceabroad.com` | `qa.globus` | |

The standard does not define a pattern for storage buckets or Artifact Registry repositories. The `storage-bucket` module README only records that app-data buckets are `prevent_destroy` and that Cloud Build creates `<project>_cloudbuild` buckets itself. Artifact Registry repositories in the environment projects are named by system or purpose (for example `globus`, `portal`, `wildpacks`, `ppp2`) without an env suffix. Treat both as convention by practice, not binding rules.

## How the modules enforce it

- `modules/service-account` has two modes. Derived mode takes `system`, `component` and `env`, builds the id and fails a precondition above 30 characters; use it only for a genuinely new account. Override mode (`account_id_override`) takes the exact live id, because GCP service account ids are immutable.
- `modules/secret-manager-secret` follows the standard. `modules/secret-manager-secret-bulk` deliberately imports secrets under their exact live names, because running services read them by name.
- `modules/cloud-sql-postgres` uses `prevent_destroy`, so a rename cannot happen by editing the config.

## Where reality departs from the standard

Most departures are legacy: resources existed before the repo and were imported under their live names. Names below come from `iac-inventory.json` and the `.tf` files under `environments/`. For `alliance-platform-agents` they are cross-checked against the live snapshot. `alliance-platform-services` has no usable live snapshot (permission denied), so only its code names are known.

### Legacy full-word environment suffixes (development)

- Cloud SQL: `applicant-portal-db-development`, `participant-keycloak-db-development`, `globus-db-development`, `mcp-db-development`
- GKE cluster: `globus-cluster-development`
- Static IPs: `globus-development-ip`, `n8n-development2-ip`, `host-portal-development-lb-ip`
- Buckets: `applicant-portal-documents-development`, `globus-documents-development`, `globus-profile-photos-development`
- Newer dev resources already use the abbreviation: `n8n-db-dev` and `terraform-ci-viewer-dev`

### Reversed or non-standard Cloud SQL names

- `n8n-dev-db` (development) has env and component reversed; the same defect the standard cites for `n8n-qa-db`. `n8n-db-dev` is the conforming name and also exists. The QA instance is now `n8n-db-qa`.
- `npe-j1-visa-postgres-db`, `alliance-mcp-gateway-db`, `sys-n8n-db` do not follow `<system>-db-<env>`. The MCP and platform-services names carry no env suffix, consistent with those projects not being per environment.

### Service accounts

Existing accounts keep their original ids (override mode). Examples that break the `-sa` rule, the env rule or the component-before-env order: `globus-dev-runtime`, `wildpacks-dev-runtime`, `gke-node-sa`, `n8n-gke-sa`, `manus-agent-sa`, `nexus-hub-runtime-sa`, `localreplitserviceaccount`, `applicant-service-sa`, `backend-service-potal`, `host-service-potal` (misspelled), `terraform-tf`, and a one-off database export/import account in QA. Most MCP accounts end in `-sa` (`asana-mcp-sa`, `teams-mcp-sa`, `gcp-mcp-sa`). Agent accounts in `alliance-platform-agents` follow `<agent>-sa` with no env, for example `overseer-agent-sa` and `security-agent-sa`, because that project is not per environment. Only `terraform-ci-viewer-dev`, `terraform-ci-viewer-qa` and `terraform-ci-viewer-prod` follow `<system>-<component>-<env>` exactly. QA and prod runtime accounts such as `globus-qa-runtime`, `globus-prod-runtime`, `wildpacks-qa-runtime`, `wildpacks-prod-runtime` and `external-secrets-qa-runtime` drop the `-sa` suffix but put the env in the middle (`<system>-<env>-<component>`), as `globus-dev-runtime` does.

### Secrets

Live names span several conventions (see the bulk module README): `secret-alias-1` to `secret-alias-26`, `mcp-api-key`, `anthropic-api-key`, `Github-github-oauthtoken-2a5058` (mixed case) and the auto-generated `globu-352a02be-9a31-11f1-8ea9-9c65eb2e83c5` that the live asana-hygiene-agent still references. In the agents project most names are per agent (`asana-hygiene-agent-api-key`, `asana-hygiene-agent-gateway-pat`) with no env suffix, and three break the pattern: `POSTHOG_PERSONAL_API_KEY`, `n8n-api-key` and `teams-platform-pulse-webhook-url`.

### Cloud Run, load balancers and IPs

- Cloud Run services have no env suffix in the agents project (`security-agent`, `pr-hygiene-agent`, `qa-to-prod-sync-agent`) and MCP project (`asana-mcp`, `globus-mcp-development`). `globus-mcp-development` carries an env word although the MCP services are meant to be single shared instances.
- `applicant-keycloak` is the service name in development, QA and prod, with no env suffix, and `db-query-proxy-prod` / `db-query-proxy-prod-broker` use `prod` instead of `-prod` after a component.
- No `shared-ingress-<env>` address exists in the code. Each environment instead has per-system addresses: `globus-qa-ip`, `host-portal-qa-ip`, `n8n-qa-ip`, `globus-prod-ip`, `n8n-prod-ip`, `wildpacks-prod-ip`. The one-IP-per-environment mandate is therefore not yet met.
- Load balancers are named for the host portal in prod (`host-portal-cloudrun-lb-prod-*`) and `mcp-lb` / `mcp-gateway-lb-ip` for the gateway, so env placement varies.

### Buckets and networks

- Buckets with no env or system pattern: `manus-agent-builds-469819`, `host-portal-metrics-storage`, `openstatus-sqld-data-skilled-script-469819-f2`.
- Dev holds buckets named for other environments: `globus-documents-prod`, `globus-profile-photos-prod`, `globus-vertex-agent-prod` and `globus-vertex-agent-staging` (the word `staging` is dead; see the staging rule above).
- QA/prod buckets put env before the noun (`qa-globus-branding-assets`, `prod-globus-branding-assets`) or after the system (`globus-qa-documents`), while dev uses the reverse (`development-globus-branding-assets`).
- The VPC named `skilled-script-vpc-qa` in QA (and `skilled-script-vpc-prod` in prod) carries the dev project id; the network README records it as a flagged naming leak that is too disruptive to rename.

For the full resource lists see `/docs/gcp-overview`, and for the module behaviours see `/docs/gcp-terraform-modules`.

## Gotchas

- Renaming a Cloud SQL instance, service account, secret container or VPC is a migration, never a Terraform edit. Do not "fix" legacy names inside an unrelated PR.
- New resources must follow the standard even when a neighbouring legacy resource does not; copy the standard, not the neighbour.
- Verify the 30-character limit before choosing a service account `component`.

## Known gaps

- The standard has no rule for buckets or Artifact Registry repositories; the descriptions above come from module READMEs and observed names.
- `alliance-platform-services` could not be inspected live, so its names are from code only.
- `docs/naming-conventions.md` lists `n8n-qa-db` as a live bug; the code now names the QA instance `n8n-db-qa`, so that note is already outdated.
- It could not be confirmed from code that a `shared-ingress-<env>` address was ever created.
