---
title: "GCP Infrastructure Overview"
slug: gcp-overview
section: GCP Infrastructure
status: stable
description: "This section documents Alliance Abroad's Google Cloud footprint as it is described by the `alliance-gcp-infra` Terraform repository and as it was observed through read-only snapshots taken on 2026-10-01."
last-updated: 2026-10-07
---

# GCP Infrastructure Overview

This section documents Alliance Abroad's Google Cloud footprint as it is described by the `alliance-gcp-infra` Terraform repository and as it was observed through read-only snapshots taken on 2026-10-01. The repo holds six Terraform environment folders under `environments/`. Each folder is one root module with its own state, and each maps to exactly one GCP project. The repo is intended to describe the resources in these projects; the drift tables in this section show where it does and does not.

Two things are easy to miss. First, the three Globus environments (`development`, `qa`, `production`) are separate GCP projects with no staging tier; the valid promotion path is development to QA to prod — reached, since the portal repos moved to the sandbox branching model (BackOfficePrototype last, on 2026-10-06), by feature branches on pooled development slots, `release/*` branches on pooled QA slots and `release/*` → `main` merges for production, not by a `development` → `qa` → `main` branch chain. Second, the MCP, platform-services and vertex folders are not Globus environments at all: they hold shared tooling, and they are not copies of one another.

_Terraform inventory generated from `alliance-gcp-infra` at commit `fc9bd1d`. Live snapshots: `skilled-script-469819-f2` read 2026-10-01; `alliance-mcp-services` read 2026-10-01; `alliance-platform-services` read 2026-10-01 (nothing readable); `production-499116` read 2026-10-01; `quality-assurance-496022` read 2026-10-01; `alliance-platform-agents` read 2026-10-01. Snapshots hold names and a few stable attributes only, never secret values._

## Projects and environments

| Environment folder | GCP project | Default region | Terraform state | Module calls | Direct resources | Live state read |
| --- | --- | --- | --- | --- | --- | --- |
| `development` | `skilled-script-469819-f2` | `us-central1` | `gs://dev-tfstate-skilled-script-469819-f2/alliance-gcp-infra` | 103 | 70 | yes |
| `mcp` | `alliance-mcp-services` | `us-central1` | `gs://mcp-tfstate-alliance-mcp-services/alliance-gcp-infra` | 65 | 61 | yes |
| `platform-services` | `alliance-platform-services` | `us-central1` | `gs://platform-services-tfstate-alliance-platform-services/alliance-gcp-infra` | 5 | 18 | no |
| `production` | `production-499116` | `us-central1` | `gs://prod-tfstate-production-499116/alliance-gcp-infra` | 149 | 68 | yes |
| `qa` | `quality-assurance-496022` | `us-central1` | `gs://qa-tfstate-quality-assurance-496022/alliance-gcp-infra` | 138 | 67 | yes |
| `vertex` | `alliance-platform-agents` | `us-central1` | `gs://dev-tfstate-skilled-script-469819-f2/alliance-gcp-infra/vertex` | 15 | 3 | yes |

## Live read coverage

| Environment | Project | Live state read | Resource types compared | Types not compared |
| --- | --- | --- | --- | --- |
| `development` | `skilled-script-469819-f2` | yes | 18 | 0 |
| `mcp` | `alliance-mcp-services` | yes | 10 | 8 |
| `platform-services` | `alliance-platform-services` | no | 17 | 1 |
| `production` | `production-499116` | yes | 16 | 2 |
| `qa` | `quality-assurance-496022` | yes | 18 | 0 |
| `vertex` | `alliance-platform-agents` | yes | 14 | 4 |

## Environment to project map

| Folder | GCP project | Purpose | In CI? |
|---|---|---|---|
| `environments/development` | `skilled-script-469819-f2` | Dev Globus (BackOffice, applicant, host portals), GKE, Cloud SQL, Redis, plus many agent and n8n services and the largest secret inventory | Plan on PR, apply on merge |
| `environments/qa` | `quality-assurance-496022` | QA Globus, plus the branching sandbox slots used for `release/*` verification | Plan on PR, apply on merge |
| `environments/production` | `production-499116` | Production Globus: Cloud Run, GKE, Cloud SQL, Redis, secrets | Plan on PR, manual apply |
| `environments/mcp` | `alliance-mcp-services` | The MCP Gateway, its backend MCP servers, Platform Hub, the shared global load balancer, OpenStatus on GKE | Plan on PR, manual apply |
| `environments/platform-services` | `alliance-platform-services` | The IT request portal, `sys-n8n` and related secrets and database | None, draft IaC |
| `environments/vertex` | `alliance-platform-agents` | The Cloud Run agent fleet (for example security, PR hygiene, branch drift, environment audit and sync agents) | None, draft IaC |

