跳到主要内容

NetworkPolicy 应用实践

NetworkPolicy vs CiliumNetworkPolicy

Kubernetes 原生的 NetworkPolicy 和 Cilium 的 CiliumNetworkPolicy 都用于定义 Pod 间的网络访问控制策略,但 CiliumNetworkPolicy 在功能上更加强大和灵活。虽然 Cilium 也兼容 NetworkPolicy,但既然安装了 Cilium 就建议使用功能更强大的 CiliumNetworkPolicy。

核心功能对比

特性NetworkPolicyCiliumNetworkPolicy
作用域命名空间级别命名空间级别
基本流量控制✅ 支持 ingress/egress✅ 支持 ingress/egress
Pod 选择器✅ 基于 label 选择✅ 支持更复杂的表达式
L3/L4 规则✅ IP/端口控制✅ IP/端口控制
L7 协议感知❌ 不支持✅ 支持 HTTP/gRPC/Kafka 等
FQDN 支持❌ 不支持✅ 支持域名匹配
显式拒绝规则❌ 只能隐式拒绝✅ 支持 egressDeny/ingressDeny
实体选择器❌ 不支持✅ 支持 toEntities/fromEntities
DNS 感知❌ 不支持✅ 支持 DNS 规则
服务选择器❌ 不支持✅ 支持 toServices

主要差异说明

1. L7 协议感知

  • NetworkPolicy 只能控制到 L3/L4 层(IP 地址和端口)。
  • CiliumNetworkPolicy 可以深入到 L7 层,控制 HTTP 方法、路径、header,gRPC 方法等。

2. FQDN 域名支持

  • NetworkPolicy 只能使用 IP 或 CIDR,无法直接控制域名访问。
  • CiliumNetworkPolicy 支持 toFQDNs,可以直接使用域名和通配符模式。

3. 显式拒绝规则

  • NetworkPolicy 采用白名单模式,未匹配的流量默认拒绝,但无法显式拒绝特定流量。
  • CiliumNetworkPolicy 支持 egressDeny/ingressDeny,可以在允许大部分流量的同时显式拒绝特定目标。

4. 实体选择器

  • NetworkPolicy 需要通过 CIDR 或选择器间接指定目标。
  • CiliumNetworkPolicy 提供 toEntities/fromEntities,可以直接选择 kube-apiserverhostremote-nodeworld 等预定义实体。

5. 选择器灵活性

  • NetworkPolicy 使用标准的 podSelectornamespaceSelector
  • CiliumNetworkPolicy 的 endpointSelector 支持更复杂的表达式。

兼容性

  • Cilium 完全兼容 Kubernetes 原生 NetworkPolicy。
  • 可以在同一集群中混用两种策略类型。

CiliumClusterwideNetworkPolicy

CiliumNetworkPolicy 和 CiliumClusterwideNetworkPolicy 的核心区别在于作用域和管理方式,它们的策略语法完全相同。

核心差异

特性CiliumNetworkPolicyCiliumClusterwideNetworkPolicy
作用域命名空间级别集群级别
资源类型命名空间资源集群资源(无命名空间)
管理权限命名空间管理员集群管理员
选择器默认范围同命名空间 Pod集群所有 Pod
跨命名空间选择需要显式指定天然支持
策略优先级普通优先级较高优先级
节点防火墙❌ 不支持✅ 支持(通过 nodeSelector 选中节点)
使用场景应用级策略集群基线策略

主要差异说明

1. 作用域和资源位置

  • CiliumNetworkPolicy 必须创建在特定命名空间中,通过 metadata.namespace 指定。
  • CiliumClusterwideNetworkPolicy 是集群级资源,没有命名空间概念。

2. 选择器行为

  • CiliumNetworkPolicy 的 endpointSelector 默认只选择同命名空间的 Pod。
  • CiliumClusterwideNetworkPolicy 的 endpointSelector 可以选择集群中任意命名空间的 Pod。

3. 跨命名空间访问控制

  • CiliumNetworkPolicy 控制跨命名空间访问时,需要在 toEndpoints/fromEndpoints 中显式指定命名空间标签。
  • CiliumClusterwideNetworkPolicy 可以直接通过命名空间标签统一管理多个命名空间的策略。

4. 管理权限和职责分离

  • CiliumNetworkPolicy 可以由命名空间管理员(有该命名空间权限的用户)管理。
  • CiliumClusterwideNetworkPolicy 需要集群管理员权限,适合平台团队管理。

5. 策略合并和优先级

  • 当同一个 Pod 同时被两种策略选中时,规则会合并生效。
  • 拒绝规则(egressDeny/ingressDeny)优先于允许规则。
  • 通常使用 CiliumClusterwideNetworkPolicy 设置安全基线,用 CiliumNetworkPolicy 添加应用特定规则。

