
Nota de traducción.: El autor del artículo, Reuven Harrison, tiene más de 20 años de experiencia en desarrollo de software y actualmente es director técnico y cofundador de Tufin, que crea soluciones para la gestión de políticas de seguridad. Al considerar las políticas de red de Kubernetes como una herramienta poderosa para la segmentación de red en un clúster, también opina que no son tan fáciles de aplicar en la práctica. Este material (bastante extenso) tiene como objetivo aumentar la concienciación de los especialistas en el tema y ayudarlos a crear las configuraciones necesarias.
Hoy en día, muchas empresas eligen cada vez más Kubernetes para ejecutar sus aplicaciones. El interés en este software es tan alto que algunos lo llaman "el nuevo sistema operativo para los centros de datos". Poco a poco, Kubernetes (o k8s) comienza a ser visto como una parte crítica del negocio que requiere la organización de procesos de negocio maduros, incluida la garantía de seguridad de la red.
Para los especialistas en seguridad que se han visto sorprendidos por el trabajo con Kubernetes, su política predeterminada puede ser una revelación: permitir todo.
Esta guía ayudará a comprender la estructura interna de las políticas de red; entender en qué se diferencian de las reglas de los cortafuegos comunes. También se discutirán algunas trampas ocultas y se ofrecerán recomendaciones que ayudarán a proteger las aplicaciones en Kubernetes.
Políticas de red de Kubernetes
El mecanismo de políticas de red de Kubernetes permite gestionar la interacción entre las aplicaciones desplegadas en la plataforma a nivel de red (capa tres en el modelo OSI). Las políticas de red carecen de algunas características avanzadas de los cortafuegos modernos, como el control a nivel 7 del OSI y la detección de amenazas, sin embargo, proporcionan un nivel básico de seguridad de la red que es un buen punto de partida.
Las políticas de red controlan las comunicaciones entre pod’s
Las cargas de trabajo en Kubernetes se distribuyen entre los pods, que consisten en uno o varios contenedores desplegados juntos. Kubernetes asigna a cada pod una dirección IP accesible desde otros pods. Las políticas de red de Kubernetes definen los derechos de acceso para grupos de pods de la misma manera que los grupos de seguridad en la nube se utilizan para gestionar el acceso a instancias de máquinas virtuales.
Definición de políticas de red
Al igual que otros recursos de Kubernetes, las políticas de red se definen en YAML. En el siguiente ejemplo, la aplicación balance obtiene acceso a postgres:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: balance
policyTypes:
- Ingress 
(Nota de traducción.: esta captura de pantalla, al igual que todas las siguientes similares, fue creada no con las herramientas nativas de Kubernetes, sino con la herramienta Tufin Orca, desarrollada por la compañía detrás del artículo original y que se menciona al final del material.)
Para definir una política de red propia, se requieren conocimientos básicos de YAML. Este lenguaje se basa en indentaciones (establecidas por espacios, no por tabulaciones). Un elemento con indentación pertenece al elemento más cercano con indentación encima de él. Un nuevo elemento de lista comienza con un guion, y todos los demás elementos tienen el formato clave-valor.
Una vez que haya descrito la política en YAML, utilice , para crearla en el clúster:
kubectl create -f policy.yamlEspecificación de la política de red
La especificación de la política de red de Kubernetes incluye cuatro elementos:
-
podSelector: define los pods afectados por esta política (objetivos) — obligatorio; -
policyTypes: indica qué tipos de políticas están incluidas en esta: ingress y/o egress — opcional, sin embargo, recomiendo describirlo explícitamente en todos los casos; -
ingress: define el tráfico permitido entrante a los pods objetivo — opcional; -
egress: define el tráfico permitido tráfico saliente de los pods objetivo — opcional.
El siguiente ejemplo, tomado del sitio de Kubernetes (he reemplazado role en app), muestra cómo se utilizan los cuatro elementos:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # <<<
matchLabels:
app: 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 

