jueves, julio 04, 2019

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.

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/pause
Guardamos ese contenido en un fichero llamado pause-pod.yaml y ejecutamos:
    kubectl apply -f pause-pod.yaml
Ahora comprobemos si el pod se ha creado:
    kubectl get po
Perfecto. Ahora a crear un deployment con la imagen de nginx:
    kubectl run nginx --image nginx
Veamos 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          3m
Vemos 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: false
cr-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:
      - restricted
Y 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: default
Creamos los objetos:
    kubectl apply -f psp-restricted.yaml
                  -f cr-restricted.yaml
                  -f rb-default-restricted.yaml
Ahora 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            1h
Como 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: demoappv1
La clave de este deployment es:
    securityContext:
      runAsUser: 1000
Esta 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           3h
Como 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ón
• 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
Finalmente 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.

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