Share via


Uso de Azure Firewall para proteger los clústeres de Azure Kubernetes Service (AKS)

En este artículo se muestra cómo proteger los clústeres de Azure Kubernetes Service (AKS) mediante Azure Firewall para proteger el tráfico entrante y saliente.

Fondo

Azure Kubernetes Service (AKS) ofrece un clúster de Kubernetes administrado en Azure. Para más información, vea Azure Kubernetes Service.

A pesar de que AKS es una solución totalmente administrada, no ofrece una solución integrada para proteger el tráfico de entrada y salida entre el clúster y las redes externas. Azure Firewall ofrece una solución a esto.

Los clústeres de AKS se implementan en una red virtual. Esta red puede ser administrada (creada por AKS) o personalizada (configurada previamente por el usuario). En cualquier caso, el clúster tiene dependencias de salida en servicios externos a esa red virtual (el servicio no tiene dependencias de entrada). Para fines operativos y de administración, los nodos de un clúster de AKS deben tener acceso a determinados puertos y nombres de dominio completo (FQDN) que describen estas dependencias de salida. Esto es necesario para varias funciones, incluidos, entre otros, los nodos que se comunican con el servidor de API de Kubernetes. Descargan e instalan los componentes principales del clúster de Kubernetes y las actualizaciones de seguridad del nodo, o extraen imágenes de contenedor del sistema base de Microsoft Container Registry (MCR), etc. Estas dependencias de salida se definen casi por completo mediante FQDN, que no tienen direcciones estáticas tras ellos. La falta de direcciones estáticas significa que no se pueden usar grupos de seguridad de red para bloquear el tráfico saliente desde un clúster de AKS. Por esta razón, de forma predeterminada, los clústeres de AKS tienen acceso de salida a Internet ilimitado. Este nivel de acceso a la red permite que los nodos y servicios que ejecuta accedan a recursos externos según sea necesario.

Sin embargo, en un entorno de producción, las comunicaciones con un clúster de Kubernetes deben protegerse para evitar la filtración de datos junto con otras vulnerabilidades. Todo el tráfico de red entrante y saliente debe supervisarse y controlarse en función de un conjunto de reglas de seguridad. Si quiere hacerlo, deberá restringir el tráfico de salida, pero un número limitado de puertos y direcciones debe seguir siendo accesible para mantener las tareas de mantenimiento del clúster correctas y satisfacer las dependencias salientes mencionadas anteriormente.

La solución más sencilla usa un dispositivo de firewall que pueda controlar el tráfico de salida en función de los nombres de dominio. Normalmente, un firewall establece una barrera entre una red de confianza y una red que no es de confianza, como Internet. Por ejemplo, Azure Firewall puede restringir el tráfico HTTP y HTTPS saliente en función del FQDN del destino, lo que proporciona un control de tráfico de salida específico, pero al mismo tiempo permite proporcionar acceso a los FQDN que abarcan las dependencias salientes de un clúster de AKS (algo que los NSG no pueden hacer). Del mismo modo, puede controlar el tráfico de entrada y mejorar la seguridad si habilita el filtrado basado en inteligencia sobre amenazas en Azure Firewall implementado en una red perimetral compartida. Este filtrado puede proporcionar alertas y denegar el tráfico hacia y desde dominios y direcciones IP malintencionadas conocidas.

Vea el siguiente vídeo de Abhinav Sriram para obtener información general rápida sobre cómo funciona en la práctica en un entorno de ejemplo:

Puede descargar un archivo ZIP desde el Centro de descarga de Microsoft que contiene un archivo de script de Bash y un archivo yaml para configurar automáticamente el entorno de ejemplo usado en el vídeo. Configure Azure Firewall para proteger tanto el tráfico de entrada como de salida. Las siguientes guías le acompañarán en cada paso del script con más detalle para que pueda crear una configuración personalizada.

En el diagrama siguiente se muestra el entorno de ejemplo del vídeo que configura el script y la guía:

Diagram showing A K S cluster with Azure Firewall for ingress egress filtering.

Hay una diferencia entre el script y la siguiente guía. El script usa identidades administradas, pero la guía usa una entidad de servicio. Esto muestra dos maneras diferentes de crear una identidad para administrar y crear recursos de clúster.

Restricción del tráfico de salida mediante Azure Firewall

Configuración mediante variables de entorno

Defina el conjunto de variables de entorno que se usarán en la creación de recursos.

PREFIX="aks-egress"
RG="${PREFIX}-rg"
LOC="eastus"
PLUGIN=azure
AKSNAME="${PREFIX}"
VNET_NAME="${PREFIX}-vnet"
AKSSUBNET_NAME="aks-subnet"
# DO NOT CHANGE FWSUBNET_NAME - This is currently a requirement for Azure Firewall.
FWSUBNET_NAME="AzureFirewallSubnet"
FWNAME="${PREFIX}-fw"
FWPUBLICIP_NAME="${PREFIX}-fwpublicip"
FWIPCONFIG_NAME="${PREFIX}-fwconfig"
FWROUTE_TABLE_NAME="${PREFIX}-fwrt"
FWROUTE_NAME="${PREFIX}-fwrn"
FWROUTE_NAME_INTERNET="${PREFIX}-fwinternet"

Creación de una red virtual con varias subredes

Cree una red virtual con dos subredes independientes, una para el clúster y otra para el firewall. Opcionalmente, también puede crear una para la entrada del servicio interno.

Empty network topology

Cree el grupo de recursos que contendrá todos los recursos.

# Create Resource Group

az group create --name $RG --location $LOC

Cree una red virtual con dos subredes para hospedar el clúster de AKS y Azure Firewall. Cada uno tiene su propia subred. Comencemos con la red de AKS.

# Dedicated virtual network with AKS subnet

az network vnet create \
    --resource-group $RG \
    --name $VNET_NAME \
    --location $LOC \
    --address-prefixes 10.42.0.0/16 \
    --subnet-name $AKSSUBNET_NAME \
    --subnet-prefix 10.42.1.0/24

# Dedicated subnet for Azure Firewall (Firewall name cannot be changed)

az network vnet subnet create \
    --resource-group $RG \
    --vnet-name $VNET_NAME \
    --name $FWSUBNET_NAME \
    --address-prefix 10.42.2.0/24

Creación y configuración de un firewall de Azure con una UDR

Deben configurarse las reglas de entrada y salida del firewall de Azure. El propósito principal del firewall es que las organizaciones puedan configurar reglas de tráfico de entrada y salida pormenorizadas hacia y desde el clúster de AKS.

Firewall and UDR

Importante

Si el clúster o la aplicación crea un gran número de conexiones de salida dirigidas al mismo subconjunto de destinos (o a uno más reducido), es posible que necesite más direcciones IP de front-end de firewall para evitar que se agoten los puertos por IP de front-end. Para obtener más información sobre cómo crear un firewall de Azure con varias direcciones IP, vea esto.

Cree un recurso de IP pública de SKU estándar que se usa como dirección de front-end de Azure Firewall.

az network public-ip create -g $RG -n $FWPUBLICIP_NAME -l $LOC --sku "Standard"

Registre la extensión de la CLI en versión preliminar para crear un firewall de Azure.

# Install Azure Firewall preview CLI extension

az extension add --name azure-firewall

# Deploy Azure Firewall

az network firewall create -g $RG -n $FWNAME -l $LOC --enable-dns-proxy true

La dirección IP creada anteriormente puede asignarse ahora al front-end del firewall.

Nota

La configuración de la dirección IP pública en el firewall de Azure puede tardar unos minutos. Para aprovechar el FQDN en las reglas de red, es necesario habilitar el proxy DNS; cuando lo esté, el firewall escuchará en el puerto 53 y reenviará las solicitudes DNS al servidor DNS especificado anteriormente. Esto permitirá al firewall traducir ese FQDN de forma automática.

# Configure Firewall IP Config

az network firewall ip-config create -g $RG -f $FWNAME -n $FWIPCONFIG_NAME --public-ip-address $FWPUBLICIP_NAME --vnet-name $VNET_NAME

Cuando el comando anterior se haya realizado correctamente, anote la dirección IP del servidor front-end del firewall para la configuración posterior.

# Capture Firewall IP Address for Later Use

FWPUBLIC_IP=$(az network public-ip show -g $RG -n $FWPUBLICIP_NAME --query "ipAddress" -o tsv)
FWPRIVATE_IP=$(az network firewall show -g $RG -n $FWNAME --query "ipConfigurations[0].privateIPAddress" -o tsv)

Nota

