7.8 Kubernetes的网络策略

为了实现细粒度的容器间网络访问隔离策略,Kubernetes从1.3版本开始引入了Network Policy机制,到1.8版本升级为networking.k8s.io/v1稳定版本。Network Policy的主要功能是对Pod或者Namespace之间的网络通信进行限制和准入控制,设置方式为将目标对象的Label作为查询条件,设置允许访问或禁止访问的客户端Pod列表。目前查询条件可以作用于Pod和Namespace级别。

为了使用Network Policy,Kubernetes引入了一个新的资源对象NetworkPolicy,供用户设置Pod之间的网络访问策略。但这个资源对象配置的仅仅是策略规则,还需要一个策略控制器(Policy Controller)进行策略规则的具体实现。策略控制器由第三方网络组件提供,目前Calico、Cilium、Kube-router、Romana、Weave Net等开源项目均支持网络策略的实现。

Network Policy的工作原理如图7.27所示,策略控制器需要实现一个API Listener,监听用户设置的NetworkPolicy定义,并将网络访问规则通过各Node的Agent进行实际设置(Agent则需要通过CNI网络插件实现)。

图7.27 Network Policy的工作原理

7.8.1 网络策略设置说明

网络策略的设置主要用于对目标Pod的网络访问进行控制,在默认情况下对所有Pod都是允许访问的,在设置了指向Pod的NetworkPolicy网络策略后,到Pod的访问才会被限制。

下面通过一个例子对NetworkPolicy资源对象的使用进行说明:

对主要参数说明如下。

◎ podSelector:定义该网络策略作用的Pod范围,本例的选择条件为包含role=db标签的Pod。

◎ policyTypes:网络策略的类型,包括ingress和egress两种,用于设置目标Pod的入站和出站的网络限制。如果未指定policyTypes,则系统默认会设置Ingress类型;若设置了egress策略,则系统自动设置Egress类型。

◎ ingress:定义允许访问目标Pod的入站白名单规则,满足from条件的客户端才能访问ports定义的目标Pod端口号。

· from:对符合条件的客户端Pod进行网络放行,规则包括基于客户端Pod的Label、基于客户端Pod所在命名空间的Label或者客户端的IP范围。

· ports:允许访问的目标Pod监听的端口号。

◎ egress:定义目标Pod允许访问的“出站”白名单规则,目标Pod仅允许访问满足to条件的服务端IP范围和ports定义的端口号。

· to:允许访问的服务端信息,可以基于服务端Pod的Label、基于服务端Pod所在命名空间的Label或者服务端IP范围。

· ports:允许访问的服务端的端口号。

通过本例所示的NetworkPolicy设置,对不同命名空间中的目标Pod进行了网络访问,发现该网络策略作用于命名空间default中包含role=db标签的全部Pod。

Ingress规则包括:

◎ 允许与目标Pod在同一个命名空间中的包含role=frontend标签的客户端Pod访问目标Pod;

◎ 允许属于包含project=myproject标签的命名空间的客户端Pod访问目标Pod;

◎ 允许属于IP地址范围172.17.0.0/16的客户端Pod访问目标Pod,但不包括属于IP地址范围172.17.1.0/24的客户端应用。

Egress规则包括:允许目标Pod访问属于IP地址范围10.0.0.0/24并监听5978端口的服务。

7.8.2 Selector功能说明

本节对namespaceSelector和podSelector选择器的功能进行说明。

在from或to配置中,namespaceSelector和podSelector可以单独设置,也可以组合配置。ingress的from段落和egress的to段落总共可以有4种选择器(Selector)的设置方式。

◎ podSelector:同一个命名空间选中的目标Pod应作为ingress来源或egress目标允许网络访问。

◎ namespaceSelector:目标命名空间中的全部Pod应作为ingress来源或egress目标允许网络访问。

◎ podSelector和namespaceSelector:在from或to配置中如果既设置了namespaceSelector又设置了podSelector,则表示选中指定命名空间中的Pod。这在YAML定义中需要进行准确设置。

◎ ipBlock:其设置的IP地址范围应作为ingress来源或egress目标允许网络访问,通常应设置为集群外部的IP地址。

下面通过两个例子对Selector的作用进行说明。

例1,在from中同时设置namespaceSelector和podSelector,该策略允许从拥有user=alice标签的命名空间中拥有role=client标签的Pod发起访问:

例2,在from中分别设置namespaceSelector和podSelector,该策略既允许从有user=alice标签的命名空间中的任意Pod发起访问,也允许从当前命名空间中有role=client标签的Pod发起访问:

集群的ingress和egress机制通常需要重写数据包的源IP或目标IP地址,如果发生了这种情况,则无法确定是在NetworkPolicy处理前还是处理后发生的,并且重写行为可能会根据网络插件、云提供商、Service实现的不同而有所不同。

