Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (Parte 3 de 3)
Vamos a terminar este artículo de Cómo gestionar la política de seguridad de los pods en Kubernetes "like a boss" que empezamos hace un par de días con una serie de ejemplos. Esta última entrega haremos supuestos y los iremos configurando uno a uno. Al final del artículo, como en la parte anterior, tendréis un pequeño vídeo con todos los ejercicios realizados.
Para comenzar, estando el sistema tal y como lo dejamos en la anterior parte de esta serie de posts, vamos a intentar crear el siguiente pod:
Lo que pasa que nosotros le dimos a los usuarios del grupo kube-system los permisos para crear pods, por eso cuando creamos anteriormente el pod pause, se creó sin problemas, porque estamos ejecutando los comandos con el usuario minikiube.
En el caso del deployment, como podemos ver, se crea sin problemas, éste crea la ReplicaSet, y la ReplicaSet crea el pod, el problema está en que la ReplicaSet usa una cuenta de servicio para la creación del pod, no se crea con la cuenta minikube. Para arreglar este problema, lo que tenemos que hacer es darle permisos a dicha cuenta.
A menos que se especifique lo contrario, en Kubernetes la cuenta se servicio que se usa para correr un pod y es la cuenta de servicio por defecto existente en cada nombre de espacio (namespace) llamada default. Así que lo que vamos a hacer es crear un PodSecurityPolicy nuevo con ciertas restricciones, un role de clúster asociado a dicha PodSecurityPolicy y asignaremos (role binding) dicho role a la cuenta de servicio default en el nombre de espacio default, que es donde estamos haciendo las pruebas. Por lo tanto, tendríamos los siguientes ficheros:
Para comprobar que nuestra política de seguridad nos permite correr contenedores sin root, creamos el siguiente deployment:
Así que creemos un fichero nuevo con el contenido anterior y ejecutemos:
Figura 9: Ejemplos de gestión de seguidad de pods
Como se puede ver la cantidad de combinaciones que se pueden hacer con las opciones que tenemos disponibles son enormes, y te permiten especificar políticas de seguridad muy concretas. Aquí os hemos mostrado algunos ejemplos sencillos, pero la idea es la misma para casos más complejos. En resumen:
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.
Happy Hacking Hackers!!!
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.
**************************************************************************************************
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (1 de 3)
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (2 de 3)
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (3 de 3)
**************************************************************************************************
Figura 8: Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (Parte 3 de 3) |
Para comenzar, estando el sistema tal y como lo dejamos en la anterior parte de esta serie de posts, vamos a intentar crear el siguiente pod:
apiVersion: v1 kind: Pod metadata: name: pause spec: containers: - name: pause image: k8s.gcr.io/pauseGuardamos ese contenido en un fichero llamado pause-pod.yaml y ejecutamos:
kubectl apply -f pause-pod.yamlAhora comprobemos si el pod se ha creado:
kubectl get poPerfecto. Ahora a crear un deployment con la imagen de nginx:
kubectl run nginx --image nginxVeamos si se han creado el deployment, la ReplicaSet y el pod:
kubectl get deployment,rs,po NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/nginx 1 0 0 0 1m NAME DESIRED CURRENT READY AGE rs/nginx-7bb7cd8db5 1 0 0 1m NAME READY STATUS RESTARTS AGE po/pause 1/1 Running 0 3mVemos el deployment, la ReplicaSet, pero el único pod que vemos es el que creamos anteriormente, no el nginx. Vamos a ver que ocurre con la ReplicaSet:
kubectl describe rs nginx-7bb7cd8db5 ... ... Events: Type Reason Age From ---- ------ ---- ---- Warning FailedCreate 9s (x16 over 2m) replicaset-controller
Message ------- Error creating: pods "nginx-7bb7cd8db5-" is forbidden:
unable to validate against any pod security policy: []¿Qué ocurre aquí?
Lo que pasa que nosotros le dimos a los usuarios del grupo kube-system los permisos para crear pods, por eso cuando creamos anteriormente el pod pause, se creó sin problemas, porque estamos ejecutando los comandos con el usuario minikiube.
En el caso del deployment, como podemos ver, se crea sin problemas, éste crea la ReplicaSet, y la ReplicaSet crea el pod, el problema está en que la ReplicaSet usa una cuenta de servicio para la creación del pod, no se crea con la cuenta minikube. Para arreglar este problema, lo que tenemos que hacer es darle permisos a dicha cuenta.
A menos que se especifique lo contrario, en Kubernetes la cuenta se servicio que se usa para correr un pod y es la cuenta de servicio por defecto existente en cada nombre de espacio (namespace) llamada default. Así que lo que vamos a hacer es crear un PodSecurityPolicy nuevo con ciertas restricciones, un role de clúster asociado a dicha PodSecurityPolicy y asignaremos (role binding) dicho role a la cuenta de servicio default en el nombre de espacio default, que es donde estamos haciendo las pruebas. Por lo tanto, tendríamos los siguientes ficheros:
psp-restricted.yaml:
apiVersion: extensions/v1beta1 kind: PodSecurityPolicy metadata: name: restricted labels: addonmanager.kubernetes.io/mode: EnsureExists spec: privileged: false allowPrivilegeEscalation: false requiredDropCapabilities: - ALL volumes: - 'configMap' - 'emptyDir' - 'projected' - 'secret' - 'downwardAPI' - 'persistentVolumeClaim' hostNetwork: false hostIPC: false hostPID: false runAsUser: rule: 'MustRunAsNonRoot' seLinux: rule: 'RunAsAny' supplementalGroups: rule: 'MustRunAs' ranges: # Forbid adding the root group. - min: 1 max: 65535 fsGroup: rule: 'MustRunAs' ranges: # Forbid adding the root group. - min: 1 max: 65535 readOnlyRootFilesystem: falsecr-restricted.yaml:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: psp:restricted labels: addonmanager.kubernetes.io/mode: EnsureExists rules: - apiGroups: ['extensions'] resources: ['podsecuritypolicies'] verbs: ['use'] resourceNames: - restrictedY rb-default-restricted.yaml:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: default:restricted namespace: default labels: addonmanager.kubernetes.io/mode: EnsureExists roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: psp:restricted subjects: - kind: ServiceAccount name: default namespace: defaultCreamos los objetos:
kubectl apply -f psp-restricted.yaml
-f cr-restricted.yaml
-f rb-default-restricted.yamlAhora creemos un deployment nuevo y comprobemos el estado de los pods:
kubectl run nginx2 --image nginx kubectl get po NAME READY STATUS RESTARTS AGE nginx2-5746fc444c-gjd58 0/1 CreateContainerConfigError 0 31s pause 1/1 Running 0 1hComo se puede observar, esta vez se ha creado el pod, pero vemos que hay un error. Veamos qué ocurre:
kubectl describe po nginx2-5746fc444c-gjd58 ... ... Error: container has runAsNonRoot and image will run as root ...Vemos que ahora Kubernetes dice que la imagen quiere correr como root, pero el contenedor debe correr como no root. Esto es porque si nos fijamos en la política de seguridad que acabamos de crear y asignar a la cuenta de servicio default hemos especificado:
... runAsUser: rule: 'MustRunAsNonRoot' ...Así que el controlador de admisión no admite este pod. El problema con la imagen nginx por defecto necesita correr como root. Si intentamos correr el pod como no root, obtendremos otro error durante la ejecución del contenedor por problemas de permiso dentro del propio contenedor.
Para comprobar que nuestra política de seguridad nos permite correr contenedores sin root, creamos el siguiente deployment:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: demoappv1 namespace: default spec: replicas: 1 selector: matchLabels: run: demoapp strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate template: metadata: labels: run: demoapp spec: securityContext: runAsUser: 1000 containers: - image: tuxotron/demoapp:v1 imagePullPolicy: Always name: demoappv1La clave de este deployment es:
securityContext: runAsUser: 1000Esta es la forma en la que decimos a Kubernetes que corra el contenedor con el id usuario 1000. Si tu imagen Docker tiene definido el usuario con el comando USER, esto no sería necesario especificar un usuario aquí, a menos que quieras sobreescribir dicho valor.
Así que creemos un fichero nuevo con el contenido anterior y ejecutemos:
kubectl apply -f demoapp-depl.yaml kubectl get po NAME READY STATUS RESTARTS AGE demoappv1-588b679f8c-v6q8x 1/1 Running 0 13s pause 1/1 Running 0 3hComo se puede apreciar, nuestro ha sido creado y está corriendo. En vez de usar MustRunAsNonRoot, podríamos especificar un rango de IDs a través de MustRunAs.
Figura 9: Ejemplos de gestión de seguidad de pods
Como se puede ver la cantidad de combinaciones que se pueden hacer con las opciones que tenemos disponibles son enormes, y te permiten especificar políticas de seguridad muy concretas. Aquí os hemos mostrado algunos ejemplos sencillos, pero la idea es la misma para casos más complejos. En resumen:
• Habilita en tu clúster el controlador de admisiónFinalmente hay que mencionar que estas son políticas de seguridad de pods, que no hay que confundir con las políticas de red. Esperamos que esta pequeña guía de securización en Kubernetes os sirva como referencia para comenzar a proteger los pods.
• Crea tu política de seguridad (tantas como necesites)
• Crea tus roles asociados a dichas políticas
• Asigna dichos roles a través de RoleBinding el/los usuarios que necesites, grupos o cuentas de servicio
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.
Happy Hacking Hackers!!!
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.
**************************************************************************************************
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (1 de 3)
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (2 de 3)
- Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (3 de 3)
**************************************************************************************************
No hay comentarios:
Publicar un comentario