Skip to content

Google Kubernetes Engine (GKE) Autopilot Multi-Tenancy

Skill metadata

Name gcp-gke-autopilot-multi-tenant · Level senior · Tags gcp gke autopilot workload-identity vpc cloud

"GKE Autopilot and Standard multi-tenancy: namespace and node isolation, Workload Identity, network policy, Shared VPC topology, VPC Service Controls, and Autopilot vs Standard trade-offs. Use when designing a multi-tenant GKE platform, isolating tenant workloads, or choosing between Autopilot and Standard."

Source: skills/cloud-gcp/gcp-gke-autopilot-multi-tenant/SKILL.md

When to Use This Skill

Triggers — load this skill when:

  • A GKE platform must isolate multiple teams or tenants safely
  • Autopilot vs Standard must be chosen against workload constraints
  • Pods need GCP API access via Workload Identity

Route elsewhere when:

  • Organization-level hierarchy and policy -> gcp-cloud-engineering-patterns
  • Cluster-agnostic packaging -> helm-kubernetes-deployment
  • Tenant cost attribution -> finops-framework-inform-optimize-operate

1. Declarative GKE Multi-Tenant Cluster (Terraform)

resource "google_container_cluster" "gke_autopilot" {
  name     = "gke-prod-autopilot"
  location = "us-central1"

  enable_autopilot = true
  network          = "projects/shared-vpc-host/global/networks/production-vpc"
  subnetwork       = "projects/shared-vpc-host/regions/us-central1/subnetworks/gke-subnet"

  ip_allocation_policy {
    cluster_secondary_range_name  = "gke-pods"
    services_secondary_range_name = "gke-services"
  }

  private_cluster_config {
    enable_private_nodes    = true
    enable_private_endpoint = false
    master_ipv4_cidr_block  = "172.16.0.0/28"
  }

  master_authorized_networks_config {
    cidr_blocks {
      cidr_block   = "10.0.0.0/8"
      display_name = "Corporate Internal Network"
    }
  }

  release_channel {
    channel = "REGULAR"
  }
}

2. GCP Security Baseline

  • GCP Workload Identity: Map Kubernetes Service Accounts directly to GCP IAM Service Accounts via IAM Binding (roles/iam.workloadIdentityUser).
  • Binary Authorization: Require cryptographic signatures on container images created through Google Cloud Build before admitting pods.
  • VPC Service Controls (VPC-SC): Place Cloud Storage, BigQuery, and Cloud SQL behind security perimeters to block data exfiltration.

3. Namespace Tenancy Controls

A tenant boundary is a namespace plus four enforced controls. A namespace alone isolates names, nothing else.

apiVersion: v1
kind: Namespace
metadata:
  name: tenant-payments
  labels: { tenant: payments, pod-security.kubernetes.io/enforce: restricted }
---
apiVersion: v1
kind: ResourceQuota          # 1. capacity: one tenant cannot starve the others
metadata: { name: tenant-quota, namespace: tenant-payments }
spec:
  hard:
    requests.cpu: "40"
    requests.memory: 160Gi
    limits.cpu: "80"
    persistentvolumeclaims: "20"
    count/services.loadbalancers: "2"
---
apiVersion: v1
kind: LimitRange             # 2. defaults: no unbounded pod inside the quota
metadata: { name: tenant-defaults, namespace: tenant-payments }
spec:
  limits:
    - type: Container
      default: { cpu: 500m, memory: 512Mi }
      defaultRequest: { cpu: 100m, memory: 128Mi }
      max: { cpu: "8", memory: 16Gi }
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy          # 3. network: default deny, then allow explicitly
metadata: { name: default-deny-all, namespace: tenant-payments }
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: allow-same-tenant-and-dns, namespace: tenant-payments }
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
  ingress: [{ from: [{ podSelector: {} }] }]
  egress:
    - to: [{ podSelector: {} }]
    - to: [{ namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: kube-system } } }]
      ports: [{ protocol: UDP, port: 53 }]

4. RBAC — bind tenant groups to a namespaced Role only — never a ClusterRole — and give each tenant its own KSA bound to its own GSA, so cloud-side authorisation follows the same boundary.

For untrusted or multi-customer code, namespace isolation is not a security boundary: add GKE Sandbox (gVisor) or separate node pools with taints, or give the tenant its own cluster.