是时候思考 Kubernetes 出向流量安全了

点击查看目录

为何要进行 Egress 流量策略管控

2021 年 CNCF 调查显示,全球将 kubernetes 用在生产环境的用户占比已达 59.77%,欧洲用户更是达到了 68.98%。用户正越来越多的将生产业务迁移到 kubernetes 环境下。Gartner 2021 Hype Cycle for Cloud Security 也显示了容器与 Kubernetes 安全已处在”slope of Enlightenment”阶段。这说明保护 kubernetes 里的应用服务正变的越来越重要。

当我们去审视运行在 kubernetes 中的大量微服务时,我们可以看到微服务安全具有典型的微边界以及需要进行持续性安全工程的特点。我们需要以每个微服务为边界进行保护,无论是其运行时,还是南北和东西流量。需要每个微服务单元在编码之初就开始着手安全考虑,进行安全左移,安全的防护设施、方法、策略应与开发者和 kubernetes 平台运维者适配。还需要有能力洞察所有的流量事件,采集所有运行时日志、事件等数据,通过持续性的安全工程系统对这些数据进行分析,聚合出规则并反馈到安全的策略设定中。

kubernetes 里的微服务不会只在集群内部封闭运行,它需要访问集群外部应用、数据库、第三方 API 服务、互联网服务等。出向流量里可能包含业务需要的外部访问,开源组件更新的访问,甚至可能是被入侵的应用向 C2 连接的流量。因此,必须对 kubernetes 中的微服务主动外出流量进行管控,确保其安全合规。在以云原生架构为核心技术驱动的数字化转型下,企业会大量采用开源技术,而这可能是最容易引入安全风险的地方,无论是否有明确的开源准入机制,企业都应足够重视这些开源产品可能的主动外访服务,将其管控好,确保安全。

管理 kubernetes 中的出向流量策略,看似简单的需求,要想做好却并不是一件容易的事。本文将和您一起分析 kubernetes 出向策略的挑战,并针对当前常见解决方案的优缺点进行分析,思考企业应如何做好 kubernetes 出向流量策略管控。

存在的挑战

动态

从技术角度看,这是第一个存在的挑战。在 kubernetes 环境下,微服务单元的 pods 将是高度动态的、分散的。IP、网段和物理位置将会随时发生变化。因此直接采用 IP 等特征进行静态化策略设定将是一件不可能的事情。策略必须依赖于其它抽象的应用标签、服务名或命名空间等进行,并能做到动态感知变化。

粒度

传统应用环境下,对一个应用出向流量策略的管控一般来说只需要对该应用所涉及的少量部署进行策略设定即可。然而在微服务加容器化的环境下,一个应用可能会有许多的微服务组成,而一个微服务又包含许多 pods。不同的微服务单元会需要不同的出向策略规则,比如 payment 需要连接第三方外部接口,而评论服务则不需要主动访问第三方服务。这意味着策略设定的粒度需要精细到每个微服务单元,并确保管控了所有相关的 pods。可以看出,策略管控粒度更细、工作量更大、复杂性更高。

协同

当我们要为不同的微服务单元部署出向策略时候,谁应该为此负责,应用开发部门?应用部署与运维部门?kubernetes 的 platformOps 部门?或是安全部门?我们以安全左移的思想去看待这件事时,显然应用部门应该考虑他的微服务是否需要主动外访,需要访问哪些外部服务。然而,如果由应用开发人员负责,是不是平台或安全部门就可以放手不管?显然不是,应用开发人员最多是为其所负责的应用设定安全策略,与应用无关的全局性基础安全策略,如何快速补救应用开发人员设定的错误策略,这些依然需要由其他团队来负责。而要想开发部门能够践行安全左移的思想,那么 PlatformOps 或安全部门则必须提供友好的工具并将安全策略的设定集成到 DevSecOps 的 pipeline 当中,如果工具或方法导致开发效率下降,开发人员将不乐意去使用。所以,这不是某一个部门的独立工作,需要多团队的协作来确保安全。

数据驱动

正如文章开始所述,安全是一个持续工程化的工作,意味着任何出向访问行为与事件都应被记录到安全工程系统中进行分析,以确保足够的可见性和洞察。出向安全管控不仅仅是一个简单策略设定,需具有完整日志、行为、事件输出的能力。

