Skip to main content

Architecture overview

The Web App Blueprint runs a working web application in each platform project of the GCP Enterprise Baseline: a Python Flask API on Google Kubernetes Engine (GKE) behind a GKE Gateway with Cloud Armor, a React single-page app served by nginx on Cloud Run behind a global external Application Load Balancer with Cloud CDN, Firestore with MongoDB compatibility for data and Memorystore for Valkey for caching. ArgoCD inside each cluster deploys the API from a GitOps repository, so a commit reaches production through pull requests.

How it works​

The browser loads the single-page app from blueprint-app.<stage>.company.com and calls the API on blueprint-api.<stage>.company.com. The app derives the API host from its own host, so one front end image serves every stage. The API caches reads in Valkey and keeps items in Firestore. ArgoCD watches the GitOps repository and rolls the API forward when a stage's image tag changes.

Two entry points​

HostPathProtection
blueprint-app.<stage>.company.comA global external Application Load Balancer with Cloud CDN, a serverless network endpoint group, then the Cloud Run service acme-usw1-<stage>-frontendCloud Armor, a Google-managed certificate, the MODERN SSL policy with TLS 1.2 minimum, HTTP redirected to HTTPS; Cloud Run accepts traffic only from the load balancer
blueprint-api.<stage>.company.comA Gateway of class gke-l7-global-external-managed, container-native endpoints, then the API pods on port 8080Cloud Armor through a GCPBackendPolicy, a Google-managed certificate through a Certificate Manager map, the MODERN SSL policy; HTTPS only, and the pods admit only Google's front ends

The infrastructure repository creates the API's reserved address, certificate map, Cloud Armor policy and SSL policy, and publishes their names. The Gateway objects themselves belong to the Helm chart, so ArgoCD owns them. Both Cloud Armor policies are built from the rule template the Baseline publishes, and request flow follows a request through each path.

Data stores without passwords​

Firestore with MongoDB compatibility (acme-usw1-<stage>-mongo, Enterprise edition) and Memorystore for Valkey (acme-usw1-<stage>-valkey) accept no password from the application. The pods run as the Kubernetes service account blueprint-app-sa, which Workload Identity Federation for GKE binds directly as an Identity and Access Management (IAM) principal:

  • Firestore. The application authenticates over MONGODB-OIDC with an OIDC callback that presents the pod's Google access token. The GKE metadata server does not issue ID tokens to a directly bound Kubernetes service account, so the callback replaces the Google provider named in the connection string.
  • Valkey. The same access token is the AUTH password, sent over TLS that the client verifies against the instance's server certificate authority (CA). The instance is reached through two Private Service Connect endpoints in the stage's data subnet.

The connection values the infrastructure publishes to the stage's Secret Manager (the URI, the database name, the endpoint address, the port and the CA) are not credentials. Workload identity lists every identity and its roles.

One stage, one stack​

Each stage is generated from the same template of eleven Terragrunt units in two folders:

stacks/webapp-stage/terragrunt.stack.hcl
# --- shared infrastructure ----------------------------------------------------

unit "gke" {
source = find_in_parent_folders("units/gke")
path = "shared-infra/gke"
values = {
zones = local.gke_zones
min_per_zone = local.gke_min_per_zone
max_per_zone = local.gke_max_per_zone
nap_cpu_limit = local.nap_cpu_limit
nap_memory_limit = local.nap_memory_limit
deletion_protection = local.gke_deletion_protection
}
}

unit "external-secrets" {
source = find_in_parent_folders("units/external-secrets")
path = "shared-infra/external-secrets"
}

unit "external-dns" {
source = find_in_parent_folders("units/external-dns")
path = "shared-infra/external-dns"
}

unit "external-dns-internal" {
source = find_in_parent_folders("units/external-dns-internal")
path = "shared-infra/external-dns-internal"
}

unit "cert-manager" {
source = find_in_parent_folders("units/cert-manager")
path = "shared-infra/cert-manager"
}

unit "argocd" {
source = find_in_parent_folders("units/argocd")
path = "shared-infra/argocd"
values = {
ha = local.argocd_ha
auto_sync = local.argocd_auto_sync
}
}

# --- the blueprint application ------------------------------------------------

unit "app-namespace" {
source = find_in_parent_folders("units/app-namespace")
path = "blueprint-app/app-namespace"
}

unit "firestore" {
source = find_in_parent_folders("units/firestore")
path = "blueprint-app/firestore"
values = {
pitr = local.firestore_pitr
backup_retention_days = local.firestore_backups
delete_protection = local.firestore_delete_protection
}
}

unit "valkey" {
source = find_in_parent_folders("units/valkey")
path = "blueprint-app/valkey"
values = {
node_type = local.valkey_node_type
replicas = local.valkey_replicas
delete_protection = local.valkey_delete_protection
}
}

unit "frontend-service" {
source = find_in_parent_folders("units/frontend-service")
path = "blueprint-app/frontend"
values = {
armor_preview = local.armor_preview
}
}

unit "api-gateway" {
source = find_in_parent_folders("units/api-gateway")
path = "blueprint-app/api-gateway"
values = {
armor_preview = local.armor_preview
}
}
  • Shared infrastructure: the GKE cluster acme-usw1-<stage>-gke with a tainted system node pool and node auto-provisioning, External Secrets, two external-dns releases (the stage's public zone and the internal zone), cert-manager with an internal certificate authority, and ArgoCD.
  • The application: the namespace and its identity, Firestore, Valkey, the API edge and the front end on Cloud Run.

Only a few values change between stages: the cluster's zones and system pool bounds, the ceiling on auto-provisioned capacity, Cloud Armor preview mode, Firestore recovery and protection, the Valkey node type and replicas, and ArgoCD's high availability and sync mode. Sizing per stage lists them.

Delivery chain​

Both images are built once and pushed under an immutable main-<short sha> tag; a GitHub Release adds vX.Y.Z to the same images. The API rolls out by pull request to the GitOps repository: dev and staging merge themselves, and prod is merged by a person and synced by hand in ArgoCD. The front end deploys a Cloud Run revision directly: to dev when frontend/ changes, to staging on a release, and to prod after the prod Environment's reviewers approve. The pattern is described in immutable artifacts and environments and promotion.

What it builds on​

The blueprint creates no network and no project. Every landing-zone value (the Shared VPC network and the stage's subnets, the GKE control-plane range, the DNS zones, the project number, the Artifact Registry path and the Cloud Armor rule template) is read at plan time from Parameter Manager parameters the Baseline publishes in each stage project. Images live in the Baseline's acme-core-artifacts project, DNS records go into its zones in acme-core-dns and acme-core-network, and the pipelines sign in through its Workload Identity Federation pool. Application secrets reach the pods from Secret Manager, which is where the Secrets Blueprint delivers them.

For every service, see the service inventory; for what a customer receives, see what you receive.