miércoles, noviembre 20, 2019

Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)

Kubernetes se está convirtiendo no sólo en el estándar para desplegar contenedores, sino también incluso en el elemento más utilizado para gestionar infraestructuras virtualizadas. Por lo tanto, la gestión de su seguridad es algo que necesitamos tener en cuenta a la hora de instalarlo. Por este motivo, ya hablamos de las políticas de seguridad de pods en una serie tres artículos centrándonos en las características de seguridad ofrecidas por Kubernetes a la hora de restringir el despliegue de pods que no cumplan con ciertos requisitos.

Figura 1: Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)

La seguridad en el mundo Docker es una prioridad, por eso escribimos el libro “Docker: SecDevOps”, el cual además de servir de iniciación a este apasionante mundo de los contenedores, hablamos de buenas prácticas de seguridad así como la posición de Docker dentro del ciclo DevOps aportando el facto de seguridad (“Sec”) para finalmente obtener un cadena SecDevOps.

Figura 2: Libro Docker: SecDevOps

En estos nuevos artículos vamos a hablar de otro componente fundamental en un despliegue de Kubernetes: Las políticas de red y su seguridad. Hablando en términos generales, las políticas de red en Kubernetes son un concepto muy sencillo, pero muy potente. En pocas palabras, una política de red nos permite establecer de una forma declarativa restricciones de comunicación entre los pods de nuestro clúster.

Antes de entrar más en detalle sobre el tema, demos un muy rápido repaso a las redes en Kubernetes. Internamente existen 4 tipos comunicación por red en Kubernetes:
· Contenedor a contenedor: los contenedores que se ejecutan dentro de un pod, comparten el mismo espacio de red del pod, es decir, dichos contenedores comparten la misma IP y se pueden comunicar a través de “localhost”, por tanto, dos contenedores que se ejecuten en un mismo pod no escuchan por el mismo puerto.
· Pod a Pod: cada pod recibe su propia dirección IP y todos los pods, por defecto, se pueden comunicar entre ellos a través de NAT.
· Servicios a Pods: los servicios en Kubernetes no son más que IP virtuales (distinto segmento de la red de pods) que pueden apuntar a cero (idealmente uno como mínimo) o más pods. Los servicios actúan más como balanceadores de carga. Estas IPs no son enrutable, es decir, no responden a “pings”.
· Tráfico externo a interno: en los tres casos anteriores hemos hablado del tráfico interno del clúster. En este caso hablamos del tráfico externo hacia dentro del clúster. Esto normalmente se consigue implementando algún tipo de balanceador de carga externo que interactúe con todos los nodos del clúster.
Una de las razones por la que Kubernetes ha ganado tanta atención, es por la posibilidad de “upgrade” o ampliación, permitiendo el reemplazo de varios de sus componentes principales, como por ejemplo el motor de contenedores (por defecto usa Docker, pero se puede reemplazar), el controlador de red, etcétera. El controlador de red en Kubernetes está basado en el proyecto CNI (Container Network Interface), el cual es más que un conjunto de especificaciones y librerías, que nos permite la implementación del componente que manejaría la red dentro de Kubernetes.

Figura 3: CNI en GitHub

Por lo tanto, nosotros podríamos crear un controlador de red e instalarlo en nuestro clúster, reemplazando el que Kubernetes use por defecto. De todas formas es posible encontrar otros proyectos que usan CNI como base para la implementación de la red.

Figura 4: Ejemplo de implementación TLS dentro de Kubernetes

Esto abre la posibilidad de escribir tus propios plugins y como es lógico, muchas empresas han escrito sus propios plugins de red para Kubernetes. Por lo tanto, y aquí viene el pequeño inconvenientes, no todos los plugins se comportan de la misma manera debido a esta variedad de implementaciones personalizadas. E incluso algunos de ellos incluso no soportan las políticas de red. Por ejemplo, AWS-CNI, el plugin de Amazon para su nube AWS, aunque éste permite ser extendido para soportar dicha características.

Ejemplos con plugins CNI

En nuestro caso, para ejecutar los ejemplos que veremos a continuación usaremos de nuevo “minikube”, el cual por defecto no soporta las políticas de red, así que instalaremos un plugin CNI llamado Cilium que sí las soporta. Cilium es un proyecto Open Source y usa Linux BPF para el filtrado de paquetes de red.

