Kubernetes之network policy解析
Kubernetes之network policy解析
Kubernetes的Network Policy是实现基于策略的网络控制的重要机制,它允许管理员通过标签选择器来控制Pod之间的网络流量。本文将详细介绍Network Policy的概念、配置方法和使用场景,帮助读者更好地理解和使用这一功能。
一、概念
Network Policy
提供了基于策略的网络控制,是针对 TCP、UDP 和 SCTP 协议在 IP 地址或端口层面控制网络流,用于隔离应用并减少攻击面。它使用标签选择器模拟传统的分段网络,并通过策略控制它们之间的流量以及来自外部的流量;目前基于linux iptables
实现,使用类似nf_conntrack
检查记录网络流量session
从而决定流量是否阻断;因此它是状态检测防火墙
。
Pod 可以与之通信的实体是通过如下三个标识符的组合来辩识的:
- 其他被允许的 Pod(例外:Pod 无法阻塞对自身的访问)
- 被允许的名字空间
- IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址)
1、前置条件
首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括:
2、pod隔离的两种类型
默认情况下,一个pod的出口和入口都是非隔离的,即pod的所有出站以及入站都是没有限制的
网络策略是相加的,所以不会产生冲突,但是如果要单独允许某一个pod间的连接,源pod和出口策略和目标pod的入口策略都需要配置。
3、NetworkPolicy 资源
以下为资源示例
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
策略作用的对象Pods:default命名空间下带有role=db标签的Pod
内向流量策略
- 允许属于
172.17.0.0/16
网段但不属于172.17.1.0/24
的源地址访问该对象Pods的TCP 6379端口 - 允许带有project=myprojects标签的namespace中所有Pod访问该对象Pods的TCP 6379端口
- 允许default命名空间下带有role=frontend标签的Pod访问该对象Pods的TCP 6379端口
- 拒绝其他所有主动访问该对象Pods的网络流量
- 允许属于
外向流量策略
- 允许该对象Pods主动访问目的地址属于
10.0.0.0/24
网段且目的端口为TCP 5978的流量 - 拒绝该对象Pods其他所有主动外向网络流量
- 允许该对象Pods主动访问目的地址属于
4、选择器to、from
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
此策略在 from
数组中仅包含一个元素,表示两种条件都必须满足,即只允许来自拥有role=client标签的pod且所有在的名称空间中标有user=alice
的连接
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
此策略在 from
数组中仅包含两个元素,表示两种条件满足其一即可,即允许来自拥有role=client标签的pod或者任何pod所在的名称空间中标有user=alice
的连接
5、默认策略
默认情况下,则不存在任何策略,但是我们可以更改默认的策略。
默认拒绝所有入站和出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
此策略可以确保即使没有被其他任何 NetworkPolicy 选择的 Pod 也不会被允许入站或出站流量
6、对端口范围进行限制(1.25 stable)
在编写 NetworkPolicy 时,你可以针对一个端口范围而不是某个固定端口。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
此准则表示允许default名称空间中所有带role: db标签的pod使用tcp协议与10.0.0.0/24网段内,并且目标端口为32000到32768之间。
7、使用hostNetwork
类型的Pod
网络插件无法正确辨别 hostNetwork
Pod 流量,因此在匹配 podSelector
和 namespaceSelector
时会忽略 hostNetwork
Pod。流向/来自 hostNetwork
Pod 的流量的处理方式与流向/来自节点 IP 的所有其他流量一样。(这是最常见的实现方式。)也就是说会将使用hostNetwork
类型的Pod识别为一个物理机,而不再是pod,可以使用 ipBlock
规则允许来自 hostNetwork
Pod 的流量。
二、使用场景
1、拒绝其他的namespace的访问
- 场景1:你的k8s集群应用按照namespaces区分生产、测试环境,你要确保生产环境不会受到测试环境错误访问影响
- 场景2:你的k8s集群有多租户应用采用namespaces区分的,你要确保多租户之间的应用隔离
在你需要隔离的命名空间创建如下策略:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: your-ns
name: deny-other-namespaces
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
2、允许外部访问服务
# 创建示例应用待暴露服务
$ kubectl run web --image=nginx --labels=app=web --port 80 --expose
# 创建网络策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-external
spec:
podSelector:
matchLabels:
app: web
ingress:
- from: []
ports:
- protocol: TCP
port: 80
三、目前无法实现的功能
截止到1.30版本
强制集群内部流量经过某公用网关(这种场景最好通过服务网格或其他代理来实现);
与 TLS 相关的场景(考虑使用服务网格或者 Ingress 控制器);
特定于节点的策略(你可以使用 CIDR 来表达这一需求不过你无法使用节点在 Kubernetes 中的其他标识信息来辩识目标节点);
基于名字来选择服务(不过,你可以使用 标签 来选择目标 Pod 或名字空间,这也通常是一种可靠的替代方案);
创建或管理由第三方来实际完成的“策略请求”;
实现适用于所有名字空间或 Pod 的默认策略(某些第三方 Kubernetes 发行版本或项目可以做到这点);
高级的策略查询或者可达性相关工具;
生成网络安全事件日志的能力(例如,被阻塞或接收的连接请求);
显式地拒绝策略的能力(目前,NetworkPolicy 的模型默认采用拒绝操作, 其唯一的能力是添加允许策略);
禁止本地回路或指向宿主的网络流量(Pod 目前无法阻塞 localhost 访问, 它们也无法禁止来自所在节点的访问请求)。