Least Privilege RBAC: Scoping & Risk Reduction
Vì Sao Quantum Trọng
Least privilege là core security principle: grant minimum permissions necessary để task. Di Kubernetes:
- Over-privileged service accounts là common misconfiguration. ví dụ: pod run dưới SA có
"*": ["*"](cluster-admin-equivalent) - Blast radius khi compromised — nếu SA token leaked, attacker punya truy cập huge. Least privilege minimize damage scope
- Compliance & audit — security teams expect principle of least privilege. Over-broad permissions fail audits
- Operational cost — over-privileged accounts mask underlying permission needs, making refactoring harder
Understanding RBAC scoping mechanisms fundamental để implement effective least privilege.
Privilege Scoping Dimensions
Kubernetes authorization có thể scoped along multiple dimensions:
1. Namespace Scoping
Highest impact dimension. RoleBinding restrict permissions đến single namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: team-a # SCOPED: only team-a
name: deployer
roleRef:
kind: ClusterRole
name: deployer
subjects:
- kind: ServiceAccount
namespace: team-a
name: my-appmy-app SA trong team-a có thể deploy, không trong team-b hoặc kube-system.
Worst practice:
kind: ClusterRoleBinding # Cluster-wide!Cluster-wide binding = permission everywhere.
2. Verb Scoping
Don't grant ["*"]; grant specific verbs:
# BAD: Too broad
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["*"] # Includes watch, create, delete, exec, etc.
# GOOD: Specific verbs
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"] # Read-onlyVerb minimization principle:
create→ minimize; requires careful validationdelete/deletecollection→ minimize; destructivewatch→ if not needed, don't grant*→ never (except để very few roles like cluster-admin)
3. Resource Scoping
Minimize resources per rule:
# BAD: Too broad
rules:
- apiGroups: [""]
resources: ["*"] # All resources
verbs: ["get", "list"]
# GOOD: Specific resources
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list"]Resource minimization:
["*"]tempting nhưng dangerous- Always enumerate specific resources
- For core API group, be explicit nếu include RBAC objects (roles, rolebindings) — often unintended
4. Resource Names Scoping
Limit đến specific resource instances:
# Moderately specific
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
# More specific: only database credentials secret
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-credentials"]
verbs: ["get"]resourceNames reduce blast radius nếu SA compromised — attacker có thể only read one secret, not all.
5. Subresources Scoping
Fine-grained control via subresources:
# Pod read-only
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# Pod logs access (separate permission)
rules:
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Pod exec (most dangerous; grant sparingly)
rules:
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]Each subresource separate permission. Pod access ≠ pod/log access ≠ pod/exec access.
Role Reduction Heuristics
Heuristic 1: Identify Core Task
Start với mà minimal diperlukan để task:
Task: "Deploy application"
Core permissions:
apps/deployments: [get, list, create, update, patch]apps/replicasets: [get, list](owned by deployment)core/pods: [get, list](for checking pod status)
NOT needed:
deletedeployments (destroy production)execpods (debugging; admin task)configmaps(might need for config, but separate permission)
Heuristic 2: Use Namespace Boundaries
Different SAs per namespace = separate RBAC chains:
# SA trong dev-team namespace
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: dev-team
name: builder
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team
name: builder
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["create", "update", "delete"] # OK để dev
---
# SA trong prod-team namespace (separate RBAC)
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: prod-team
name: builder
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: prod-team
name: builder
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"] # Read-only trong prodSeparate SAs enforces boundary — dev SA cannot touch prod.
Heuristic 3: Separate "Read" từ "Write"
Create distinct roles để authorization separation:
# Read-only access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
# Write access (separate role)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-editor
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "update", "patch", "delete"]Bind read/write tergantung vào team needs. Some teams chỉ read.
Heuristic 4: Restrict Dangerous Verbs
Verbs mà phải grant sparingly:
| Verb | Danger | When Needed |
|---|---|---|
* | Cluster-admin | Bootstrap only |
delete, deletecollection | Data loss | Only explicit cleanup roles |
create (on RBAC objects) | Privilege escalation | Admins only |
impersonate | Privilege escalation | Admins, delegators only |
exec | Direct pod access | Debugging roles only |
logs | Information disclosure | Debugging roles only |
portforward | Network access | Debugging roles only |
Multi-Stage Deployment Pattern
Least privilege để multi-stage deployment (dev → staging → prod):
Stage 1: Development (Permissive)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: developer
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["*"] # Full access trong devDevelopers iterate quickly, don't need scoping overhead.
Stage 2: Staging (Moderate)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: staging
name: deployer
rules:
# Can deploy, but not delete
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "create", "update", "patch"]
# Can view logs for debugging
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
# Cannot delete
# Cannot exec pods
# Cannot access secretsStaging deployer limited; tests changes without production-risk exposure.
Stage 3: Production (Restrictive)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: prod
name: deployer
rules:
# Can only update specific deployments
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["update", "patch"]
resourceNames: ["api-server", "web-frontend"]
# Can view, not delete
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# Cannot delete
# Cannot create
# Cannot exec
# Cannot access secretsProd deployer minimal — update existing, view status, no destructive actions.
Blast Radius Analysis
Scenario: SA Token Leaked
Nếu SA token compromise, damage scope limited bởi RBAC permissions.
Over-privileged SA:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]Attacker có thể:
- Delete entire cluster
- Extract all secrets
- Escalate tới other namespaces
- Disable audit logging
Blast radius: ENTIRE CLUSTER
Least privilege SA:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# Only trong own namespace (RoleBinding)Attacker có thể:
- List pods trong one namespace
- Infer deployment names, configs
Blast radius: ONE NAMESPACE, READ-ONLY
Quantifying Risk
Risk = (Blast Radius) × (Likelihood of Compromise) × (Damage per Access)
Over-privileged: 100% of cluster × higher likelihood × devastating damage
Least privilege: 5% of cluster × same likelihood × limited damage
Risk reduction: ~95%Anti-Patterns
Anti-Pattern 1: "Just Use Cluster-Admin"
# ANTI-PATTERN
kind: ClusterRoleBinding
roleRef:
name: cluster-admin
subjects:
- kind: ServiceAccount
name: my-appProblem:
- Unnecessary blast radius
- Fails security audits
- No granularity để debugging
- Compliance violation
Anti-Pattern 2: Wildcards for "convenience"
# ANTI-PATTERN
rules:
- resources: ["*"]
verbs: ["*"]"Just in case we need it later" → security debt.
Anti-Pattern 3: No Namespace Scoping
# ANTI-PATTERN: Cluster-wide binding for namespace task
kind: ClusterRoleBinding
subjects:
- kind: ServiceAccount
namespace: team-a
name: appGrants team-a:app access cluster-wide; should be RoleBinding in team-a namespace.
Audit để Least Privilege Violations
Find Over-Broad Permissions
# Find all roles với resource: "*"
kubectl get roles,clusterroles -A -o json | \
jq '.items[] | select(.rules[]? | .resources[]? == "*")'
# Find all roles với verb: "*"
kubectl get roles,clusterroles -A -o json | \
jq '.items[] | select(.rules[]? | .verbs[]? == "*")'
# Find ClusterRoleBindings (usually too broad)
kubectl get clusterrolebindings -o wide | grep -v "kube-" | grep -v "system:"Regular Permission Review
# Extract all permissions từ RBAC
kubectl get roles,clusterroles -A -o json | \
jq '.items[] | {name: .metadata.name, rules}' | \
tee rbac-audit.json
# Compare với previous audit để changes
diff <(jq '.[].name' rbac-audit-old.json) \
<(jq '.[].name' rbac-audit-new.json)Least Privilege Checklist
☐ Service accounts scoped đến namespace (RoleBinding, not ClusterRoleBinding)?
☐ Verbs minimized (no ["*"])?
☐ Resources enumerated (no ["*"])?
☐ Dangerous verbs (delete, exec, create RBAC) granted minimally?
☐ Subresources separated (pods vs pods/exec vs pods/log)?
☐ ResourceNames used để single-resource restrictions?
☐ Read permissions separate từ write permissions?
☐ Cluster-admin không used except admins?
☐ Impersonate permissions explicitly granted?
☐ Regular audit từ permissions?Summary
Least privilege RBAC core principles:
- Scope namespace — RoleBinding to namespace, not ClusterRoleBinding
- Minimize verbs — enumerate specific actions
- Enumerate resources — no ["*"]
- Separate read/write — different roles
- Use subresources — pod ≠ pod/exec
- Audit regularly — detect drift
Implementing least privilege:
- Identify core task
- Grant minimum permissions
- Test with actual workload
- Regular permission review
- Enforce via policy (e.g., fail without scoped bindings)