- 前言
- Kubernetes NetworkPolicy 架构
- Cilium CiliumNetworkPolicy 深度解析
- Calico GlobalNetworkPolicy 深度解析
- Cilium vs Calico vs 原生 NetworkPolicy 对比表
- 实施指南
- 监控与排障
- 故障案例与恢复流程
- 生产环境部署检查清单
- 高级模式:多集群网络策略
- 结语
- 参考资料

前言
在 Kubernetes 集群中,Pod 默认可以 与其他所有 Pod 自由通信。这在开发初期很方便,但在生产环境中会成为严重的安全威胁。因为只要有一个 Pod 被攻破,攻击者就能向集群内的所有服务横向移动。实际上,2024 年 CNCF Security Audit 调查的 Kubernetes 安全事故中,有 67% 源于内部网络隔离不足。
零信任网络(Zero Trust Network) 架构正是针对这一问题的答案,其原则是即便处于网络内部的流量也一律不予信任,只放行被明确允许的通信。在 Kubernetes 中实现这一点的核心工具就是 NetworkPolicy。
不过,原生的 Kubernetes NetworkPolicy 只支持 L3/L4(IP、端口)层面的控制,并不提供基于 DNS 的策略或基于 HTTP 路径的过滤等高级能力。为了突破这一局限,Cilium 与 Calico 这类 CNI 插件应运而生。Cilium 基于 eBPF 提供精细到 L7 的策略,Calico 则通过 BGP 路由与 GlobalNetworkPolicy 实现企业级的网络安全。
本文从 Kubernetes NetworkPolicy 的基础概念讲起,综合介绍 Cilium 与 Calico 的高级策略实现、对比分析、监控与排障、真实故障案例与恢复流程,以及生产环境部署检查清单。
Kubernetes NetworkPolicy 架构
NetworkPolicy 基本结构
Kubernetes NetworkPolicy 是在 Pod 级别控制网络流量的命名空间级资源。实际策略由 CNI 插件执行,在不支持 NetworkPolicy 的 CNI(例如 Flannel)上,即使创建了该资源也不会产生任何效果。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
environment: production
podSelector:
matchLabels:
role: frontend
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
这条策略的行为如下。
- 目标 Pod 选择:通过
podSelector应用于带有app: api-server标签的 Pod - 入站规则:仅允许来自 production 命名空间的 frontend Pod,以及 10.0.0.0/8 网段(排除 10.0.1.0/24)访问 TCP 8080 端口
- 出站规则:仅允许访问 database Pod 的 TCP 5432 以及 DNS(UDP 53)流量
Default Deny 策略
零信任的基础是 先阻断所有流量,再仅显式放行必要的通信。Default Deny 策略会阻断命名空间内所有 Pod 的入站与出站流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
空的 podSelector 会选中命名空间内的所有 Pod。虽然 policyTypes 中同时指定了 Ingress 与 Egress,但由于没有任何放行规则,所有流量都会被阻断。必须单独放行 DNS,服务发现才能正常工作。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
命名空间隔离模式
在大规模集群中,命名空间之间的隔离必不可少。下面是只允许同一命名空间内通信的模式。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-isolation
namespace: team-alpha
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
当 podSelector: {} 没有搭配 namespaceSelector 时,只会匹配当前命名空间中的所有 Pod。借此可以简洁地实现命名空间之间的隔离。
Cilium CiliumNetworkPolicy 深度解析
Cilium 架构与 eBPF
Cilium 利用 Linux 内核的 eBPF(extended Berkeley Packet Filter) 技术,在内核层面执行网络策略。与传统基于 iptables 的方案不同,eBPF 提供可编程的数据平面,因此即使策略数量增加,性能也几乎不会下降。
Cilium 的核心组件如下。
- Cilium Agent:在每个节点上以 DaemonSet 运行,负责编译 eBPF 程序并加载到内核
- Cilium Operator:负责整个集群范围的资源管理
- Hubble:实时观测网络流的监控工具
- Envoy Proxy:应用 L7 策略时作为透明代理工作
L3-L7 过滤实现
Cilium 的 CiliumNetworkPolicy 涵盖原生 NetworkPolicy 的全部能力,并额外支持 L7(HTTP、gRPC、Kafka)层面的精细控制。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-api-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: GET
path: '/api/v1/products'
- method: POST
path: '/api/v1/orders'
headers:
- 'Content-Type: application/json'
- method: GET
path: '/healthz'
这条策略在 frontend Pod 访问 api-server 的流量中,只放行 GET /api/v1/products、POST /api/v1/orders(必须带 JSON Content-Type 头)以及 GET /healthz 请求。PUT、DELETE 等其他 HTTP 方法都会被阻断。
基于 DNS 的策略
Cilium 可以基于 FQDN(Fully Qualified Domain Name)控制出站流量。在需要把外部 API 调用限制到特定域名时非常有用。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: dns-based-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-service
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: '53'
protocol: ANY
rules:
dns:
- matchPattern: '*.stripe.com'
- matchPattern: '*.amazonaws.com'
- toFQDNs:
- matchPattern: '*.stripe.com'
toPorts:
- ports:
- port: '443'
protocol: TCP
- toFQDNs:
- matchPattern: '*.amazonaws.com'
toPorts:
- ports:
- port: '443'
protocol: TCP
这条策略把 payment-service 限制为只能与 stripe.com 和 amazonaws.com 域名进行 HTTPS 通信。DNS 查询本身也只对这些域名放行。
CiliumClusterwideNetworkPolicy
需要在整个集群范围生效的策略要使用 CiliumClusterwideNetworkPolicy。
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: block-metadata-access
spec:
endpointSelector: {}
egressDeny:
- toCIDR:
- 169.254.169.254/32
toPorts:
- ports:
- port: '80'
protocol: TCP
这条策略阻断集群内所有 Pod 访问云元数据服务(169.254.169.254)。这是防止通过 IMDS 窃取凭据攻击的重要安全措施。
Calico GlobalNetworkPolicy 深度解析
Calico 架构
Calico 是 Tigera 开发的网络方案,提供基于 BGP(Border Gateway Protocol)的 L3 路由与策略引擎。主要组件如下。
- Felix:运行在每个节点上的代理,管理路由表与 iptables/eBPF 规则
- BIRD:BGP 客户端,负责在节点之间交换路由信息
- Typha:位于 Felix 与 Kubernetes API Server 之间的代理,用于降低 API Server 负载
- calicoctl:管理 Calico 资源的 CLI 工具
GlobalNetworkPolicy 实现
Calico 的 GlobalNetworkPolicy 是不依附于命名空间的集群级策略,其优先级高于 Kubernetes 标准 NetworkPolicy。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: deny-egress-to-internet
spec:
selector: environment == 'production'
types:
- Egress
egress:
- action: Allow
destination:
nets:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- action: Allow
protocol: UDP
destination:
ports:
- 53
- action: Deny
destination:
notNets:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
这条策略让 production 环境的所有 Pod 只能访问 RFC 1918 私有 IP 网段与 DNS 流量,阻断直接连接互联网。
Calico 分层(Tier)体系
在 Calico Enterprise 中,可以使用策略分层来明确管理策略的执行顺序。
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
name: security
spec:
order: 100
---
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
name: platform
spec:
order: 200
---
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: security.block-known-threats
spec:
tier: security
order: 10
selector: all()
types:
- Ingress
- Egress
ingress:
- action: Deny
source:
nets:
- 198.51.100.0/24
- action: Pass
egress:
- action: Deny
destination:
nets:
- 198.51.100.0/24
- action: Pass
由于安全团队的策略会先于平台团队的策略被评估,因此可以在不受平台策略影响的前提下阻断已知威胁 IP。
Cilium vs Calico vs 原生 NetworkPolicy 对比表
下表对比了各方案的主要功能与特性。
| 项目 | Kubernetes NetworkPolicy | Cilium | Calico |
|---|---|---|---|
| 策略范围 | 命名空间 | 命名空间 + 集群 | 命名空间 + 集群 |
| L3/L4 支持 | O | O | O |
| L7 支持 | X | O (HTTP, gRPC, Kafka, DNS) | 部分(仅 Enterprise) |
| 基于 DNS 的策略 | X | O(FQDN 匹配) | O (Calico Enterprise) |
| 策略引擎 | 依赖 CNI | eBPF 原生 | iptables / eBPF 可选 |
| 性能(策略 1000+) | 基于 iptables 性能下降 | eBPF 保持稳定性能 | eBPF 模式下良好 |
| 监控 | 需要额外工具 | 内置 Hubble | calicoctl + Prometheus |
| FQDN 出站 | X | O | O (Enterprise) |
| 策略分层 | X | X | O (Enterprise) |
| Host 防火墙 | X | O | O |
| 加密 | X | WireGuard/IPsec | WireGuard |
| 多集群 | X | Cluster Mesh | Calico Federation |
| CNCF 等级 | 标准 | Graduated | -(Tigera 商用) |
| GUI 管理 | X | Hubble UI | Calico Enterprise UI |
实施指南
分阶段落地 Default Deny
在生产环境中一次性应用 Default Deny 可能引发大规模故障。下面是安全的分阶段实施流程。
阶段 1:以审计模式起步(Cilium)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: audit-default-deny
namespace: staging
annotations:
policy.cilium.io/audit-mode: 'true'
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- matchLabels:
reserved:host: ''
egress:
- toEndpoints:
- matchLabels:
reserved:host: ''
在审计模式下,策略不会真正阻断流量,而是把本应被阻断的流量通过 Hubble 记录成日志。
阶段 2:用 Hubble 分析流量
# 用 Hubble CLI 查看被策略审计(audit)的流量
hubble observe --namespace staging --verdict AUDIT --output json | \
jq '.flow | {src: .source.labels, dst: .destination.labels, port: .l4.TCP.destination_port}'
# 掌握命名空间内的通信模式
hubble observe --namespace staging --type trace:to-endpoint \
--output compact --last 1000
阶段 3:编写放行策略后启用 Default Deny
根据审计日志的分析结果编写好全部必要的放行策略后,再移除审计模式的 annotation,使策略正式生效。
微服务策略模式
下面是真实微服务环境中常用的策略模式。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: microservice-pattern
namespace: ecommerce
spec:
endpointSelector:
matchLabels:
app: order-service
ingress:
- fromEndpoints:
- matchLabels:
app: api-gateway
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: POST
path: '/orders'
- method: GET
path: '/orders/[0-9]+'
egress:
- toEndpoints:
- matchLabels:
app: inventory-service
toPorts:
- ports:
- port: '8080'
protocol: TCP
- toEndpoints:
- matchLabels:
app: payment-service
toPorts:
- ports:
- port: '8080'
protocol: TCP
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: '53'
protocol: ANY
这条策略把 order-service 限制为只接收来自 api-gateway 的订单相关 HTTP 请求,并且只能与 inventory-service 和 payment-service 通信。
监控与排障
用 Hubble 监控 Cilium
Hubble 是 Cilium 内置的网络观测工具,基于 eBPF 实时采集所有网络流。
# 启用 Hubble(Cilium Helm 安装时)
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
# 查看特定命名空间中被丢弃的流量
hubble observe --namespace production --verdict DROPPED \
--output json --last 100
# 追踪特定 Pod 之间的通信
hubble observe --from-pod production/api-server-7d9f8b6c5d-x2k4m \
--to-pod production/database-5f7b9c8d6e-m3n7p --output compact
# 查看策略生效状态
cilium policy get --endpoint 12345
# 查看 Cilium 端点状态
cilium endpoint list -o json | \
jq '.[] | select(.status.policy.realized.denied > 0) | {id: .id, labels: .status.labels}'
用 calicoctl 排查 Calico
# 查看 Calico 节点状态
calicoctl node status
# 查看已生效的策略列表
calicoctl get networkpolicy --all-namespaces -o wide
calicoctl get globalnetworkpolicy -o wide
# 模拟特定工作负载的策略评估
calicoctl get workloadendpoint --all-namespaces -o yaml | \
grep -A 5 "api-server"
# 在 Felix 日志中确认策略生效情况
kubectl logs -n calico-system -l k8s-app=calico-node -c calico-node \
--tail=100 | grep -i "policy"
# 查看 BGP 邻居状态
calicoctl node status | grep -A 10 "BGP"
Prometheus 指标采集
Cilium 与 Calico 都会暴露 Prometheus 指标。
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: cilium-metrics
namespace: monitoring
spec:
selector:
matchLabels:
k8s-app: cilium
namespaceSelector:
matchNames:
- kube-system
endpoints:
- port: metrics
interval: 15s
path: /metrics
主要的监控指标如下。
cilium_policy_verdict_total:策略判定结果(FORWARDED、DROPPED、AUDIT)计数器cilium_drop_count_total:被策略丢弃的数据包数量cilium_policy_import_errors_total:策略解析错误数量calico_felix_active_local_policies:Felix 正在活跃管理的策略数量calico_felix_iptables_save_errors:iptables 规则保存错误数量
故障案例与恢复流程
案例 1:一次性应用 Default Deny 导致全部服务中断
状况:运维团队未经测试就在生产命名空间应用了 Default Deny 策略。由于遗漏了 DNS 放行策略,所有服务的服务发现失败,进而连锁导致所有微服务之间无法互相通信。
症状:
- 所有 Pod 的 readiness probe 失败
- 服务之间的 HTTP 请求超时
- DNS 查询无响应
恢复流程:
# 1. 紧急处置:移除引发问题的 Default Deny 策略
kubectl delete networkpolicy default-deny-all -n production
# 2. 确认状态
kubectl get pods -n production -o wide
kubectl get endpoints -n production
# 3. 确认 DNS 通信
kubectl exec -n production deploy/api-server -- nslookup kubernetes.default
# 4. 分析根本原因后重新应用正确的策略集合
# - 先应用 DNS 放行策略
kubectl apply -f allow-dns-egress.yaml
# - 应用服务间通信策略
kubectl apply -f service-communication-policies/
# - 最后再应用 Default Deny
kubectl apply -f default-deny-all.yaml
教训:Default Deny 必须在放行策略全部生效之后再最后应用,并且务必先在预发布环境完成验证。
案例 2:Cilium DNS 策略与 CoreDNS 缓存不一致
状况:应用了 Cilium 基于 FQDN 的出站策略,但 CoreDNS 缓存的 DNS 响应绕过了 Cilium 的 DNS 代理,导致策略未能生效。
症状:
- 特定 FQDN 策略间歇性失效
- 在 Hubble 中观测不到针对该 FQDN 的 DNS 查询
- CoreDNS 缓存 TTL 过期后策略恢复正常
恢复流程:
# 1. 确认 CoreDNS 缓存
kubectl exec -n kube-system deploy/coredns -- \
curl -s http://localhost:9153/metrics | grep 'coredns_cache'
# 2. 确认 Cilium DNS 代理日志
cilium monitor --type drop --related-to fqdn
# 3. 重新应用 DNS 策略并重启 Cilium Agent
kubectl rollout restart daemonset/cilium -n kube-system
# 4. 确认 CoreDNS 配置中经由 Cilium DNS 代理的转发
kubectl get configmap coredns -n kube-system -o yaml
案例 3:Calico 策略顺序冲突
状况:两个团队各自独立编写 GlobalNetworkPolicy,生成了 order 值相同的策略,导致非预期的 Allow 规则先于 Deny 被评估,安全策略因此失效。
症状:
- 本应被阻断的流量被放行
- 用 calicoctl 查看策略顺序时发现冲突
恢复流程:
# 1. 确认所有 GlobalNetworkPolicy 的 order
calicoctl get globalnetworkpolicy -o yaml | grep -E "name:|order:"
# 2. 修正冲突策略的 order
calicoctl apply -f - <<EOF
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: security-block-external
spec:
order: 50
selector: all()
types:
- Egress
egress:
- action: Deny
destination:
notNets:
- 10.0.0.0/8
EOF
# 3. 验证策略生效顺序
calicoctl get globalnetworkpolicy -o wide | sort -k3 -n
生产环境部署检查清单
事前准备
- 确认 CNI 插件(Cilium/Calico)已安装并正常运行
- 确认所有命名空间都设置了合适的标签
- 确认所有工作负载都带有 app、role 等可用于选择的标签
- 为 kube-system 命名空间的核心服务(CoreDNS、metrics-server)准备放行策略
策略应用顺序
- 阶段 1:向所有命名空间应用 DNS 放行策略
- 阶段 2:放行与 kube-system 命名空间之间的必要通信
- 阶段 3:应用服务间通信放行策略
- 阶段 4:应用外部通信放行策略
- 阶段 5:先在预发布环境测试 Default Deny 策略
- 阶段 6:在生产环境应用 Default Deny(同时进行流量监控)
监控必备项
- 用 Hubble 或 calicoctl 搭建被丢弃流量的实时监控
- 在 Prometheus + Grafana 仪表盘中加入策略相关指标
- 配置策略违规时的 PagerDuty/Slack 告警
- 搭建周期性策略审计(Policy Audit)的自动化流程
运维注意事项
- 变更策略时始终使用
--dry-run=client选项做事前验证 - 基于 CIDR 的策略易受 IP 变动影响,优先使用基于标签的策略
- Headless Service 会直接使用 Pod IP,需要单独考虑策略
- 确认 NodePort、LoadBalancer 服务的入站流量路径
- 使用 Cilium Host Policy 时注意不要阻断节点间通信(kubelet、etcd)
- 策略备份与 Git 仓库管理(建议接入 GitOps)
回滚计划
- 准备好紧急情况下可立即移除 Default Deny 策略的脚本
- 建立策略变更前后 Hubble/calicoctl 快照对比流程
- 搭建可从 Git 立即恢复回滚目标策略旧版本的流水线
高级模式:多集群网络策略
Cilium Cluster Mesh
使用 Cilium Cluster Mesh 可以跨多个集群应用网络策略。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: cross-cluster-policy
namespace: shared-services
spec:
endpointSelector:
matchLabels:
app: shared-database
ingress:
- fromEndpoints:
- matchLabels:
app: backend
io.cilium.k8s.policy.cluster: cluster-east
toPorts:
- ports:
- port: '5432'
protocol: TCP
- fromEndpoints:
- matchLabels:
app: backend
io.cilium.k8s.policy.cluster: cluster-west
toPorts:
- ports:
- port: '5432'
protocol: TCP
Calico Federation
在 Calico 中,可以通过 Federation 为远程集群的服务配置网络策略。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: federated-service-access
spec:
selector: app == 'frontend'
types:
- Egress
egress:
- action: Allow
destination:
selector: app == 'api-gateway'
namespaceSelector: global()
protocol: TCP
结语
Kubernetes 网络策略是集群安全的核心组成部分。仅靠原生 NetworkPolicy 也能实现 L3/L4 层面的隔离,但在真实生产环境中,Cilium 或 Calico 这类 CNI 插件的高级能力是必不可少的。
Cilium 的优势在于基于 eBPF 的高性能数据平面、L7 策略、基于 DNS 的出站控制以及 Hubble 可观测性。Calico 则凭借 BGP 路由集成、GlobalNetworkPolicy 与策略分层体系,更适合企业级环境。
无论选择哪种方案,都应采用以 Default Deny 策略为基础的零信任思路,并在应用策略前务必通过审计模式和预发布环境进行充分验证。网络策略并非一次应用就万事大吉,而是需要随着服务演进持续管理和更新的、活的安全要素,这一点绝不能忘记。
参考资料
현재 단락 (1/505)
在 Kubernetes 集群中,Pod 默认可以 **与其他所有 Pod 自由通信**。这在开发初期很方便,但在生产环境中会成为严重的安全威胁。因为只要有一个 Pod 被攻破,攻击者就能向集群内的所...