Si utiliza el acceso seguro al servidor de la API de AKS con intervalos de direcciones IP autorizados, debe agregar la dirección IP pública del firewall en el intervalo de IP autorizado.

Creación de una UDR con un salto al firewall de Azure

Azure enruta automáticamente el tráfico entre redes locales, las redes virtuales y las subredes de Azure. Si desea cambiar algún enrutamiento predeterminado de Azure, debe crear una tabla de rutas.

Cree una tabla de rutas vacía para asociarla a una subred determinada. La tabla de rutas definirá el próximo salto como el firewall de Azure creado anteriormente. Cada subred puede tener cero o una ruta de tablas de ruta asociada.

# Create UDR and add a route for Azure Firewall

az network route-table create -g $RG -l $LOC --name $FWROUTE_TABLE_NAME
az network route-table route create -g $RG --name $FWROUTE_NAME --route-table-name $FWROUTE_TABLE_NAME --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address $FWPRIVATE_IP
az network route-table route create -g $RG --name $FWROUTE_NAME_INTERNET --route-table-name $FWROUTE_TABLE_NAME --address-prefix $FWPUBLIC_IP/32 --next-hop-type Internet

Consulte en la documentación sobre las tablas de rutas de red virtual cómo invalidar las rutas del sistema predeterminadas de Azure o agregar rutas adicionales a la tabla de rutas de una subred.

Adición de reglas de firewall

Nota

Para las aplicaciones fuera de los espacios de nombres kube-system o gatekeeper-system que necesitan comunicarse con el servidor de la API, se requiere una regla de red adicional para permitir la comunicación TCP al puerto 443 para la dirección IP del servidor de la API, además de agregar una regla de aplicación para fqdn-tag AzureKubernetesService.

Puede usar las tres reglas de red siguientes para configurar el firewall. Puede que necesite adaptar estas reglas en función de su implementación. La primera regla permite el acceso al puerto 9000 a través de TCP. La segunda regla permite el acceso al puerto 1194 y 123 a través de UDP. Las dos reglas solo permitirán el tráfico destinado al CIDR de la región de Azure que se use, en este caso, Este de EE. UU.

Por último, agregamos una tercera regla de red que abre el puerto 123 a un FQDN del servidor de hora de Internet (por ejemplo:ntp.ubuntu.com) a través de UDP. Agregar un FQDN como una regla de red es una de las características específicas de Azure Firewall y tendrá que adaptarla cuando use opciones propias.

Después de establecer las reglas de red, también se agregará una regla de aplicación mediante AzureKubernetesService, que abarca los FQDN necesarios a los que se puede acceder a través del puerto TCP 443 y el puerto 80. Además, es posible que deba configurar reglas de red y de aplicación adicionales en función de la implementación. Para más información, consulte Reglas de FQDN y red de salida para clústeres de Azure Kubernetes Service (AKS).

Adición de reglas de red de FW

az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apiudp' --protocols 'UDP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 1194 --action allow --priority 100
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apitcp' --protocols 'TCP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 9000
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'time' --protocols 'UDP' --source-addresses '*' --destination-fqdns 'ntp.ubuntu.com' --destination-ports 123

Incorporación de reglas de aplicación FW

az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwar' -n 'fqdn' --source-addresses '*' --protocols 'http=80' 'https=443' --fqdn-tags "AzureKubernetesService" --action allow --priority 100

Para más información acerca del servicio Azure Firewall, consulte la documentación de Azure Firewall.

Asociación de la tabla de rutas a AKS

Para asociar el clúster al firewall, la subred dedicada del clúster debe hacer referencia a la tabla de rutas creada anteriormente. Para crear la asociación, se puede emitir un comando a la red virtual que contiene el clúster y el firewall para actualizar la tabla de rutas de la subred del clúster.

# Associate route table with next hop to Firewall to the AKS subnet

az network vnet subnet update -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --route-table $FWROUTE_TABLE_NAME

Implementación de AKS con el tipo de salida UDR a la red existente

Ahora, un clúster de AKS se puede implementar en una red virtual existente. También se usará el tipo de salida userDefinedRouting; esta característica garantiza que se fuerza el tráfico saliente a través del firewall y que no existen otras rutas de salida (de forma predeterminada, se podría usar el tipo de salida Load Balancer).

aks-deploy

