Políticas de red (Network Policies)
Si quieres controlar el tráfico de red a nivel de dirección IP o puerto (capa OSI 3 o 4), puedes considerar el uso de Kubernetes NetworkPolicies para las aplicaciones que corren en tu clúster. Las NetworkPolicies son una estructura enfocada en las aplicaciones que permite establecer cómo un Pod puede comunicarse con otras "entidades" (utilizamos la palabra "entidad" para evitar sobrecargar términos más comunes como "Endpoint" o "Service", que tienen connotaciones específicas de Kubernetes) a través de la red. Las NetworkPolicies se aplican a uno o ambos extremos de la conexión a un Pod, sin afectar a otras conexiones.
Las entidades con las que un Pod puede comunicarse son de una combinación de estos 3 tipos:
- Otros Pods permitidos (excepción: un Pod no puede bloquear el acceso a sí mismo)
- Namespaces permitidos
- Bloqueos de IP (excepción: el tráfico hacia y desde el nodo donde se ejecuta un Pod siempre está permitido, independientemente de la dirección IP del Pod o del nodo)
Cuando se define una NetworkPolicy basada en Pods o Namespaces, se utiliza un Selector para especificar qué tráfico se permite desde y hacia los Pod(s) que coinciden con el selector.
Por otro lado, cuando se crean NetworkPolicies basadas en IP, se definen políticas basadas en bloques de IP (rangos CIDR).
Prerrequisitos
Las políticas de red son implementadas por el plugin de red. Para usar políticas de red, debes estar utilizando una solución de red que soporte NetworkPolicy. Crear un recurso NetworkPolicy sin un controlador que lo habilite no tendrá efecto alguno.
Dos Tipos de Aislamiento de Pod
Hay dos tipos de aislamiento para un Pod: el aislamiento para la salida y el aislamiento para la entrada. Estos se refieren a las conexiones que pueden establecerse. El término "Aislamiento" en el contexto de este documento no es absoluto, sino que significa "se aplican algunas restricciones". La alternativa, "no aislado para $dirección", significa que no se aplican restricciones en la dirección descrita. Los dos tipos de aislamiento (o no) se declaran independientemente, y ambos son relevantes para una conexión de un Pod a otro.
Por defecto, un Pod no está aislado para la salida; todas las conexiones salientes están permitidas. Un Pod está aislado para la salida si hay alguna NetworkPolicy con "Egress" en su policyTypes
que seleccione el Pod; decimos que tal política se aplica al Pod para la salida. Cuando un Pod está aislado para la salida, las únicas conexiones permitidas desde el Pod son las permitidas por la lista egress
de las NetworkPolicy que se aplique al Pod para la salida. Los valores de esas listas egress
se combinan de forma aditiva.
Por defecto, un Pod no está aislado para la entrada; todas las conexiones entrantes están permitidas. Un Pod está aislado para la entrada si hay alguna NetworkPolicy con "Ingress" en su policyTypes
que seleccione el Pod; decimos que tal política se aplica al Pod para la entrada. Cuando un Pod está aislado para la entrada, las únicas conexiones permitidas en el Pod son las del nodo del Pod y las permitidas por la lista ingress
de alguna NetworkPolicy que se aplique al Pod para la entrada. Los valores de esas listas de direcciones se combinan de forma aditiva.
Las políticas de red no entran en conflicto; son aditivas. Si alguna política(s) se aplica a un Pod para una dirección determinada, las conexiones permitidas en esa dirección desde ese Pod es la unión de lo que permiten las políticas aplicables. Por tanto, el orden de evaluación no afecta al resultado de la política.
Para que se permita una conexión desde un Pod de origen a un Pod de destino, tanto la política de salida del Pod de origen como la de entrada del Pod de destino deben permitir la conexión. Si cualquiera de los dos lados no permite la conexión, ésta no se producirá.
El Recurso NetworkPolicy
Ver la referencia NetworkPolicy para una definición completa del recurso.
Un ejemplo de NetworkPolicy pudiera ser este:
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
Campos Obligatorios: Como con todos los otras configuraciones de Kubernetes, una NetworkPolicy
necesita los campos apiVersion
, kind
, y metadata
. Para obtener información general
sobre cómo funcionan esos ficheros de configuración, puedes consultar
Configurar un Pod para usar un ConfigMap,
y Gestión de Objetos.
spec: NetworkPolicy spec contiene toda la información necesaria para definir una política de red dado un Namespace.
podSelector: Cada NetworkPolicy incluye un podSelector
el cual selecciona el grupo de Pods en los cuales aplica la política. La política de ejemplo selecciona Pods con el label "role=db". Un podSelector
vacío selecciona todos los Pods en un Namespace.
policyTypes: Cada NetworkPolicy incluye una lista de policyTypes
la cual puede incluir Ingress
, Egress
, o ambas. Los campos policyTypes
indican si la política aplica o no al tráfico de entrada hacia el Pod seleccionado, el tráfico de salida desde el Pod seleccionado, o ambos. Si no se especifican policyTypes
en una NetworkPolicy el valor Ingress
será siempre aplicado por defecto y Egress
será aplicado si la NetworkPolicy contiene alguna regla de salida.
ingress: Cada NetworkPolicy puede incluir una lista de reglas ingress
permitidas. Cada regla permite el tráfico con que se relaciona a ambos valores de las secciones de from
y ports
. La política de ejemplo contiene una única regla, la cual se relaciona con el tráfico sobre un solo puerto, desde uno de los tres orígenes definidos, el primero especificado por el valor ipBlock
, el segundo especificado por el valor namespaceSelector
y el tercero especificado por el podSelector
.
egress: Cada NetworkPolicy puede incluir una lista de reglas de egress
permitidas. Cada regla permite el tráfico con que se relaciona a ambos valores de las secciones de to
and ports
. La política de ejemplo contiene una única regla, la cual se relaciona con el tráfico en un único puerto para cualquier destino en el rango de IPs 10.0.0.0/24
.
Por lo tanto, la NetworkPolicy de ejemplo:
- Aísla los Pods "role=db" en el Namespace "default" para ambos tipos de tráfico ingress y egress (si ellos no están aún aislados)
- (Reglas Ingress) permite la conexión hacia todos los Pods en el Namespace "default" con el label "role=db" en el puerto TCP 6379 desde los siguientes orígenes:
- cualquier Pod en el Namespace "default" con el label "role=frontend"
- cualquier Pod en un Namespace con el label "project=myproject"
- La dirección IP en los rangos 172.17.0.0–172.17.0.255 y 172.17.2.0–172.17.255.255 (por ejemplo, todo el rango de IPs de 172.17.0.0/16 con excepción del 172.17.1.0/24)
- (Egress rules) permite conexión desde cualquier Pod en el Namespace "default" con el label "role=db" hacia CIDR 10.0.0.0/24 en el puerto TCP 5978
Ver el artículo de Declarar Network Policy para más ejemplos.
Comportamiento de los selectores to
y from
Existen cuatro tipos de selectores que pueden ser especificados en una sección de ingress
from
o en una sección de egress
to
:
podSelector: Este selector selecciona Pods específicos en el mismo Namespace que la NetworkPolicy para permitir el tráfico como origen de entrada o destino de salida.
namespaceSelector: Este selector selecciona Namespaces específicos para permitir el tráfico como origen de entrada o destino de salida.
namespaceSelector y podSelector: Una única entrada to
/from
que especifica tanto namespaceSelector
como podSelector
selecciona Pods específicos dentro de Namespaces específicos. Es importante revisar que se utiliza la sintaxis de YAML correcta. A continuación se muestra un ejemplo de esta política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
contiene un elemento from
permitiendo conexiones desde los Pods con el label role=client
en Namespaces con el label user=alice
. Por el contrario, esta política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
contiene dos elementos en el array from
, y permite conexiones desde Pods en los Namespaces con el label role=client
, o desde cualquier Pod en cualquier Namespace con el label user=alice
.
En caso de duda, utilice kubectl describe
para ver cómo Kubernetes ha interpretado la política.
ipBlock: Este selector selecciona rangos CIDR de IP específicos para permitirlas como origen de entrada o destino de salida. Estas IPs deben ser externas al clúster, ya que las IPs de Pod son efímeras e impredecibles.
Los mecanismos de entrada y salida del clúster a menudo requieren reescribir la IP de origen o destino
de los paquetes. En los casos en los que esto ocurre, no está definido si esto ocurre antes o
después del procesamiento de NetworkPolicy, y el comportamiento puede ser diferente para diferentes
combinaciones de plugin de red, proveedor de nube, implementación de Service
, etc.
En el caso de la entrada, esto significa que en algunos casos se pueden filtrar paquetes
entrantes basándose en la IP de origen real, mientras que en otros casos, la "IP de origen" sobre la que actúa la
la NetworkPolicy actúa puede ser la IP de un LoadBalancer
o la IP del Nodo donde este el Pod involucrado, etc.
Para la salida, esto significa que las conexiones de los Pods a las IPs de Service
que se reescriben a
IPs externas al clúster pueden o no estar sujetas a políticas basadas en ipBlock
.
Políticas por defecto
Por defecto, si no existen políticas en un Namespace, se permite todo el tráfico de entrada y salida hacia y desde los Pods de ese Namespace. Los siguientes ejemplos muestran cómo cambiar el comportamiento por defecto en ese Namespace.
Denegar todo el tráfico de entrada por defecto
Puedes crear una política que "por defecto" aisle a un Namespace del tráfico de entrada con la creación de una política que seleccione todos los Pods del Namespace pero no permite ningún tráfico de entrada en esos Pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
Esto asegura que incluso los Pods que no están seleccionados por ninguna otra NetworkPolicy también serán aislados del tráfico de entrada. Esta política no afecta el aislamiento en el tráfico de salida desde cualquier Pod.
Permitir todo el tráfico de entrada
Si tu quieres permitir todo el tráfico de entrada a todos los Pods en un Namespace, puedes crear una política que explícitamente permita eso.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
Con esta política en curso, ninguna política(s) adicional puede hacer que se niegue cualquier conexión entrante a esos Pods. Esta política no tiene efecto sobre el aislamiento del tráfico de salida de cualquier Pod.
Denegar por defecto todo el tráfico de salida
Puedes crear una política que "por defecto" aisle el tráfico de salida para un Namespace, creando una NetworkPolicy que seleccione todos los Pods pero que no permita ningún tráfico de salida desde esos Pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
Esto asegura que incluso los Pods que no son seleccionados por ninguna otra NetworkPolicy no tengan permitido el tráfico de salida. Esta política no cambia el comportamiento de aislamiento para el tráfico de entrada de ningún Pod.
Permitir todo el tráfico de salida
Si quieres permitir todas las conexiones desde todos los Pods de un Namespace, puedes crear una política que permita explícitamente todas las conexiones salientes de los Pods de ese Namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
Con esta política en vigor, ninguna política(s) adicional puede hacer que se niegue cualquier conexión de salida desde esos Pods. Esta política no tiene efecto sobre el aislamiento para el tráfico de entrada a cualquier Pod.
Denegar por defecto todo el tráfico de entrada y de salida
Puede crear una política que "por defecto" en un Namespace impida todo el tráfico de entrada y de salida creando la siguiente NetworkPolicy en ese Namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Esto asegura que incluso los Pods que no son seleccionados por ninguna otra NetworkPolicy no tendrán permitido el tráfico de entrada o salida.
Soporte a SCTP
Kubernetes v1.20 [stable]
Como característica estable, está activada por defecto. Para deshabilitar SCTP a nivel de clúster, usted (o el administrador de su clúster) tiene que deshabilitar la feature gate SCTPSupport
para el API Server con el flag --feature-gates=SCTPSupport=false,...
.
Cuando esta feature gate está habilitada, puede establecer el campo protocol
de una NetworkPolicy como SCTP
.
Apuntar a un rango de puertos
Kubernetes v1.22 [beta]
Cuando se escribe una NetworkPolicy, se puede apuntar a un rango de puertos en lugar de un solo puerto.
Esto se puede lograr con el uso del campo endPort
, como el siguiente ejemplo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
La regla anterior permite que cualquier Pod con la etiqueta role=db
en el Namespace default
se comunique
con cualquier IP dentro del rango 10.0.0.0/24
sobre el protocolo TCP, siempre que el puerto
esté entre el rango 32000 y 32768.
Se aplican las siguientes restricciones al utilizar este campo:
- Como característica en estado beta, está activada por defecto. Para desactivar el campo
endPort
a nivel de clúster, usted (o su administrador de clúster) debe desactivar la feature gateNetworkPolicyEndPort
en el API Server con el flag--feature-gates=NetworkPolicyEndPort=false,...
. - El campo
endPort
debe ser igual o mayor que el campoport
. - Sólo se puede definir
endPort
si también se defineport
. - Ambos puertos deben ser numéricos.
endPort
en las especificaciones de NetworkPolicy.
Si su plugin de red
no soporta el campo endPort
y usted especifica una NetworkPolicy que use este campo,
la política se aplicará sólo para el campo port
.
Como apuntar a un Namespace usando su nombre
Kubernetes 1.22 [stable]
El plano de control de Kubernetes establece una etiqueta inmutable kubernetes.io/metadata.name
en todos los
Namespaces, siempre que se haya habilitado la feature gate NamespaceDefaultLabelName
.
El valor de la etiqueta es el nombre del Namespace.
Aunque NetworkPolicy no puede apuntar a un Namespace por su nombre con algún campo de objeto, puede utilizar la etiqueta estandarizada para apuntar a un Namespace específico.
Que no puedes hacer con políticas de red (al menos, aún no)
Actualmente, en Kubernetes 1.25, la siguiente funcionalidad no existe en la API de NetworkPolicy, pero es posible que se puedan implementar soluciones mediante componentes del sistema operativo (como SELinux, OpenVSwitch, IPTables, etc.) o tecnologías de capa 7 (Ingress controllers, implementaciones de Service Mesh) o controladores de admisión. En caso de que seas nuevo en la seguridad de la red en Kubernetes, vale la pena señalar que las siguientes historias de usuario no pueden (todavía) ser implementadas usando la API NetworkPolicy.
- Forzar que el tráfico interno del clúster pase por una puerta de enlace común (esto se puede implementar con una malla de servicios u otro proxy).
- Cualquier cosa relacionada con TLS (se puede implementar con una malla de servicios o un Ingress controllers para esto).
- Políticas específicas de los nodos (se puede utilizar la notación CIDR para esto, pero no se puede apuntar a los nodos por sus identidades Kubernetes específicamente).
- Apuntar Services por nombre (sin embargo, puede orientar los Pods o los Namespaces por su labels, lo que suele ser una solución viable).
- Creación o gestión de "solicitudes de políticas" que son atendidas por un tercero.
- Políticas que por defecto son aplicadas a todos los Namespaces o Pods (hay algunas distribuciones y proyectos de Kubernetes de terceros que pueden hacer esto).
- Consulta avanzada de políticas y herramientas de accesibilidad.
- La capacidad de registrar los eventos de seguridad de la red (por ejemplo, las conexiones bloqueadas o aceptadas).
- La capacidad de negar explícitamente las políticas (actualmente el modelo para NetworkPolicies es negar por defecto, con sólo la capacidad de añadir reglas de permitir).
- La capacidad de impedir el tráfico entrante de Loopback o de Host (actualmente los Pods no pueden bloquear el acceso al host local, ni tienen la capacidad de bloquear el acceso desde su nodo residente).
Siguientes pasos
- Leer el artículo de como Declarar de Políticas de Red para ver más ejemplos.
- Ver más recetas de escenarios comunes habilitados por los recursos de las NetworkPolicy.