业界方案分析

接下来,我们来逐一分析当前业界关于出向策略管控的解决方案,首先我们将其分为 6 大类方案,然后再逐一分析:

Category Solutions or products Description
Platform based Kubernetes Network policy
Openshift EgressIP
Openshift Egress Router pod
Openshift Egress Firewall
Openshift EgressNetworkPolicy
A specific feature of a platform provider
CNI based Calico Egress pod
Calico Enhanced Network policy
Cilium Enhanced Network policy
Kube-ovn
The capability of CNI
Service Mesh NGINX Service Mesh
Istio
A function of Service Mesh
Micro segmentation PrismaNeu
Vector
From ZTA perspective or use enforcer container to control egress
Fusion F5 CES(Container Egress Service)
Fortinet
Use k8s native method to integrate exist security assets to k8s
Others DNS interception
Proxy pod
Intercept coredns or use a proxy pod as forward proxy

Platform based

kubernetes 自带的 Network policy,这是最容易想到的关于出向安全策略管控方法。它是 k8s 的自身能力,对于开发者或 PlatformOps 人员来说具有天然的亲和性,能够很好的适应安全左移的思想。但 Network policy 需 CNI 支持。其它一些缺点在于:

  • 没有集群全局性的策略能力,不同 namespace 下要维护独立的 policy
  • 没有以 k8s svc 名称为条件的选择能力(可改为选 pod 标签,但不灵活)
  • 无显式拒绝能力,通过策略的隔离性特点,然后施加具体的白名单
  • 规则无优先级概念
  • 无明确的集群外访规则,外部目标服务只能依靠宽泛的 ipblock
  • 纯四层,无七层的控制能力
  • 无策略执行调试能力
  • 无策略执行日志
  • Networkpolicy 的“隔离性”特点使得维护工作变得及其麻烦,例如,本身只想控制其对互联网的访问,但因为隔离性,就不得不额外维护该 pod 在集群内的所有出向(东西向)访问
  • 不能解决 k8s 与外部安全设备协同问题。试想一下,Network policy 做了规则控制后,那么外部的安全设备就可以为该集群打开一个默认通行的规则吗?

Openshift,在 Egress 方面有四个特性与之有关,分别是标准的 Network Policy,Egress IP,Egress Router,Egress Firewall 以及 Egress NetworkPolicy。

  • Network Policy,当 Openshift 使用 OVN-Kubernetes 作为 CNI 时完全支持,而传统的 Openshift SDN CNI 则仅是部分支持。与标准的 kubernetes 并无不同,其优缺点这里不再做额外分析。
  • EgressIP,是用来实现 Pods 流量离开集群时候使用确定性源 IP 的一种功能。当使用 Openshift SDN CNI 时,该功能将 Egress IP 应用到指定的 nodes 上作为 secondary IP,并用于 SNAT。当使用 OVN-kubernetes CNI 时候,则通过 OVS 为具体的 pods 执行 snat 规则。使用 EgressIP,本身并不是出向安全策略管控的直接方法,但是借助为不同的 namespace 指定确定的源 IP,这样可以在集群外部的安全设备上部署一些策略来执行控制。显而易见,这种策略控制方式比较粗放,无法做到对不同服务的精细化粒度。如果 pods 分散在不同的 nodes 上,则还会存在 pods 出集群流量要先在不同 nodes 之间穿越问题,增加了额外的延迟。此外,EgressIP 还必须与 nodes 的主网络地址同属相同网段,且一个 node 不可以拥有一个以上的 EgressIP。EgressIP 也不支持公有云以及 Redhat Openstack Platform。
  • Egress Router Pod,它是一种特殊的 pod,拥有两个网卡,使用 MacVlan 技术将其中一个容器网卡与外部网络直接连通。所有 pods 出集群流量都会经过该 pod。根据不同的 CNI(SDN 或 OVN-kubernetes), 具有的功能也不同,在 OVN-kubernetes CNI 下仅支持重定向操作。一般来说这并不适合大规模使用,从 Egress 安全策略设定角度,这也依然无法区分不同服务,且集中的 Egress pod 容易成为性能瓶颈。
  • EgressFirewall,它实际是 OVN-kubernetes 的特性。容许为某个 project 或 namespace 设置出向访问规则,可以基于协议,端口,IP,DNS 等维度。协议仅支持 TCP,UDP,SCTP 三种,无法支持其它协议控制。它只容许基于 namespace 级别设定,一个 namespace 中只容许设置一个规则文件,无法为集群内的不同 service 来设定不同的 Egress 规则。同时它限制每个 namespace/project 最大 8000 条规则。也不支持可观测或事件。
  • Egress NetworkPolicy,与 EgressFirewall 功能类似,当采用 Openshift SDN CNI 时候支持该 CRD。但是 Egress NetworkPolicy 具有更多的限制性,例如每个 namespace/project 最大支持 1000 条规则,且必须打开 nework policy 或 multitennat 模式。

