๐Ÿท๏ธ Manage role based access control (RBAC)#

RBAC

  • Managing Role-Based Access Control (RBAC) in Kubernetes involves defining and enforcing granular permissions for users, groups, and service accounts to ensure security and operational efficiency.

  • The core components of Kubernetes RBAC are Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings, which are used to define and assign permissions.

  • Roles define permissions within a specific namespace, while ClusterRoles define permissions across the entire cluster, including access to cluster-scoped resources like nodes or persistent volumes.

  • A RoleBinding grants the permissions defined in a Role to a subject (user, group, or service account) within a specific namespace, whereas a ClusterRoleBinding grants those permissions cluster-wide.

User#

Create a new user.#

แ… sudo useradd -s /bin/bash DevDan
แ… sudo passwd DevDan

Create namespaces#

แ… k create ns development
แ… k create ns production

Create user certificate.#

แ… openssl genrsa -out DevDan.key 2048
แ… openssl req -new -key DevDan.key -out DevDan.csr -subj "/CN=DevDan/O=development"
แ… sudo openssl x509 -req -in DevDan.csr \
-CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key \
-CAcreateserial -out DevDan.crt -days 45

Create user and context (in kubeconfig).#

แ… k config set-credentials DevDan --client-certificate=./DevDan.crt --client-key=./DevDan.key
แ… yq -r '.users[] | select (.name == "DevDan")' .kube/config
{
  "name": "DevDan",
  "user": {
    "client-certificate": "/home/guisam/DevDan.crt",
    "client-key": "/home/guisam/DevDan.key"
  }
}
แ… k config get-users
NAME
DevDan
kubernetes-admin
แ… k config set-context DevDan --cluster=kubernetes \
--user=DevDan --namespace=development
แ… k config set-context ProdDan --cluster=kubernetes \
--user=DevDan --namespace=production
แ… k config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          DevDan                        kubernetes   DevDan             development
          ProdDan                       kubernetes   DevDan             production
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin

Create roles and rolebindings.#

แ… cat <<EOF > dev-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: development
  name: developer
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["list", "get", "watch", "create", "update", "patch", "delete"]
EOF
แ… cat <<EOF > rolebind.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: developer-role-binding
  namespace: development
subjects:
- kind: User
  name: DevDan
  apiGroup: ""
roleRef:
  kind: Role
  name: developer
  apiGroup: ""
EOF
แ… cat <<EOF > prod-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: production
  name: dev-prod
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["list", "get", "watch"]
EOF
แ… cat <<EOF > prodrolebind.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: production-role-binding
  namespace: production
subjects:
- kind: User
  name: DevDan
  apiGroup: ""
roleRef:
  kind: Role
  name: dev-prod
  apiGroup: ""
EOF
แ… k apply -f dev-role.yaml -f rolebind.yaml -f prod-role.yaml -f prodrolebind.yaml
แ… k --context ProdDan-context run test --image=nginx
Error from server (Forbidden): pods is forbidden: User "DevDan" cannot create resource "pods" in API group "" in the namespace "production"

ServiceAccount#

ServiceAccount

A service account is a specialized identity for processes running within a Pod, providing a distinct and manageable way for workloads to authenticate and interact with the Kubernetes API server. It is a non-human account managed by the Kubernetes API server, typically bound to a specific namespace, and exists as a ServiceAccount object within the cluster. Service accounts are essential for enabling automated processes, such as applications, system components, or external services, to securely access cluster resources by using credentialsโ€”specifically, a signed JSON Web Token (JWT)โ€”which are automatically mounted into Pods. By default, every namespace includes a default service account, and Pods are assigned this default account unless explicitly configured otherwise. The permissions granted to a service account are controlled through Role-Based Access Control (RBAC), allowing administrators to enforce the principle of least privilege by defining precise access rights.

Service Account Token#

Long-Lived Token#

Warning

Not recommended as token never expires.

Create a serviceaccount and a secret.

แ… k create sa long-lived-sa
แ… cat <<EOF > long-lived-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  creationTimestamp: null
  name: long-lived-secret
  annotations:
    kubernetes.io/service-account.name: long-lived-sa
type: kubernetes.io/service-account-token
EOF

Tip

แ… k create secret generic long-lived-secret \
--dry-run=client --type=kubernetes.io/service-account-token \
-o yaml > long-lived-secret.yaml

then add annotations.kubernetes.io/service-account.name.

Create a role and a rolebinding.

แ… k create role long-lived-role \
--verb=get,list,watch --resource=pods,deployments
แ… k create rolebinding long-lived-rb \
--role=long-lived-role --serviceaccount=default:long-lived-sa
rolebinding.rbac.authorization.k8s.io/long-lived-rb created

Create pod.

แ… k run long-lived-pod --image=nginx --dry-run=client -o yaml > long-lived-pod.yaml
แ… diff -u long-lived-pod.yaml{.before,}
--- long-lived-pod.yaml.before  2025-11-03 16:59:02.724965164 +0100
+++ long-lived-pod.yaml 2025-11-03 17:00:06.517864947 +0100
@@ -12,4 +12,6 @@
     resources: {}
   dnsPolicy: ClusterFirst
   restartPolicy: Always
+  serviceAccountName: long-lived-sa
+  automountServiceAccountToken: true
 status: {}
แ… k apply -f long-lived-pod.yaml

Check.

แ… k exec -ti long-lived-pod -- bash
root@long-lived-pod:/# token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
root@long-lived-pod:/# cacert=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
root@long-lived-pod:/# ns=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
root@long-lived-pod:/# apt update &> /dev/null && apt install -y jq &> /dev/null
root@long-lived-pod:/# curl -s --cacert $cacert -H "Authorization: Bearer $token" \
> https://kubernetes/api/v1/namespaces/"$ns"/pods/ | jq -r '.items[].metadata.name'
lg-lv-pod
po-test

Time Bound Token#

Create a serviceaccount and a token.

k create sa tb-sa
k create token tb-sa --duration 1h

Create a role and bind it to the serviceaccount.

k create role tb-role --verb=get,list,watch --resource=pods,deployments
k create rolebinding tb-rolebinding --role=tb-role --serviceaccount=default:tb-sa

Create a pod.

k run tb-pod --image=nginx --dry-run=client -o yaml > tb-pod.yaml
diff -u tb-pod.yaml{.before,}
--- tb-pod.yaml.before  2025-11-03 18:52:10.138414525 +0100
+++ tb-pod.yaml 2025-11-03 18:55:47.907040341 +0100
@@ -12,4 +12,5 @@
     resources: {}
   dnsPolicy: ClusterFirst
   restartPolicy: Always
+  serviceAccountName: tb-sa
 status: {}
k apply -f tb-pod.yaml

Same check as long-lived sa.