Kubernetes RBAC Configuration

Role-Based Access Control (RBAC) is the standard authorization mechanism in Kubernetes that determines what authenticated users and service accounts can do within a cluster. Proper RBAC configuration is essential for multi-tenant environments, compliance requirements, and security-conscious deployments. This guide covers Roles, ClusterRoles, RoleBindings, ServiceAccounts, and implementing the principle of least privilege.

Table of Contents

RBAC Fundamentals

RBAC in Kubernetes works by associating subjects (users, groups, service accounts) with rules that define what actions (verbs) they can perform on resources.

Key Concepts

Subject: An entity requesting access (users, groups, service accounts)

Verb: Actions that can be performed (get, list, create, delete, watch, patch, update)

Resource: Kubernetes objects being controlled (pods, deployments, services, secrets, configmaps)

ApiGroup: Logical grouping of resources by API version

RBAC Evaluation Flow

When a request is made to the Kubernetes API:

  1. Authentication identifies the user/service account
  2. Authorization checks if the subject has permission for the action
  3. Admission controllers may apply additional policies
  4. The request is allowed or denied

API Resources and Verbs

Common verbs used in RBAC:

  • get: Read a specific resource
  • list: Read multiple resources
  • watch: Stream changes to resources
  • create: Create new resources
  • update: Modify existing resources
  • patch: Apply partial updates
  • delete: Remove resources
  • deletecollection: Delete multiple resources at once
  • exec: Execute commands in pods

Roles and ClusterRoles

Role Definition

Roles are namespace-scoped permissions. They grant access to resources within a specific namespace.

Basic role example:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]

Multiple resources:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-developer
  namespace: development
rules:
- apiGroups: [""]
  resources: ["pods", "services"]
  verbs: ["get", "list", "create", "delete", "watch"]
- apiGroups: [""]
  resources: ["pods/logs"]
  verbs: ["get"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "update", "patch"]

ClusterRole Definition

ClusterRoles are cluster-wide permissions, not limited to a specific namespace. They're useful for permissions that apply across the cluster.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-admin-custom
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
  resources: ["storageclasses"]
  verbs: ["get", "list"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  verbs: ["get", "list"]

Wildcard Resources

Grant access to all verbs for specific resources:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-manager
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["*"]  # All verbs on pods

Resource Names

Restrict access to specific resource instances:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["app-config", "database-config"]
  verbs: ["get"]

RoleBindings and ClusterRoleBindings

RoleBinding

RoleBindings connect a Role to subjects within a namespace.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: production
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader
subjects:
- kind: User
  name: "[email protected]"
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding

ClusterRoleBindings bind ClusterRoles to subjects at the cluster level.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: secret-reader
subjects:
- kind: User
  name: "[email protected]"
  apiGroup: rbac.authorization.k8s.io

Binding to ServiceAccounts

Most commonly, RoleBindings bind to ServiceAccounts:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployment-manager
  namespace: apps
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-editor
subjects:
- kind: ServiceAccount
  name: app-deployer
  namespace: apps

Multiple Subjects

One RoleBinding can apply to multiple subjects:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developers-binding
  namespace: development
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: app-developer
subjects:
- kind: User
  name: "[email protected]"
  apiGroup: rbac.authorization.k8s.io
- kind: User
  name: "[email protected]"
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: "developers"
  apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
  name: ci-pipeline
  namespace: development

ServiceAccounts

Creating ServiceAccounts

ServiceAccounts are Kubernetes identities for workloads and processes.

# Create a service account
kubectl create serviceaccount app-manager -n production

# View the service account
kubectl get serviceaccount -n production
kubectl describe serviceaccount app-manager -n production

Declaratively:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: database-operator
  namespace: data-layer
automountServiceAccountToken: true

Binding Roles to ServiceAccounts

# Create a role
kubectl create role pod-reader --verb=get,list --resource=pods -n production

# Bind the role to the service account
kubectl create rolebinding pod-reader-binding \
  --role=pod-reader \
  --serviceaccount=production:app-manager \
  -n production

Using ServiceAccount Tokens

View the token for a service account:

kubectl get secrets -n production
kubectl get secret app-manager-token-xxxxx -n production -o jsonpath='{.data.token}' | base64 -d

Workload Identity

Assign a ServiceAccount to a Pod:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: production
spec:
  serviceAccountName: app-manager
  automountServiceAccountToken: true
  containers:
  - name: app
    image: my-app:1.0

Least Privilege Implementation

Principles

  1. Deny by default: Grant only necessary permissions
  2. Specific resources: Target specific resources, not wildcards
  3. Specific verbs: Only grant required actions
  4. Time-bound access: Use temporary or session-based access when possible
  5. Regular audits: Review and cleanup permissions regularly

Minimal Read-Only Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-viewer
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["pods/logs"]
  verbs: ["get"]

Deployment Operator Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-operator
  namespace: production
rules:
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "update", "patch"]
- apiGroups: ["apps"]
  resources: ["deployments/rollback"]
  verbs: ["create"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get"]

Namespace Admin (Limited ClusterRole)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: namespace-admin
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["get", "list"]

Practical Examples

Example: CI/CD Pipeline ServiceAccount

For a GitLab or GitHub Actions pipeline:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-pipeline
  namespace: ci-cd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-manager
  namespace: ci-cd
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "update", "patch"]
- apiGroups: ["apps"]
  resources: ["deployments/rollback"]
  verbs: ["create"]
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployment-binding
  namespace: ci-cd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-manager
