Networking Security para Kubernetes

Networking Security para Kubernetes

Las políticas juegan un papel fundamental para definir como los pods interactúan entre ellos o con redes externas.

Introducción

No descubrimos nada al decir que las políticas de networking son esenciales para asegurar y manejar el tráfico dentro de nuestro cluster. Nos habilitan a controlar la comunicación entre pods, mejorar la seguridad, proveer un control granular del tráfico en estos ambientes escalables como nuestros clusters de Kubernetes. La manera de mantener una infraestructura segura y eficiente.

Ambiente

En esta entrada vamos a descubrir algunas políticas a implementar, para ello sera necesario crear un ambiente. Elegí este proyecto que tiene 2 tiers, un Backend con MySQL y un Frontend con Flask. Dejó el proyecto, para que puedan crear el ambiente.

Vamos a ver que tenemos en el cluster.

Debería verse algo así.

Vamos a generar las políticas necesarias para asegurar este aplicativo. La idea es que solo el Frontend atienda las consultas.

Políticas

1.Default Deny All Ingress and Egress

Esta política es una medida de seguridad básica, donde vamos a impedir todo el tráfico de entrada y salida a los pods, actua como un firewall que bloquea todo el tráfico salvo que especifiquemos lo contrario. Es una buena practica bloquear todo el trafico e ir gradualmente añadiendo reglas que permitan las comunicaciones necesarias.

Para implementar una política de negación, por defecto, debemos crear un objeto NetworkPolicy. En este caso aplicará sobre el namespace default y denegaremos el ingreso y egreso.

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

Perfecto, ya no podemos ingresar a nuestra aplicación.

2.Allow Frontend to 0.0.0.0

Vamos agregar una política para que solo pueda consumirse el frontend.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-two-tier-app
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: two-tier-app
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0

¿Que está pasado? Ahora si podemos ingresar al frontend, pero el frontend no logra conectarse con el backend. Afinamos una nueva política, para que tengamos conexión a la Base de Datos. Vamos a crear dos políticas, una para que two-tier-app se comunique con mysql en el puerto 3306 y otra para que mysql pueda devolver el resultado a two-tier-app.

Primero veamos los labels, para trabajar mejor.

3.Allow Frontend to Backend

Ahora si creamos las políticas. La primera permitimos la comunicación de two-tier-app a mysql en el puerto 3306.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-two-tier-app-to-mysql
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: two-tier-app
    ports:
    - protocol: TCP
      port: 3306

La segunda, permitimos que mysql retorne el resultado.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-mysql-to-two-tier-app
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: two-tier-app
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: mysql
    ports:
    - protocol: TCP
      port: 3306

¡Listo! Ya podemos acceder a la aplicación, que ahora se comunica con la base de datos. Sin embargo, ningún pod, excepto la aplicación, puede conectarse con el exterior.

Vamos a hacer una prueba desde los diferentes containers. Si hacemos un curl desde el Frontend, vamos a obtener esta respuesta.

Pero si lo hacemos desde el Backend, el resultado será diferente porque solamente el label two-tier-app tiene permisos para las comunicaciones con el exterior.

Existen muchas clases de políticas para mejorar la seguridad, como conexiones entre namespaces, restriccion de rangos, manejar comunicaciones atraves de labels, combinaciones entre Pods y Namespaces, etc.

Espero que les sirva para dar los primeros pasos en esta clase de objetos tan necesarios.