Simplificando Kubernetes
Día 15: Descomplicando RBAC e controle de acesso no Kubernetes
Contenido del Día 15
¿Qué vamos a aprender hoy?
Hoy hablaremos de...
RBAC
¿Qué es RBAC?
RBAC es un acrónimo que significa Control de Acceso Basado en Roles (Role-Based Access Control). Es un método de control de acceso que permite a un administrador definir permisos específicos para usuarios y grupos de usuarios. Esto significa que los administradores pueden controlar quién tiene acceso a qué recursos y qué pueden hacer con esos recursos.
En Kubernetes, es fundamental comprender cómo funciona RBAC, ya que a través de él se definen los permisos de acceso a los recursos del clúster, como quién puede crear un Pod, un Deployment, un Service, entre otros.
Primer ejemplo de RBAC
Supongamos que necesitamos dar acceso al clúster a un desarrollador de nuestra empresa, pero no queremos que tenga acceso a todos los recursos del clúster, sino solo a los recursos necesarios para desarrollar su aplicación.
Para lograrlo, crearemos un usuario llamado developer
y le daremos acceso para crear y administrar los Pods en el espacio de nombres dev
.
Existen dos formas de hacerlo. La primera y más antigua es mediante la creación de un Token de acceso, y la segunda y más nueva es mediante la creación de un usuario.
Creación de un Usuario para Acceso al clúster
Bueno, ahora que ya sabemos cuáles serán los permisos de nuestro nuevo usuario, podemos comenzar a crearlo.
Lo primero que necesitamos hacer es generar una clave privada para nuestro usuario. Para ello, utilizaremos el comando openssl
:
openssl genrsa -out developer.key 2048
Con el comando anterior, estamos creando una clave privada de 2048 bits y guardándola en el archivo developer.key
. El parámetro genrsa
indica que queremos generar una clave privada, y el parámetro -out
indica el nombre del archivo en el que queremos guardar la clave.
Una vez creada la clave, debemos generar una Solicitud de Firma de Certificado (Certificate Signing Request o CSR), que es un archivo que contiene el certificado que hemos creado y que se enviará a Kubernetes para que lo firme y genere el certificado final.
openssl req -new -key developer.key -out developer.csr -subj "/CN=developer"
En el comando anterior, estamos creando un certificado para nuestro usuario utilizando la clave privada que creamos anteriormente. El parámetro req
indica que queremos crear un certificado, el parámetro -key
indica el nombre del archivo de la clave privada que queremos utilizar, el parámetro -out
indica el nombre del archivo en el que queremos guardar el certificado, y el parámetro -subj
indica el nombre del usuario que queremos crear.
Ahora, con los dos archivos en mano, podemos comenzar a crear nuestro usuario en el clúster, pero antes, necesitamos crear una Solicitud de Firma de Certificado (Certificate Signing Request o CSR), que es un archivo que contiene el certificado que hemos creado y que se enviará a Kubernetes para que lo firme y genere el certificado final.
Pero para crear el archivo, primero debemos tener el contenido del certificado en base64. Para ello, utilizaremos el comando base64
:
cat developer.csr | base64 | tr -d '\n'
Con el comando anterior, estamos leyendo el contenido del archivo developer.csr
, convirtiéndolo a base64 y eliminando el salto de línea.
El contenido del certificado en base64 será algo similar a esto:
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwCgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K%
Recuerda eliminar el salto de línea al final del archivo, que se representa con el %
.
Agora que tenemos el contenido del certificado en base64, cópielo y péguelo en el archivo developer.yaml
que vamos a crear a continuación:
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: developer
spec:
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 31536000 # 1 year
usages:
- client auth
En el archivo anterior, estamos definiendo la siguiente información:
apiVersion
: La versión de la API que estamos utilizando para crear nuestro usuario.kind
: El tipo de recurso que estamos creando, en este caso, una Solicitud de Firma de Certificado (CSR).metadata.name
: El nombre de nuestro usuario.spec.request
: El contenido del certificado en base64.spec.signerName
: El nombre del firmante del certificado, que en este caso es el kube-apiserver, que será responsable de firmar nuestro certificado.spec.expirationSeconds
: El tiempo de cad
ucidad del certificado, que en este caso es de 1 año.
spec.usages
: El tipo de uso del certificado, que en este caso esclient auth
(autenticación de cliente).
Una vez que haya creado este archivo y copiado el contenido del certificado en base64, puede aplicar el recurso utilizando el siguiente comando:
kubectl apply -f developer.yaml
Esto enviará la solicitud de firma de certificado al clúster Kubernetes para que sea firmada y se genere el certificado final para el usuario "developer".
kubectl apply -f developer.yaml
Vamos listar los CSR del clúster para ver el estado de nuestro usuario:
kubectl get csr
El resultado será algo similar a esto:
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-4zd8k 15m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-68wsv 15m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-jkm8t 15m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-r2hcr 15m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-x52kj 15m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
developer 3s kubernetes.io/kube-apiserver-client kubernetes-admin 365d Pending
Observe que nuestro usuario tiene el estado Pending
porque el kube-apiserver aún no ha firmado nuestro certificado. Puede seguir el estado de su usuario con el siguiente comando:
kubectl describe csr developer
El resultado será algo similar a esto:
Name: developer
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"developer"},"spec":{"expirationSeconds":31536000,"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}}
CreationTimestamp: Wed, 31 Jan 2024 11:52:24 +0100
Requesting User: kubernetes-admin
Signer: kubernetes.io/kube-apiserver-client
Requested Duration: 365d
Status: Pending
Subject:
Common Name: developer
Serial Number:
Events: <none>
Hasta ahora todo va bien, ahora debemos aprobar nuestro certificado utilizando el comando kubectl certificate approve
:
kubectl certificate approve developer
Ahora vamos listar los CSR (Solicitudes de firma de certificado) del clúster nuevamente:
kubectl get csr
El resultado será algo parecido a esto:
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-4zd8k 17m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-68wsv 17m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-jkm8t 17m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-r2hcr 17m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
csr-x52kj 16m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:abcdef <none> Approved,Issued
developer 88s kubernetes.io/kube-apiserver-client kubernetes-admin 365d Approved,Issued
Listo, nuestro certificado ha sido firmado con éxito. Ahora podemos obtener el certificado de nuestro usuario y guardarlo en un archivo. Para ello, utilizaremos el comando kubectl get csr
:
kubectl get csr developer -o jsonpath='{.status.certificate}' | base64 --decode > developer.crt
En el comando anterior, estamos obteniendo el certificado de nuestro usuario, decodificándolo en base64 y guardándolo en el archivo developer.crt
.
Para obtener el certificado, estamos utilizando el parámetro -o jsonpath='{.status.certificate}'
para que el comando devuelva solo el certificado del usuario y no toda la información del CSR.
Puede verificar el contenido del certificado mediante el comando:
cat developer.crt
Ahora tenemos nuestro certificado final creado y podemos utilizarlo para acceder al clúster, pero antes debemos definir lo que nuestro usuario puede hacer en el clúster.
Creando un Rol para nuestro usuario
Cuando creamos un nuevo usuario o ServiceAccount en Kubernetes, no tiene acceso a nada en el clúster. Para que pueda acceder a los recursos del clúster, debemos crear un Rol y asociarlo al usuario.
La definición de un Rol consiste en un archivo donde especificamos qué permisos tendrá el usuario en el clúster y para qué recursos tendrá acceso. Dentro del Rol es donde definimos:
- En qué espacio de nombres (namespace) tendrá acceso el usuario.
- A qué grupos de API (apiGroups) tendrá acceso el usuario.
- A qué recursos tendrá acceso el usuario.
- A qué verbos tendrá acceso el usuario.
apiGroups
Los grupos de API (apiGroups) son los grupos de recursos de Kubernetes, que se dividen en core
y named
. Puede consultar todos los grupos de recursos de Kubernetes mediante el comando kubectl api-resources
.
Veamos la lista de grupos de recursos de Kubernetes:
kubectl api-resources
La lista es larga, pero el resultado será algo similar a esto:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
customresourcedefinitions crd,crds apiextensions.k8s.io/v1 false CustomResourceDefinition
apiservices apiregistration.k8s.io/v1 false APIService
controllerrevisions apps/v1 true ControllerRevision
daemonsets ds apps/v1 true DaemonSet
deployments deploy apps/v1 true Deployment
replicasets rs apps/v1 true ReplicaSet
statefulsets sts apps/v1 true StatefulSet
tokenreviews authentication.k8s.io/v1 false TokenReview
localsubjectaccessreviews authorization.k8s.io/v1 true LocalSubjectAccessReview
selfsubjectaccessreviews authorization.k8s.io/v1 false SelfSubjectAccessReview
selfsubjectrulesreviews authorization.k8s.io/v1 false SelfSubjectRulesReview
subjectaccessreviews authorization.k8s.io/v1 false SubjectAccessReview
horizontalpodautoscalers hpa autoscaling/v2 true HorizontalPodAutoscaler
cronjobs cj batch/v1 true CronJob
jobs batch/v1 true Job
certificatesigningrequests csr certificates.k8s.io/v1 false CertificateSigningRequest
leases coordination.k8s.io/v1 true Lease
endpointslices discovery.k8s.io/v1 true EndpointSlice
events ev events.k8s.io/v1 true Event
flowschemas flowcontrol.apiserver.k8s.io/v1beta3 false FlowSchema
prioritylevelconfigurations flowcontrol.apiserver.k8s.io/v1beta3 false PriorityLevelConfiguration
ingressclasses networking.k8s.io/v1 false IngressClass
ingresses ing networking.k8s.io/v1 true Ingress
networkpolicies netpol networking.k8s.io/v1 true NetworkPolicy
runtimeclasses node.k8s.io/v1 false RuntimeClass
poddisruptionbudgets pdb policy/v1 true PodDisruptionBudget
clusterrolebindings rbac.authorization.k8s.io/v1 false ClusterRoleBinding
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole
rolebindings rbac.authorization.k8s.io/v1 true RoleBinding
roles rbac.authorization.k8s.io/v1 true Role
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
csidrivers storage.k8s.io/v1 false CSIDriver
csinodes storage.k8s.io/v1 false CSINode
csistoragecapacities storage.k8s.io/v1 true CSIStorageCapacity
storageclasses sc storage.k8s.io/v1 false StorageClass
volumeattachments storage.k8s.io/v1 false VolumeAttachment
Donde la primera columna es el nombre del recurso, la segunda columna es el nombre abreviado del recurso, la tercera columna es la versión de la API a la que pertenece el recurso, la cuarta columna indica si el recurso se encuentra o no en un espacio de nombres (Namespaced), y la quinta columna es el tipo de recurso.
Echemos un vistazo a un recurso específico, por ejemplo, el recurso pods
:
kubectl api-resources | grep pods
El resultado será algo similar a esto:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
pods po v1 true Pod
Donde:
NAME
: Nombre del recurso.SHORTNAMES
: Nombre abreviado del recurso.APIVERSION
: Versión de la API a la que pertenece el recurso.NAMESPACED
: Indica si el recurso se encuentra o no en un espacio de nombres.KIND
: Tipo de recurso.
Pero, ¿qué significa que un recurso esté en un espacio de nombres (Namespaced)? Un recurso Namespaced es un recurso que puede crearse dentro de un espacio de nombres (namespace), por ejemplo, un Pod, un Deployment, un Service, etc. Por otro lado, un recurso que no es Namespaced es un recurso que no puede crearse dentro de un espacio de nombres, como un Nodo (Node), un Volumen Persistente (PersistentVolume), un ClusterRole, etc. ¿Sencillo, verdad?
Ahora bien, ¿cómo sabemos cuál es el apiGroup de un recurso? El apiGroup de un recurso es el nombre del grupo de recursos al que pertenece. Por ejemplo, el recurso pods
pertenece al grupo de recursos core
, y el recurso deployments
pertenece al grupo de recursos apps
. Cuando un recurso es de tipo core
, no es necesario especificar su apiGroup, ya que Kubernetes asume automáticamente que pertenece al grupo de recursos core
, y esto se refleja en apiVersion: v1
.
Por otro lado, apiVersion: apps/v1
indica que el recurso pertenece al grupo de recursos apps
, y su versión de API es v1
. Dentro del grupo apps
, encontramos recursos importantes como deployments
, replicasets
, daemonsets
, statefulsets
, entre otros.
Los recursos son las entidades que Kubernetes administra y gestiona. Estos recursos se dividen en dos categorías principales: core
y named
. Puede consultar todos los recursos de Kubernetes utilizando el comando kubectl api-resources
.
Los recursos denominados core
son recursos predefinidos que vienen instalados con Kubernetes. Por otro lado, los recursos denominados named
son recursos que se instalan mediante Custom Resource Definitions (CRD), como por ejemplo, el recurso ServiceMonitor
utilizado por Prometheus.
A continuación, listaremos los recursos de Kubernetes que no están en un espacio de nombres (non-namespaced):
kubectl api-resources --namespaced=false
El resultado será similar a lo siguiente:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
componentstatuses cs v1 false ComponentStatus
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumes pv v1 false PersistentVolume
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
customresourcedefinitions crd,crds apiextensions.k8s.io/v1 false CustomResourceDefinition
apiservices apiregistration.k8s.io/v1 false APIService
tokenreviews authentication.k8s.io/v1 false TokenReview
selfsubjectaccessreviews authorization.k8s.io/v1 false SelfSubjectAccessReview
selfsubjectrulesreviews authorization.k8s.io/v1 false SelfSubjectRulesReview
subjectaccessreviews authorization.k8s.io/v1 false SubjectAccessReview
certificatesigningrequests csr certificates.k8s.io/v1 false CertificateSigningRequest
flowschemas flowcontrol.apiserver.k8s.io/v1beta3 false FlowSchema
prioritylevelconfigurations flowcontrol.apiserver.k8s.io/v1beta3 false PriorityLevelConfiguration
ingressclasses networking.k8s.io/v1 false IngressClass
runtimeclasses node.k8s.io/v1 false RuntimeClass
clusterrolebindings rbac.authorization.k8s.io/v1 false ClusterRoleBinding
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
csidrivers storage.k8s.io/v1 false CSIDriver
csinodes storage.k8s.io/v1 false CSINode
storageclasses sc storage.k8s.io/v1 false StorageClass
volumeattachments storage.k8s.io/v1 false VolumeAttachment
De esta manera, podemos identificar cuáles son los recursos nativos de Kubernetes y cuáles son los recursos instalados a través de CRD (Definiciones de Recursos Personalizados, por sus siglas en inglés), como por ejemplo, ServiceMonitor
de Prometheus.
Por lo tanto, el nombre del recurso es el nombre que utilizamos para crear el recurso, como por ejemplo, pods
, deployments
, services
, etc.
Verbos
Los verbos definen las acciones que un usuario puede realizar en un recurso determinado. Por ejemplo, los verbos pueden incluir crear, listar, actualizar, eliminar, etc.
Para que pueda ver los verbos que se pueden utilizar, vamos a utilizar el comando kubectl api-resources
con la opción -o wide
:
kubectl api-resources -o wide
El resultado se verá similar a esto:
NAME SHORTNAMES APIVERSION NAMESPACED KIND VERBS CATEGORIES
bindings v1 true Binding create
componentstatuses cs v1 false ComponentStatus get,list
configmaps cm v1 true ConfigMap create,delete,deletecollection,get,list,patch,update,watch
endpoints ep v1 true Endpoints create,delete,deletecollection,get,list,patch,update,watch
events ev v1 true Event create,delete,deletecollection,get,list,patch,update,watch
limitranges limits v1 true LimitRange create,delete,deletecollection,get,list,patch,update,watch
namespaces ns v1 false Namespace create,delete,get,list,patch,update,watch
nodes no v1 false Node create,delete,deletecollection,get,list,patch,update,watch
persistentvolumeclaims pvc v1 true PersistentVolumeClaim create,delete,deletecollection,get,list,patch,update,watch
persistentvolumes pv v1 false PersistentVolume create,delete,deletecollection,get,list,patch,update,watch
pods po v1 true Pod create,delete,deletecollection,get,list,patch,update,watch all
podtemplates v1 true PodTemplate create,delete,deletecollection,get,list,patch,update,watch
replicationcontrollers rc v1 true ReplicationController create,delete,deletecollection,get,list,patch,update,watch all
resourcequotas quota v1 true ResourceQuota create,delete,deletecollection,get,list,patch,update,watch
secrets v1 true Secret create,delete,deletecollection,get,list,patch,update,watch
serviceaccounts sa v1 true ServiceAccount create,delete,deletecollection,get,list,patch,update,watch
services svc v1 true Service create,delete,deletecollection,get,list,patch,update,watch all
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration create,delete,deletecollection,get,list,patch,update,watch api-extensions
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration create,delete,deletecollection,get,list,patch,update,watch api-extensions
customresourcedefinitions crd,crds apiextensions.k8s.io/v1 false CustomResourceDefinition create,delete,deletecollection,get,list,patch,update,watch api-extensions
apiservices apiregistration.k8s.io/v1 false APIService create,delete,deletecollection,get,list,patch,update,watch api-extensions
controllerrevisions apps/v1 true ControllerRevision create,delete,deletecollection,get,list,patch,update,watch
daemonsets ds apps/v1 true DaemonSet create,delete,deletecollection,get,list,patch,update,watch all
deployments deploy apps/v1 true Deployment create,delete,deletecollection,get,list,patch,update,watch all
replicasets rs apps/v1 true ReplicaSet create,delete,deletecollection,get,list,patch,update,watch all
statefulsets sts apps/v1 true StatefulSet create,delete,deletecollection,get,list,patch,update,watch all
tokenreviews authentication.k8s.io/v1 false TokenReview create
localsubjectaccessreviews authorization.k8s.io/v1 true LocalSubjectAccessReview create
selfsubjectaccessreviews authorization.k8s.io/v1 false SelfSubjectAccessReview create
selfsubjectrulesreviews authorization.k8s.io/v1 false SelfSubjectRulesReview create
subjectaccessreviews authorization.k8s.io/v1 false SubjectAccessReview create
horizontalpodautoscalers hpa autoscaling/v2 true HorizontalPodAutoscaler create,delete,deletecollection,get,list,patch,update,watch all
cronjobs cj batch/v1 true CronJob create,delete,deletecollection,get,list,patch,update,watch all
jobs batch/v1 true Job create,delete,deletecollection,get,list,patch,update,watch all
certificatesigningrequests csr certificates.k8s.io/v1 false CertificateSigningRequest create,delete,deletecollection,get,list,patch,update,watch
leases coordination.k8s.io/v1 true Lease create,delete,deletecollection,get,list,patch,update,watch
endpointslices discovery.k8s.io/v1 true EndpointSlice create,delete,deletecollection,get,list,patch,update,watch
events ev events.k8s.io/v1 true Event create,delete,deletecollection,get,list,patch,update,watch
flowschemas flowcontrol.apiserver.k8s.io/v1beta3 false FlowSchema create,delete,deletecollection,get,list,patch,update,watch
prioritylevelconfigurations flowcontrol.apiserver.k8s.io/v1beta3 false PriorityLevelConfiguration create,delete,deletecollection,get,list,patch,update,watch
ingressclasses networking.k8s.io/v1 false IngressClass create,delete,deletecollection,get,list,patch,update,watch
ingresses ing networking.k8s.io/v1 true Ingress create,delete,deletecollection,get,list,patch,update,watch
networkpolicies netpol networking.k8s.io/v1 true NetworkPolicy create,delete,deletecollection,get,list,patch,update,watch
runtimeclasses node.k8s.io/v1 false RuntimeClass create,delete,deletecollection,get,list,patch,update,watch
poddisruptionbudgets pdb policy/v1 true PodDisruptionBudget create,delete,deletecollection,get,list,patch,update,watch
clusterrolebindings rbac.authorization.k8s.io/v1 false ClusterRoleBinding create,delete,deletecollection,get,list,patch,update,watch
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole create,delete,deletecollection,get,list,patch,update,watch
rolebindings rbac.authorization.k8s.io/v1 true RoleBinding create,delete,deletecollection,get,list,patch,update,watch
roles rbac.authorization.k8s.io/v1 true Role create,delete,deletecollection,get,list,patch,update,watch
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass create,delete,deletecollection,get,list,patch,update,watch
csidrivers storage.k8s.io/v1 false CSIDriver create,delete,deletecollection,get,list,patch,update,watch
csinodes storage.k8s.io/v1 false CSINode create,delete,deletecollection,get,list,patch,update,watch
csistoragecapacities storage.k8s.io/v1 true CSIStorageCapacity create,delete,deletecollection,get,list,patch,update,watch
storageclasses sc storage.k8s.io/v1 false StorageClass create,delete,deletecollection,get,list,patch,update,watch
volumeattachments storage.k8s.io/v1 false VolumeAttachment create,delete,deletecollection,get,list,patch,update,watch
Ahora, observe que tenemos una nueva columna llamada VERBS
, que contiene todos los verbos que se pueden utilizar con el recurso, y la columna CATEGORIES
, que muestra la categoría del recurso. Sin embargo, nuestro enfoque aquí está en los verbos, así que echemos un vistazo a ellos.
Los verbos se dividen en:
create
: Permite que el usuario cree un recurso.delete
: Permite que el usuario elimine un recurso.deletecollection
: Permite que el usuario elimine una colección de recursos.get
: Permite que el usuario obtenga un recurso.list
: Permite que el usuario liste los recursos.patch
: Permite que el usuario actualice un recurso.update
: Permite que el usuario actualice un recurso.watch
: Permite que el usuario siga los cambios en un recurso.
Por ejemplo, tomemos la línea del recurso pods
:
NAME SHORTNAMES APIVERSION NAMESPACED KIND VERBS CATEGORIES
pods po v1 true Pod create,delete,deletecollection,get,list,patch,update,watch all
Con esto, sabemos que el usuario puede crear, eliminar, eliminar una colección, obtener, listar, actualizar y seguir los cambios en un Pod. ¡Muy sencillo!
Ahora que conocemos bien los resources
, apiGroups
y verbs
, crearemos nuestra Role para nuestro usuario.
Para ello, crearemos un archivo llamado developer-role.yaml
con el siguiente contenido:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: dev
rules:
- apiGroups: [""] # "" indica el grupo de recursos principal
resources: ["pods"]
verbs: ["get", "watch", "list", "update", "create", "delete"]
En el archivo anterior, definimos la siguiente información:
apiVersion
: Versión de la API que estamos utilizando para crear nuestro usuario.kind
: Tipo de recurso que estamos creando, en este caso, una Role.metadata.name
: Nombre de nuestra Role.metadata.namespace
: Namespace en el que se creará nuestra Role.rules
: Reglas de nuestra Role.rules.apiGroups
: Grupos de recursos a los que tendrá acceso nuestra Role.rules.resources
: Recursos a los que tendrá acceso nuestra Role.rules.verbs
: Verbos a los que tendrá acceso nuestra Role.
Estoy seguro de que le resulta fácil comprender la Role, que básicamente establece lo que nuestro usuario puede hacer en el clúster. En resumen, estamos diciendo que el usuario que utilice esta Role podrá realizar todas las operaciones con el recurso pods
en el espacio de nombres dev
. ¡Tan sencillo como volar!
Recuerde que esta Role puede ser reutilizada por otros usuarios y que puede crear tantas Roles como desee, así como crear Roles para otros perfiles de usuarios y otros recursos, como deployments
, services
, configmaps
, etc.
¡Ah, antes de continuar, creemos el espacio de nombres dev
:
kubectl create ns dev
Ahora que hemos creado nuestro archivo y el espacio de nombres, vamos a aplicarlo en el clúster:
kubectl apply -f developer-role.yaml
Para verificar si nuestra Role se ha creado correctamente, enumeremos las Roles en el clúster:
kubectl get roles -n dev
La salida será algo como:
NAME CREATED AT
developer 2024-01-31T11:32:08Z
Para ver los detalles de la Role, utilizaremos el comando kubectl describe
:
kubectl describe role developer -n dev
La salida será algo parecida a esto:
Name: developer
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list update create delete]
Listo, nuestra Role ya está creada, pero aún no la hemos asociado a nuestro usuario. Para hacerlo, crearemos un RoleBinding.
El RoleBinding es el recurso que asocia un usuario a una Role, es decir, a través del RoleBinding definimos qué usuario tiene acceso a qué Role. Puedes pensar en ello como si fuera una insignia de Desarrollador, donde la Role sería la insignia y el RoleBinding sería la insignia con el nombre del usuario. ¿Tiene sentido?
Para ello, crearemos un archivo llamado developer-rolebinding.yaml
con el siguiente contenido:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: DeveloperRoleBinding
namespace: dev
subjects:
- kind: User
name: developer
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
En el archivo anterior, estamos definiendo la siguiente información:
apiVersion
: La versión de la API que estamos utilizando para crear nuestro usuario.kind
: El tipo de recurso que estamos creando, en este caso, un RoleBinding.metadata.name
: El nombre de nuestro RoleBinding.metadata.namespace
: El espacio de nombres en el que se creará nuestro RoleBinding.subjects
: Los usuarios que tendrán acceso a la Role.subjects.kind
: El tipo de usuario, que en este caso esUser
.subjects.name
: El nombre del usuario, que en este caso esdeveloper
.roleRef
: La referencia a la Role a la que el usuario tendrá acceso.roleRef.kind
: El tipo de Role, que en este caso esRole
.roleRef.name
: El nombre de la Role, que en este caso esdeveloper
.roleRef.apiGroup
: El grupo de recursos de la Role, que en este caso esrbac.authorization.k8s.io
.
No es nada complicado, y una vez más, está muy claro lo que estamos haciendo, que es darle acceso al usuario developer
con la Role developer
en el espacio de nombres dev
.
Ahora que tenemos nuestro archivo creado, apliquémoslo:
kubectl apply -f developer-rolebinding.yaml
Para verificar si nuestro RoleBinding se creó correctamente, enumeremos los RoleBindings en el clúster:
kubectl get rolebindings -n dev
La salida será:
NAME ROLE AGE
DeveloperRoleBinding Role/developer 9s
Para ver los detalles del RoleBinding, utilizaremos el comando kubectl describe
:
kubectl describe rolebinding DeveloperRoleBinding -n dev
La salida será algo similar a esto:
Name: DeveloperRoleBinding
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: developer
Subjects:
Kind Name Namespace
---- ---- ---------
User developer
Listo, el RoleBinding se ha creado con éxito. Ahora, vamos a probar nuestro usuario.
Agregando el certificado del usuario al kubeconfig
Ahora que hemos creado con éxito nuestro usuario, debemos agregar el certificado del usuario al kubeconfig para poder acceder al clúster con nuestro usuario.
Para hacerlo, utilizaremos el comando kubectl config set-credentials
:
kubectl config set-credentials developer --client-certificate=developer.crt --client-key=developer.key --embed-certs=true
El comando kubectl config set-credentials
se utiliza para agregar un nuevo usuario al kubeconfig y recibe los siguientes parámetros:
--client-certificate
: Ruta del certificado del usuario.--client-key
: Ruta de la clave del usuario.--embed-certs
: Indica si el certificado debe incrustarse en el kubeconfig.
En nuestro caso, estamos proporcionando la ruta del certificado y la clave del usuario, y estamos indicando que el certificado debe incrustarse en el kubeconfig.
Ahora debemos crear un contexto para nuestro usuario utilizando el comando kubectl config set-context
:
kubectl config set-context developer --cluster=NOMBRE-DEL-CLÚSTER --namespace=dev --user=developer
Si no recuerdas qué es un contexto en Kubernetes, te ayudaré a recordarlo. Un contexto es un conjunto de configuraciones que define el acceso a un clúster, es decir, un contexto está compuesto por un clúster, un usuario y un espacio de nombres (namespace). Cuando creas un nuevo usuario, debes crear un nuevo contexto para él, de modo que pueda acceder al clúster.
Para obtener los nombres de los clústeres, puedes utilizar el comando kubectl config get-clusters
, de esta manera podrás obtener el nombre del clúster que deseas utilizar.
Con esto, nuestro nuevo usuario está listo para ser utilizado, pero antes verifiquemos si funciona correctamente.
Accediendo al clúster con el nuevo usuario
Una vez que hemos creado nuestro usuario y que el certificado del usuario se ha agregado al kubeconfig, y que ya tenemos un contexto para el usuario, podemos probar el acceso al clúster.
Para hacerlo, debemos cambiar al contexto del usuario utilizando el comando kubectl config use-context
:
kubectl config use-context developer