6. 配置节点防火墙

  • CiliumClusterwideNetworkPolicy 支持将网络策略应用到节点上,用于设置节点维度防火墙。
  • 这种策略只能由 CiliumClusterwideNetworkPolicy 来配置,CiliumNetworkPolicy 不支持。

典型使用场景

CiliumNetworkPolicy 适用于:

  • 微服务之间的访问控制。
  • 应用特定的网络隔离需求。
  • 开发团队自主管理的网络策略。
  • 命名空间内的细粒度控制。

CiliumClusterwideNetworkPolicy 适用于:

  • 集群默认拒绝策略(default deny)。
  • 统一管理多个基础设施命名空间的网络策略。
  • 全局安全基线和合规要求。
  • 跨命名空间的统一访问控制。
  • 限制对敏感资源(如 kube-apiserver)的访问。
  • 配置节点防火墙。

最佳实践

分层管理策略:

  1. 使用 CiliumClusterwideNetworkPolicy 设置集群安全基线(如默认拒绝、DNS 访问、基础设施互通)。
  2. 使用 CiliumNetworkPolicy 实现应用特定的网络策略(如服务间调用、外部 API 访问)。

权限分离:

  • 平台团队管理 CiliumClusterwideNetworkPolicy,确保集群整体安全。
  • 应用团队管理 CiliumNetworkPolicy,满足业务需求。

命名规范:

  • 集群策略使用描述性前缀,如 default-deny-allglobal-infrastructure
  • 命名空间策略使用应用相关名称,如 frontend-to-backendallow-external-api

用法实践

安全基线:默认拒绝

集群默认拒绝 egress 流量(dns 解析除外,kube-system 命名空间中的 pod 除外),严格控制集群 Pod 的网络访问权限:

备注

通常 ingress 流量不设置全局的默认拒绝,可针对敏感业务单独设置 ingress 策略(如 A 只允许被 B 访问)。

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: default-deny
spec:
description: "Block all the traffic (except DNS) by default"
egress:
- toEndpoints: # 允许集群所有 Pod 通过 coredns 解析域名
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
endpointSelector:
matchExpressions: # 不限制 kube-system 命名空间中 Pod 的 egress 流量
- key: io.kubernetes.pod.namespace
operator: NotIn
values:
- kube-system

统一管控基础设施的网络策略

集群中可能会部署许多基础设施相关应用,分散在多个命名空间,我们可以用 CiliumClusterwideNetworkPolicy 和命名空间标签来统一设置这些命名空间的网络策略(假设这些命名空间都打上了 role=infrastructure 这个 label):

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: default-infrastructure
spec:
endpointSelector: # 选中所有基础设施命名空间中的 Pod
matchLabels:
io.cilium.k8s.namespace.labels.role: infrastructure
egress: # 配置 egress 策略
- toEndpoints: # 允许访问所有基础设施命名空间中的 Pod
- matchLabels:
io.cilium.k8s.namespace.labels.role: infrastructure
- toEndpoints: # 允许 访问 coredns 解析域名
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
- toFQDNs: # 允许调用腾讯云相关 API
- matchPattern: '*.tencent.com'
- matchPattern: '*.*.tencent.com'
- matchPattern: '*.*.*.tencent.com'
- matchPattern: '*.*.*.*.tencent.com'
- matchPattern: '*.*.*.*.*.tencent.com'
- matchPattern: '*.tencentcloudapi.com'
- matchPattern: '*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.*.*.tencentcloudapi.com'
- matchPattern: '*.tencentyun.com'
- matchPattern: '*.*.tencentyun.com'
- matchPattern: '*.*.*.tencentyun.com'
- matchPattern: '*.*.*.*.tencentyun.com'
- matchPattern: '*.*.*.*.*.tencentyun.com'
- toCIDR: # 允许访问腾讯云上的平台服务
- 169.254.0.0/16 # 169.254.0.0/16 是腾讯云上的保留网段,一些平台服务会使用这个 IP,如 TKE 集群 apiserver 的 VIP、COS 存储、镜像仓库等。
- toEntities: # 允许访问 apiserver
- kube-apiserver
- toEntities: # 允许访问集群中所有节点的 10250 端口,可用于监控指标采集
- host
- remote-node
toPorts:
- ports:
- port: "10250"
protocol: TCP

配置节点防火墙

apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
name: default-host-firewall
spec:
nodeSelector: {} # 选中所有节点
ingress:
- fromEntities:
- cluster # 不限制集群内的流量
- toPorts:
- ports: # 允许 ssh 访问
- port: "22"
protocol: TCP
- icmps: # 允许 ping 请求
- fields:
- type: EchoRequest
family: IPv4

多租户隔离

很多时候集群是多租户共享,如果每个租户使用一个命名空间,平台可以使用 CiliumNetworkPolicy 限制租户的业务 Pod 只能在同名空间下互访:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-same-namespace
namespace: tenant-001
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- {}
egress:
- toEndpoints:
- {}

