Kubernetes: Cómo gestionar autorización de recursos con RBAC (Parte 2) #docker #kubernetes
Continuamos con nuestro artículo sobre Kubernetes y RBAC justo donde lo dejamos en la primera parte (jugando con los espacios de nombres), así que echa un vistazo al anterior post para repasar y manos a la obra. Ahora vamos a centrarnos en la creación de roles y su asociación a diferentes usuarios y grupos.
En este ejemplo, que vamos a usar de base para explicar sus componentes, podemos ver un fichero de creación de un role para tener control total total al espacio de nombres de cybercaronte (luego veremos como se crea):
Lo siguiente es definir las reglas (rules). En este case vemos como tenemos entradas bajo rules:
Ahora sí, vamos a crear los dos roles, uno para el espacio de nombres cybercaronte:
Primero vamos a asignar al usuario cybercaronte el role cybercaronte-full-control. Para ello creamos un fichero (cybercaronte-fullcontrol-binding.yaml) con el siguiente contenido
kubectl config use-context cybercaronte kubectl get pods -n cybercaronte No resources found.
Como podemos ver esta vez no recibimos ningún error. Si intentamos consultar los pods del espacio de nombres tuxotron:
Figura 6: Kubernetes: Cómo gestionar autorización de recursos con RBAC (Parte 2) |
En este ejemplo, que vamos a usar de base para explicar sus componentes, podemos ver un fichero de creación de un role para tener control total total al espacio de nombres de cybercaronte (luego veremos como se crea):
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: cybercaronte-full-control namespace: cybercaronte rules: - apiGroups: [""] resources: ["*"] verbs: ["*"]Como todo objeto en Kubernetes, vemos como en este caso tenemos definidos los atributos kind, apiVersion y metadata. Ojo a este caso, como estamos creando un role, tenemos que especificar el espacio de nombres donde queremos crearlo con el atributo namespace dentro de metadata.
Figura 7: Proceso de arranque de minikube |
Lo siguiente es definir las reglas (rules). En este case vemos como tenemos entradas bajo rules:
• apiGroups: aquí especificamos la(s) API(s) que queremos autorizar. Si lo dejamos vacío (""), implica que dicha regla (rule), se aplica a las APIs core de Kubernetes. Alguno de los grupos disponibles, además del core, son: extensions, apps, etc. Si quieres ver todas las APIs disponible en tu clúster, puedes ejecutar el siguiente comando:
kubectl api-versions
• resources: aquí, si queremos aplicar la regla a todos los dispositivos, podemos poner un asterisco, o bien listar los recursos que deseamos. Por ejempo: pods, secrets, configmaps, deployments, services, etc.
• verbs: en Kubernetes el recibe todas las peticiones es el component API Server, que no es ni más ni menos que un servicio Rest. Por lo que toda petición se basa en un recurso y un verbo: GET, POST, PUT, etc. En el caso de Kubernetes, éste define su propia lista de verbos como son: get, list, watch, create, update, patch, delete, bind, etcetera.Si creamos ese role y se lo asignamos a un usuario, dicho usuario prácticamente tendría control total sobre el espacio de nombres donde dicho role es creado. Un apunte importante es que podemos añadir varias reglas a un role:
rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: ["batch", "extensions"] resources: ["jobs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]En este caso, tenemos dos reglas, la primera indica que podemos leer, listar y observar pods a través del uso de cualquier API de Kubernetes. La segunda indica que podemos obtener, listar, observar, crear, actualizar, parchear y borrar recursos del tipo (Kind) job definidos bajo las APIs batch y extensions.
Ahora sí, vamos a crear los dos roles, uno para el espacio de nombres cybercaronte:
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: cybercaronte-full-control namespace: cybercaronte rules: - apiGroups: [""] resources: ["*"] verbs: ["*"]Y otro para el espacio de nombres tuxotron:
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: tuxotron-full-control namespace: tuxotron rules: - apiGroups: [""] resources: ["*"] verbs: ["*"]Creamos dos ficheros (cybercaronte-fullcontrol-role.yaml y tuxotron-fullcontrol-role.yaml) con dicho contenido y ejecuta:
kubectl apply -f cybercaronte-fullcontrol-role.yaml kubectl apply -f tuxotron-fullcontrol-role.yamlPara comprobar que los roles se han creado:
kubectl get role -n cybercaronte kubectl get role -n tuxotronAhora que tenemos los usuarios y los roles creados, tenemos que asignarles los roles a los usuarios. Para ello necesitamos crear los objectos RoleBinding.
Primero vamos a asignar al usuario cybercaronte el role cybercaronte-full-control. Para ello creamos un fichero (cybercaronte-fullcontrol-binding.yaml) con el siguiente contenido
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: full-control namespace: cybercaronte subjects: - kind: User name: cybercaronte apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: cybercaronte-full-control apiGroup: rbac.authorization.k8s.ioCrea el RoleBinding:
kubectl apply -f cybercaronte-fullcontrol-binding.yamlPara probar si funciona, cambiemos de contexto a cybercaronte y a ver si ahora podemos consultar los pods del espacio de nombres cybercaronte:
kubectl config use-context cybercaronte kubectl get pods -n cybercaronte No resources found.
kubectl get pods -n tuxotron Error from server (Forbidden): pods is forbidden: User "cybercaronte" cannot list resource "pods" in API group "" in the namespace "tuxotron"Vemos como recibimos un error porque el usuario cybercaronte no tiene acceso a los pods del espacio de nombres tuxotron.
Figura 8: Rafael Troncoso (tuxotron), Chema Alonso (sujetando el libro Docker:SecDevOps), Elías Grande y Fran Ramírez (cybercaronte) en la RootedCon 2019. Al fondo, el poster del "Profesor Alonso" de Cels Piñol. |
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: full-control namespace: tuxotron subjects: - kind: User name: tuxotron apiGroup: rbac.authorization.k8s.io roleRef: - kind: Role name: tuxotron-full-control apiGroup: rbac.authorization.k8s.ioAntes de poder crear este RoleBinding tenemos que cambiar de contexto a minikube primero:
kubectl config use-context minikube kubectl apply -f tuxotron-fullcontrol-binding.yaml
Vamos a explicar un poco la estructura de este objeto. Lo primero a recalcar es el nombre (metadata.name), si te fijas bien en los dos RoleBindings que hemos creado usan exactamente el mismo nombre. Esto es posible, porque los RoleBindings pertenecen a un nombre de espacio, y en nuestro ejemplo hemos creado cada RoleBidning en distintos espacios de nombre. Si hubiéramos usado el CLusterRoleBinding, esto no sería posible porque en ese caso habría un conflicto de nombres.
El apartado subjects es donde decimos a quién la vamos a asignar el role. El atributo Kind debe ser User, Group o ServiceAccount. Luego tenemos name, éste corresponde al nombre de usuario, grupo o cuenta de servicio y por último el apiGroup que es rbac.authorization.k8s.io
Luego tenemos el apartado roleRef. Aquí es dónde especificamos el role que queremos asignar. El atributo Kind define el tipo de role: Role o ClusterRole. Name es el nombre del role en sí y finalmente el apiGroup que al igual que el caso anterior es rbac.authorization.k8s.io
Por último, veamos un ejemplo donde daremos acceso al espacio de nombres equipo al grupo developers. Vamos a crear un role a nivel de clúster para dar acceso total sobre pods, deployments, servicios, replicasets y secretos:
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: full-control rules: - apiGroups: ["extensions", "apps", ""] resources: ["pods", "deployments", "secrets", "services", "replicasets"] verbs: ["*"]Copiamos el contenido a un fichero (developers-role.yaml) y ejecuta el siguiente comando:
kubectl apply -f developers-role.yamlUn par de apuntes sobre este fichero. Lo primero es que el tipo (Kind) es ClusterRole y como vemos no tiene especificado el espacio de nombres (namespace). Este es un objeto global del clúster. Ahora creemos otro fichero (developers-binding.yaml) con el siguiente contenido:
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: full-control namespace: equipo subjects: - kind: Group name: developers apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: full-control apiGroup: rbac.authorization.k8s.io
Como vemos, el contenido de este fichero es similar a los anteriores, con par de diferencias. En el apartado subjects, usamos el tipo Group, porque estamos asignando el role a un grupo y no a un usuario. Y en el apartado roleRef, el tipo es ClusterRole y no Role, ya que el role al que estamos haciendo referencia es del tipo ClusterRole. Para crear dicho RoleBinding:
kubectl apply -f developers-binding.yaml
Recuerda que cuando creamos los usuarios, ambos los creamos bajo la organización developers `/O=developers`. Por lo tanto, cybercaronte y tuxotron deberían tener acceso a los pods, servicios, secretos, replicasets y deployments del espacio de nombres. Comprobemos que cybercaronte tiene acceso:
kubectl config use-context cybercaronteSwitched to context "cybercaronte". kubectl get pod -n equipo No resources found. kubectl get deployment -n equipo No resources found. kubectl get configmap -n equipo Error from server (Forbidden): configmaps is forbidden: User "cybercaronte" cannot list resource "configmaps" in API group "" in the namespace "equipo"
Como hemos podido comprobar, cuando consultamos los pods y los deployments no recibimos ningún error. “No resources found” es porque no hemos creado nada en el espacio de nombres. Cuando consultamos los configmaps vemos que recibimos un error, ya que ese recurso no tenemos acceso. Si hacemos las mismas pruebas con el usuario tuxotron, los resultados deberían ser el mismo.
Figura 9: Kubernetes: Cómo gestionar autorización de recursos con RBAC [Parte 2]
Esperamos que te hayas animado a llegar al final de este artículo y por lo menos tengas suficiente información para entender como funciona el RBAC en Kubernetes. Os dejamos por aquí también algunas de las referencias que tenemos sobre Docker escritas ya en este blog, para que tengáis toda la información disponible y accesible.
[BlogPost] SecDevOps: Una explicación en 5 minutos (o poco más)
[BlogPost] Cómo montar un entorno de pentesting desde cero en Docker
[BlogPost] SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus apps
[BlogPost] Docker Distroless Images: Cómo crear imágenes Docker sin SO ni shell
[BlogPost] Dagda Docker Security Suite: Auditoría de seguridad en aplicaciones dockerizadas
[BlogPost] Docker de My WordPress in Paranoid Mode
[BlogPost] Docker de My WordPress in Paranoid Mode (WPM): "The Making of"
[BlogPost] Hacking Kubernetes: Auditoría de seguridad y explotación de vulnerabilidades
[BlogPost] Kubernetes: Cómo gestionar autorización de recursos con RBAC
Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.
Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.
1 comentario:
hola estimados. yo he instalado k8 con un user "x", mi duda es como logro que el server API no me rechace si intento usar kubectl con otro usuario de Linux. Este user adicional lo use a traves de esta guia y la numero uno.
Gracias¡¡¡
Publicar un comentario