Tenga en cuenta que no es obligatorio incluir los cuatro elementos. Solo es obligatorio podSelector, los demás parámetros se pueden utilizar opcionalmente.
Si se omite policyTypes, la política se interpretará de la siguiente manera:
- Por defecto, se asume que define el lado de ingress. Si la política no contiene indicaciones explícitas al respecto, el sistema asumirá que todo el tráfico está prohibido.
- El comportamiento en el lado de egress se determinará por la presencia o ausencia del parámetro egress correspondiente.
Para evitar errores, recomiendo siempre especificar explícitamente policyTypes.
De acuerdo con la lógica anterior, en caso de que los parámetros ingress y/o egress se omitan, la política prohibirá todo el tráfico (ver "Regla de limpieza" a continuación).
La política por defecto es permitir
Si no se definen políticas, Kubernetes permite por defecto todo el tráfico. Todos los pod pueden intercambiar información libremente entre sí. Desde el punto de vista de la seguridad, esto puede parecer poco lógico, pero recuerde que Kubernetes fue originalmente creado por los desarrolladores con el objetivo de facilitar la interacción de las aplicaciones. Las políticas de red se agregaron más tarde.
Los espacios de nombres
Los espacios de nombres (Namespaces) son un mecanismo de trabajo colaborativo de Kubernetes. Están destinados a aislar entornos lógicos entre sí, permitiendo el intercambio de datos entre espacios de nombres de forma predeterminada.
Como la mayoría de los componentes de Kubernetes, las políticas de red habitan en un espacio de nombres específico. En el bloque metadata se puede especificar a qué espacio pertenece la política:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: my-namespace # <<<
spec:
... Si el espacio de nombres en los metadatos no se especifica explícitamente, el sistema utilizará el namespace indicado en kubectl (por defecto, namespace=default):
kubectl apply -n my-namespace -f namespace.yamlRecomiendo especificar explícitamente el namespace, a menos que esté escribiendo una política destinada a varios espacios de nombres.
Principal elemento podSelector en la política será seleccionar pod’s del espacio de nombres al que pertenece la política (no tiene acceso a pod’s de otro espacio de nombres).
De manera similar, los podSelector’s en bloques ingress y egress solo pueden seleccionar pod’s de su propio espacio de nombres, a menos que los combine mediante namespaceSelector (esto se discutirá en la sección 'Filtrar por espacios de nombres y pod’s').
Reglas de nomenclatura de políticas
Los nombres de las políticas son únicos dentro de un espacio de nombres. No puede haber dos políticas con el mismo nombre en un mismo espacio, pero puede haber políticas con nombres idénticos en diferentes espacios. Esto es conveniente cuando desea aplicar la misma política en múltiples espacios.
Me gusta especialmente una de las formas de nombrar. Consiste en combinar el nombre del espacio de nombres con los pod’s objetivo. Por ejemplo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres # <<<<
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Etiquetas
A objetos de Kubernetes, como pod’s y espacios de nombres, se les pueden adjuntar etiquetas personalizadas. Las etiquetas (labels — etiquetas) son equivalentes a tags en la nube. Las políticas de red de Kubernetes utilizan etiquetas para seleccionar pod’s, a los que se aplican:
podSelector:
matchLabels:
role: db… o espacios de nombres, a los que se aplican. En este ejemplo se seleccionan todos los pod’s en espacios de nombres con las etiquetas correspondientes:
namespaceSelector:
matchLabels:
project: myproject Una advertencia: al usar namespaceSelector asegúrese de que los espacios de nombres seleccionados contengan la etiqueta necesaria. Tenga en cuenta que los espacios de nombres incorporados, como default y kube-system, por defecto no contienen etiquetas.
Para agregar una etiqueta a un espacio, puede hacerlo de la siguiente manera:
kubectl label namespace default namespace=default En este caso, el namespace en la sección metadata debe referirse al nombre real del espacio y no a la etiqueta:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default # <<<<
spec:
...Fuente y destinatario
Las políticas de firewall consisten en reglas con fuentes y destinos. Las políticas de red de Kubernetes se definen para un objetivo: el conjunto de pods a los que se aplican, y luego establecen reglas para el tráfico entrante (ingress) y/o saliente (egress). En nuestro ejemplo, el objetivo de la política serán todos los pods en el espacio de nombres default con una etiqueta con la clave app y el valor db:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: 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 

