Namespaces and RBAC in EKS are not just about isolating workloads; they’re fundamentally about defining trust boundaries in a shared Kubernetes cluster.
Let’s see this in action. Imagine a simple scenario: two teams, 'dev' and 'staging', needing separate environments within the same EKS cluster.
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: staging
Now, how do we ensure the 'dev' team can only deploy to 'dev' and the 'staging' team to 'staging', and neither can touch each other’s resources or cluster-level configurations? This is where RBAC (Role-Based Access Control) comes in.
First, we define Roles which are collections of permissions within a specific namespace. For the 'dev' team, a Role might look like this:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-developer-role
namespace: dev
rules:
- apiGroups: ["", "apps", "batch", "extensions"]
resources: ["pods", "deployments", "services", "jobs", "configmaps", "secrets", "ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
This Role grants broad permissions for common Kubernetes resources, but only within the dev namespace.
Next, we create RoleBindings to connect these Roles to specific users or groups. If your EKS cluster is integrated with AWS IAM, you’ll typically bind IAM users or roles. For the 'dev' team, let’s say their IAM users are part of an IAM group dev-team-group.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-team-binding
namespace: dev
subjects:
- kind: Group
name: dev-team-group # This refers to an IAM Group
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev-developer-role # The Role defined above
apiGroup: rbac.authorization.k8s.io
This RoleBinding effectively says: "Anyone in the dev-team-group IAM group can perform the actions defined in the dev-developer-role within the dev namespace." The same pattern would be repeated for the 'staging' team, using a staging namespace, a staging-developer-role, and a staging-team-group IAM group.
The mental model is layered:
- Namespaces: These are logical partitions. Think of them as virtual clusters within your EKS cluster. They provide a scope for resource names and a primary mechanism for separation. If you create a
Deploymentnamedmy-appindev, it doesn’t conflict with aDeploymentnamedmy-appinstaging. - Roles: These define what actions (verbs like
get,create,delete) can be performed on which resources (likepods,deployments) within a specific namespace. They are the granular permission sets. - RoleBindings: These are the glue, linking subjects (users, groups, service accounts) to
Roles. They determine who gets what permissions.
Crucially, Roles and RoleBindings are namespace-scoped. For permissions that apply cluster-wide (e.g., managing Nodes, ClusterRoles, or PersistentVolumes), you’d use ClusterRoles and ClusterRoleBindings. For multi-tenancy, you’d typically restrict tenants from having ClusterRole access and only grant them namespace-specific Roles.
The power of this system is its explicitness. You’re not relying on implicit assumptions; you’re defining precise access controls. This prevents accidental or malicious interference between tenants. For example, a 'dev' team member might try to kubectl delete namespace staging – this command would be rejected by the Kubernetes API server because their RoleBinding only grants them permissions within the dev namespace.
A common pitfall is forgetting to grant get, list, and watch permissions to namespaces and events for users who need to observe resources across different namespaces or see cluster-wide events. Without get and list on namespaces, a user might not even see that the staging namespace exists, let alone be able to interact with it if they were granted broader permissions.
The next step in hardening multi-tenancy often involves integrating network policies to control traffic flow between pods in different namespaces, further segmenting your tenants.