RBAC
RBAC
Control de Acceso Basado en Rol es una forma de controlar que puede o no puede hacer cierto usuario en el cluster, esto se controla especificando diferentes roles con sus reglas para después asignar usuarios a ese rol. De esta manera se evita que todos los usuarios tengan un control total del cluster.
Por defecto RBAC en minikube viene habilitado, aún que es bueno comprobarlo por si acaso.
# comprobar que esta habilitado
➜ kubectl cluster-info dump | grep -i authorization-mode
"--authorization-mode=Node,RBAC",
# habilitar
➜ minikube start --vm-driver=none --extra-config=apiserver.authorization-mode=RBAC
Permisos
Kubernetes diferencia dos tipos de permisos, Role y ClusterRole
donde los dos son muy similares, son una lista de resources
y verbs
donde resources especifica a que tipo de objeto tienes permiso acceder pods, deployments ...
y verbs se refiere a acciones que puedes hacer listar, crear, eliminar ...
la diferencia es que Role
se refiere a los permisos que tienes dentro de un namespace y ClusterRole
son los permisos que tiene dentro del cluster.
Binding
El binding en kubernetes es la asociación de un usuario, grupo o serviceAccound a un Role o ClusterRole. Binding es un objeto con dos denominaciones diferentes RoleBinding
y ClusterRoleBinding
según se utilice para asociar Roles
o ClusterRoles
.
Usuarios
kubernetes no tiene ningun objeto donde puedas crear usuarios, de esta manera todos los usuarios seran externos a la aplicación de kubernetes
kubernetes solo aporta el método de autenticación y soporta diferentes métodos x509 clients certs, statik token file, bootstrap tokens, static Password File, service Account Tokens
.
Un nuevo usuario necesita instalar y configurar kubectl
para que la api le deje autentificar en alguno de los métodos anteriormente nombrados.
x509 clients certs
Uso de certificados es el método mas utilizado y el que por defecto utiliza minikube, en los siguientes pasos se muestra como añadir un usuario nuevo.
- El nuevo cliente genera su llave y el certificado csr para que lo firme el administrador del cluster. Es importante que
CN/=jorge
se refiere al usuario y/O=dev
es el grupo del usuario.
➜ openssl genrsa -out jorgekey.pem 2048
➜ openssl req -new -key jorgekey.pem -out jorgecsr.pem -subj "/CN=jorge/O=dev"
- El administrador confirma el
csr
del nuevo cliente/usuario y lo firma con la CA del cluster
# identificar donde esta la CA del cluster
➜ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority: /home/debian/.minikube/ca.crt
server: https://192.168.88.2:8443
# firmar el csr del cliente y generar el certificado
➜ openssl x509 -req -in jorgecsr.pem -CAkey /home/debian/.minikube/ca.key -CA /home/debian/.minikube/ca.crt -days 365 -CAcreateserial -out jorgecrt.pem
Signature ok
subject=CN = jorge, O = dev
Getting CA Private Key
- En este paso el administrador del cluster nos a proporcionado dos archivos
jorgecrt.pem, ca.crt
el nuevo certificado y la clave pública del cluster. Ahora el cliente tiene que configurar su kubectl para poder acceder al cluster
# añadir cluster a la configuración de kubectl
jorge@pc02:~$ kubectl config set-cluster minikube --server=https://192.168.88.2:8443 --certificate-authority=ca.crt
# añadir credenciales del usuario
jorge@pc02:~$ kubectl config set-credentials jorge --client-certificate=jorgecrt.pem --client-key=jorgekey.pem
# crear un espacio de trabajo del usuario
jorge@pc02:~$ kubectl config set-context jorge --cluster=minikube --user=jorge
# utilizar ese espacio
jorge@pc02:~$ kubectl config use-context jorge
Comprobar que todo se a aplicado correctamente:
jorge@pc02:~$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority: /home/jorge/ca.crt
server: https://192.168.88.2:8443
name: minikube
contexts:
- context:
cluster: minikube
user: jorge
name: jorge
current-context: jorge
kind: Config
preferences: {}
users:
- name: jorge
user:
client-certificate: /home/jorge/jorgecrt.pem
client-key: /home/jorge/jorgekey.pem
Nota: Una vez configurado
kubectl
, si el administrador no nos asigna ningún tipo de Role no tendremos permisos para hacer nada. Una vez asignado un Role podremos hacer lo que ese Role nos permita.
Role
En los Roles hay que tener en cuenta el namespace
en el que se asignan los permisos, los resources
(objetos) a los que se podrá acceder y los verbs
permisos que se tendrá sobre los objetos.
verbs
Los verbs indica que puedes hacer sobre algún objeto, esta es la tabla de los diferentes verbs que existen.
HTTP verb | request verb |
---|---|
POST | create |
GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) |
PUT | update |
PATCH | patch |
DELETE | delete (for individual resources), deletecollection (for collections) |
Resources
Los resources son los diferentes objetos que encontramos en kubernetes, Pods, Replicasets, Deployments, ...
➜ ~ kubectl api-resources
NAME SHORTNAMES APIGROUP
pods po
secrets
services svc
deployments deploy apps
replicasets rs apps
....
Template de ejemplo de Role en el namespace default donde puede ver, listar y observar (describir) Pods. El apartado apiGroups
se tiene que indicar solo cuando el objeto pertenece a un APIGROUP, como podemos ver en el bloque de arriba que deployments pertenece al apigroup apps.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
Una vez desplegado el rol se verá de la siguiente forma. Para asignar este rol a un usuario o grupo se tiene que utilizar Rolebinding
➜ kubectl get roles
NAME AGE
pod-reader 13s
➜ kubectl describe role pod-reader
Name: pod-reader
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list]
Rolebinding
Rolebinding es el enlace entre roles y Usuarios/Grupos. En este ejemplo muestro como enlazar el usuario jorge
con el role pod-reader
.
Las secciones importantes del objeto RoleBinding
son:
- especificar el namespace donde trabajar
subjects
el Usuer o Group que enlazarroleRef
la referencia al rol que pertenecerá
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: users-read-pods
namespace: default
subjects:
- kind: User
name: jorge
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Comprobación de que se a asignado los permisos correctamente.
➜ kubectl get rolebinding
NAME AGE
users-read-pods 49s
# miro la descripción completa del enlace
➜ kubectl describe rolebinding users-read-pods
Name: users-read-pods
Role:
Kind: Role
Name: pod-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User jorge
Actualmente estoy trabajando como administrador minikube, cambio a jorge para comprobar permisos
➜ kubectl config current-context
minikube
# cambiar a usuario jorge
➜ kubectl config use-context jorge
Switched to context "jorge".
# puedo ver pods de namespace default
➜ kubectl get pods
No resources found in default namespace.
# y no puedo verbni hacer nada mas.
➜ kubectl get pods -n dev
Error from server (Forbidden): pods is forbidden: User "jorge" cannot list resource "pods" in API group "" in the namespace "dev"
➜ kubectl get svc
Error from server (Forbidden): services is forbidden: User "jorge" cannot list resource "services" in API group "" in the namespace "default"
ClusterRole
ClusterRole es exactamente lo mismo que role pero en vez de dar permisos sobre un namespace, da permisos sobre todo un cluster.
En este ejemplo e juntado el ClusterRol
con el ClusterRolebinding
porque es exactamente igual a role, simplemente se cambia el kind
de referencia al objeto.
El siguiente template otorga al usuario jorge permisos de lectura de Pods y deployments sobre todo el cluster.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-pod-deploy-reader
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: users-read-pods-deploy
subjects:
- kind: User
name: jorge
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-pod-deploy-reader
apiGroup: rbac.authorization.k8s.io
Cluster admin
Por defecto kubernetes ya tiene roles definidos, como se ve en el siguiente bloque, en el caso de querer asignar ese rol ya definido como por ejemplo el cluster-admin
simplemente se tendría que hacer la asignación al usuario.
➜ k8s git:(proceso) ✗ kubectl get clusterroles
NAME AGE
admin 66d
cluster-admin 66d
edit 66d
kubernetes-dashboard 9d
system:aggregate-to-admin 66d
system:aggregate-to-edit 66d
...
Asignación de role cluster-admin a usuario jorge.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: users-cluster-admin
subjects:
- kind: User
name: jorge
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
Grupos roles
Los grupos de roles son muy útiles en la gestión de permisos, ya que te permite agrupar a un grupo a tener ciertos permisos.
El grupo de un usuario se establece en el método de crear el usuario, utilizando certificados ➜ openssl req -new -key jorgekey.pem -out jorgecsr.pem -subj "/CN=jorge/O=dev"
, en este caso el usuario jorge
pertenece al grupo dev
El siguiente ejemplo de template se ve como se crea un clusterRoleBinding de el grupo de usuarios dev
asignando los permisos del ClusterRole con nombre svc-clusterrole
.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: svc-clusterrole
rules:
- apiGroups: ["apps"]
resources: ["services","Pods","replicasets","deployments"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-svc
subjects:
- kind: Group
name: dev
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: svc-clusterrole
apiGroup: rbac.authorization.k8s.io
ServiceAccount
ServiceAccount proporciona una identidad para los procesos que se ejecutan en un Pod.
Cuando alguien accede a un cluster utilizando por ejemplo kubectl
, el api server lo autentica como usuario y puede ver que ocurre en el cluster, según los permisos. Los procesos de los contenedores también pueden consultar datos al api server, pero para eso necesitan autenticarse y para eso utilizan serviceAccount.
ServiceAccount utiliza un tocken para la autenticación del pod con la api, este tocken se monta automáticamente en el pod al crearlo, si no se especifica ninguno se monta el de por default, y según los permisos que se otorgan a ese tocken puede acceder a distintas consultas de la api.
Ejemplo de serviceAccount simple.
sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa
Un serviceAccount solo implica crear un tocken, para que este tenga utilidad se tiene que aplicarle un role y asociarlo con un binding a algún pod.
# desplegar serviceaccount
➜ kubectl apply -f k8s/RBAC/serviceacount/sa.yaml
serviceaccount/my-sa created
# por defecto kubernetes ya tiene uno
➜ kubectl get sa
NAME SECRETS AGE
default 1 67d
my-sa 1 20s
# vemos que se a creado el tocken my-sa-token-7z2ms
➜ kubectl describe sa my-sa
Name: my-sa
Namespace: default
...
Mountable secrets: my-sa-token-7z2ms
Tokens: my-sa-token-7z2ms
# comprovamos que exise ese tocken
➜ kubectl get secrets
NAME TYPE DATA AGE
default-token-k8kw2 kubernetes.io/service-account-token 3 67d
my-sa-token-7z2ms kubernetes.io/service-account-token 3 57s
Asociar SA a Pod
En el siguiente template se muestra como se asigna un rol a un serviceAccount y este se asigna a un Pod
# creo el service account
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
name: deployment-test
labels:
app: front-nginx
spec:
replicas: 1
selector:
matchLabels:
app: front-nginx
template:
metadata:
labels:
app: front-nginx
spec:
# assigno el SA my-sa al pod
serviceAccountName: my-sa
containers:
- name: nginx
image: nginx:alpine
---
# creo el role de permisos que tendra el SA
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: sa-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
# assigno el Role al SA
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sa-read-pods
namespace: default
# subjects.kind especifica el objeto SA, y el name del SA
subjects:
- kind: ServiceAccount
name: my-sa
apiGroup: ""
roleRef:
kind: Role
name: sa-reader
apiGroup: rbac.authorization.k8s.io
Verificar la asignación y utilizar el token
# vemos el pod desplegado
➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
deployment-test-79bb7486b-cnx7s 1/1 Running 0 8m16s
# verificamos que se a asignado bien el SA al Pod
➜ kubectl get pod deployment-test-79bb7486b-cnx7s -o yaml
...
serviceAccount: my-sa
serviceAccountName: my-sa
...
# entramos en el pod y utilizar el token haciendo una consulta a la api.
➜ kubectl exec -it deployment-test-79bb7486b-cnx7s -- sh
/ # apk add curl
/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -H "Authorization: Bearer ${TOKEN}" https://kubernetes/api/v1/namespaces/default/pods --insecure
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/default/pods",
"resourceVersion": "430633"
},
"items": [
{
"metadata": {
"name": "deployment-test-79bb7486b-cnx7s",
"generateName": "deployment-test-79bb7486b-",
...