All six default to region `us-central1` in their variables. Live services also run in `northamerica-northeast1` (for example the gateway and admin services in the MCP project), so the region in the folder is a default, not a guarantee. State lives in GCS buckets named in each folder's `backend.tf` (`dev-tfstate-skilled-script-469819-f2`, `qa-tfstate-quality-assurance-496022`, `prod-tfstate-production-499116`, `mcp-tfstate-alliance-mcp-services`, `platform-services-tfstate-alliance-platform-services`). The vertex folder reuses the development bucket under the prefix `alliance-gcp-infra/vertex`. The platform-services drift-workflow comment records that its state bucket did not exist when checked on 2026-08-21.

## How infrastructure changes flow

Infrastructure changes are made through pull requests to `alliance-gcp-infra`. A pull request touching `environments/development`, `qa`, `production` or `mcp`, or `modules/**`, triggers `terraform-plan-pr`, which plans the changed environments with a viewer-only service account and comments the plan. Vertex and platform-services have no plan or apply workflow. After merge to `main`, development and QA apply automatically (`terraform-apply-dev`, `terraform-apply-qa`). Production applies only through a manual `workflow_dispatch` of `terraform-apply-prod` with the typed phrase `apply-to-production`; the MCP project is also manual (`terraform-apply-mcp`, workflow_dispatch only) and gated by the typed phrase `apply-to-mcp`. A merge to `main` touching production fires `terraform-plan-notify-prod`, which runs a read-only plan and posts a tracking issue with the pending changes without applying. Each apply workflow has a destroy-count circuit breaker that refuses to apply when the plan destroys more than the threshold: the threshold is 3 for dev and QA and 1 for prod and MCP. See `/docs/gcp-terraform-workflows`.

Application deploys are a separate path. Service images are built and rolled out by each application repo's own CI (GitHub Actions, Cloud Build triggers, or `gcloud run deploy` outside Terraform for some MCP services), not by the Terraform apply workflows. Terraform creates the service shells, identities, secrets (names only), buckets, networks and IAM; it does not own secret values, database schemas or users, or runtime bootstrap. For the application side see `/docs/onboarding-cicd-deployment` and `/docs/git-branching-release-model`, and for the repos themselves `/docs/repo-inventory`.

The `terraform-ci-viewer-<env>` service accounts are viewer-only, with an additional `roles/storage.objectUser` grant scoped to their own state bucket so that `terraform plan` can take the state lock. Read the plan comment itself on any pull request rather than relying on the check status alone.

The nightly `terraform-drift-detect` workflow (09:17 UTC) covers only development, qa, production and mcp. Its header comment says vertex and platform-services are deliberately excluded because they are unapplied draft IaC.

## Reading guide

- Per-project pages: `/docs/gcp-env-development`, `/docs/gcp-env-qa`, `/docs/gcp-env-production`, `/docs/gcp-env-mcp`, `/docs/gcp-env-platform-services`, `/docs/gcp-env-vertex`.
- How the code is organised: `/docs/gcp-terraform-modules` (module catalogue) and `/docs/gcp-naming-conventions` (the `<system>-<component>-<env>` pattern with env as dev, qa or prod, and one service account per workload).
- How changes are applied: `/docs/gcp-terraform-workflows`, and `/docs/gcp-runbooks` for wipe and rebuild, post-deploy verification and similar procedures.
- Cross-cutting topics: `/docs/gcp-iam-and-workload-identity`, `/docs/gcp-networking-and-load-balancing`, `/docs/gcp-secrets-and-data-stores`.
- Where Terraform and reality disagree: `/docs/gcp-drift-report`.
- Policy and background: `/docs/dev-only-deployment-policy` for the dev-only MCP hosting rule and `/docs/disaster-recovery-plan` for backup and rollback.

## What the generated tables mean

