为了实现细粒度的容器间网络访问隔离策略,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的工作原理
网络策略的设置主要用于对目标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端口的服务。
本节对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的策略的约束。
在一个命名空间没有设置任何网络策略的情况下,对其中Pod的ingress和egress网络流量并不会有任何限制。在命名空间级别可以设置一些默认的全局网络策略,以便管理员对整个命名空间进行统一的网络策略设置。
以下是一些常用的命名空间级别的默认网络策略。
(1)默认禁止ingress访问。该策略禁止任意客户端访问该命名空间中的任意Pod,起到隔离访问的作用:

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

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

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


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

下面以一个提供服务的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的功能。
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社区正在积极讨论其中一些功能特性,有兴趣的读者可以持续关注社区的进展并参与讨论。