subjects:
- kind: ServiceAccount
  name: ci-pipeline
  namespace: ci-cd

Example: Read-Only Monitoring Account

For monitoring dashboards and observability:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: metrics-reader
rules:
- apiGroups: [""]
  resources: ["pods", "nodes", "services", "endpoints"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
  resources: ["jobs", "cronjobs"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: metrics-reader
subjects:
- kind: ServiceAccount
  name: monitoring
  namespace: monitoring

Example: Developer Sandbox Namespace

Limited access for development teams:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dev-deployer
  namespace: dev-sandbox
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-pod-manager
  namespace: dev-sandbox
rules:
- apiGroups: [""]
  resources: ["pods", "pods/logs", "pods/status"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["create", "get", "list", "update", "patch", "delete", "watch"]
- apiGroups: [""]
  resources: ["services", "configmaps"]
  verbs: ["create", "get", "list", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-deployer-binding
  namespace: dev-sandbox
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: dev-pod-manager
subjects:
- kind: ServiceAccount
  name: dev-deployer
  namespace: dev-sandbox

Auditing and Troubleshooting

Checking Permissions

Check what a user can do:

# Check if a user can perform an action
kubectl auth can-i get pods [email protected]
kubectl auth can-i create deployments [email protected] -n production

# Recursive check
kubectl auth can-i "*" pods --as=ci-pipeline --as-group=system:serviceaccounts:ci-cd

Listing All Permissions

View all roles in a namespace:

kubectl get roles -n production
kubectl describe role pod-reader -n production

View all cluster-wide roles:

kubectl get clusterroles | grep -v system

Auditing RBAC Changes

Enable audit logging in kube-apiserver:

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
  resources: ["rolebindings", "clusterrolebindings"]
  namespaces: ["production"]

Start API server with audit:

kube-apiserver \
  --audit-log-path=/var/log/audit.log \
  --audit-policy-file=/etc/kubernetes/audit-policy.yaml \
  --audit-max-age=30 \
  --audit-max-backup=10 \
  --audit-max-size=100

Troubleshooting Denied Requests

When a request is denied:

# View recent events
kubectl get events -A --sort-by='.lastTimestamp'

# Check service account token
kubectl get serviceaccount -n production app-manager -o yaml

# Test permissions
kubectl auth can-i list pods --as=system:serviceaccount:production:app-manager -n production

Conclusion

RBAC is fundamental to securing Kubernetes deployments on your VPS or baremetal infrastructure. By implementing the principle of least privilege, regularly auditing permissions, and following best practices for ServiceAccount and Role management, you create a secure multi-tenant environment. Start with overly restrictive permissions and gradually grant access as needed, rather than starting permissive. Test permissions thoroughly before deploying to production, and maintain clear documentation of what each role and ServiceAccount is authorized to do.