CNI based

以 Calico 和 Cilium 为典型代表的 CNI,在标准 k8s Network Policy 上扩展了部分能力,主要表现在:

  • 支持全局策略(Calico,Cilium)
  • DNS-based 策略支持(Calico 企业,Cilium)
  • L7 仅 HTTP 协议扩展(Calico,Cilium)
  • Log(Calico,Cilium)
  • 扩展策略的应用对象到 pod 以外,例如 node 等(Calico,Cilium)
  • 层次化策略,角色化边界设定(Calico 企业)

要实现这些能力,企业首先需使用这些 CNI。部分企业特性,例如层次化策略与角色设定、DNS 支持等需要额外购买服务。这会造成用户 CNI 技术锁定,不利于多云场景部署。Calico 在中国也没有服务销售,这些都会阻碍客户体验。在 CNI 上采取复杂的安全策略,会导致在集群内部创建大量复杂的规则,造成排错困难,运维成本增大。大量的规则,也可能会导致网络性能下降。

对于 Calico Egress Pod,是一个特殊的 pod,拥有固定的可路由的 SNAT 地址,当 Egress 流量从该专用 pod 流出时,携带了专用固定地址,这容许外部防火墙等安全设备基于该固定地址进行策略设定。其行为上与 Openshift 的 Egress Router pod 类似,从 Egress 安全策略设定角度,它无法为不同服务执行细粒度的安全策略设定或成为性能瓶颈。

Service Mesh

Service Mesh 并不是 Egress 流量管控的专门方案,因此要通过 Service Mesh 实现 Egress 的管控意味着首先需要部署整体 Service Mesh 方案,比如 Istio。如果仅仅是为了实现 Egress 的管控,这样的方案会显得较重。Service Mesh 所支持的协议范围也较少,这对于企业的安全策略来说还不足够。

在 Istio 中,当设置 meshConfig.outboundTrafficPolicy.mode 为 REGISTRY_ONLY 后,可以通过 sidecar 结合 ServiceEntry 资源实现外部服务访问的白名单。也可以通过结合 Egress Gateway 将流量导向到专门的 Egress Gateway。相比于 ServiceEntry 方法,Egress Gateway 则结合了 VirtualService 和 DestinationRule 来实现更多的控制,配合 AuthorizationPolicy 则可以控制粒度更细一些。

无论哪种方式,都必须依赖 sidecar 进行流量的劫持,如果有威胁绕开或破坏了 sidecar,则意味着有害访问可以直接绕开管控,这个安全问题在 Istio 的文档中被反复提及。所以本质上来说它不是一个很好的 Egress 流量管控方案。同时,Service Mesh 的思维更多是面向开发者(尽管它常常体现的是平台层面的能力),所以我们依然需要回答这样一个问题:当开发者设置了外部服务访问白名单后,集群外部是否就可以信任开发者这样的设置,外部安全设备是否就可以设置为容许集群的任意外部访问?

Micro Segmentation

微分段一般是 Zero Trust Architecture (ZTA) 领域热衷的概念,通过技一些技术(如 TC,IPtables,DPI)对底层流量进行探查、操纵与控制,实现对容器内进程、容器间通信、容器与集群外的通信的可视化与策略控制。一般来说会在集群的各个主机上安装 DaemonSet 类容器实现对底层流量的探查。此类方案可以基于较细的粒度进行 Egress 策略控制,例如对哪些应用相关 pods 通过哪些协议访问哪些外部服务,亦可选择诸如 Service account 或 Label 等要素。对于应用层加密数据,如果是 Istio 环境则可通过探查 sidecar 与应用容器之间流量实现明文探查;如果是应用容器自身直接加密则无法实现探查,但可以通过结合 DNS 解析、SNI 实现一定程度上的策略管控。