对于ingress策略,这意味着在某些情况下能基于真实源IP对入站的数据包进行过滤,而在其他情况下,NetworkPolicy所作用的“源IP”可能是LoadBalancer的IP或Pod所在节点的IP。

对于egress策略,这意味着从Pod到被重写为集群外部IP的服务IP的连接(Connection)可能受到(也可能不受到)基于ipBlock的策略的约束。

7.8.3 为命名空间配置默认的网络策略

在一个命名空间没有设置任何网络策略的情况下,对其中Pod的ingress和egress网络流量并不会有任何限制。在命名空间级别可以设置一些默认的全局网络策略,以便管理员对整个命名空间进行统一的网络策略设置。

以下是一些常用的命名空间级别的默认网络策略。

(1)默认禁止ingress访问。该策略禁止任意客户端访问该命名空间中的任意Pod,起到隔离访问的作用:

(2)默认允许ingress访问。该策略允许任意客户端访问该命名空间中的任意Pod:

(3)默认禁止egress访问。该策略禁止该命名空间中的所有Pod访问任意外部服务:

(4)默认允许egress访问。该策略允许该命名空间中的所有Pod访问任意外部服务:

(5)默认同时禁止ingress和egress访问。该策略禁止任意客户端访问该命名空间中的任意Pod,同时禁止该命名空间中的所有Pod访问任意外部服务:

7.8.4 网络策略应用示例

下面以一个提供服务的Nginx Pod为例,为两个客户端Pod设置不同的网络访问权限:允许拥有role=nginxclient标签的Pod访问Nginx容器,没有这个标签的客户端容器会被禁止访问。

(1)创建目标Pod,设置app=nginx标签:

(2)为目标Nginx Pod设置网络策略,创建NetworkPolicy的YAML文件,内容如下:

该网络策略的作用目标Pod应包含app=nginx标签,通过from设置允许访问的客户端Pod包含role=nginxclient标签,并设置允许客户端访问的端口号为80。

创建该NetworkPolicy资源对象:

(3)创建两个客户端Pod,一个包含role=nginxclient标签,另一个无此标签。分别进入各Pod,访问Nginx容器,验证网络策略的效果:

登录Pod“client1”:

尝试连接Nginx容器的80端口:

成功访问到Nginx的服务,说明NetworkPolicy生效。

登录Pod“client2”:

尝试连接Nginx容器的80端口:

访问超时,说明NetworkPolicy生效,对没有role=nginxclient标签的客户端Pod拒绝访问。

说明:本例中的网络策略是基于Calico提供的calico-kube-controllers实现的,calico-kube-controllers持续监听Kubernetes中NetworkPolicy的定义,与各Pod通过标签进行关联,将允许访问或拒绝访问的策略通知到各calico-node,最终calico-node完成对Pod间网络访问的设置,实现Pod间的网络隔离。有兴趣的读者可以尝试使用其他CNI插件的网络策略控制器来实现NetworkPolicy的功能。

7.8.5 NetworkPolicy的发展

Kubernetes从1.12版本开始引入了对SCTP的支持,到1.19版本时达到Beta阶段,默认启用,可以通过kube-apiserver的启动参数--feature-gates=SCTPSupport=false进行关闭。启用后,可以在NetworkPolicy资源对象中设置protocol字段的值为SCTP,启用对SCTP的网络隔离设置。需要说明的是,要求CNI插件提供对SCTP的支持。

另外,在Kubernetes 1.20版本中,以下功能在网络策略(NetworkPolicy API)中仍然无法提供实现。如果需要这些功能,则可以选择使用操作系统提供的功能组件如SELinux、Open vSwitch、IPTables等;或7层网络技术如Ingress Controller、Service Mesh等;或通过准入控制器(Admission Controller)等替代方案进行实现。

◎ 强制集群内部的流量都经过一个公共网关(最好使用Service Mesh或其他Proxy)。

◎ TLS相关功能(最好使用Service Mesh或其他Proxy)。

◎ 特定于节点(Node)的网络策略(当前无法基于Kubernetes信息将网络策略设置在特定节点上)。

◎ 按名称指定服务或命名空间(当前仅支持通过Label进行设置)。

◎ 创建或管理第三方提供实现的策略请求(Policy Request)。

◎ 适用于所有命名空间或Pod的默认策略。

◎ 高级策略查询和可达性工具。

◎ 在单个策略声明中指向目标端口号范围的能力。

◎ 对网络安全事件进行日志记录的能力(例如连接被阻止或接受的事件)。

◎ 显式设置拒绝策略的能力(当前仅支持设置默认的拒绝策略,仅可以添加“允许”的规则)。

◎ 阻止通过本地回路(loopback)发起流量或从主机上发起流量的策略管理能力(当前Pod无法阻止从本机Localhost发起的访问,也不能阻止从其他同组节点发起的访问)。

Kubernetes社区正在积极讨论其中一些功能特性,有兴趣的读者可以持续关注社区的进展并参与讨论。