GKE’s multi-tenancy is less about physically separating clusters and more about logically carving up a single cluster to serve multiple distinct users or applications.
Let’s see it in action. Imagine you have a shared GKE cluster and want to give a team, let’s call them "frontend-team," their own isolated space.
# Create a namespace for the frontend team
kubectl create namespace frontend-team
# Grant the frontend team read-only access to their namespace
kubectl create role frontend-read-only \
--namespace=frontend-team \
--verb=get,list,watch \
--resource=pods,deployments,services,configmaps,secrets
# Bind a user or group to this role
kubectl create rolebinding frontend-team-binding \
--namespace=frontend-team \
--role=frontend-read-only \
--user=frontend-user@example.com
Now, frontend-user@example.com can only get, list, and watch resources within the frontend-team namespace. They can’t see or affect anything in, say, the backend-team namespace. This is the core of namespace isolation and RBAC in action.
The problem this solves is resource contention and security in a shared Kubernetes environment. Without it, one team could accidentally (or intentionally) impact another’s workloads, deploy unauthorized resources, or even gain access to sensitive data. By segmenting the cluster, you create secure boundaries.
Internally, Kubernetes uses Role-Based Access Control (RBAC) to enforce these boundaries. A Namespace is a logical grouping of resources. A Role defines a set of permissions (verbs like get, create, delete) on specific resources (like pods, services). A RoleBinding then connects a user, group, or service account to a Role within a specific Namespace. For cluster-wide permissions, you’d use ClusterRole and ClusterRoleBinding, but for tenancy, Role and RoleBinding are your primary tools.
The exact levers you control are the Role definitions and the RoleBinding assignments. You can be extremely granular:
- Resource types:
pods,deployments,services,configmaps,secrets,persistentvolumeclaims,ingresses, etc. - Verbs:
get,list,watch,create,update,patch,delete. - Scope:
Namespace(usingRole/RoleBinding) orCluster(usingClusterRole/ClusterRoleBinding).
For a truly isolated tenant, you’d typically create a dedicated Namespace for them, define a Role with the necessary permissions for their applications (e.g., create, get, list, watch, update, patch on pods, deployments, services, configmaps, secrets), and then bind that Role to their service accounts or users using a RoleBinding. You might also want to restrict their ability to create Namespaces themselves or modify cluster-wide resources by not granting them ClusterRole permissions.
A common pitfall is forgetting to restrict egress traffic from a tenant’s namespace. By default, pods can often reach any other pod in the cluster, even across namespaces. To truly isolate, you’ll need to implement NetworkPolicies that explicitly define which pods can communicate with each other, effectively creating a firewall within your cluster.
The next concept to grapple with is managing shared resources like ingress controllers and persistent storage across multiple tenants.