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.

  1. 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"
  1. 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
  1. 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 enlazar
  • roleRef 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-",
...