Sección ingress en esta política abre el tráfico entrante hacia los pods objetivo. En otras palabras, el ingress actúa como la fuente, y el objetivo es el destinatario correspondiente. De manera similar, el egress es el destinatario, y el objetivo es su fuente.

Esto equivale a dos reglas para el firewall: Ingress → Objetivo; Objetivo → Egress.
Egress y DNS (¡importante!)
Al limitar el tráfico saliente, presta especial atención a DNS — Kubernetes utiliza este servicio para mapear servicios a direcciones IP. Por ejemplo, la siguiente política no funcionará, ya que no has permitido que la aplicación balance acceda a DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
policyTypes:
- Egress 
Se puede corregir permitiendo el acceso al servicio DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to: # <<<
ports: # <<<
- protocol: UDP # <<<
port: 53 # <<<
policyTypes:
- Egress 
El último elemento a — está vacío, y por lo tanto elige indirectamente todos los pods en todos los espacios de nombres, permitiendo balance enviar solicitudes DNS al servicio correspondiente de Kubernetes (que generalmente opera en el espacio kube-system).
Este enfoque funciona, sin embargo, es excesivamente permisivo e inseguro, ya que permite dirigir consultas DNS fuera del clúster.
Se puede mejorar en tres pasos secuenciales.
1. Permitir consultas DNS solo dentro del clúster, agregando namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: {} # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
2. Permitir consultas DNS solo en el espacio de nombres kube-system.
Para ello, es necesario agregar una etiqueta en el espacio de nombres kube-system: kubectl label namespace kube-system namespace=kube-system — y definirla en la política mediante namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: # <<<
matchLabels: # <<<
namespace: kube-system # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
3. Los paranoicos pueden ir aún más lejos y restringir las consultas DNS a un servicio DNS específico en kube-system. En la sección "Filtrar por espacios de nombres y pods" se explicará cómo lograrlo.
Otra opción es permitir DNS a nivel de espacio de nombres. En este caso, no será necesario abrirlo para cada servicio:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.dns
namespace: default
spec:
podSelector: {} # <<<
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress Vacío podSelector selecciona todos los pods en el espacio de nombres.

El primer ajuste y el orden de las reglas
En los cortafuegos normales, la acción ("Permitir" o "Denegar") en relación con un paquete se determina por la primera regla que cumple. En Kubernetes, el orden de las políticas no tiene relevancia.
Por defecto, cuando no se establecen políticas, las comunicaciones entre los pods están permitidas y pueden intercambiar información libremente. Una vez que comienzas a formular políticas, cada pod afectado por al menos una de ellas se vuelve aislado según la disyunción (lógica OR) de todas las políticas que lo seleccionan. Los pods no afectados por ninguna política permanecen abiertos.
Este comportamiento se puede modificar utilizando una regla de limpieza.
Regla de limpieza ("Denegar")
Las políticas de cortafuegos generalmente prohíben cualquier tráfico no permitido explícitamente.
En Kubernetes no existe una acción de "denegar" (deny), sin embargo, se puede lograr un efecto similar con una política permisiva, eligiendo un grupo vacío de pods de origen (ingress):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress 
Esta política selecciona todos los pods en el espacio de nombres y deja indefinido el ingreso, prohibiendo todo el tráfico entrante.
De manera similar, se puede restringir todo el tráfico saliente del espacio de nombres:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress 
Tenga en cuenta que cualquier política adicional que permita el tráfico a los pods en el espacio de nombres tendrá prioridad sobre esta regla (similar a añadir una regla de permiso antes de una de denegación en la configuración del cortafuegos).
Permitir todo (Any-Any-Any-Allow)
Para crear una política de 'Permitir todo', es necesario complementar la política de denegación anterior con un elemento vacío ingress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
namespace: default
spec:
podSelector: {}
ingress: # <<
- {} # <<
policyTypes:
- Ingress 
Esto abre el acceso desde todos los pods en todos los espacios de nombres (y todas las IP) a cualquier pod en el espacio de nombres default. Este comportamiento está habilitado por defecto, por lo que generalmente no es necesario definirlo adicionalmente. Sin embargo, a veces puede ser necesario deshabilitar temporalmente algunos permisos específicos para diagnosticar un problema.
La regla se puede restringir y permitir el acceso sólo a un conjunto específico de pods (app:balance) en el espacio de nombres default:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-to-balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
ingress:
- {}
policyTypes:
- Ingress 
La siguiente política permite todo el tráfico entrante (ingress) y saliente (egress), incluido el acceso a cualquier IP fuera del clúster:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress 

