gke-multitenancy · git:20261019.982e177 · 2026-10-19 · sha256 bfd88668dd064a97
gke-multitenancy git:20261019.982e177A
Immutable. This exact content never changes and is served at /api/v1/blob/bfd88668dd064a97.
---
name: gke-multitenancy
description: >-
Plans and configures multi-tenancy on GKE. Covers namespace isolation, RBAC
planning for teams, resource quotas, LimitRanges, network isolation, and
cost allocation. Use when designing GKE multi-tenancy, configuring GKE
namespaces, setting up resource quotas, or isolating GKE teams. Don't use
for single-tenant cluster configuration or general deployment instructions
(use gke-basics or gke-app-onboarding instead).
metadata:
category: Containers
---
# GKE Multi-Tenancy
This reference covers enterprise multi-tenancy patterns on GKE, including
namespace isolation, RBAC planning, resource quotas, and network segmentation.
> **MCP Tools:** `get_k8s_resource`, `check_k8s_auth`, `describe_k8s_resource`
>
> A change goes out as a pull request to the GitOps repository, never as a write from here: Kubernetes objects as YAML through `gke-manifest-generation`, cluster settings and other Google Cloud resources as Config Connector YAML through `gcp-config-connector`, opened with `submit-suggestion`. Each profile's config offers only the `gke` MCP server's read tools, and the broker refuses `kubectl` and `gcloud` writes.
## When to Use
- Multiple teams sharing a single GKE cluster
- Isolating workloads by environment (dev/staging/prod) within one cluster
- Implementing least-privilege access control
- Cost allocation across teams or projects
## Multi-Tenancy Models
| Model | Isolation | Complexity | Cost |
| ----------------------------- | ------------ | ---------- | -------------- |
| **Namespace-per-team** | Soft (RBAC + | Low | Lowest (shared |
: : Network : : cluster) :
: : Policy) : : :
| **Namespace-per-environment** | Soft | Low | Low |
| **Node pool-per-team** | Medium | Medium | Medium |
: : (dedicated : : :
: : compute) : : :
| **Cluster-per-team** | Hard (full | High | Highest |
: : isolation) : : :
> **Golden path recommendation**: Start with namespace-per-team for cost
> efficiency. Escalate to stronger isolation only when compliance requires it.
## Namespace Isolation Setup
### 1. Create Namespaces
The namespaces are proposed as a pull request through `submit-suggestion`:
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: team-a
labels:
team: a
---
apiVersion: v1
kind: Namespace
metadata:
name: team-b
labels:
team: b
```
### 2. RBAC Configuration
**Principle**: Grant minimal permissions per namespace. Never bind to
`system:authenticated`.
```yaml
# Namespace-scoped role for a team
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: team-a-developer
namespace: team-a
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "services", "configmaps", "jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-a-developers
namespace: team-a
subjects:
- kind: Group
name: "team-a@example.com" # Google Group
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: team-a-developer
apiGroup: rbac.authorization.k8s.io
```
**RBAC best practices:** Use Google Groups for subject bindings. Prefer
namespace-scoped Roles over ClusterRoles. See the `gke-platform-security` skill
for full RBAC hardening guidance.
### 3. Resource Quotas
Prevent any single team from consuming all cluster resources:
```yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
pods: "50"
services: "10"
persistentvolumeclaims: "10"
```
### 4. LimitRanges
Set default and maximum resource constraints per container:
```yaml
apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "4"
memory: "8Gi"
```
> [!IMPORTANT] **Mandatory Defaults**: When defining `min` or `max` limits in a
> `LimitRange`, you **must** also define corresponding `default` and
> `defaultRequest` values. If you set a `min` or `max` without defaults, any pod
> deployed without explicit resource requests/limits will be rejected by the
> admission controller.
### 5. Network Isolation
Apply default-deny per namespace (see the `gke-workload-security` skill), then
allow intra-team traffic:
```yaml
# Allow same-namespace pods to talk + DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: team-a
spec:
podSelector: {}
ingress:
- from:
- podSelector: {}
egress:
- to:
- podSelector: {}
- to: # Allow DNS
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
```
## Cost Allocation
### Labels for Cost Attribution
Label namespaces for billing in their manifests, proposed as a pull request through
`submit-suggestion`: for example `cost-center: engineering` on `team-a` and
`cost-center: data-science` on `team-b`.
### GKE Cost Allocation
Enable GKE cost allocation to break down costs by namespace and label. It is a cluster
setting (`spec.costManagementConfig.enabled`), changed as Config Connector YAML on the
cluster's `ContainerCluster` through `gcp-config-connector`.
View in Cloud Billing > GKE Cost Allocation.