Least Privilege RBAC
A namespace-scoped Role and RoleBinding implementing least-privilege access control with read-only permissions for pods.
Overview
This template creates a namespace-scoped Role with minimal read-only permissions (get, watch, list on pods) and a RoleBinding that assigns it to a specific ServiceAccount. It demonstrates the principle of least privilege: grant only the exact permissions an application needs.
Security threat addressed: Overly permissive RBAC roles (especially cluster-admin or wildcard permissions) allow attackers to escalate privileges, read secrets, create privileged pods, and take full control of the cluster.
When to use: Use this as a starting point for every application that needs Kubernetes API access. Customize the resources and verbs to match your application’s actual requirements.
Threat Model
- Blast radius containment: If a pod’s service account token is stolen, the attacker can only perform the specific actions defined in the Role, not cluster-wide operations.
- Privilege escalation prevention: Namespace-scoped Roles prevent lateral movement to other namespaces. No wildcard permissions mean no unintended access to Secrets or other sensitive resources.
- Credential theft limitation: Even if an attacker obtains the service account token, read-only access to pods provides minimal value for further attacks.
MITRE ATT&CK:
- T1078 — Valid Accounts: Wildcard permissions allow reading Secrets, creating privileged pods, and other dangerous operations.
- T1078.004 — Valid Accounts: Cloud Accounts: Cluster-admin grants full control, equivalent to root on every node.
Real-world scenario: An attacker compromises a web application and steals the mounted service account token. With least-privilege RBAC, they can only list pods in one namespace, rather than reading secrets or creating backdoor deployments cluster-wide.
YAML Source
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
labels:
app.kubernetes.io/name: k8s-security
app.kubernetes.io/part-of: k8s-security-pro
app.kubernetes.io/managed-by: k8s-security-pro
rules:
# LEAST PRIVILEGE PRINCIPLE
# Only grant the specific verbs and resources needed.
# NEVER use wildcards ('*') in production roles.
- apiGroups: [""] # "" indicates the core API group
resources: ["pods", "pods/log"] # Specific resources only
verbs: ["get", "watch", "list"] # Read-only access. No 'create', 'delete', or 'update'.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
labels:
app.kubernetes.io/name: k8s-security
app.kubernetes.io/part-of: k8s-security-pro
app.kubernetes.io/managed-by: k8s-security-pro
subjects:
- kind: ServiceAccount
name: my-app-sa # The ServiceAccount your app uses
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# If an attacker compromises a pod with a 'cluster-admin' or broad role,
# they effectively own your entire cluster. By limiting permissions, you contain the breach.
Installation
kubectl:
kubectl apply -f 04_least_privilege_rbac.yaml
Helm:
helm install k8s-security ./charts/k8s-security -f values-prod.yaml
Kustomize:
kubectl apply -k kustomize/overlays/prod
Verification
# Verify the Role exists and check its permissions
kubectl get role pod-reader -n <namespace> -o yaml
# Verify the RoleBinding
kubectl get rolebinding read-pods -n <namespace> -o yaml
# Test permissions with the ServiceAccount (should succeed)
kubectl auth can-i list pods -n <namespace> --as=system:serviceaccount:<namespace>:my-app-sa
# Test that write access is denied (should return "no")
kubectl auth can-i create pods -n <namespace> --as=system:serviceaccount:<namespace>:my-app-sa
# Test that secrets access is denied (should return "no")
kubectl auth can-i get secrets -n <namespace> --as=system:serviceaccount:<namespace>:my-app-sa
# Audit all ClusterRoleBindings with cluster-admin
kubectl get clusterrolebindings -o jsonpath='{range .items[?(@.roleRef.name=="cluster-admin")]}{.metadata.name}{"\t"}{.subjects}{"\n"}{end}'
CIS Benchmark References
- 5.1.1 — Ensure that the cluster-admin role is only used where required. This template demonstrates proper scoped roles as an alternative to cluster-admin.
- 5.1.3 — Minimize wildcard use in Roles and ClusterRoles. This template uses explicit verb and resource lists, never wildcards.
MITRE ATT&CK References
- T1078 — Valid Accounts: Wildcard RBAC permissions allow reading Secrets, creating privileged pods, and escalating to cluster-admin. Least-privilege roles prevent this.
- T1078.004 — Valid Accounts: Cloud Accounts: Cluster-admin grants full control equivalent to root on every node. Namespace-scoped roles contain the blast radius.
Further Reading
- Kubernetes RBAC Best Practices: Least Privilege Done Right — Master RBAC design patterns, common mistakes, auditing commands, and workload identity integration.