La combinación de múltiples políticas
Las políticas se combinan utilizando un lógico O en tres niveles; los permisos de cada pod se establecen según la disyunción de todas las políticas que lo afectan:
1. En los campos from y a se pueden definir tres tipos de elementos (todos se combinan utilizando O):
-
namespaceSelector— selecciona el espacio de nombres completo; -
podSelector— selecciona pods; -
ipBlock— selecciona una subred.
En este caso, el número de elementos (incluso idénticos) en las secciones from/a no está limitado. Todos se combinarán lógicamente con un O.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
2. Dentro de la política, la sección ingress puede tener múltiples elementos from (se combinan con un OR lógico). De manera similar, la sección egress puede incluir múltiples elementos a (también se combinan mediante disyunción):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- from:
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
3. Diferentes políticas también se combinan con un OR lógico
Pero al combinarlas, hay una restricción que : Kubernetes puede combinar políticas solo con diferentes policyTypes (Ingress o Egress). Las políticas que definen ingress (o egress) sobrescribirán las unas a las otras.
La relación entre namespaces
Por defecto, la comunicación entre namespaces está permitida. Esto se puede modificar mediante una política restrictiva que limitará el tráfico saliente y/o entrante al namespace (ver "Regla de limpieza" arriba).
Al bloquear el acceso en un namespace (ver "Regla de limpieza" arriba), puede hacer excepciones en la política restrictiva permitiendo conexiones desde un namespace específico mediante namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: # <<<
matchLabels:
namespace: default
policyTypes:
- Ingress 
Como resultado, todos los pods en el namespace default tendrán acceso a los pods postgres en el namespace database. Pero, ¿qué pasa si desea abrir el acceso a postgres solo pods específicos en el namespace default?
Filtrar por namespaces y pods
Kubernetes versión 1.11 y posterior permite combinar operadores namespaceSelector y podSelector usando un AND lógico. Esto se vería así:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector:
matchLabels:
namespace: default
podSelector: # <<<
matchLabels:
app: admin
policyTypes:
- Ingress 
¿Por qué esto se interpreta como AND en lugar del común OR?
Tenga en cuenta que podSelector no comienza con un guión. En YAML, esto significa que podSelector y el que le precede namespaceSelector se refieren al mismo elemento de la lista. Por lo tanto, se combinan con un AND lógico.
La adición de un guion antes de podSelector resultará en la creación de un nuevo elemento de la lista, que se combinará con el anterior namespaceSelector mediante un OR lógico.
Para seleccionar pods con una etiqueta específica en todos los espacios de nombre, escriba vacío namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Múltiples etiquetas se combinan con AND
Las reglas de firewall con múltiples objetos (hosts, redes, grupos) se combinan utilizando un OR lógico. La siguiente regla se activará si la fuente del paquete coincide con Host_1 OR Host_2:
| Fuente | Destino | Servicio | Acción |
| ----------------------------------------|
| Host_1 | Subnet_A | HTTPS | Permitir |
| Host_2 | | | |
| ----------------------------------------| Por otro lado, en Kubernetes, varias etiquetas podSelector o namespaceSelector se combinan con un AND lógico. Por ejemplo, la siguiente regla seleccionará pods que tengan ambas etiquetas, role=db Y version=v2:
podSelector:
matchLabels:
role: db
version: v2La misma lógica se aplica a todos los tipos de operadores: selectores de objetivos de políticas, selectores de pods y selectores de espacios de nombres.
Subredes y direcciones IP (IPBlocks)
Para segmentar la red, los firewalls utilizan VLAN, direcciones IP y subredes.
En Kubernetes, las direcciones IP se asignan a los pods automáticamente y pueden cambiar con frecuencia, por lo que se utilizan etiquetas para seleccionar pods y espacios de nombres en políticas de red.
Las subredes (ipBlocks) se utilizan para gestionar las conexiones externas (North-South) entrantes (ingress) o salientes (egress). Por ejemplo, esta política permite a todos los pods del espacio de nombres default acceder al servicio DNS de Google:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-dns
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.8/32
ports:
- protocol: UDP
port: 53 
Un selector de pods vacío en este ejemplo significa 'seleccionar todos los pods en el espacio de nombres'.
Esta política solo permite el acceso a 8.8.8.8; el acceso a cualquier otra IP está prohibido. Por lo tanto, en esencia, ha bloqueado el acceso al servicio DNS interno de Kubernetes. Si aún desea abrirlo, indíquelo explícitamente.
Normalmente ipBlocks y podSelectors son mutuamente excluyentes, ya que las direcciones IP internas de los pods no se utilizan en ipBlocks. Al especificar las IP internas de los pods, usted permitirá efectivamente las conexiones hacia/desde los pods con estas direcciones. En la práctica, no sabrá qué dirección IP utilizar, por lo que no deben usarse para seleccionar pods.
Como contrapunto, la siguiente política incluye todas las IP y, por lo tanto, permite el acceso a todos los demás pods:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 
Se puede abrir el acceso solo a direcciones IP externas, excluyendo las direcciones IP internas de los pods. Por ejemplo, si la subred de su pod es 10.16.0.0/14:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.16.0.0/14 
Puertos y protocolos
Normalmente, los pods escuchan en un puerto. Esto significa que simplemente no se requieren números de puerto en las políticas y se puede dejar todo por defecto. Sin embargo, se recomienda que las políticas sean lo más restrictivas posible, por lo que en algunos casos puede ser necesario especificar los puertos:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
ports: # <<<<
- port: 443 # <<<<
protocol: TCP # <<<<
- port: 80 # <<<<
protocol: TCP # <<<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Tenga en cuenta que el selector ports se aplica a todos los elementos en el bloque a o from, en el que se encuentra. Para especificar diferentes puertos para diferentes conjuntos de elementos, divídalo ingress o egress en varios subsecciones con a o from y en cada uno especifique sus puertos:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
ports: # <<<<
- port: 443 # <<<<
protocol: TCP # <<<<
- from:
- podSelector:
matchLabels:
app: admin
ports: # <<<<
- port: 80 # <<<<
protocol: TCP # <<<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Funcionamiento de los puertos por defecto:
- Si omite completamente la definición de puertos (
ports), esto significa todos los protocolos y todos los puertos; - Si omite la definición del protocolo (
protocol), esto significa TCP; - Si omite la definición del puerto (
port), esto significa todos los puertos.
Mejor práctica: no confíe en los valores predeterminados, especifique lo que necesita explícitamente.
Tenga en cuenta que debe utilizar los puertos de los pod, no los de los servicios (más detalles en el siguiente párrafo).
¿Las políticas están definidas para pods o servicios?
Normalmente, los pods en Kubernetes se comunican entre sí a través de un servicio, que es un equilibrador de carga virtual que redirige el tráfico a los pods que implementan el servicio. Se podría pensar que las políticas de red controlan el acceso a los servicios, pero no es así. Las políticas de red de Kubernetes funcionan con los puertos de los pods, no con los de los servicios.
Por ejemplo, si un servicio escucha en el puerto 80, pero redirige el tráfico al puerto 8080 de sus pods, en la política de red es necesario especificar precisamente el 8080.
Se debe considerar que este mecanismo es subóptimo: al cambiar la estructura interna del servicio (los puertos que escuchan los pods), será necesario actualizar las políticas de red.
Un nuevo enfoque arquitectónico utilizando Service Mesh (por ejemplo, consulte Istio a continuación - nota del traductor) permite abordar este problema.
¿Es necesario especificar tanto Ingress como Egress?
La respuesta corta es sí; para que el pod A pueda comunicarse con el pod B, es necesario permitirle establecer una conexión saliente (para esto es necesario configurar una política de egress), y el pod B debe poder aceptar una conexión entrante (para ello, por lo tanto, se necesita una política de ingress).
Sin embargo, en la práctica, se puede confiar en la política predeterminada que permite conexiones en una o ambas direcciones.
Si un pod-fuente es seleccionado por una o varias egress-políticas, las restricciones impuestas se determinarán por su disyunción. En este caso, se deberá permitir explícitamente la conexión al pod-destinatario. Si el pod no es seleccionado por ninguna política, su tráfico saliente (egress) está permitido por defecto.
De manera similar, el destino del pod-destinatario, seleccionado por una o varias ingress-políticas, se determinará por su disyunción. En este caso, es necesario permitirle explícitamente recibir tráfico del pod-fuente. Si el pod no es seleccionado por ninguna política, todo el tráfico entrante (ingress) para él está permitido por defecto.
Véase la sección 'Stateful o Stateless' a continuación.
Registros
Las políticas de red de Kubernetes no pueden registrar tráfico. Esto dificulta determinar si la política está funcionando correctamente y complica enormemente el análisis en términos de seguridad.
Control del tráfico hacia servicios externos
Las políticas de red de Kubernetes no permiten especificar un nombre de dominio completo (DNS) en las secciones de egress. Este hecho causa una gran incomodidad al intentar restringir el tráfico a destinos externos que carecen de una dirección IP fija (como aws.com).
Verificación de políticas
Los firewalls le advertirán o incluso se negarán a aceptar una política errónea. Kubernetes también realiza cierta verificación. Al establecer una política de red a través de kubectl, Kubernetes puede afirmar que es incorrecta y negarse a aceptarla. En otros casos, Kubernetes aceptará la política y la complementará con los detalles faltantes. Se pueden ver con el siguiente comando:
kubernetes get networkpolicy -o yamlTenga en cuenta que el sistema de verificación de Kubernetes no es infalible y puede pasar por alto ciertos tipos de errores.
Ejecución
Kubernetes no implementa políticas de red por sí mismo, sino que actúa como una puerta de enlace API, delegando la ardua tarea de control a un sistema subyacente llamado Container Networking Interface (CNI). Establecer políticas en un clúster de Kubernetes sin asignar el CNI correspondiente es similar a crear políticas en un servidor de firewall sin instalarlas posteriormente en los firewalls. Debe asegurarse de contar con un CNI adecuado o, en el caso de las plataformas de Kubernetes alojadas en la nube, (puede consultar la lista de proveedores, — nota del traductor), implementar políticas de red que configuren el CNI por usted.
Tenga en cuenta que Kubernetes no le advertirá si establece una política de red sin el CNI auxiliar correspondiente.
¿Stateful o Stateless?
Todos los CNI de Kubernetes con los que he tenido experiencia son stateful (por ejemplo, Calico utiliza Linux conntrack). Esto permite que un pod reciba respuestas a una conexión TCP que ha iniciado sin necesidad de volver a establecerla. Sin embargo, no conozco un estándar de Kubernetes que garantice el almacenamiento de estado (statefulness).
Gestión avanzada de políticas de seguridad
Aquí hay algunas formas de aumentar la eficacia de la ejecución de políticas de seguridad en Kubernetes:
- El patrón arquitectónico Service Mesh utiliza contenedores sidecar para proporcionar telemetría detallada y control del tráfico a nivel de servicios. Un ejemplo es .
- Algunos proveedores de CNI han ampliado sus herramientas para que vayan más allá de las políticas de red de Kubernetes.
- ofrece transparencia y automatización de las políticas de red de Kubernetes.
El paquete Tufin Orca gestiona las políticas de red de Kubernetes (y sirve como fuente de las capturas de pantalla mencionadas anteriormente).
Información adicional
- ;
- ;
- ;
- .
Conclusión
Las políticas de red de Kubernetes ofrecen un buen conjunto de herramientas para la segmentación de clústeres, sin embargo, son poco intuitivas y tienen muchas sutilezas. Creo que debido a esta complejidad, las políticas de muchos clústeres existentes contienen errores. Las posibles soluciones a este problema son la automatización de definiciones de políticas o la aplicación de otros medios de segmentación.
Espero que esta guía ayude a aclarar algunas dudas y resolver problemas que pueda enfrentar.
P.D. del traductor
También puedes leer en nuestro blog:
- «Regreso a los microservicios junto con Istio»: , , ;
- «Guía ilustrada sobre la configuración de redes en Kubernetes»: , ;
- «»;
- «»;
- «».
Fuente: habr.com
