How to Configure Kubernetes RBAC on RHEL 7
Role-Based Access Control (RBAC) is the standard authorization mechanism in Kubernetes, allowing administrators to define precisely which users, groups, and service accounts can perform which actions on which resources. Without RBAC, any authenticated user could potentially read secrets, delete deployments, or escalate their privileges across namespaces. On RHEL 7 enterprise environments where Kubernetes clusters often serve multiple teams and applications, a well-designed RBAC policy is a security requirement rather than an optional enhancement. This tutorial covers the four core RBAC objects — Role, ClusterRole, RoleBinding, and ClusterRoleBinding — and walks through practical examples including creating read-only access for pods, binding roles to users and service accounts, and integrating RBAC with Helm deployments.
Prerequisites
- RHEL 7 system with a running Kubernetes cluster
kubectlconfigured with admin-level access (system:mastersorcluster-admin)- Basic familiarity with
kubectl getand YAML manifests - OpenSSL available for generating user certificates (pre-installed on RHEL 7)
- RBAC enabled on the API server (enabled by default in kubeadm clusters)
Step 1: Understand RBAC Object Types
Before writing any YAML, it is important to understand the four RBAC primitives and when to use each one.
Role vs ClusterRole
A Role grants permissions within a single namespace. If you want a developer to read pods only in the dev namespace, a Role is the correct object. A ClusterRole grants permissions cluster-wide, across all namespaces, and can also be used to control access to non-namespaced resources like nodes, persistent volumes, and custom resource definitions.
RoleBinding vs ClusterRoleBinding
A RoleBinding binds a Role or ClusterRole to a subject within a single namespace. A ClusterRoleBinding binds a ClusterRole to a subject cluster-wide. You can bind a ClusterRole with a namespaced RoleBinding to grant cluster-level role definitions scoped to one namespace, which is a common pattern for reusable roles across teams.
Step 2: Create a Read-Only Role for Pods
Create a namespace for this demonstration, then define a role that allows only reading pods and their logs:
kubectl create namespace dev-team
Save the following to pod-reader-role.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
kubectl apply -f pod-reader-role.yaml
kubectl get role pod-reader -n dev-team
The empty string in apiGroups refers to the core API group, which includes pods, services, configmaps, and secrets. The verbs list determines allowed operations. The values get, list, and watch are read-only. Never add create, update, patch, or delete unless explicitly required by the use case.
Step 3: Create a User Certificate and Bind the Role
Kubernetes does not manage user accounts internally. The most common approach on self-managed clusters is to issue client certificates signed by the cluster CA.
Generate a private key and certificate signing request for a user named alice:
openssl genrsa -out alice.key 2048
openssl req -new -key alice.key -out alice.csr
-subj "/CN=alice/O=dev-team"
Sign the CSR with the Kubernetes cluster CA, typically located at /etc/kubernetes/pki/ on kubeadm clusters:
openssl x509 -req -in alice.csr
-CA /etc/kubernetes/pki/ca.crt
-CAkey /etc/kubernetes/pki/ca.key
-CAcreateserial
-out alice.crt
-days 365
Add the user to your kubeconfig and create a context for them:
kubectl config set-credentials alice
--client-certificate=alice.crt
--client-key=alice.key
kubectl config set-context alice-context
--cluster=kubernetes
--namespace=dev-team
--user=alice
Now bind the pod-reader role to alice in the dev-team namespace. Save to alice-rolebinding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-pod-reader
namespace: dev-team
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f alice-rolebinding.yaml
Step 4: Create and Bind a ServiceAccount
Applications running inside pods authenticate using ServiceAccounts rather than user certificates. Create a ServiceAccount and bind the pod-reader role to it:
kubectl create serviceaccount pod-watcher -n dev-team
Save the binding to pod-watcher-binding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-watcher-binding
namespace: dev-team
subjects:
- kind: ServiceAccount
name: pod-watcher
namespace: dev-team
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f pod-watcher-binding.yaml
To use this ServiceAccount in a pod, reference it in the pod spec:
apiVersion: v1
kind: Pod
metadata:
name: audit-pod
namespace: dev-team
spec:
serviceAccountName: pod-watcher
containers:
- name: kubectl
image: bitnami/kubectl:latest
command: ["sleep", "3600"]
Step 5: Verify Permissions with kubectl auth can-i
The kubectl auth can-i command is the fastest way to audit what a user or service account can do without actually performing the action:
# Check as yourself (admin)
kubectl auth can-i delete pods -n dev-team
# Check as alice
kubectl auth can-i list pods -n dev-team --as=alice
kubectl auth can-i delete pods -n dev-team --as=alice
# Check as a service account
kubectl auth can-i list pods -n dev-team
--as=system:serviceaccount:dev-team:pod-watcher
Expected output for allowed actions is yes and for denied actions is no. Use the --list flag to enumerate every verb allowed for a given subject:
kubectl auth can-i --list -n dev-team --as=alice
Step 6: Create a ClusterRole and ClusterRoleBinding
Some resources are cluster-scoped and cannot be accessed via namespaced Roles. To grant a user read-only access to nodes and persistent volumes:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-resource-reader
rules:
- apiGroups: [""]
resources: ["nodes", "persistentvolumes", "namespaces"]
verbs: ["get", "list", "watch"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alice-cluster-reader
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-resource-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f cluster-reader-role.yaml
kubectl apply -f alice-clusterrolebinding.yaml
Step 7: RBAC for Helm Deployments
Helm 3 runs with the permissions of the kubeconfig user that executes it. When Helm runs from inside a CI/CD pod, that pod’s ServiceAccount needs appropriate permissions to create, update, and delete Kubernetes resources. Create a ServiceAccount for Helm with namespace-scoped deployment rights:
kubectl create serviceaccount helm-deployer -n dev-team
kubectl create rolebinding helm-deployer-binding
--clusterrole=admin
--serviceaccount=dev-team:helm-deployer
--namespace=dev-team
Using the built-in admin ClusterRole scoped to one namespace via a namespaced RoleBinding is a pragmatic pattern for CI/CD pipelines. It grants full namespace control without cluster-admin privileges, preventing a compromised CI runner from affecting other namespaces.
Step 8: Switch kubeconfig Context and Test
Switch to the alice context to test that permissions are working as expected:
kubectl config use-context alice-context
kubectl get pods -n dev-team # Should succeed
kubectl get secrets -n dev-team # Should be denied
kubectl delete pod audit-pod -n dev-team # Should be denied
Switch back to the admin context when done:
kubectl config use-context kubernetes-admin@kubernetes
If a command that should be denied returns an error like Error from server (Forbidden), your RBAC policies are working correctly. That is the expected and desired behavior.
Conclusion
You have configured Kubernetes RBAC on RHEL 7 by creating namespaced Roles and cluster-wide ClusterRoles, binding them to users and ServiceAccounts using RoleBindings and ClusterRoleBindings, and verified the results using kubectl auth can-i. RBAC policies should always follow the principle of least privilege: start with the minimum read-only access and expand permissions only when a specific operational need is demonstrated and approved. Audit your RBAC configuration regularly using kubectl auth can-i --list or third-party tools such as rbac-lookup and kubectl-who-can to identify over-privileged accounts before they become security vulnerabilities in your RHEL 7 Kubernetes environment.