Con empresas grandes y pequeñas que están adoptando rápidamente la plataforma, la seguridad se ha convertido en una preocupación importante, en parte debido a la curva de aprendizaje inherente a la comprensión de cualquier infraestructura nueva, y en parte debido a las vulnerabilidades encontradas. 

Kubernetes trae otra dinámica de seguridad a la mesa: sus valores predeterminados están orientados a facilitar que los usuarios puedan ponerse en marcha rápidamente, así como a ser compatibles con versiones anteriores de Kubernetes que carecían de características de seguridad importantes . En consecuencia, muchas configuraciones importantes de Kubernetes no son seguras por defecto .

Una configuración importante que exige atención desde una perspectiva de seguridad es la función de políticas de red . Las políticas de red especifican cómo los grupos de pods pueden comunicarse entre sí y con otros puntos finales de la red. Puede pensar en ellos como el equivalente Kubernetes de un firewall.

Cómo configurar las políticas de red de Kubernetes Ingress

Presentamos aquí una guía paso a paso sobre cómo configurar políticas de red. La especificación de la política de red es compleja y puede ser difícil de entender y usar correctamente. En esta guía, ofrecemos recomendaciones que mejoran significativamente la seguridad. Los usuarios pueden implementar fácilmente estas recomendaciones sin necesidad de conocer las especificaciones en detalle.

Use un complemento de red que admita políticas de red

Lo primero es lo primero: use un complemento de red que realmente aplique las políticas de red . Aunque Kubernetes siempre admite operaciones en el NetworkPolicyrecurso, simplemente crear el recurso sin un complemento que lo implemente no tendrá ningún efecto.

“Aislar” sus pods

Cada política de red tiene un podSelectorcampo, que selecciona un grupo de pods (cero o más). Cuando una política de red selecciona un pod, se dice que la política de red se aplica a él.

Cada política de red también especifica una lista de conexiones permitidas (entrada y salida). Cuando se crea la política de red, todos los pods a los que se aplica pueden hacer o aceptar las conexiones que figuran en ella. En otras palabras, una política de red es esencialmente una lista blanca de conexiones permitidas: se permite una conexión hacia o desde un pod si está permitido por al menos una de las políticas de red que se aplican al pod.

Sin embargo, esta historia tiene un giro importante: en base a todo lo descrito hasta ahora, uno pensaría que, si no se aplican políticas de red a un pod, entonces no se permitirían conexiones hacia o desde él. Lo contrario, de hecho, es cierto: si no se aplican políticas de red a un pod, entonces todas las conexiones de red hacia y desde él están permitidas (a menos que la conexión esté prohibida por una política de red aplicada al otro par en la conexión).

Este comportamiento se relaciona con la noción de “aislamiento”: los pods están “aislados” si se les aplica al menos una política de red; si no se aplican políticas, son “no aisladas”. Las políticas de red no se aplican en pods no aislados . Aunque es algo contrario a la intuición, este comportamiento existe para facilitar la puesta en marcha de un clúster: un usuario que no comprende las políticas de red puede ejecutar sus aplicaciones sin tener que crear una.

Por lo tanto, le recomendamos que comience aplicando una política de red “default-deny-all”. El efecto de la siguiente especificación de política es aislar todos los pods, lo que significa que solo se permitirán conexiones explícitamente incluidas en la lista blanca por otras políticas de red.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Sin dicha política, es muy fácil encontrarse con un escenario en el que elimine una política de red, con la esperanza de prohibir las conexiones enumeradas en ella, pero descubra que el resultado es que todas las conexiones a algunos pods de repente se permiten, incluidas las que no estaban No está permitido antes. Tal escenario ocurre cuando la política de red que eliminó fue la única que se aplicó a un pod en particular, lo que significa que la eliminación de la política de red causó que el pod se volviera “no aislado”.

Nota importante: dado que las políticas de red son recursos de espacio de nombres, deberá crear esta política para cada espacio de nombres. Puede hacerlo ejecutando kubectl -n <namespace> create -f <filename>cada espacio de nombres.

Permitir explícitamente el acceso a Internet para los pods que lo necesitan

Con solo la default-deny-allpolítica vigente en cada espacio de nombres, ninguno de sus pods podrá comunicarse entre sí ni recibir tráfico de Internet. Para que la mayoría de las aplicaciones funcionen, deberá permitir que algunos pods reciban tráfico de fuentes externas. Una forma conveniente de permitir esta configuración sería designar etiquetas que se apliquen a los pods a los que desea permitir el acceso desde Internet y crear políticas de red que se dirijan a esas etiquetas. Por ejemplo, la siguiente política de red permite el tráfico de todas las fuentes (incluidas las externas) para los pods que tienen la networking/allow-internet-access=trueetiqueta (nuevamente, como en la sección anterior, tendrá que crear esto para cada espacio de nombres):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: internet-access
spec:
  podSelector:
    matchLabels:
      networking/allow-internet-access: "true"
  policyTypes:
  - Ingress
  ingress:
  - {}

Para un conjunto de políticas más bloqueado, lo ideal sería especificar bloques CIDR más específicos , así como enumerar explícitamente los puertos y protocolos permitidos . Sin embargo, esta política proporciona un buen punto de partida, con una seguridad mucho mayor que la predeterminada.

Permitir explícitamente la comunicación necesaria de pod a pod

Después de seguir los pasos anteriores, también deberá agregar políticas de red para permitir que los pods se comuniquen entre sí. Tiene algunas opciones sobre cómo habilitar las comunicaciones de pod a pod, según su situación:

Si no sabe qué cápsulas necesitan hablar entre sí

En este caso, un buen punto de partida es permitir que todos los pods en el mismo espacio de nombres se comuniquen entre sí y explícitamente coloquen en la lista blanca la comunicación entre los espacios de nombres, ya que eso suele ser más raro. Puede usar la siguiente política de red para permitir toda la comunicación de pod a pod dentro de un espacio de nombres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}

Si conoce las fuentes y sumideros para la comunicación

A menudo, la comunicación entre los pods en una aplicación sigue un paradigma de hub-and-speak, con algunos pods centrales con los que muchos otros pods necesitan hablar. En este caso, podría considerar crear una etiqueta que designe los pods que pueden hablar con el “centro”. Por ejemplo, si su hub es un pod de base de datos y tiene una app=dbetiqueta, puede permitir el acceso a la base de datos solo desde los pods que tienen una networking/allow-db-access=trueetiqueta aplicando la siguiente política:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-db-access
spec:
  podSelector:
    matchLabels:
      app: "db"
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          networking/allow-db-access: "true"

Podría hacer algo similar si tiene un servidor que inicia conexiones a muchos otros pods. Si desea incluir explícitamente en la lista blanca los pods con los que el servidor puede hablar, puede establecer la networking/allow-server-to-access=trueetiqueta en ellos y aplicar la siguiente política de red (suponiendo que su servidor tenga la etiqueta app=server) en ellos:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-server-to-access
spec:
  podSelector:
    matchLabels:
      networking/allow-server-to-access: "true"
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: "server"

Si sabe exactamente qué conexiones deben permitirse

Dentro del mismo espacio de nombres

Los usuarios avanzados que saben exactamente qué conexiones de pod a pod deberían permitirse en su aplicación pueden permitir explícitamente cada una de esas conexiones. Si desea que los pods en la implementación A puedan comunicarse con los pods en la implementación B, puede crear la siguiente política para incluir esa conexión en la lista blanca, después de reemplazar las etiquetas con las etiquetas de la implementación específica:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-server-to-access
spec:
  podSelector:
    matchLabels:
      deployment-b-pod-label-1-key: deployment-b-pod-label-1-value
      deployment-b-pod-label-2-key: deployment-b-pod-label-2-value
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          deployment-a-pod-label-1-key: deployment-a-pod-label-1-value
          deployment-a-pod-label-2-key: deployment-a-pod-label-2-value
A través de espacios de nombres

Para permitir conexiones entre espacios de nombres, deberá crear una etiqueta para el espacio de nombres de origen (desafortunadamente, Kubernetes no tiene ninguna etiqueta en los espacios de nombres de forma predeterminada) y agregar una namespaceSelectorconsulta al lado de la podSelectorconsulta. Para etiquetar un espacio de nombres, simplemente puede ejecutar el comando:kubectl label namespace <name> networking/namespace=<name>

Con esta etiqueta de espacio de nombres en su lugar, puede permitir que la implementación A en el espacio de nombres N1 se comunique con la implementación B en el espacio de nombres N2 aplicando la siguiente política de red:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-n1-a-to-n2-b
  namespace: N2
spec:
  podSelector:
    matchLabels:
      deployment-b-pod-label-1-key: deployment-b-pod-label-1-value
      deployment-b-pod-label-2-key: deployment-b-pod-label-2-value
  policyTypes:
  - Ingress
  ingress:
  - from:
    -  namespaceSelector:
        matchLabels:
          networking/namespace: N1
       podSelector:
        matchLabels:
          deployment-a-pod-label-1-key: deployment-a-pod-label-1-value
          deployment-a-pod-label-2-key: deployment-a-pod-label-2-value
¿Qué pasa con las nuevas implementaciones?

Si bien las conexiones explícitamente a la lista blanca de esta manera son excelentes para la seguridad, este enfoque afecta la usabilidad. Cuando crea nuevas implementaciones, no podrán hablar con nada de forma predeterminada hasta que aplique una política de red. Para mitigar esta experiencia de usuario potencialmente frustrante, puede crear el siguiente par de políticas de red, que permiten a los pods etiquetados networking/allow-all-connections=truehablar con todos los otros pods en el mismo espacio de nombres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-from-new
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          networking/allow-all-connections: "true"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-to-new
spec:
  podSelector:
    matchLabels:
      networking/allow-all-connections: "true"
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}

Luego puede aplicar la networking/allow-all-connections=trueetiqueta a todas las implementaciones recién creadas, de modo que su aplicación funcione hasta que cree políticas de red especialmente diseñadas para ellos, momento en el cual puede eliminar la etiqueta.

Si bien estas recomendaciones proporcionan un buen punto de partida, las políticas de red están mucho más involucradas. Si está interesado en explorarlos con más detalle, asegúrese de consultar el tutorial de Kubernetes y algunas prácticas recetas de políticas de red .

En una publicación futura de esta serie, lanzaremos una herramienta de código abierto que le permite aplicar fácilmente las recomendaciones de este artículo, así como algunas otras prácticas recomendadas.

¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 5)

compartir en ....
Avatar

Acerca de Brian Alexander Diaz

Brian Alexander Diaz Investigador en temas de seguridad y Devops Mi nombre es Brian Alexander Diaz. El objetivo de este blog es promover la cultura y mentalidad en seguridad por todo el Internet y que la gente aprenda a facilitar su vida y crear  sistemas mas seguros .

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *