在 GKE 集群上使用 Cloud Service Mesh 出站流量网关的最佳实践

本文档介绍如何使用 Cloud Service Mesh 出站流量网关和其他 Google Cloud 控制措施保护来自 Google Kubernetes Engine (GKE) 集群上部署的工作负载的出站流量。这些控制措施可以根据来源应用的身份、团队的命名空间、目标网域和传出请求的其他属性来限制与外部服务的连接。

您可以将配套教程作为蓝图,在您自己的集群中配置出站流量控制。

本文档的目标受众包括管理由一个或多个软件交付团队使用的 GKE 集群的网络、平台和安全工程师。对于必须展示其遵从了法规(例如 GDPRPCI)的组织,此处介绍的控制措施可能尤为有用。

简介

传统的网络安全方法是围绕一组应用定义安全边界,并在这些边界上使用防火墙,以根据来源和目标 IP 地址允许或拒绝流量,同时信任边界内的应用和流量。但是,这种信任存在风险。恶意内部人员或破解了边界的任何人员可以在网络内自由移动、访问和渗漏数据、攻击第三方系统以及干扰管理系统。

当 Kubernetes 集群上运行的工作负载与互联网上的主机建立出站连接时,应用传统的基于 IP 的安全控制措施可能会很复杂,原因如下:

  • pod IP 地址不足以表示建立连接的工作负载的身份。在 Kubernetes 环境中,pod IP 地址是临时分配的,并随着 pod 的加入和退出频繁回收。

  • 通常不可能为特定目标主机确定一小组固定的 IP 地址。IP 地址经常变化,因区域而异,并且可能来自较大的范围,或者代表缓存、代理或 CDN

  • 共享同一多租户集群的多个团队共享来源 IP 范围,但他们可能会有不同的外部连接要求。

Cloud Service Mesh 是 Google 全面支持的开源 Istio 服务网格的发行版。服务网格提供了连接、管理和保护应用通信的统一方式。服务网格采取以应用为中心的方法并使用可信应用身份,而非基于网络 IP 的方法。

您可以透明地部署服务网格,而无需修改现有的应用代码。服务网格对网络行为进行声明式控制,有助于将负责交付和发布应用功能的开发团队的工作与网络管理员的职责分离开来。

Cloud Service Mesh 提供了在网格边缘部署独立转发代理(称为出站流量网关)的部署选项。本指南介绍如何将出站流量网关代理的功能与 Google Cloud 功能相结合,以控制、授权和观察部署到 GKE 集群的工作负载的出站流量。

概念性组件

深度防御架构

下图显示了一个采用深度防御方法的架构,它对一个多团队使用的集群的出站流量进行精细控制。这些控制措施基于第 4 层(传输)第 7 层(应用)网络控制。

整体架构

该架构使用以下资源和控制措施:

  • 专用 GKE 集群:专用 GKE 集群上的节点仅具有内部 IP 地址,默认不连接到互联网。

  • Cloud NAT:Cloud NAT 允许从专用集群到互联网的出站访问。

  • Virtual Private Cloud (VPC) 防火墙规则:您可以配置 VPC 防火墙规则,将第 4 层(传输)控制应用于与 GKE 集群中节点的连接。您可以根据服务账号网络标记将 VPC 防火墙规则应用于虚拟机。

  • 具有不同服务账号的 GKE 节点池:您可以根据节点所属的节点池配置要应用的不同防火墙规则。

  • Kubernetes 命名空间:您可以为每个团队创建命名空间,以提供隔离和委派管理控制。网络管理员使用专用命名空间部署出站流量网关并配置到外部主机的路由。

  • Kubernetes 网络政策:通过网络政策,您可以向 pod 应用第 4 层控制。每项网络政策的范围都限定为一个命名空间,并且可以更精细地限定为命名空间中的特定 pod。

  • 出站流量网关:离开网格中 pod 的流量通过专用节点上运行的专用出站流量网关代理定向。您可以使用横向 pod 自动扩缩器部署出站流量网关,以使副本数随流量扩缩。

  • 授权政策:使用网格授权政策将第 7 层(应用)控制应用于网格内 pod 之间的流量以及离开网格的流量。

  • Sidecar 资源:使用 Sidecar 资源控制每个工作负载 pod 中运行的 Sidecar 代理的配置范围。您可以使用 Sidecar 资源配置工作负载可见的命名空间、pod 和外部服务。

  • 专用 Google 访问通道:此选项允许专用集群上的节点和 pod 访问 Google API,并从 Container Registry 拉取 Docker 映像。

  • GKE Workload Identity:借助 Workload Identity,您可以根据最小权限原则使用 Identity and Access Management (IAM) 将 API 权限授予特定工作负载,而无需处理 Secret。

配置出站流量控制

如果您使用出站流量网关保护来自网格的出站流量,我们建议您配置本部分中介绍的深度防御控制。

使用专用 GKE 和 Cloud NAT

在安全至关重要的领域,许多组织的首要要求是避免向工作负载分配公共 IP 地址。专用 GKE 集群可满足此要求。您可以在专用集群上配置 VPC 原生模式,从而向 pod 和服务分配 VPC 次要范围中的 IP 地址。VPC 原生 pod IP 地址在 VPC 网络中是原生可路由的。

某些工作负载可能需要访问 VPC 网络之外的服务和互联网。如需允许工作负载连接到外部主机而无需分配公共 IP 地址,请配置 Cloud NAT 以提供网络地址转换 (NAT)。

确保配置 Cloud NAT 使得出站流量网关能够建立足够的与外部目标的并发连接。通过恰当设置每个虚拟机的端口数下限,可以避免端口耗尽以及连接重用延迟方面的问题。如需了解详情,请参阅 Cloud NAT 地址和端口概览。增加出站流量网关副本的数量有助于降低端点独立映射冲突的概率。

为 Google API 和服务配置专用 Google 访问通道

您的工作负载可能需要能够访问 Google API 和服务。将专用 Google 访问通道与自定义 DNS 区域搭配使用,从而利用 4 个 IP 地址允许专用 VPC 子网连接到 Google API。使用这些 IP 地址时,pod 不需要外部 IP 地址,并且流量始终不会离开 Google 网络。您可以使用 private.googleapis.com (199.36.153.8/30) 或 restricted.googleapis.com (199.36.153.4/30),具体取决于您是否使用 VPC Service Controls

使用 Workload Identity 和 IAM 进一步保护 Google API 和服务

建议使用 Workload Identity 来允许 GKE 工作负载向 Google API 进行身份验证,管理员可以使用 IAM 应用“最小权限”授权控制措施。

使用专用 Google 访问通道、Workload Identity 和 IAM 时,您可以安全地允许工作负载 pod 绕过出站流量网关并直接连接到 Google API 和服务。

使用 Kubernetes 命名空间进行管理控制

命名空间是一种组织资源,适用于具有许多用户、团队或租户的环境。它们可被视为虚拟集群,允许将各组 Kubernetes 资源的管理职责委派给不同的管理员。

命名空间是隔离管理控制的一项重要功能。但默认情况下,命名空间不提供节点隔离、数据层面隔离或网络隔离。

Cloud Service Mesh 基于 Kubernetes 命名空间构建,将它们用作服务网格中的租户单元。网格授权政策和 Sidecar 资源可根据命名空间、身份和网络流量的第 7 层(应用)属性来限制可见性和访问权限。

同样,您可以使用 Kubernetes 网络政策在第 4 层(传输)允许或拒绝网络连接。

在专用网关节点上运行出站流量网关

在专用网关节点池中的节点上运行出站流量网关具有多项优势。面向外部的节点可以使用安全强化的配置,并且您可以将 VPC 防火墙规则配置为阻止工作负载直接访问外部主机。可以使用集群自动扩缩器独立自动扩缩节点池。

如需允许对出站流量网关进行单独管理控制,请将其部署到专用 istio-egress 命名空间。但是,命名空间是集群范围的资源,无法用它来控制部署运行的节点。对于部署控制,请使用节点选择器进行出站流量网关部署,这样它会在标记为网关节点池成员的节点上运行。

确保只有网关 pod 可以在网关节点上运行。其他 pod 应从网关节点驱逐,否则出站流量控制可能会被绕过。通过使用污点和容忍,您可以阻止工作负载在某些节点上运行。您应该将网关节点池中的节点设置为污点,并在出站流量网关部署中添加相应的容忍。

将 VPC 防火墙规则应用于特定节点

您可以配置服务网格路由,以通过网关节点池中运行的出站流量网关定向来自默认节点池中运行的工作负载的出站流量。但是,网格的路由配置不应被视为可信的安全边界,因为工作负载可以通过多种方式绕过网格代理。

要阻止应用工作负载直接连接到外部主机,请将限制性出站防火墙规则应用于默认节点池中的节点。对网关节点应用单独的防火墙规则,以使其上运行的出站流量网关 pod 可以连接到外部主机。

创建 VPC 防火墙规则时,您可以指定防火墙规则允许或拒绝的端口和协议,以及防火墙规则应用的流量方向。出站规则应于传出流量,入站规则应用于传入流量。出站规则默认为 allow,入站规则默认为 deny

防火墙规则会按照您指定的优先级编号按顺序应用。防火墙规则是有状态的,这意味着如果允许来自某个虚拟机的特定流量,则也将允许使用同一连接的返回流量。

下图展示了如何根据分配给节点的服务账号将不同的防火墙规则应用于两个不同的节点池中的节点。在这种情况下,默认的 deny all 防火墙规则拒绝整个 VPC 的出站访问。为了避免覆盖集群运行所必需的默认防火墙规则,您的 deny all 规则应使用较低优先级,例如 65535。将额外和更高优先级的出站防火墙规则应用于网关节点,以允许它们通过端口 80 和 443 直接连接到的外部主机。默认节点池无法访问外部主机。

防火墙节点池

将 Kubernetes 网络政策用作 pod 和命名空间的防火墙

作为一项深度防御策略的一部分,请使用 Kubernetes 网络政策添加一层额外的安全保障。网络政策的范围限定为命名空间,并在第 4 层(传输)运行。通过网络政策,您可以限制以下入站和出站流量:

  • 命名空间之间
  • 到命名空间内的 pod
  • 到特定端口和 IP 地址块。

当任何网络政策选择命名空间中的 pod 之后,任何未明确允许的连接都会被拒绝。在应用多个网络政策时,结果将累加,并且是政策的集合。政策的应用顺序无关紧要。

配套教程包含以下网络政策示例:

  • 允许从工作负载命名空间到 istio-systemistio-egress 命名空间的出站连接。pod 必须能够连接到 istiod 和出站流量网关。
  • 允许工作负载从工作负载命名空间向 kube-system 命名空间中的端口 53 发出 DNS 查询。
  • (可选)允许同一命名空间中的工作负载相互连接。
  • (可选)允许不同应用团队使用的命名空间之间的出站连接。
  • 允许从工作负载命名空间到 Google API 的 VIP(使用专用 Google 访问通道公开)的出站连接。Cloud Service Mesh 提供代管式 CA 并将其作为 API 公开,因此 Sidecar 代理必须能够连接到该 CA。某些工作负载可能需要访问 Google API。
  • 允许从工作负载命名空间到 GKE 元数据服务器的出站连接,使 Sidecar 代理和工作负载可以进行元数据查询并向 Google API 进行身份验证。

默认情况下,当 Sidecar 代理注入工作负载 pod 后,系统会对 iptables 规则进行编程,以便代理能够捕获所有入站和出站 TCP 流量。但是,如前所述,工作负载可以通过某些方式绕过代理。VPC 防火墙规则可阻止来自运行工作负载的默认节点的直接出站访问。您可以使用 Kubernetes 网络政策来确保不允许来自工作负载命名空间的直接外部出站流量,并且此出站流量可以流向 istio-egress 命名空间。

如果您同时使用网络政策控制入站流量,则需要创建与出站政策对应的入站政策。

Cloud Service Mesh 配置和安全

服务网格中运行的工作负载不根据其 IP 地址标识。Cloud Service Mesh 以 X.509 证书和密钥的形式为每个工作负载分配一个高强度的可验证身份。使用经过身份验证和加密的双向 TLS (mTLS) 连接在工作负载之间建立可信通信。

通过为每个应用使用 mTLS 身份验证和明确定义的身份,您可以使用网格授权政策来精细控制工作负载与外部服务的通信方式。

虽然流量可以直接从 Sidecar 代理离开网格,但如果您需要进行额外的控制,我们建议您按照本指南中的说明通过出站流量网关路由流量。

在专用命名空间中管理出站流量控制的配置

允许网络管理员通过为出站流量相关网格配置使用专用的 istio-egress 命名空间来集中管理控制措施。如前所建议,将出站流量网关部署到 istio-egress 命名空间。您可以在此命名空间中创建和管理服务条目、网关和授权政策。

需要明确配置外部目标

确保仅使用服务网格注册表中明确定义的外部主机的路由对网格代理进行编程。在每个命名空间的默认 Sidecar 资源中,将出站流量政策模式设置为 REGISTRY_ONLY。设置网格的出站流量政策不应被视为安全边界控制措施。

使用服务条目定义外部目标

配置服务条目以在网格的服务注册表中明确注册外部主机。默认情况下,服务条目对所有命名空间可见。使用 exportTo 属性可以控制某个服务条目对哪些命名空间可见。服务条目决定在网格代理中配置的出站路由,但不应被视为确定工作负载可与哪些外部主机连接的安全控制措施。

使用网关资源配置出站流量网关行为

使用网关资源配置出站流量网关的负载均衡行为。您可以为特定的一组主机、协议和端口配置负载平衡器,并将其与出站流量网关部署相关联。例如,可以为通过端口 80 和 443 流向任何外部主机的出站流量配置网关。

在 Cloud Service Mesh 1.6 及更高版本中,自动 mTLS 默认处于启用状态。通过自动 mTLS,客户端 Sidecar 代理会自动检测服务器是否具有 Sidecar。客户端 Sidecar 会将 mTLS 发送到具有 Sidecar 的工作负载,并将纯文本流量发送到没有 Sidecar 的工作负载。即使启用了自动 mTLS,从 Sidecar 代理发送到出站流量网关的流量也不会自动使用 mTLS。要指示如何保护与出站流量网关的连接,您必须在网关资源上设置 TLS 模式。尽可能为从 Sidecar 代理到出站流量网关的连接使用 mTLS。

您可以允许工作负载自行发起 TLS (HTTPS) 连接。如果工作负载发起 TLS 连接(通常在端口 443 上),您必须配置网关以便为该端口上的连接使用 passthrough 模式。但是,使用 passthrough 模式意味着网关无法基于工作负载的身份或加密请求的属性应用授权政策。此外,无法同时使用 mTLS 和 passthrough

tls 直通

配置虚拟服务和目标规则以通过网关路由流量

使用虚拟服务目标规则配置路由,使来自 Sidecar 代理的流量通过出站流量网关到达外部目标。虚拟服务定义匹配特定流量的规则。匹配的流量将被发送到目标位置。目标规则可以定义子集(例如出站流量网关或外部主机),以及在流量被路由到目标时应如何处理流量。

对多个目标主机使用单个目标规则,以明确指定应如何保护从 Sidecar 代理到网关的流量。如前所述,首选方法是工作负载发送纯文本请求,Sidecar 代理发起到网关的 mTLS 连接。

对每个外部主机使用一个目标规则,将出站流量网关配置为在转发到目标时将纯文本 HTTP 请求“升级”为使用 TLS (HTTPS) 连接。将纯文本连接升级为 TLS 通常称为 TLS 源。

使用 Sidecar 资源控制代理配置的范围

为每个命名空间配置默认的 Sidecar 资源以控制 Sidecar 代理的行为。使用 Sidecar 资源的出站流量属性控制并尽量减少代理的出站监听器中配置的目标主机。典型的最小配置可能包括每个命名空间中的以下目标:

  • 同一命名空间中的 pod
  • Google API 和服务
  • GKE 元数据服务器
  • 使用服务条目配置的特定外部主机

在 Sidecar 代理中配置出站监听器不应被视为安全控制措施。

最佳做法是使用 Sidecar 资源来限制代理配置的大小。默认情况下,网格中的每个 Sidecar 代理都配置为允许向每个其他代理发送流量。将代理配置限制为需要通信的主机,可以大大减少 Sidecar 代理和控制层面的内存消耗量。

使用授权政策在出站流量网关上允许或拒绝流量

AuthorizationPolicy 是一种资源,可让您为网格流量配置精细的访问权限控制政策。您可以创建政策来根据来源、目标或流量本身的属性(例如 HTTP 请求的主机或标头)允许或拒绝流量。

要根据来源工作负载的身份或命名空间允许或拒绝连接,必须使用 mTLS 对与出站流量网关的连接进行身份验证。从 Sidecar 到出站流量网关的连接不会自动使用 mTLS,因此与网关的连接的目标规则必须明确指定 ISTIO_MUTUAL TLS 模式

要使用授权政策在网关允许或拒绝请求,工作负载应向网格外的目标发送纯文本 HTTP 请求。然后,Sidecar 代理可以使用 mTLS 将请求转发到网关,网关可以发起与外部主机的安全 TLS 连接。

如需支持不同团队和应用的出站流量要求,请为每个命名空间或工作负载配置单独的“最小权限”授权政策。例如,您可以根据来源工作负载的命名空间和请求的属性指定规则,从而在出站流量网关上应用不同的政策,如下所示:

  • 如果来源命名空间为 team-x 并且目标主机为 example.com,则允许流量。

    授权政策示例

  • 如果来源命名空间为 team-y 并且目标主机为 httpbin.org 并且路径为 /status/418,则允许流量。

    使用 httpbin 的授权政策

所有其他请求都会被拒绝。

将出站流量网关配置为发起与目标的 TLS (HTTPS) 连接

配置目标规则使出站流量网关发起与外部目标的 TLS (HTTPS) 连接。

要使出站流量网关上的 TLS 源起作用,工作负载必须发送纯文本 HTTP 请求。如果工作负载发起 TLS,出站流量网关会在原始 TLS 之上封装 TLS,那么对外部服务的请求将失败。

由于工作负载发送纯文本 HTTP 请求,因此将工作负载的 Sidecar 代理配置为在将请求发送到网关时建立 mTLS 连接。然后,出站流量网关会终止 mTLS 连接,并发起到目标主机的常规 TLS (HTTPS) 连接。

出站流量网关上的 TLS 源

这样做具有很多优势:

  • 您可以使用授权政策根据来源工作负载和请求的属性来允许或拒绝流量。

  • 工作负载 pod 和出站流量网关之间的流量经过加密和身份验证 (mTLS),出站流量网关和目标之间的流量经过加密 (TLS/HTTPS)。

  • 在网格中,Sidecar 代理可以观察 HTTP 请求的属性(例如标头)并执行相应操作,从而提供额外的可观察性和控制选项。

  • 可以简化应用代码。开发者无需处理证书或 HTTPS 客户端库,服务网格能够使用标准和最新的加密方式确保通信安全。

  • 出站流量网关发起的到外部服务的 TLS 连接可以重复用于来自多个 pod 的流量。连接重复使用更为高效,并且降低了达到连接数上限的风险。

DNS、主机名和通配符

根据目标主机路由、拒绝或允许流量时,您必须完全信任 DNS 系统的完整性,其可将 DNS 名称解析为正确的 IP 地址。在 Kubernetes Engine 集群上,Kubernetes DNS 服务处理 DNS 查询,然后将外部查询委派给 GKE 元数据服务器和内部 DNS。路由到外部主机时,将服务条目的解析属性设置为 DNS,使 Sidecar 代理负责进行 DNS 查询。

Cloud Service Mesh 可以根据通配符主机路由流量。最简单的情况是共享通用名称并托管在一组共同的服务器上的主机的通配符。例如,如果一组服务器可以处理与 *.example.com 匹配的网域,则可以使用通配符主机。

由于 Istio 使用的 Envoy 代理存在某些限制,因此标准出站流量网关无法基于更宽泛的和任意的通配符主机(如 *.com)进行转发。Envoy 只能将流量路由到预定义主机、预定义 IP 地址或请求的原始目标 IP 地址。使用出站流量网关时,请求的原始目标 IP 会丢失,因为它会被替换为网关的 IP,并且无法预先配置任意目标主机。

政策的管理强制执行

使用 Kubernetes 基于角色的访问权限控制 (RBAC)

只有获得授权的管理员才能配置出站流量控制。配置 Kubernetes 基于角色的访问权限控制 (RBAC) 可以避免未经授权规避出站流量控制。应用 RBAC 角色,使得只有网络管理员能够管理 istio-egressistio-system,kube-system 命名空间及以下资源:

  • Sidecar
  • ServiceEntry
  • 网关
  • AuthorizationPolicy
  • NetworkPolicy

限制容忍的使用

如前所述,您可以使用污点和容忍来防止工作负载 pod 部署到网关节点上。但是,默认情况下,没有什么机制可以阻止部署容忍网关节点的工作负载,这样一来,出站流量控制就会被绕过。如果能够对部署流水线强制执行集中式管理控制,您可以使用它们来对某些容忍密钥实施限制。

另一种方法是使用 Kubernetes 准入控制。Anthos 包含一个称为政策控制器的组件,它充当 Kubernetes 准入控制器并验证部署是否满足您指定的政策限制。

确保记录流量

一般而言,有必要记录跨越网络边界的所有流量。如果您需要证明您遵从常见的数据保护法规,那么流量日志记录就非常重要。流量日志直接发送到 Cloud Logging,可从 Google Cloud 控制台中的 Cloud Service Mesh 信息中心访问。您可以根据各种属性(包括来源/目的地、身份、命名空间、流量属性和延迟时间)过滤日志。

为了能够使用 kubectl 轻松进行调试,请在安装 Cloud Service Mesh 时使用 accessLogFile 设置允许流量日志记录发送到 stdout

每当 Mesh CA 为工作负载创建证书时,系统都会将审核日志发送到 Cloud Logging。

考虑为多集群网格中的出站流量网关使用单独的集群

Cloud Service Mesh 可以跨多个 GKE 集群部署。多集群网格引入了控制出站流量的新可能性和一些限制。

您可以将出站流量网关部署到不运行常规工作负载的独立集群,而不是部署到专用节点池。使用单独的集群可以在工作负载和网关之间实现类似隔离,而无需使用污点和容忍。出站流量网关可与入站流量网关或其他中央服务共享单独的集群。

您可以在多集群部署中使用 Kubernetes 网络政策,但由于它们在第 4 层(传输)运行,因此无法根据目标命名空间或 pod 限制跨集群连接。

后续步骤