# Creating User and Role in Kubernetes and Binding Them via RBAC

LLMS index: [llms.txt](/en/llms.txt)

---

In Kubernetes there are no "users" in the traditional sense — there are ServiceAccounts and certificates, bound to roles through RBAC. Without proper configuration, anyone holding a kubeconfig gets full access to the cluster. Below is the complete cycle: create a ServiceAccount, define permissions, bind them, and verify.

## Creating ServiceAccount and Generating kubeconfig

Start by creating a ServiceAccount in the target namespace:

```bash
kubectl create serviceaccount devops-sa -n staging
```

To generate a kubeconfig, extract the token from secrets and build the config file:

```bash
SA_NAME=devops-sa
SA_NS=staging

TOKEN=$(kubectl -n $SA_NS get secret $(kubectl -n $SA_NS get sa $SA_NAME -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode)

kubectl config set-credentials $SA_NAME --token=$TOKEN
kubectl config set-context devops-staging --cluster=$(kubectl config current-context) --user=$SA_NAME --namespace=$SA_NS
kubectl config use-context devops-staging
```

> [!WARNING]
> A ServiceAccount token is a plain bearer token. If the kubeconfig leaks, an attacker gains access with that SA's privileges. Store the file with `600` permissions.

## Defining Role and ClusterRole

A Role is namespace-scoped; a ClusterRole is cluster-scoped. The difference is critical: a Role grants no rights outside its namespace, a ClusterRole does.

Example Role allowing read and create operations on pods in the `staging` namespace:

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

Example ClusterRole for managing ingresses across the entire cluster:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-manager
rules:
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
```

> [!TIP]
> An empty string `""` in `apiGroups` refers to the core API group (`v1`). For apps, networking, batch — specify the corresponding groups. The full list of groups is available via `kubectl api-resources`.

## Creating RoleBinding and ClusterRoleBinding

A RoleBinding binds a Role to a subject within a namespace. A ClusterRoleBinding binds a ClusterRole cluster-wide.

Binding a Role to a ServiceAccount in the `staging` namespace:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: devops-pod-access
  namespace: staging
subjects:
  - kind: ServiceAccount
    name: devops-sa
    namespace: staging
roleRef:
  kind: Role
  name: pod-reader-writer
  apiGroup: rbac.authorization.k8s.io
```

Binding a ClusterRole to the same SA (now with cluster-wide ingress rights):

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: devops-ingress-access
subjects:
  - kind: ServiceAccount
    name: devops-sa
    namespace: staging
roleRef:
  kind: ClusterRole
  name: ingress-manager
  apiGroup: rbac.authorization.k8s.io
```

| Binding | Scope | Role type | When to use |
|---|---|---|---|
| RoleBinding | Single namespace | Role or ClusterRole | Read/write in a specific ns |
| ClusterRoleBinding | Entire cluster | ClusterRole | Global rights (node, pv, dns) |

## Verifying and Debugging Access Rights

After applying the YAML, confirm the SA actually received the intended permissions:

```bash
kubectl auth can-i get pods --as=system:serviceaccount:staging:devops-sa -n staging
kubectl auth can-i create pods --as=system:serviceaccount:staging:devops-sa -n staging
kubectl auth can-i get ingresses --as=system:serviceaccount:staging:devops-sa
```

The last command checks via ClusterRoleBinding — it returns `yes` if the binding is correct.

If something doesn't work, check the audit log or use `kubectl auth reconcile` with `--dry-run=server` for a preview:

```bash
kubectl auth reconcile role-binding.yaml --dry-run=server
```

Another useful trick is to find which RoleBindings are attached to a specific SA:

```bash
kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | \
  jq '.items[] | select(.subjects[]?.name=="devops-sa") | {name: .metadata.name, kind: .kind, namespace: .metadata.namespace}'
```

> [!NOTE]
> `kubectl auth can-i` checks permissions only — it does not account for NetworkPolicy or PodSecurityPolicy. If a pod fails to start, the issue may lie there.

Bottom line: RBAC in Kubernetes works as a chain — SA → Role/ClusterRole → Binding. Each link can be verified independently, which greatly simplifies debugging. Start with minimum privileges and expand as needed; never grant `cluster-admin` without a compelling reason.