La subred de destino en la que se va a realizar la implementación se define con la variable de entorno $SUBNETID. No definimos la variable $SUBNETID en los pasos anteriores. Para establecer el valor del id. de la subred, puede usar el comando siguiente:

SUBNETID=$(az network vnet subnet show -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --query id -o tsv)

Definirá el tipo de salida para usar el UDR que ya existe en la subred. Esta configuración permitirá a AKS omitir la configuración y el aprovisionamiento de IP para el equilibrador de carga.

Importante

Para obtener más información sobre el tipo de salida UDR, incluidas las limitaciones, vea UDR de tipo de salida.

Sugerencia

Se pueden agregar otras características a la implementación del clúster, como Clúster privado o cambiar el SKU de SO.

La característica de intervalos de IP autorizados del servidor de API de AKS se puede agregar para limitar el acceso del servidor de API solo al punto de conexión público del firewall. La característica de intervalos IP autorizados se indica en el diagrama como opcional. Al habilitar la característica de intervalos de IP autorizados para limitar el acceso del servidor de API, las herramientas de desarrollo deben usar una JumpBox desde la red virtual del firewall, o bien debe agregar todos los puntos de conexión de desarrollador al intervalo de direcciones IP autorizado.

az aks create -g $RG -n $AKSNAME -l $LOC \
  --node-count 3 \
  --network-plugin azure \
  --outbound-type userDefinedRouting \
  --vnet-subnet-id $SUBNETID \
  --api-server-authorized-ip-ranges $FWPUBLIC_IP

Nota

Para crear y usar su propia VNet y tabla de rutas con el complemento de red kubenet, necesita usar una identidad administrada asignada por el usuario. Para la identidad administrada asignada por el sistema, no podemos obtener el id. de identidad antes de crear el clúster, lo que causa un retraso para que la asignación de roles surta efecto.

Para crear y usar su propia red virtual y tabla de rutas con el complemento de red azure, se admiten identidades administradas asignadas por el sistema y asignadas por el usuario.

Habilitación del acceso de desarrollador al servidor de API

Si en el paso anterior ha usado intervalos IP autorizados para el clúster, tendrá que agregar las direcciones IP de las herramientas de desarrollador a la lista de intervalos IP autorizados del clúster de AKS para poder acceder al servidor de API desde ahí. Otra opción consiste en configurar una JumpBox con las herramientas necesarias en una subred independiente de la red virtual del firewall.

Agrege otra dirección IP a los intervalos autorizados con el siguiente comando:

# Retrieve your IP address
CURRENT_IP=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)

# Add to AKS approved list
az aks update -g $RG -n $AKSNAME --api-server-authorized-ip-ranges $CURRENT_IP/32

Use el comando az aks get-credentials para configurar kubectl para conectarse a su clúster de Kubernetes recién creado.

az aks get-credentials -g $RG -n $AKSNAME

Restricción del tráfico de entrada mediante Azure Firewall

Ahora puede empezar a exponer servicios e implementar aplicaciones en este clúster. En este ejemplo, se expondrá un servicio público, pero también puede optar por exponer un servicio interno a través de un equilibrador de carga interno.

Public Service DNAT

Para implementar aplicación de votación de Azure, copie el código YAML siguiente en un archivo llamado example.yaml.

# voting-storage-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: voting-storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: voting-storage
  template:
    metadata:
      labels:
        app: voting-storage
    spec:
      containers:
      - name: voting-storage
        image: mcr.microsoft.com/azuredocs/voting/storage:2.0
        args: ["--ignore-db-dir=lost+found"]
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 250m
            memory: 256Mi
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_DATABASE
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
---
# voting-storage-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: voting-storage-secret
type: Opaque
data:
  MYSQL_USER: ZGJ1c2Vy
  MYSQL_PASSWORD: UGFzc3dvcmQxMg==
  MYSQL_DATABASE: YXp1cmV2b3Rl
  MYSQL_ROOT_PASSWORD: UGFzc3dvcmQxMg==
---
# voting-storage-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
# voting-storage-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: voting-storage
  labels:
    app: voting-storage
spec:
  ports:
  - port: 3306
    name: mysql
  selector:
    app: voting-storage
