google/gke-multitenancy
>- 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).
npx skills add https://github.com/google/skills --skill gke-multitenancy
This reference covers enterprise multi-tenancy patterns on GKE, including
namespace isolation, RBAC planning, resource quotas, and network segmentation.
> MCP Tools: apply_k8s_manifest, get_k8s_resource, check_k8s_auth,
> describe_k8s_resource, delete_k8s_resource
| 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.
kubectl create namespace team-a
kubectl create namespace team-b
kubectl label namespace team-a team=a
kubectl label namespace team-b team=b
Principle: Grant minimal permissions per namespace. Never bind to
system:authenticated.
# 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: "[email protected]" # 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.
Prevent any single team from consuming all cluster resources:
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"
Set default and maximum resource constraints per container:
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.
Apply default-deny per namespace (see the gke-workload-security skill), then
allow intra-team traffic:
# 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
# Label namespaces for billing
kubectl label namespace team-a cost-center=engineering
kubectl label namespace team-b cost-center=data-science
Enable GKE cost allocation to break down costs by namespace and label:
gcloud container clusters update <CLUSTER_NAME> --region <REGION> \
--enable-cost-allocation
View in Cloud Billing > GKE Cost Allocation.
Take google/gke-multitenancy from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.