Kubernetes Dev & Ops in Practice 2 — Namespace & RBAC Design
Namespace isolation strategies and RBAC design principles for multi-team, multi-environment Kubernetes operations. A practical guide to maintaining least privilege while maximizing developer productivity.
Why Namespace and RBAC Must Come First
When you spin up a cluster, only the default namespace exists. Teams often start by deploying everything there, but as teams grow and services multiply, this structure inevitably causes problems.
- Team A accidentally runs
kubectl delete pods --alland takes down Team B’s services - A developer modifies production Secrets by mistake
- One team’s workload monopolizes cluster resources
Namespace and RBAC are the first structural line of defense against these problems.
1. Namespace Isolation Strategies
Environment-Based (Small Teams)
cluster
├── development
├── staging
└── production
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: development
team: platform
---
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: staging
---
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: production
Team + Environment (Medium to Large Teams)
cluster
├── team-a-dev
├── team-a-prod
├── team-b-dev
├── team-b-prod
└── platform # shared infra (monitoring, ingress, etc.)
Per-team namespaces enable resource isolation and independent deployments between teams.
Service-Based (Microservices)
cluster
├── auth-service
├── payment-service
├── notification-service
└── platform
Per-service namespaces let you use NetworkPolicy to precisely control inter-service communication.
2. ResourceQuota — Per-Namespace Resource Caps
Without per-namespace resource caps, one team’s workload can consume the entire cluster.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a-dev
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
services: "10"
persistentvolumeclaims: "5"
secrets: "20"
configmaps: "20"
LimitRange — Enforce Defaults
Without explicit resource declarations, Pods run without limits. LimitRange enforces defaults.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-a-dev
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: 256Mi
defaultRequest:
cpu: "100m"
memory: 128Mi
max:
cpu: "2"
memory: 2Gi
3. RBAC Design Principles
RBAC defines who (Subject) can do what (Verb) to which resources (Resource).
Role Hierarchy
| Role | Target | Permissions |
|---|---|---|
| cluster-admin | Platform team | Entire cluster |
| namespace-admin | Team lead | Full namespace |
| developer | Developer | Read + Pod ops + logs |
| viewer | Auditors, interns | Read-only |
Developer Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: team-a-dev
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "endpoints", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/exec", "pods/log", "pods/portforward"]
verbs: ["get", "create"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["get", "list", "watch", "patch"]
# List secrets but never read their contents
- apiGroups: [""]
resources: ["secrets"]
verbs: ["list"]
Viewer Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
namespace: team-a-dev
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["get", "list", "watch"]
RoleBinding — Assign Roles to Users
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: team-a-dev
subjects:
- kind: User
name: alice@company.com
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: team-a-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
4. ServiceAccount Least Privilege
If a Pod doesn’t need to call the Kubernetes API, disable the default ServiceAccount token mount.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: team-a-dev
automountServiceAccountToken: false
When API access is required, create a dedicated ServiceAccount with minimal permissions.
apiVersion: v1
kind: ServiceAccount
metadata:
name: resource-watcher
namespace: platform
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: resource-watcher
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: resource-watcher
subjects:
- kind: ServiceAccount
name: resource-watcher
namespace: platform
roleRef:
kind: ClusterRole
name: resource-watcher
apiGroup: rbac.authorization.k8s.io
5. Validating RBAC
# Check a specific user's permissions
kubectl auth can-i get pods --namespace team-a-dev --as alice@company.com
kubectl auth can-i delete secrets --namespace production --as alice@company.com
# List all your current permissions
kubectl auth can-i --list --namespace team-a-dev
# Check ServiceAccount permissions
kubectl auth can-i get deployments \
--as system:serviceaccount:platform:resource-watcher
6. Namespace Initialization Script
#!/bin/bash
# init-namespace.sh <team> <env>
TEAM=$1
ENV=$2
NS="${TEAM}-${ENV}"
kubectl create namespace $NS
kubectl label namespace $NS team=$TEAM environment=$ENV
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: $NS
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "30"
EOF
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: $NS
subjects:
- kind: Group
name: ${TEAM}-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
EOF
echo "Namespace $NS initialized."
Summary
| Design Element | Core Principle |
|---|---|
| Namespace | Separate by team or environment, define defaults |
| ResourceQuota | Cap CPU/memory/objects per namespace |
| LimitRange | Enforce defaults on Pods without resource specs |
| RBAC | Least privilege; no Secret reads by default |
| ServiceAccount | Disable token mount when API access isn’t needed |
Next: Workload Pattern Selection — when to use Deployment, StatefulSet, DaemonSet, and Job/CronJob.