Fusion

上述的多种类型方案,主要切入点是在集群内。在客户的实际生产环境中,kubernetes 集群是一种资源性对象,从企业整体安全角度来看,外部安全设备依然有必要对 kubernetes 集群的出向流量进行管控。让外部安全设备与 kubernetes 集群融合,其难点在于,传统安全设备不是直接面向 kubernetes 设计。高动态性、IP 无关性会成为传统设备进行 kubernetes 出向流量管控的难点。但这并不是无法解决的技术难题,如果外部安全设备具有较好的 API 接口,通过专门设计的控制器则可以解决上述技术难题。这样,外部安全防护的措施便可以应用到 kubernetes 集群上来,形成完整的纵深防御体系。同时可以保护企业已有投资,节约成本。通过面向 kubernetes 的自定义资源类型设计,负责外部安全设备的团队也因此可以介入到 kubernetes 集群的整体安全工作中来,避免了团队的割裂。

F5 的 Application Firewall Manager (AFM) 通过专用的免费控制器(CES)实现了以 kubernetes 原生自定义资源(CRD)方式进行 Egress 策略的控制,并实现了安全规则与角色的层次化设定,让安全设备管理员融合到了 kubernetes 平台。借助 AFM 的能力,可实现 Egress 流量的高级访问规则、限流、协议检查、日志与事件可视化等。

Fortinet 自身以及与 Calico 企业版联合,也实现了与 kubernetes 的集成,但其主要特点是将 kubernetes 资源对象转化并写入 Fortinet 的地址组中,其管理视角依然是防火墙管理员视角,而不是 kubernetes native 方式。

Others

Proxy pod 是一种普通的正向代理,应用使用该代理实现对外部业务的访问。此种方式一般仅适合小规模场景,不适合大规模集群及复杂业务。DNS interception,其原理是通过 patch coredns,如果应用访问 ExternalService 对象中设定的外部服务,则将请求引导到一个专用的 proxy pod 上(例如 Envoy 等)实现对流量的处理。该方案同样不适合大规模场景。

在完成对上述 6 类 Egress 流量管控方案的分析后,让我们来总结和对比一下这些方案的优缺点:

方案特性比较
方案特性比较

可以看出 Network Policy 虽然是一个 kubernetes 原生的方式,但显然并不适合于集群 Egress 流量的管控。CNI 类产品有了一定的增强,但是在协议检测、企业级支持方面还是不够。微分段类产品具有相对完整的能力,但是微分段是一个整体性的解决方案,仅仅使用微分段实现集群出向流量的管控会显得投入较大,且微分段的产品一般底层技术较为复杂,运维难度较高。将外部安全设施融入到 kubernetes 当中实现出向流量管控的解决方法更加适合企业,无论是功能特性还是运维复杂度都比较适合,更加重要的是,该类方案将企业的传统安全资产与现代应用架构进行了结合,让不同部门能够紧密协同,形成纵深防御体系。

总结

我们往往重视 Ingress 的能力,而忽视了 Egress 流量的安全管控。但无论从安全还是合规的角度,Egress 流量都应加强管控。当漏洞已经侵入应用后,Egress 流量管控往往是最后一个保护的关口。在上当前众多方案中,大部分的方案是基于 kubernetes 内的 Network Policy 实现,有的依赖于特定的 CNI,有的依赖于特定的编排平台。但当我们从企业的整体安全架构去考虑时,将外部安全设备引入到 kubernetes 安全体系当中一件非常必要的事情,只有这样才能实现真正的全面防御。而当我们讨论 DevSecOps 时,需要让开发、平台、安全乃至网络这些不同团队同时参与到整体安全工作中,实现跨团队的紧密协作。关于 F5 CES 方案是如何实现 kubernetes Egress 流量安全管控,以及如何实现不同团队紧密协作,请看考 Github CES 项目

林静

林静

F5 资深架构师

专注云原生下的应用交付,F5 CIS-C,CES,BIG-IP Kubernetes Gateway API 项目负责人与布道师。https://linjing.io

编辑本页