使用 Azure Kubernetes 服务 (AKS) 中的 Azure 防火墙限制网络流量

了解如何使用 AKS 群集的出站网络和 FQDN 规则来通过 AKS 中的 Azure 防火墙控制出口流量。 为了简化此配置,Azure 防火墙提供了 Azure Kubernetes 服务 (AzureKubernetesService) 完全限定的域名 (FQDN) 标记来限制来自 AKS 群集的出站流量。 本文介绍如何通过 Azure 防火墙配置 AKS 群集流量规则。

注意

FQDN 标记包含 AKS 群集的出站网络和 FQDN 规则中列出的所有 FQDN,并自动更新。

对于生产方案,建议在 Azure 防火墙上至少有 20个前端 IP,以避免 SNAT 端口耗尽问题。

以下信息提供了部署的示例体系结构:

Locked down topology

  • 强制公共入口流量流经防火墙筛选器
    • AKS 代理节点隔离在专用子网中
    • Azure 防火墙部署在自己的子网中
    • DNAT 规则将防火墙公共 IP 转换为负载均衡器前端 IP
  • 出站请求使用用户定义的路由 (UDR) 从代理节点发送到 Azure 防火墙内部 IP
    • 来自 AKS 代理节点的请求遵循 UDR,该 UDR 位于 AKS 群集部署到的子网中
    • Azure 防火墙通过公共 IP 前端将流量传出虚拟网络
    • 对公共 Internet 或其他 Azure 服务的访问流量会流入和流出防火墙前端 IP 地址
    • API 服务器授权的 IP 范围(包括防火墙公共前端 IP 地址)可以保护对 AKS 控制平面的访问
  • 内部流量

配置环境变量

定义创建资源时要使用的一组环境变量。

PREFIX="aks-egress"
RG="${PREFIX}-rg"
LOC="chinaeast2"
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"

创建包含多个子网的虚拟网络

预配包含两个单独子网的虚拟网络:其中一个子网用于群集,一个子网用于防火墙。 还可以选择为内部服务入口创建一个。

Empty network topology

  1. 使用 az group create 命令创建资源组。

    az group create --name $RG --location $LOC
    
  2. 使用 az network vnet createaz network vnet subnet create 命令创建具有两个子网的虚拟网络来托管 AKS 群集和 Azure 防火墙。

    # 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 can't be changed)
    az network vnet subnet create \
        --resource-group $RG \
        --vnet-name $VNET_NAME \
        --name $FWSUBNET_NAME \
        --address-prefix 10.42.2.0/24
    

创建和设置 Azure 防火墙

你需要配置 Azure 防火墙入站和出站规则。 防火墙的主要用途是使组织能够针对传入和传出 AKS 群集的流量配置精细的规则。

重要

如果群集或应用程序创建众多定向到相同目标或目标子集的出站连接,则可能需要更多的防火墙前端 IP 来避免用尽每个前端 IP 的端口。

有关如何创建具有多个 IP 的 Azure 防火墙的详细信息,请参阅使用 Bicep 创建具有多个公共 IP 地址的 Azure 防火墙

Firewall and UDR

  1. 使用 az network public-ip create 命令创建标准 SKU 公共 IP 资源。 此资源将用作 Azure 防火墙前端地址。

    az network public-ip create -g $RG -n $FWPUBLICIP_NAME -l $LOC --sku "Standard"
    
  2. 注册 Azure 防火墙 CLI 扩展,以使用 az extension add 命令创建 Azure 防火墙。

    az extension add --name azure-firewall
    
  3. 使用 az network firewall create 命令创建 Azure 防火墙并启用 DNS 代理,并将 --enable-dns-proxy 设置为 true

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

为 Azure 防火墙设置公共 IP 地址可能需要几分钟时间。 准备就绪后,可以将之前创建的 IP 地址分配给防火墙前端。

注意

若要在网络规则上利用 FQDN,需要启用 DNS 代理。 当启用 DNS 代理时,防火墙侦听端口 53 并将 DNS 请求转发到上面指定的 DNS 服务器。 这允许防火墙自动转换 FQDN。

  1. 使用 az network firewall ip-config create 命令创建 Azure 防火墙 IP 配置。

    az network firewall ip-config create -g $RG -f $FWNAME -n $FWIPCONFIG_NAME --public-ip-address $FWPUBLICIP_NAME --vnet-name $VNET_NAME
    
  2. 前面的命令成功后,请保存防火墙前端 IP 地址以便稍后进行配置。

    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)
    

注意

如果通过授权 IP 地址范围安全访问 AKS API 服务器,需要将防火墙公共 IP 添加到授权的 IP 范围。

创建包含 Azure 防火墙跃点的路由

Azure 自动在 Azure 子网、虚拟网络与本地网络之间路由流量。 若要更改 Azure 的任何默认路由,可以创建一个路由表。

重要

UDR (userDefinedRouting) 的出站类型要求路由表中有 0.0.0.0/0 的路由和 NVA 的下一个跃点目标。 路由表已具有指向 Internet 的默认 0.0.0.0/0。 如果 Azure 没有用于源网络地址转换 (SNAT) 的公共 IP 地址,只需添加此路由将无法提供出站 Internet 连接。 AKS 将验证你没有创建指向 Internet 的 0.0.0.0/0 路由,而是创建了指向网关、NVA 等的路由。使用 UDR 出站类型时,不会创建用于入站请求的负载均衡器公共 IP 地址,除非配置了 loadbalancer 类型的服务。 如果设置了 UDR 的出站类型,则 AKS 永远不会为出站请求创建公共 IP 地址。 有关详细信息,请参阅 Azure 负载均衡器的出站规则

  1. 使用 az network route-table create 命令创建一个要与给定子网关联的空路由表。 该路由表将下一跃点定义为前面创建的 Azure 防火墙。 每个子网可以有一个与之关联的路由表,也可以没有。

    az network route-table create -g $RG -l $LOC --name $FWROUTE_TABLE_NAME
    
  2. 使用 az network route-table route create 命令在子网的路由表中创建路由。

    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
    

有关如何覆盖 Azure 的默认系统路由或将其他路由添加到子网的路由表的信息,请参阅虚拟网络路由表文档

添加防火墙规则

注意

对于需要与 API 服务器通信的 kube 系统或 gatekeeper 系统命名空间外部的应用程序,除了为 fqdn-tag AzureKubernetesService 添加应用程序规则之外,还需要一条额外的网络规则来允许与 API 服务器 IP 的端口 443 进行 TCP 通信。

本部分介绍三个网络规则和一个可用于在防火墙上配置的应用程序规则。 你可能需要根据部署调整这些规则。

  • 第一个网络规则允许通过 TCP 访问端口 9000。
  • 第二个网络规则允许通过 UDP 访问端口 1194 和 123。 如果要部署到由世纪互联运营的 Azure,请参阅世纪互联运营的 Azure 的必需网络规则。 这两个规则将仅允许发往本文中的 Azure 区域 CIDR(即“中国东部”)的流量。
  • 第三个网络规则通过 UDP 向 ntp.ubuntu.com FQDN 开放端口 123。 将 FQDN 添加为网络规则是 Azure 防火墙的一项特定功能,因此你使用自己的选项时需要对其进行调整。
  • 第四和第五个网络规则允许从 GitHub 容器注册表 (ghcr.io) 和 Docker Hub (docker.io) 拉取容器。
  1. 使用 az network firewall network-rule create 命令创建网络规则。

    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
    
    az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'ghcr' --protocols 'TCP' --source-addresses '*' --destination-fqdns ghcr.io pkg-containers.githubusercontent.com --destination-ports '443'
    
    az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'docker' --protocols 'TCP' --source-addresses '*' --destination-fqdns docker.io registry-1.docker.io production.cloudflare.docker.com --destination-ports '443'
    
  2. 使用 az network firewall application-rule create 命令创建应用程序规则。

    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
    

若要详细了解 Azure 防火墙,请参阅 Azure 防火墙文档

将路由表关联到 AKS

若要将群集与防火墙相关联,群集子网的专用子网必须引用前面创建的路由表。 使用 az network vnet subnet update 命令将路由表关联到 AKS。

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

部署遵循你的出站规则的 AKS 群集

现在,你可以将 AKS 群集部署到现有的虚拟网络中。 你将使用 userDefinedRouting 出站类型,这可确保强制任何出站流量通过防火墙,并且不存在其他出口路径。 也可以使用 loadBalancer 出站类型

aks-deploy

要部署到的目标子网是使用环境变量 ($SUBNETID) 定义的。 使用以下命令设置子网 ID 的值:

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

使用子网中已存在的 UDR 来定义出站类型。 此配置使 AKS 跳过负载均衡器的设置和 IP 预配。

提示

可以向群集部署添加其他功能,例如专用群集

可以添加 API 服务器授权 IP 范围的 AKS 功能,以将 API 服务器限制为仅访问防火墙的公共终结点。 已授权 IP 范围功能在图中表示为可选。 启用授权 IP 范围功能以限制 API 服务器访问权限时,开发者工具必须使用防火墙的虚拟网络中的 jumpbox,或者必须将所有开发者终结点添加到授权 IP 范围。


注意

如果你未指定自己的 kubelet 托管标识,AKS 将在节点资源组中创建系统分配的 kubelet 标识。

对于用户定义的路由,系统分配的标识仅支持 CNI 网络插件。

使用 az aks create 命令,通过 CNI 网络插件使用系统分配的托管标识创建 AKS 群集。

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

使开发人员能够访问 API 服务器

如果在上一步中为群集使用了已授权 IP 范围,则必须将开发人员工具 IP 地址添加到 AKS 群集的已批准 IP 范围列表,以便从该处访问 API 服务器。 你还可以使用位于防火墙的虚拟网络中的单独子网内的所需工具配置 jumpbox。

  1. 使用以下命令检索 IP 地址:

    CURRENT_IP=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)
    
  2. 使用 az aks update 命令将 IP 地址添加到批准的范围中。

    az aks update -g $RG -n $AKSNAME --api-server-authorized-ip-ranges $CURRENT_IP/32
    
  3. 使用 az aks get-credentials 命令将 kubectl 配置为连接到 AKS 群集。

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

在 AKS 上部署公共服务

现在可以开始公开服务并将应用程序部署到此群集。 在此示例中,我们将公开一个公共服务,但你也可能需要使用内部负载均衡器公开内部服务。

Public Service DNAT

  1. 查看 AKS 应用商店演示快速入门清单,查看将创建的所有资源。

  2. 使用 kubectl apply 命令部署服务。

    kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/aks-store-demo/main/aks-store-quickstart.yaml
    

允许入站流量通过 Azure 防火墙

重要

当使用 Azure 防火墙来限制出口流量并创建一个 UDR 来强制所有出口流量时,请确保在 Azure 防火墙中创建适当的 DNAT 规则来正确地允许入口流量。 结合使用 Azure 防火墙和 UDR 时,会因为路由不对称而中断入口设置。 如果 AKS 子网的默认路由指向防火墙的专用 IP 地址,但使用的是公共负载均衡器 - 传入或 Kubernetes 服务类型 loadBalancer。 在这种情况下,将通过负载均衡器的公共 IP 地址接收传入的负载均衡器流量,但返回路径将通过防火墙的专用 IP 地址。 由于防火墙是有状态的,并且无法识别已建立的会话,因此会丢弃返回的数据包。 若要了解如何将 Azure 防火墙与入口或服务负载均衡器集成,请参阅将 Azure 防火墙与 Azure 标准负载均衡器集成

若要配置入站连接,你需要向 Azure 防火墙写入 DNAT 规则。 为了测试与群集的连接,为防火墙前端公共 IP 地址定义了规则,以便路由到内部服务公开的内部 IP。 可以自定义目标地址。 转换的地址必须是内部负载均衡器的 IP 地址。 转换的端口必须是 Kubernetes 服务的已公开端口。 还需要指定分配给 Kubernetes 服务创建的负载均衡器的内部 IP 地址。

  1. 使用 kubectl get services 命令获取分配给负载均衡器的内部 IP 地址。

    kubectl get services
    

    该 IP 地址将在 EXTERNAL-IP 列中列出,如以下示例输出所示:

    NAME              TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)              AGE
    kubernetes        ClusterIP      10.0.0.1       <none>        443/TCP              9m10s
    order-service     ClusterIP      10.0.104.144   <none>        3000/TCP             11s
    product-service   ClusterIP      10.0.237.60    <none>        3002/TCP             10s
    rabbitmq          ClusterIP      10.0.161.128   <none>        5672/TCP,15672/TCP   11s
    store-front       LoadBalancer   10.0.89.139    20.39.18.6    80:32271/TCP         10s
    
  2. 使用 kubectl get svc voting-app 命令获取服务 IP。

    SERVICE_IP=$(kubectl get svc store-front -o jsonpath='{.status.loadBalancer.ingress[*].ip}')
    
  3. 使用 az network firewall nat-rule create 命令添加 NAT 规则。

    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
    

验证连接

在浏览器中导航到 Azure 防火墙前端 IP 地址来验证连接。

应看到 AKS 商店应用。 在此示例中,防火墙公共 IP 为 52.253.228.132

Screenshot showing the Azure Store Front App opened in a local browser.

在此页上,可以查看产品,将其添加到购物车,然后下订单。

清理资源

若要清理 Azure 资源,请使用 az group delete 命令删除 AKS 资源组。

az group delete -g $RG

后续步骤

本文介绍了如何使用 Azure 防火墙保护出站流量。 如果需要,则可以概括上述步骤,以便按照出站类型 userDefinedRoute 文档将流量转发到首选出口解决方案。