The tables above are generated, not hand-written. The declared side is parsed from the `.tf` files in each environment folder at the time the page was built. The live side comes from read-only snapshots collected on 2026-10-01 (date only, no time captured), with resource names only and no secret values. Each resource type is compared as: live, declared, matched, live-only (exists in GCP, not declared), platform-created (auto-generated by Google, such as default firewall rules, expected not to be declared), IaC-only (declared, not seen live) and unresolved (name could not be mapped). Snapshots age quickly; any change after 2026-10-01 is not reflected until the page is regenerated.

## Where live verification was and was not possible

- Development, qa and prod were read through the gateway for those environments, using read-only list and describe commands. Some multi-command calls failed transiently (recorded for development, production and the agents project) and were retried in smaller calls.
- `alliance-platform-agents` (the vertex folder) was read through the gateway's agents environment.
- `alliance-mcp-services` is not a selectable gateway environment. It was read with a development-environment token that has only partial read access, so project IAM, workload identity pools, Cloud SQL, Redis, Firestore, buckets, Artifact Registry, Pub/Sub, DNS and scheduler sections were denied or not collected.
- `alliance-platform-services` could not be read at all; even `projects describe` was denied. Its zero live counts in the tables mean "not collected", not "empty", and declared resources there cannot be matched to live ones for that reason.
- Not inspected anywhere: GKE workloads (no `kubectl`), regional Cloud Build triggers outside the regions noted in each snapshot, and secret values.

## Cross-project facts

- Shared things: the development project hosts the Artifact Registry that several MCP services in `alliance-mcp-services` pull images from, the vertex folder shares the development state bucket, and the agents project references secrets in the development project by project number. Treat these as dependencies when changing or decommissioning anything in development.
- Production-named resources in the development project (confirmed in the development snapshot): buckets `globus-documents-prod`, `globus-profile-photos-prod`, `globus-vertex-agent-prod`, `globus-vertex-agent-staging` and `terraform-state-skilled-script-prod`, and a `globus-prod` network endpoint group. Prod-named does not mean it lives in the prod project. There is also staging-named material (a `stg-globus-maps-rot` API key, `globus-vertex-agent-staging`) although no staging environment exists.
- The MCP project holds both `mcp-production-*` and `mcp-development-*` secret names, although MCP servers are meant to be single, non-environment-specific instances.
- The agent fleet is largely outside Terraform: in the vertex project all 11 live Cloud Run services are undeclared, as are most secrets, while a few declared service accounts and secrets were not seen live.
- Stale README: `README.md` in `alliance-gcp-infra` still says QA is mid-rebuild and that development and production are not under Terraform. The `.tf` files and workflows show both have apply workflows. The README also says only that vertex and platform-services are not yet documented in detail; the workflow comments describe them as unapplied draft IaC. Trust the code.
- Existing Nexus pages: `/docs/git-branching-release-model` describes a git-tracked `slots.json` for QA sandbox slots, while `environments/qa/branching-sandbox.tf` keeps slot state in Cloud Run labels; that page itself notes the difference.

## Security observations

Snapshot notes record items that should be reviewed, without implying any were exploited. In development: several external-domain accounts hold project roles (including `roles/storage.admin` for users of one external company domain and `roles/bigquery.admin` for another), two Cloud SQL instances have public IPv4 enabled, every Cloud Run service allows ingress from all, one API key has no API target restriction, and deleted service accounts still appear in IAM. In QA: a temporary external account holds viewer and Cloud SQL roles, a deleted service account remains bound, and one service account holds `roles/owner`. Basic roles (editor, owner) are in use on default and automation service accounts in development. The agents project lists a project owner who is an individual and cross-project principals with run and storage roles. None of this could be checked for the MCP and platform-services projects because IAM was unreadable there. These facts should be reviewed by the platform owner.

## Known gaps

- Platform-services live state is entirely unverified; MCP is partly unverified.
- Vertex and platform-services Terraform is described as unapplied draft IaC in workflow and backend comments, so declared-versus-live there is not a trustworthy drift signal.
- The development project has a domain mapping for `nexus.allianceabroad.com` pointing at a `nexus-hub` service that does not exist in that project (dangling per the snapshot).
- Production and QA Cloud Build triggers were checked only in the regions noted in the snapshots.