---
# voting-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: voting-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: voting-app
  template:
    metadata:
      labels:
        app: voting-app
    spec:
      containers:
      - name: voting-app
        image: mcr.microsoft.com/azuredocs/voting/app:2.0
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http
        env:
        - name: MYSQL_HOST
          value: "voting-storage"
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_DATABASE
        - name: ANALYTICS_HOST
          value: "voting-analytics"
---
# voting-app-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: voting-app
  labels:
    app: voting-app
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
    name: http
  selector:
    app: voting-app
---
# voting-analytics-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: voting-analytics
spec:
  replicas: 1
  selector:
    matchLabels:
      app: voting-analytics
      version: "2.0"
  template:
    metadata:
      labels:
        app: voting-analytics
        version: "2.0"
    spec:
      containers:
      - name: voting-analytics
        image: mcr.microsoft.com/azuredocs/voting/analytics:2.0
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http
        env:
        - name: MYSQL_HOST
          value: "voting-storage"
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: voting-storage-secret
              key: MYSQL_DATABASE
---
# voting-analytics-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: voting-analytics
  labels:
    app: voting-analytics
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: voting-analytics

Para implementar el servicio, ejecute:

kubectl apply -f example.yaml

Adición de una regla de DNAT al firewall de Azure

Importante

Cuando use Azure Firewall para restringir el tráfico de salida y cree una ruta definida por el usuario (UDR) para forzar todo el tráfico de salida, asegúrese de crear una regla DNAT adecuada en el firewall para permitir correctamente el tráfico de entrada. El uso de Azure Firewall con una UDR interrumpe la configuración de entrada debido al enrutamiento asimétrico. (El problema se produce si la subred de AKS tiene una ruta predeterminada que va a la dirección IP privada del firewall, pero está usando un equilibrador de carga público, de entrada o de servicio de Kubernetes del tipo: LoadBalancer). En este caso, el tráfico entrante del equilibrador de carga se recibe a través de su dirección IP pública, pero la ruta de vuelta pasa a través de la dirección IP privada del firewall. Dado que el firewall es con estado, quita el paquete de vuelta porque el firewall no tiene conocimiento de una sesión establecida. Para aprender a integrar Azure Firewall con el equilibrador de carga de entrada o de servicio, consulte Integración de Azure Firewall con Azure Standard Load Balancer.

Para configurar la conectividad de entrada, se debe escribir una regla de DNAT en el firewall de Azure. Para probar la conectividad con el clúster, se define una regla para la dirección IP pública de front-end del firewall que se va a enrutar a la dirección IP interna expuesta por el servicio interno.

La dirección de destino se puede personalizar porque es el puerto del firewall al que se va a acceder. La dirección traducida debe ser la dirección IP del equilibrador de carga interno. El puerto traducido debe ser el puerto expuesto para el servicio Kubernetes.

Deberá especificar la dirección IP interna asignada al equilibrador de carga creado por el servicio Kubernetes. Para recuperar la dirección, ejecute:

kubectl get services

La dirección IP necesaria se mostrará en la columna EXTERNAL-IP y será similar a la siguiente.

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes         ClusterIP      10.41.0.1       <none>        443/TCP        10h
voting-analytics   ClusterIP      10.41.88.129    <none>        8080/TCP       9m
voting-app         LoadBalancer   10.41.185.82    20.39.18.6    80:32718/TCP   9m
voting-storage     ClusterIP      10.41.221.201   <none>        3306/TCP       9m

Para obtener la IP del servicio, ejecute lo siguiente:

SERVICE_IP=$(kubectl get svc voting-app -o jsonpath='{.status.loadBalancer.ingress[*].ip}')

Para agregar la regla de NAT, ejecute lo siguiente:

az network firewall nat-rule create --collection-name exampleset --destination-addresses $FWPUBLIC_IP --destination-ports 80 --firewall-name $FWNAME --name inboundrule --protocols Any --resource-group $RG --source-addresses '*' --translated-port 80 --action Dnat --priority 100 --translated-address $SERVICE_IP

Validar conectividad

Vaya a la dirección IP de front-end del firewall de Azure en un explorador para validar la conectividad.

Debería ver la aplicación de votación de AKS. En este ejemplo, la dirección IP pública del firewall es 52.253.228.132.

Screenshot shows the A K S Voting App with buttons for Cats, Dogs, and Reset, and totals.

Limpieza de recursos

Para limpiar los recursos de Azure, elimine el grupo de recursos de AKS.

az group delete -g $RG

Pasos siguientes