如果是每个租户的业务 Pod 分布有多个命名空间,但有相同的命名空间标签来标识租户,这可以使用 CiliumClusterwideNetworkPolicy 来实现:

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: tenant-001
spec:
endpointSelector: # 选中租户 001 所有命名空间下的 Pod
matchLabels:
io.cilium.k8s.namespace.labels.tenant-id: "001"
egress: # 只允许租户 001 的 Pod 访问自己的业务 Pod
- toEndpoints:
- matchLabels:
io.cilium.k8s.namespace.labels.tenant-id: "001"
ingress: # 只允许租户 001 的 Pod 被自己的业务 Pod 访问
- fromEndpoints:
- matchLabels:
io.cilium.k8s.namespace.labels.tenant-id: "001"

限制 apiserver 的访问

如需严格限制 apiserver 的访问,避免集群被攻击或减少不必要的控制面压力,可先配置一个全局的默认拒绝规则(参考前面的 安全基线:默认拒绝 示例),然后在按需配置允许哪些 Pod 访问。

允许 test 命名空间下所有 pod 访问 apiserver:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-allow-apiserver
namespace: test
spec:
endpointSelector: {}
egress:
- toEntities:
- kube-apiserver

允许 test 命名空间下的 A 服务访问 apiserver:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: from-a-to-apiserver
namespace: test
spec:
endpointSelector:
matchLabels:
app: a
egress:
- toEntities:
- kube-apiserver

限制业务的入流量:保护敏感服务

限制 A 只能被 B 访问,且只能访问 80/TCP 端口

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: from-b-to-a
spec:
endpointSelector:
matchLabels:
app: a
ingress:
- fromEndpoints:
- matchLabels:
app: b
toPorts:
- ports:
- port: "80"
protocol: TCP

限制 A 只能被 B 访问,且只能访问部分接口

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: from-b-to-a-api
spec:
description: "Allow HTTP API from a to b"
endpointSelector:
matchLabels:
role: a
ingress:
- fromEndpoints:
- matchLabels:
role: b
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET" # 允许 GET /public
path: "/public"
- method: "PUT" # 允许 PUT /avatar,但需要携带 X-My-Header: true 的 header
path: "/avatar$"
headers:
- 'X-My-Header: true'

限制 A 只能被集群外部访问

如果 A 对外提供服务, CLB 直连 Pod,处理来自公网的请求,不允许其它流量(如来自集群内 Pod 或节点),可配置如下策略:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: from-world-to-a
spec:
endpointSelector:
matchLabels:
app: a
ingress:
- fromEntities:
- world

限制业务的出流量

A 只能访问 B

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: egress-a-to-b
spec:
endpointSelector:
matchLabels:
app: a
egress:
- toEndpoints:
- matchLabels:
app: b

A 只能访问同名空间下的 Pod

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-all-from-a
spec:
endpointSelector:
matchLabels:
app: a
egress:
- toEndpoints:
- {}

A 只能访问指定网段下的服务

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-a-to-cidr
spec:
endpointSelector:
matchLabels:
role: a
egress:
- toCIDR:
- 192.0.2.0/24
toPorts:
- ports:
- port: "80"
protocol: TCP

A 只能访问指定端口范围的服务

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-a-ports
spec:
endpointSelector:
matchLabels:
app: a
egress:
- toPorts:
- ports: # 只能发送目标端口在 80-444 的 TCP 流量
- port: "80"
endPort: 444
protocol: TCP

A 只能访问指定域名的服务

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: from-a-to-domains
spec:
endpointSelector:
matchLabels:
app: a
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
- toFQDNs:
- matchName: 'imroc.cc'
- matchPattern: '*.imroc.cc'
- matchPattern: '*.*.*.myqcloud.com'
- matchPattern: '*.tencent.com'
- matchPattern: '*.*.tencent.com'
- matchPattern: '*.*.*.tencent.com'
- matchPattern: '*.*.*.*.tencent.com'
- matchPattern: '*.*.*.*.*.tencent.com'
- matchPattern: '*.tencentcloudapi.com'
- matchPattern: '*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.*.tencentcloudapi.com'
- matchPattern: '*.*.*.*.*.tencentcloudapi.com'
- matchPattern: '*.tencentyun.com'
- matchPattern: '*.*.tencentyun.com'
- matchPattern: '*.*.*.tencentyun.com'
- matchPattern: '*.*.*.*.tencentyun.com'
- matchPattern: '*.*.*.*.*.tencentyun.com'

显式禁止:A 不能访问 B

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: deny-a-to-b
spec:
endpointSelector:
matchLabels:
app: a
egressDeny:
- toEndpoints: # 显式禁止 A 访问 B
- matchLabels:
app: b
egress:
- toEntities: # 允许 A 的其它流量
- all

参考资料