Google Kubernetes Engine: NetworkPolicy que permite la salida a k8s-metadata-proxy

Oct 02 2020

Contexto

Tengo un clúster de Google Kubernetes Engine (GKE) con Workload Identity habilitado. Como parte de Workload Identity, se ejecuta un DaemonSet k8s-metadata-proxy en el clúster. Tengo un espacio de nombres my-namespacey quiero denegar todo el tráfico de salida de los pods en el espacio de nombres, excepto la salida al DaemonSet k8s-metadata-proxy. Como tal, tengo la siguiente NetworkPolicy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace
spec:
  # Apply to all pods.
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - ports:
    # This is needed to whitelist k8s-metadata-proxy. See https://github.com/GoogleCloudPlatform/k8s-metadata-proxy
    - protocol: TCP
      port: 988

Problema

NetworkPolicy es demasiado amplia porque permite el tráfico TCP de salida a cualquier host en el puerto 988 en lugar de solo la salida al DaemonSet k8s-metadata-proxy, pero parece que no puedo encontrar una manera de especificar .spec.egress[0].topara lograr la granularidad que quiero.

He probado los siguientes tos:

  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          namespace: kube-system
    ports:
    - protocol: TCP
      port: 988
  - to:
    - ipBlock:
        cidr: <cidr of pod IP range>
    - ipBlock:
        cidr: <cidr of services IP range>
    ports:
    - protocol: TCP
      port: 988

pero estas reglas dan como resultado que se bloquee el tráfico hacia el proxy de metadatos k8s.

Pregunta

¿Cómo puedo seleccionar el DaemonSet k8s-metadata-proxy en la toparte de una regla de salida en a networking.k8s.io/v1/NetworkPolicy?

Respuestas

DawidKruk Oct 05 2020 at 12:55

Como dije en el comentario:

Hola. Puede agregar podSelector.matchLabels a su definición de salida para permitir que su pod se conecte solo a los pods con una etiqueta específica. Puede leer más sobre esto aquí: cloud.google.com/kubernetes-engine/docs/tutorials/…

Este comentario podría ser engañoso ya que la comunicación con gke-metadata-serverse describe en la documentación oficial:

  • Cloud.google.com: Kubernetes Engine: Identidad de carga de trabajo: GKE-MDS

Centrándose en la parte de la documentación anterior:

Comprender el servidor de metadatos de GKE

El servidor de metadatos de GKE es un nuevo servidor de metadatos diseñado para usarse con Kubernetes. Se ejecuta como un daemonset , con un Pod en cada nodo del clúster. El servidor de metadatos intercepta solicitudes HTTP parahttp://metadata.google.internal( 169.254.169.254:80), incluidas las solicitudes como GET /computeMetadata/v1/instance/service-accounts/default/tokenrecuperar un token para la cuenta de servicio de Google en la que el Pod está configurado para actuar. El tráfico al servidor de metadatos nunca sale de la instancia de VM que aloja el Pod.

Nota : Si tiene una política de red de clúster estricta , debe permitir la salida a 127.0.0.1/32 en el puerto 988 para que su pod pueda comunicarse con el servidor de metadatos de GKE.

La regla para permitir el tráfico solo GKE Metadata serverse describe en el último párrafo de la cita anterior. La YAMLdefinición debería verse a continuación:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: egress-rule
  namespace: restricted-namespace # <- namespace your pod is in 
spec:
  policyTypes:
  - Egress
  podSelector:
    matchLabels:
      app: nginx # <- label used by pods trying to communicate with metadata server
  egress:
  - to:
    - ipBlock:
        cidr: 127.0.0.1/32 # <- allow communication with metadata server #1 
  - ports:
    - protocol: TCP
      port: 988 # <- allow communication with metadata server #2 

Asumiendo que:

  • Tienes un clúster de Kubernetes con:
    • Network Policy habilitado
    • Workload Identity habilitado
  • Estás Podsintentando comunicarte desde el restricted-namespaceespacio de nombres

El resultado para describir necesario NetworkPolicy:

  • $ kubectl describe networkpolicy -n restricted-namespace egress-rule
Name:         egress-rule
Namespace:    restricted-namespace
Created on:   2020-10-04 18:31:10 +0200 CEST
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"networking.k8s.io/v1","kind":"NetworkPolicy","metadata":{"annotations":{},"name":"egress-rule","namespace":"restricted-name...
Spec:
  PodSelector:     app=nginx
  Allowing ingress traffic:
    <none> (Selected pods are isolated for ingress connectivity)
  Allowing egress traffic:
    To Port: <any> (traffic allowed to all ports)
    To:
      IPBlock:
        CIDR: 127.0.0.1/32
        Except: 
    ----------
    To Port: 988/TCP
    To: <any> (traffic not restricted by source)
  Policy Types: Egress

¡Descargo de responsabilidad!

La aplicación de esas reglas negará todo el tráfico de los pods con app=nginxetiquetas que no están destinadas al servidor de metadatos.

Puede crear y execen el pod con una etiqueta app=nginxde la siguiente manera:

kubectl run -it --rm nginx \
--image=nginx \
--labels="app=nginx" \
--namespace=restricted-namespace \
-- /bin/bash

¡Propina!

¡La imagen nginxse usa ya que se curlinstaló por defecto!

Con este ejemplo, no podrá comunicarse con el servidor DNS. Tu también puedes:

  • permita que sus pods se comuniquen con el servidor DNS
  • establecer la envvariable para el servidor de metadatos (169.254.169.254)

Ejemplo de comunicación con GKE Metadata Server:

  • $ curl 169.254.169.254/computeMetadata/v1/instance/ -H 'Metadata-Flavor: Google'
attributes/
hostname
id
service-accounts/
zone

Recursos adicionales:

  • Cloud.google.com: Compute: almacenar la recuperación de metadatos


Para permitir que pods específicos envíen tráfico solo a los pods específicos en puertos específicos, puede usar la siguiente política:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: egress-rule
  namespace: restricted-namespace # <- namespace of "source" pod
spec:
  policyTypes:
  - Egress
  podSelector:
    matchLabels:
      app: ubuntu # <- label for "source" pod
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: nginx # <- label for "destination" pod
  - ports:
    - protocol: TCP
      port: 80 # <- allow only port 80