El control de acceso basado en roles (RBAC) es el mecanismo de autorización estándar de Kubernetes: decide qué puede hacer cada usuario, grupo o ServiceAccount una vez autenticado. En este tutorial crearás permisos de solo lectura para una aplicación, darás a un desarrollador acceso completo pero limitado a un namespace mediante un certificado de cliente, y verificarás cada permiso con kubectl auth can-i antes de darlo por bueno. Todos los ejemplos siguen el principio de mínimo privilegio.
Requisitos previos
Para seguir esta guía necesitas:
- Un clúster de Kubernetes con RBAC activado (lo está por defecto en kubeadm, k3s y los servicios gestionados).
kubectlconfigurado con credenciales de administrador del clúster, desde una máquina con Ubuntu 24.04 u otro sistema conopenssl.- Conocimientos básicos de manifiestos YAML de Kubernetes.
Comprueba que tienes permisos de administrador:
kubectl auth can-i '*' '*' --all-namespaces
yes
Cómo funciona RBAC
RBAC se basa en cuatro objetos de la API rbac.authorization.k8s.io/v1:
| Objeto | Alcance | Qué hace |
|---|---|---|
Role | Un namespace | Lista de permisos (verbos sobre recursos) dentro de ese namespace |
ClusterRole | Todo el clúster | Lista de permisos sobre recursos de clúster (nodos, namespaces) o reutilizable en varios namespaces |
RoleBinding | Un namespace | Asigna un Role o un ClusterRole a sujetos, solo dentro de su namespace |
ClusterRoleBinding | Todo el clúster | Asigna un ClusterRole a sujetos en todos los namespaces |
Los sujetos pueden ser User, Group o ServiceAccount. Kubernetes no tiene objetos de usuario: el nombre de usuario y los grupos los aporta el método de autenticación (por ejemplo, el CN y la O de un certificado, o las claims de un token OIDC).
Los permisos son solo aditivos: no existen reglas de denegación. Todo lo que no se permite explícitamente está prohibido. Los verbos habituales son get, list, watch, create, update, patch y delete.
Paso 1: Crear un namespace de trabajo
Crea el namespace donde aplicarás los permisos:
kubectl create namespace dev
Paso 2: Dar permisos de solo lectura a una ServiceAccount
Las aplicaciones que consultan la API de Kubernetes (un operador, un panel, un job de CI) deben usar una ServiceAccount propia con los permisos mínimos. Crea la ServiceAccount, un Role que solo permite leer pods y sus registros, y el RoleBinding que los une:
nano pod-reader.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader
namespace: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader
namespace: dev
subjects:
- kind: ServiceAccount
name: pod-reader
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
El grupo de API vacío ("") corresponde a los recursos del núcleo, como pods, services o secrets. Los Deployments pertenecen al grupo apps y los Ingress a networking.k8s.io. Para saber el grupo de cualquier recurso, usa kubectl api-resources.
Aplica el manifiesto:
kubectl apply -f pod-reader.yaml
Verifica los permisos haciéndote pasar por la ServiceAccount con --as. El formato del nombre es system:serviceaccount:<namespace>:<nombre>:
kubectl auth can-i list pods -n dev --as=system:serviceaccount:dev:pod-reader
kubectl auth can-i delete pods -n dev --as=system:serviceaccount:dev:pod-reader
kubectl auth can-i list pods -n default --as=system:serviceaccount:dev:pod-reader
kubectl auth can-i get secrets -n dev --as=system:serviceaccount:dev:pod-reader
yes
no
no
no
Solo puede leer pods, y solo en dev. Para usarla desde un pod, indica serviceAccountName: pod-reader en su especificación; Kubernetes monta automáticamente un token de corta duración en /var/run/secrets/kubernetes.io/serviceaccount/. Para usarla desde fuera del clúster (por ejemplo en CI), genera un token temporal:
kubectl create token pod-reader -n dev --duration=1h
Notadesde Kubernetes 1.24 las ServiceAccounts no crean Secrets con tokens permanentes. Usa tokens temporales siempre que puedas.
Paso 3: Reutilizar los ClusterRoles predefinidos
Kubernetes incluye ClusterRoles pensados para usuarios que conviene reutilizar antes de escribir los tuyos:
| ClusterRole | Permisos |
|---|---|
view | Lectura de casi todos los recursos de un namespace, excepto Secrets y Roles |
edit | Lectura y escritura de la mayoría de recursos, incluidos Secrets, pero no de Roles ni RoleBindings |
admin | Todo lo de edit más gestionar Roles y RoleBindings dentro del namespace |
cluster-admin | Control total del clúster; úsalo solo para administradores |
Un ClusterRole asignado con un RoleBinding solo concede permisos dentro del namespace del RoleBinding. Así puedes dar el rol edit en dev sin tocar el resto del clúster. Lo harás en el siguiente paso para el grupo de desarrolladores:
nano dev-team-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-team-edit
namespace: dev
subjects:
- kind: Group
name: dev-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
kubectl apply -f dev-team-binding.yaml
Comprueba los permisos de un usuario ficticio del grupo con --as y --as-group:
kubectl auth can-i create deployments -n dev --as=ana --as-group=dev-team
kubectl auth can-i create deployments -n default --as=ana --as-group=dev-team
kubectl auth can-i create rolebindings -n dev --as=ana --as-group=dev-team
yes
no
no
Paso 4: Crear un usuario con certificado de cliente
Si tu clúster usa certificados X.509 para autenticar usuarios (kubeadm y k3s lo hacen), puedes emitir uno firmado por la CA del clúster mediante la API de CertificateSigningRequest. El CN del certificado será el nombre de usuario y la O, el grupo.
Notaen muchos servicios de Kubernetes gestionados la autenticación de usuarios se hace con OIDC o con el proveedor de identidad del servicio, y el firmante de certificados de cliente puede estar desactivado. En ese caso, el grupo
dev-teamdel paso 3 vendrá de las claims de tu proveedor y puedes saltar este paso.
Genera la clave privada y la petición de firma para el usuario ana del grupo dev-team:
openssl genrsa -out ana.key 3072
openssl req -new -key ana.key -out ana.csr -subj "/CN=ana/O=dev-team"
Crea el objeto CertificateSigningRequest con la petición codificada en base64:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: ana
spec:
request: $(base64 -w0 ana.csr)
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 7776000
usages:
- client auth
EOF
expirationSeconds limita la validez del certificado a 90 días. Aprueba la petición y descarga el certificado firmado:
kubectl certificate approve ana
kubectl get csr ana -o jsonpath='{.status.certificate}' | base64 -d > ana.crt
Comprueba que el certificado contiene el usuario y el grupo correctos:
openssl x509 -in ana.crt -noout -subject -enddate
subject=CN = ana, O = dev-team
notAfter=Dec 24 10:15:02 2026 GMT
Crea un kubeconfig independiente para Ana a partir de los datos del clúster actual:
CLUSTER=$(kubectl config view --minify -o jsonpath='{.clusters[0].name}')
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt
kubectl config set-cluster "$CLUSTER" --server="$SERVER" --certificate-authority=ca.crt --embed-certs=true --kubeconfig=ana.kubeconfig
kubectl config set-credentials ana --client-certificate=ana.crt --client-key=ana.key --embed-certs=true --kubeconfig=ana.kubeconfig
kubectl config set-context ana@dev --cluster="$CLUSTER" --user=ana --namespace=dev --kubeconfig=ana.kubeconfig
kubectl config use-context ana@dev --kubeconfig=ana.kubeconfig
Prueba el acceso con ese kubeconfig:
kubectl --kubeconfig=ana.kubeconfig get pods
kubectl --kubeconfig=ana.kubeconfig get pods -n kube-system
No resources found in dev namespace.
Error from server (Forbidden): pods is forbidden: User "ana" cannot list resource "pods" in API group "" in the namespace "kube-system"
Entrega a Ana el archivo ana.kubeconfig por un canal seguro y borra de tu máquina ana.key una vez entregado: contiene la clave privada del usuario.
Importantelos certificados de cliente no se pueden revocar en Kubernetes. Si una clave se ve comprometida, elimina los bindings del usuario o del grupo y espera a que caduque. Por eso conviene usar
expirationSecondscortos.
Paso 5: Escribir un ClusterRole propio
Cuando necesitas permisos sobre recursos de ámbito de clúster, como nodos, usa un ClusterRole con un ClusterRoleBinding. Por ejemplo, un rol para que un equipo de monitorización pueda consultar nodos y namespaces sin modificarlos:
nano node-viewer.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-viewer
rules:
- apiGroups: [""]
resources: ["nodes", "namespaces"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-viewer-ops
subjects:
- kind: Group
name: ops-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-viewer
apiGroup: rbac.authorization.k8s.io
kubectl apply -f node-viewer.yaml
kubectl auth can-i list nodes --as=luis --as-group=ops-team
kubectl auth can-i delete nodes --as=luis --as-group=ops-team
yes
no
Evita en tus reglas el comodín * en verbs o resources, y ten cuidado con estos permisos, que equivalen en la práctica a ser administrador:
getolistsobresecrets: da acceso a todos los tokens y contraseñas del namespace.createsobrepodso workloads: permite montar cualquier Secret o ServiceAccount del namespace dentro de un pod.escalate,bindeimpersonate: permiten concederse más permisos o actuar como otro usuario.
Paso 6: Auditar los permisos existentes
Lista todos los permisos efectivos de un sujeto en un namespace:
kubectl auth can-i --list -n dev --as=system:serviceaccount:dev:pod-reader
Resources Non-Resource URLs Resource Names Verbs
selfsubjectreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
pods/log [] [] [get list watch]
pods [] [] [get list watch]
...
Las primeras líneas son permisos básicos que todo usuario autenticado tiene para consultar su propia identidad. Revisa periódicamente quién tiene cluster-admin, que es la asignación más peligrosa:
kubectl get clusterrolebindings -o wide | grep -w cluster-admin
Y consulta todos los bindings de un namespace con sus roles y sujetos:
kubectl get rolebindings -n dev -o wide
Cada usuario puede comprobar su propia identidad y grupos con:
kubectl --kubeconfig=ana.kubeconfig auth whoami
ATTRIBUTE VALUE
Username ana
Groups [dev-team system:authenticated]
Solución de problemas
Forbidden aunque el binding existe. Revisa que el namespace del RoleBinding coincide con el que usas, que el nombre de la ServiceAccount incluye su namespace en subjects, y que el apiGroups de la regla es el del recurso (por ejemplo apps para Deployments). kubectl auth can-i con --as te dirá exactamente qué falla.
No puedes modificar el roleRef de un binding. Es un campo inmutable. Borra el RoleBinding y créalo de nuevo con el rol correcto.
La CSR se queda en estado Pending. Falta aprobarla con kubectl certificate approve. Si aparece como Approved pero sin certificado, el firmante kubernetes.io/kube-apiserver-client no está disponible en tu clúster (habitual en servicios gestionados); usa el método de autenticación del proveedor.
Error al crear un Role con permisos que tú no tienes. Kubernetes impide conceder permisos que no posees, salvo que tengas el verbo escalate. Crea el rol con una cuenta que ya tenga esos permisos.
Conclusión
Has dado a una ServiceAccount acceso de solo lectura a un namespace, asignado el rol edit a un grupo mediante un RoleBinding, creado un usuario con certificado de cliente de duración limitada, definido un ClusterRole propio y auditado los permisos resultantes. Como siguientes pasos puedes integrar la autenticación del clúster con un proveedor OIDC para gestionar usuarios y grupos de forma centralizada, limitar el tráfico entre pods con políticas de red y activar los registros de auditoría del API server para saber quién hizo cada cambio.