El primer paso será arrancar nuestro clúster con minikube (usaremos la versión 1.5.2 y la versión 1.16.2 de Kubernetes). Para ello, le tenemos que decir a “minikube” que vamos a usar un plugin de red basado en CNI. Además, le dedicaremos a nuestro clúster 4Gb de memoria:
minikube start --network-plugin=cni --memory=4096
Una vez esté el clúster arriba, montamos el sistema de ficheros BPF:
minikube ssh -- sudo mount bpffs -t bpf /sys/fs/bpf
Finalmente instalamos Cilium (asumimos que tienes instalado kubectl):
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml
El proceso puede tardar varios minutos. Puedes observar la creación de los componentes con el siguiente comando:
kubectl -n kube-system get pods --watch
Aquí podéis ver un vídeo con todos esos pasos.


Figura 5: Instalacion de Cilium en minikube

Como con el resto de los objetos en Kubernetes, las políticas de red pueden ser definidas en ficheros YAML. Siguiendo el mismo criterio que el resto, tenemos tres atributos que son requeridos a la hora definir nuestro fichero manifiesto:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
        name: test-network-policy
        namespace: default
    ...
    ...
En este caso apiVersion y kind serían siempre el mismo, pero el atributo metadata varía, ya que ahí es dónde especificas el nombre de la política, el nombre de espacio, etcétera. Las políticas de red se definen a nivel del nombre de espacio, así que puedes crear políticas con el mismo nombre, siempre y cuando pertenezcan a distintos espacios de nombre. Veamos un ejemplo más completo:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
        name: test-network-policy
        namespace: default
    spec:
        podSelector:
            matchLabels:
                role: db
        policyTypes:
        - Ingress
        - Egress
        ingress:
        - from:
          - ipBlock:
              cidr: 172.17.0.0/16
              except:
             - 172.17.1.0/24
          - namespaceSelector:
              matchLabels:
                project: myproject
          - podSelector:
              matchLabels:
                role: frontend
          ports:
          - protocol: TCP
            port: 6379
        egress:
        - to:
            - ipBlock:
                cidr: 10.0.0.0/24
            ports:
            - protocol: TCP
              port: 5978
Vamos a explicar especificación de este ejemplo (toda la parte que se encuentra por debajo de spec).
· podSelector: se especifica la selección de pods a los que la política de red será aplicada. Si el podSelector se define como vacío {}, la política se aplica a todos los pods. 
· policyTypes: actualmente acepta dos valores Ingress (tráfico de entrada) y Egress (tráfico de salida). Si no se especifica este atributo, el valor por defecto es Ingress.
· ingress: puede incluir una lista de reglas asociadas a puertos. Se permitirá el tráfico de entrada que venga de alguna de las fuentes especificadas, al puerto o los puertos definidos. 
En el ejemplo anterior, permitimos que los pods del espacio de nombre default con la etiqueta role=db (spec.podSelector.matchLabels) se puedan conectar los pods cuya IP se encuentren en el rango 172.17.0.0/16 (spec.ingress.from.ipBlock.cidr), excepto los que se encuentren en el rango 172.17.1.0/24 (spec.ingress.from.ipBlock.except). 
También se pueden conectar los pods que pertenezcan al espacio de nombres que contengan la etiqueta project=myproject (spec.ingress.from.namespaceSelector) y aquellos pods, sin importar el espacio de nombres, que tengan la etiqueta role=frontend (spec.ingress.from.podSelector). Estas restricciones se aplican sólo al puerto 6379/TCP (spec.ingress.from.ports...).
· egress: aquí igualmente se puede incluir una lista con varias reglas que restrinja hacia dónde se puede conectar nuestro pod. Siguiendo el ejemplo anterior, el pod o pods en el nombre de espacio default con la etiqueta role=db, sólo se puede conectar a pods en el rango de IP 10.0.0.0/24 (spec.egress.to.ipBlock) y al puerto 5978/TCP (spec.egress.to.ports…). El resto de las conexiones estarían cortadas.
Como se ha visto en el ejemplo anterior existen cuatro formas de seleccionar los pods en las reglas de ingress y egress:
· podSelector 
· namespaceSelector 
· podSelector y namespaceSelector 
· ipBlock
Y aquí dejamos esta primera parte. En la siguiente continuaremos profundizando en todas las posibilidades que permite el uso de estas políticas de seguridad de red en entornos Kubernetes.

Happy Hacking Hackers!!!

*********************************************************************************************
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (2 de 3)
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (3 de 3)
*********************************************************************************************

Autores:

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", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.

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" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.

No hay comentarios:

Entrada destacada

Mi nueva vida como CDCO (Chief Digital Consumer Officer)

Hace tres años y medio, cuando me convirtieron en CDO de Telefónica , se montó un lío en los medios que me pilló totalmente por sorpresa....

Entradas populares