上一篇我们拆解了 Kubernetes NetworkPolicy 的标准模型 – 基于 Pod selector 和 namespace selector 的 L3/L4 访问控制。标准 NetworkPolicy 的局限性在那篇文章的结尾已经提到:它只能做到 IP + 端口级别的过滤,无法理解 HTTP 方法、gRPC 服务名、Kafka topic 这些应用层语义。更关键的是,它的底层实现依赖 iptables 规则,而 iptables 规则是以 IP 地址为匹配条件的 – 在 Pod IP 随时变化的 Kubernetes 环境中,这从根本上就是一个脆弱的安全模型。
Cilium 的回答是:抛弃 IP,用身份(Identity)作为安全原语。
这篇文章是 Cilium 深度拆解的安全专题续篇。那篇文章从整体架构角度介绍了 Cilium 的 eBPF 数据面和 Identity 模型的基本概念。本文会专注于安全维度,深入拆解 Identity 的分配机制、eBPF datapath 中的身份传递、L7 协议级访问控制、透明 mTLS 的实现,以及这些技术如何组合成一个完整的零信任网络架构。
如果你还没读过 eBPF 安全机制的基础知识,建议先看 eBPF 安全机制,那篇文章覆盖了 eBPF verifier、capability 检查和安全边界的核心概念。
本文基于 Cilium v1.16.x,Linux 6.x 内核。部分内部实现可能随版本演进而调整。 实验环境:Ubuntu 22.04, kernel 6.5, kind 集群 + Cilium Helm 安装。
一、为什么 IP-Based 安全在 Kubernetes 中不够用
IP 地址的短暂性
传统网络安全的基石是 IP 地址:防火墙规则、ACL、安全组,全部以”源 IP / 目标 IP + 端口”作为匹配条件。这在物理网络或虚拟机环境中是合理的 – 一台服务器的 IP 通常是长期稳定的。但在 Kubernetes 中,IP 地址是短暂的(ephemeral):
$ kubectl get pod -o wide
NAME READY IP NODE
frontend-abc123-xk9z2 1/1 10.244.1.47 node-1
# 滚动更新后,IP 完全变化
$ kubectl rollout restart deploy/frontend
$ kubectl get pod -o wide
NAME READY IP NODE
frontend-abc123-j7q4n 1/1 10.244.1.52 node-1同一个 Deployment,滚动更新一次,Pod IP
就变了。如果安全策略写死了
10.244.1.47,更新后就失效了。更糟糕的是,这个
IP 可能被分配给一个完全不同的 Pod –
安全策略不仅失效,还可能错误地放行了不该放行的流量。
SNAT 导致的源信息丢失
即使 IP 没变,Kubernetes 的网络模型也会在多个环节丢失源
IP 信息。当流量经过 kube-proxy 的 NodePort 或 LoadBalancer
时,源 IP 被 SNAT 成节点 IP。后端 Pod 看到的
src_ip 是节点地址,无法区分实际的客户端。基于源
IP 的安全策略在这条路径上完全无法生效。
externalTrafficPolicy: Local 可以保留源
IP,但它限制了流量只能路由到本地
Pod,牺牲了负载均衡能力。这是一个典型的安全与功能的
trade-off。
IP-Based 策略的规模问题
在大规模集群中,IP-based 策略还有规则膨胀的问题:
| 集群规模 | Pod 数量 | iptables 规则数(估算) | 规则更新延迟 |
|---|---|---|---|
| 小型 | 100 | ~500 | <1s |
| 中型 | 1,000 | ~5,000 | 2-5s |
| 大型 | 10,000 | ~50,000 | 10-30s |
| 超大型 | 50,000 | ~250,000 | >60s |
每个 NetworkPolicy 规则最终被翻译成一组 iptables
规则,规则数量与 Pod 数量成正比。当集群有上万个 Pod
时,iptables-restore
的全量刷新可能需要几十秒,在这个窗口期内安全策略是不一致的。
Cilium 的 Identity 模型从根本上解决了这个问题:策略规则数量与 Identity 数量成正比,而 Identity 数量远小于 Pod 数量。一万个相同标签的 Pod 共享同一个 Identity,策略规则只需要一条。
二、Cilium Identity 模型深度拆解
什么是 Cilium Identity
Cilium Identity 是一个 32 位无符号整数,代表一组具有相同安全相关标签(security-relevant labels)的工作负载。两个 Pod 如果拥有完全相同的安全标签集合,就会被分配相同的 Identity。
$ kubectl get cep -n default frontend-abc123-xk9z2 -o yaml
apiVersion: cilium.io/v2
kind: CiliumEndpoint
metadata:
name: frontend-abc123-xk9z2
status:
identity:
id: 48372
labels:
- k8s:app=frontend
- k8s:env=prod
- k8s:io.kubernetes.pod.namespace=defaultIdentity 48372 代表的不是某一个 Pod,而是所有具有
app=frontend, env=prod 标签、运行在
default namespace 的 Pod。无论这些 Pod 的 IP
怎么变化,Identity 始终是 48372。
安全相关标签的筛选
不是所有 Pod 标签都参与 Identity 计算。Cilium 会自动排除
pod-template-hash、controller-revision-hash
等频繁变化的标签,只保留安全相关的标签。可以通过配置显式控制:
# Cilium ConfigMap
labels: "k8s:io.kubernetes.pod.namespace k8s:app k8s:env"这个筛选逻辑确保了 Identity 的稳定性:Pod
滚动更新时,pod-template-hash 变化不会导致
Identity 重新分配。
Label 到 Identity 的映射:kvstore Allocation
Identity 的分配是全局的,需要集中式存储保证唯一性。Cilium 支持两种后端:
方式一:etcd(kvstore 模式)
# etcd 中的存储结构
/cilium/state/identities/v1/id/48372
-> {"labels": ["k8s:app=frontend", "k8s:env=prod", ...]}
/cilium/state/identities/v1/labels/
SHA256("k8s:app=frontend;k8s:env=prod;...") -> 48372
分配流程:Cilium Agent 发现新 Pod,提取安全标签,计算 SHA256 哈希,在 etcd 中查找是否已有对应 Identity。如果有就复用;如果没有,分配新的数字 ID 并写回 CiliumEndpoint CRD。
方式二:CRD-based(Kubernetes CRD 模式)
$ kubectl get ciliumidentity 48372 -o yaml
apiVersion: cilium.io/v2
kind: CiliumIdentity
metadata:
name: "48372"
security-labels:
k8s:app: frontend
k8s:env: prod
k8s:io.kubernetes.pod.namespace: defaultCRD 模式不需要额外的 etcd 集群,直接使用 Kubernetes API Server 存储 Identity 数据,降低了运维复杂度。
特殊保留 Identity
| Identity | 含义 | 用途 |
|---|---|---|
| 0 | unknown |
无法识别身份的流量 |
| 1 | host |
节点本身的流量 |
| 2 | world |
集群外部的流量 |
| 3 | unmanaged |
非 Cilium 管理的 Endpoint |
| 4 | health |
Cilium 健康检查 |
| 6 | remote-node |
其他节点的流量 |
| 7 | kube-apiserver |
API Server |
这些保留 Identity 允许你编写策略,例如”只允许来自
kube-apiserver 的流量访问 webhook
endpoint”,而不需要知道 API Server 的具体 IP。
Identity 在 eBPF Datapath 中的传递
Identity 分配完成后,如何在数据面中使用?这是 Cilium 最精妙的设计之一。
同节点通信:ipcache Map 查找
// bpf/lib/identity.h(简化)
static __always_inline __u32 lookup_ip4_remote_identity(__be32 ip)
{
struct ipcache_key key = {
.lpm_key.prefixlen = 32,
.family = ENDPOINT_KEY_IPV4,
.ip4 = ip,
};
struct remote_endpoint_info *info;
info = map_lookup_elem(&IPCACHE_MAP, &key);
if (info)
return info->sec_identity;
return WORLD_ID;
}IPCACHE_MAP 是 BPF LPM Trie Map,存储 IP 到
Identity 的映射。每个节点的 Cilium Agent 持续同步这个
Map。
跨节点通信(隧道模式):Identity 嵌入 VXLAN GBP 字段
封装后的包:
[ETH][Outer IP][VXLAN Header + GBP: Identity=48372][Inner ETH][IP][TCP][Payload]
发送端 eBPF 程序将源 Identity 写入 VXLAN 的 GBP(Group-Based Policy)扩展字段,接收端直接读取,无需再查 ipcache。
跨节点通信(直接路由模式):依赖 ipcache
直接路由模式没有隧道头携带 Identity,接收端通过 ipcache Map 反查源 Pod IP 对应的 Identity。
CT Entry 与身份缓存
Cilium 的 Connection Tracking 表不仅记录连接状态,还缓存了 Identity:
// bpf/lib/conntrack.h(简化)
struct ct_entry {
__u64 rx_packets;
__u64 tx_packets;
__u32 lifetime;
__u16 flags;
__u32 src_sec_id; // 源 Identity 缓存
__u32 ifindex;
};连接建立后,源 Identity 被缓存在
ct_entry.src_sec_id 中,后续数据包直接从 CT
表获取 Identity,不需要每次查 ipcache –
这是关键的性能优化。
三、跨集群 Identity 同步:ClusterMesh
在多集群环境中,不同集群的 Identity
编号可能冲突。ClusterMesh 通过
clustermesh-apiserver 解决这个问题。
ClusterMesh 架构
$ cilium clustermesh enable --service-type LoadBalancer
$ cilium clustermesh connect --destination-context cluster-2每个集群运行一个
clustermesh-apiserver(轻量级 etcd
代理),暴露本集群的 Identity 和 Service 信息。远端集群的
Cilium Agent 连接到这个 apiserver,将远端的 Identity 和
ipcache 数据合并到本地。
Identity 编号的全局唯一性
通过 cluster ID 前缀避免编号冲突:
cluster:
name: cluster-1
id: 1 # 范围:1-255相同标签的 Pod 在不同集群中可能有不同的 Identity 编号,但 ClusterMesh 确保策略评估时正确匹配。
跨集群策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-cross-cluster-frontend
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
io.cilium.k8s.policy.cluster: cluster-1
toPorts:
- ports:
- port: "8080"
protocol: TCP策略基于 Identity(标签)而非 IP,即使跨集群 CIDR 完全不同,策略依然生效。
四、L7 Policy:协议级别的访问控制
超越 L3/L4 的需求
标准 NetworkPolicy 只能做”允许访问 80 端口”。但现实中的安全需求远比这复杂:“只允许 GET,禁止 DELETE”、“只允许访问 /api/v1/health”、“只允许向 Kafka 的 events topic 发布消息”。Cilium 通过 per-node Envoy proxy 实现 L7 策略。
当 CiliumNetworkPolicy 包含 L7 规则时,eBPF 程序将匹配的流量重定向到 Envoy。Envoy 解析应用层协议并执行策略检查。通过的流量转发到目标 Pod,被拒绝的返回 HTTP 403 或 TCP RST。
HTTP 策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-http-policy
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/.*"
- method: POST
path: "/api/v1/orders"
headers:
- 'Content-Type: application/json'只允许 app=frontend 对
app=api-server 发起 GET /api/v1/*
和 POST /api/v1/orders(需 JSON
Content-Type)。其他请求(DELETE、PUT、/admin
等)全部拒绝。
gRPC 策略
gRPC 在 HTTP/2 之上运行,Cilium 将 gRPC 方法映射为 HTTP/2 的 POST + path,因此复用 HTTP 规则语法:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-grpc-policy
spec:
endpointSelector:
matchLabels:
app: user-service
ingress:
- fromEndpoints:
- matchLabels:
app: api-gateway
toPorts:
- ports:
- port: "9090"
protocol: TCP
rules:
http:
- method: POST
path: "/user.UserService/GetUser"
- method: POST
path: "/user.UserService/ListUsers"Kafka 策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-kafka-policy
spec:
endpointSelector:
matchLabels:
app: kafka-broker
ingress:
- fromEndpoints:
- matchLabels:
app: event-producer
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
- apiKey: "produce"
topic: "user-events"
- apiKey: "metadata"
- fromEndpoints:
- matchLabels:
app: event-consumer
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
- apiKey: "fetch"
topic: "user-events"
- apiKey: "offsets"
- apiKey: "metadata"实现了 Kafka 读写分离:event-producer
只能写入,event-consumer 只能读取 – L3/L4
策略根本无法实现。
L7 策略的性能影响
| 场景 | 额外延迟 | 说明 |
|---|---|---|
| 纯 L3/L4(eBPF only) | ~0 | 不经过 proxy |
| L7 HTTP/gRPC(Envoy redirect) | 0.5-2ms | 按需 redirect |
| L7 Kafka | 1-3ms | 协议解析较重 |
Cilium 的关键优势:只有需要 L7 策略的流量才经过 Envoy。没有 L7 策略的流量完全在 eBPF 内处理。这与 Istio 的 sidecar 模式不同 – Istio 中所有流量都要经过 sidecar proxy。
五、Mutual TLS:Cilium 的透明 mTLS
为什么需要 mTLS
Identity 解决了”你是谁”,但还需要解决”我怎么验证你确实是你声称的那个人”。没有加密和身份验证,攻击者可以伪造 IP 或 Identity。mTLS 提供加密、服务端认证和客户端认证三重保护。
Cilium 的透明 mTLS(基于 SPIFFE)
Cilium 1.14+ 支持透明 mTLS,基于 SPIFFE 标准:
$ helm upgrade cilium cilium/cilium \
--set authentication.mutual.spire.enabled=true \
--set authentication.mutual.spire.install.enabled=true启用后:SPIRE Agent 为 Cilium 提供 SPIFFE SVID
证书;当策略要求 authentication.mode: required
时,eBPF 将流量重定向到 mTLS handshake
组件;双方交换证书完成握手;后续流量加密传输。对应用完全透明。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: require-mtls
spec:
endpointSelector:
matchLabels:
app: payment-service
ingress:
- fromEndpoints:
- matchLabels:
app: order-service
authentication:
mode: required
toPorts:
- ports:
- port: "8443"
protocol: TCPSPIFFE Identity 与 Cilium Identity 的关系
SPIFFE ID
格式:spiffe://cluster.local/ns/default/sa/frontend(trust
domain / namespace / service account)。
两者互补:Cilium Identity 是基于标签的数字编号,用于 eBPF 快速策略查找;SPIFFE Identity 是基于 X.509 证书的加密身份,用于 mTLS 验证。eBPF 做快速路径过滤,mTLS 做慢速路径验证和加密。
Cilium mTLS 与 Istio mTLS 的区别
| 维度 | Cilium mTLS | Istio mTLS |
|---|---|---|
| 架构 | 透明,无 sidecar | Sidecar proxy(Envoy) |
| 性能开销 | 较低(内核态 + 按需) | 较高(每 Pod 一个 Envoy) |
| 粒度 | 按策略启用 | 全局或 namespace 级别 |
| 证书管理 | SPIRE | Istio CA (istiod) |
| 协议支持 | TCP/TLS | HTTP/gRPC/TCP |
| 资源消耗 | 低(共享 per-node Envoy) | 高(每 Pod 一个 sidecar) |
| 成熟度 | 较新(1.14+) | 成熟(生产验证多年) |
核心区别:Istio 为每个 Pod 注入 Envoy sidecar,所有流量经 sidecar 加解密。Cilium 在 eBPF 层完成拦截,只在需要 mTLS 时触发加密。千 Pod 集群中,Istio 需要运行 1000 个 sidecar(各约 50-100MB 内存),Cilium 只需每节点一个共享 Envoy。
六、零信任网络架构在 Kubernetes 中的落地
零信任的核心原则
零信任模型的核心是”永不信任,始终验证”。在 Kubernetes 中具体化为四点:默认拒绝(无明确允许则拒绝)、最小权限(只允许必需的资源访问)、身份感知(基于工作负载身份而非网络位置)、持续验证(每次请求都验证)。
第一步:默认拒绝策略
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: default-deny-all
spec:
endpointSelector: {}
ingress:
- fromEntities:
- cluster
egress:
- toEntities:
- cluster
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCP默认拒绝所有流量,只保留集群内基础通信和 DNS 访问。
第二步:按需开放最小权限
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-server-policy
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
authentication:
mode: required
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/.*"
- method: POST
path: "/api/v1/orders"
egress:
- toEndpoints:
- matchLabels:
app: database
toPorts:
- ports:
- port: "5432"
protocol: TCP第三步:持续验证
当 Pod 标签变化时,Cilium Agent 重新计算安全标签,分配新 Identity,更新 eBPF Map,已有连接会被重新评估。如果新 Identity 不再被允许,连接立即断开。不存在”先通过验证,后续免检”的漏洞。
零信任成熟度模型
| 等级 | 能力 | Cilium 对应功能 |
|---|---|---|
| L0 | 无网络策略 | 默认状态 |
| L1 | L3/L4 默认拒绝 + 白名单 | CiliumNetworkPolicy (L3/L4) |
| L2 | Identity-based 策略 | Cilium Identity + eBPF |
| L3 | L7 协议感知策略 | L7 Policy (HTTP/gRPC/Kafka) |
| L4 | mTLS 加密 + 身份验证 | SPIFFE + Cilium mTLS |
| L5 | 持续验证 + 可观测性 | Hubble + Policy Audit Mode |
七、Network Policy Editor:可视化策略管理
Cilium Policy Editor
Cilium 提供了 Web 版 Network Policy
Editor(https://editor.networkpolicy.io/),支持可视化创建和调试网络策略。上传集群的
CiliumEndpoint 和 CiliumNetworkPolicy 资源后,Editor
自动绘制交互式网络拓扑图,展示所有
Endpoint、Identity、允许/拒绝的流量方向。
命令行策略调试
# 查看 Endpoint 策略状态
$ cilium endpoint list
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS
2847 Enabled Enabled 48372 k8s:app=frontend
3912 Enabled Enabled 99001 k8s:app=api-server
# 模拟策略评估
$ cilium policy trace \
--src-identity 48372 \
--dst-identity 99001 \
--dport 8080/TCP
Final verdict: ALLOWEDcilium policy trace
是调试利器,模拟数据包从源 Identity 到目标 Identity
的策略评估过程。
Hubble 策略可观测性
# 实时观察被拒绝的流量
$ hubble observe --verdict DROPPED
Oct 10 14:23:01: default/unknown-pod:54321 (ID:0)
-> default/api-server-xyz:8080 (ID:99001)
http-request DROPPED (HTTP/1.1 DELETE /api/v1/users)
# 按 Identity 过滤
$ hubble observe --from-identity 48372 --to-identity 99001
Oct 10 14:23:05: default/frontend-abc:38291 (ID:48372)
-> default/api-server-xyz:8080 (ID:99001)
http-request FORWARDED (HTTP/1.1 GET /api/v1/health)八、实验:配置 Cilium L7 Policy
环境准备
# 创建 kind 集群
$ kind create cluster --name cilium-lab --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true
kubeProxyMode: none
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# 安装 Cilium
$ helm install cilium cilium/cilium --version 1.16.4 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true
$ cilium status --wait部署测试应用
# test-app.yaml -- api-server(nginx 模拟三个端点)
apiVersion: v1
kind: ConfigMap
metadata:
name: api-nginx-conf
data:
default.conf: |
server {
listen 80;
location /api/v1/health { return 200 '{"status":"ok"}'; }
location /api/v1/users { return 200 '{"users":["alice","bob"]}'; }
location /api/v1/admin { return 200 '{"admin":true}'; }
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 1
selector: { matchLabels: { app: api-server } }
template:
metadata: { labels: { app: api-server, env: prod } }
spec:
containers:
- name: api
image: nginx:1.25
ports: [{ containerPort: 80 }]
volumeMounts: [{ name: conf, mountPath: /etc/nginx/conf.d }]
volumes: [{ name: conf, configMap: { name: api-nginx-conf } }]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector: { matchLabels: { app: frontend } }
template:
metadata: { labels: { app: frontend, env: prod } }
spec:
containers:
- { name: curl, image: "curlimages/curl:8.5.0", command: ["sleep","infinity"] }
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: attacker
spec:
replicas: 1
selector: { matchLabels: { app: attacker } }
template:
metadata: { labels: { app: attacker } }
spec:
containers:
- { name: curl, image: "curlimages/curl:8.5.0", command: ["sleep","infinity"] }$ kubectl apply -f test-app.yaml
$ kubectl wait --for=condition=Ready pod -l app=api-server --timeout=60s
$ kubectl wait --for=condition=Ready pod -l app=frontend --timeout=60s验证无策略时的访问
$ API_IP=$(kubectl get pod -l app=api-server -o jsonpath='{.items[0].status.podIP}')
# frontend 和 attacker 都能访问所有路径
$ kubectl exec deploy/frontend -- curl -s http://$API_IP/api/v1/admin
{"admin":true}
$ kubectl exec deploy/attacker -- curl -s http://$API_IP/api/v1/admin
{"admin":true}应用 L7 策略:只允许 GET /api/v1/health
# l7-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-server-l7-policy
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/health"$ kubectl apply -f l7-policy.yaml验证 L7 策略效果
# frontend -> GET /api/v1/health:允许(200)
$ kubectl exec deploy/frontend -- curl -s -o /dev/null -w "%{http_code}" \
http://$API_IP/api/v1/health
200
# frontend -> GET /api/v1/users:L7 拒绝(403)
$ kubectl exec deploy/frontend -- curl -s -o /dev/null -w "%{http_code}" \
http://$API_IP/api/v1/users
403
# frontend -> DELETE /api/v1/health:方法不匹配,L7 拒绝(403)
$ kubectl exec deploy/frontend -- curl -s -o /dev/null -w "%{http_code}" \
-X DELETE http://$API_IP/api/v1/health
403
# attacker -> GET /api/v1/health:Identity 不匹配,L3/L4 直接丢弃
$ kubectl exec deploy/attacker -- curl -s --connect-timeout 5 \
http://$API_IP/api/v1/health
# 超时 -- 流量在 eBPF 层面被丢弃,连接无法建立用 Hubble 观察策略决策
$ hubble observe --namespace default --follow
# 允许的请求:
# default/frontend-xxx (ID:48372) -> default/api-server-xxx:80 (ID:99001)
# http-request FORWARDED (HTTP/1.1 GET /api/v1/health)
# L7 拒绝:
# default/frontend-xxx (ID:48372) -> default/api-server-xxx:80 (ID:99001)
# http-request DROPPED (HTTP/1.1 GET /api/v1/admin)
# L3/L4 拒绝:
# default/attacker-xxx (ID:67890) -> default/api-server-xxx:80 (ID:99001)
# Policy denied DROPPED (TCP Flags: SYN)三种场景清晰可见:L7 放行、L7 拒绝、L3/L4 拒绝。注意 L3/L4 拒绝发生在 TCP SYN 阶段,连接根本没有建立。
九、生产环境最佳实践
渐进式策略部署
不要一次性在生产环境启用默认拒绝。推荐的渐进路径:
# 阶段 1:审计模式 -- 只记录不拦截
$ cilium config set policy-audit-mode enabled
# 用 Hubble 收集流量模式
$ hubble observe --verdict AUDIT --output json > traffic-baseline.json
# 阶段 2:分析基线,生成策略
# 阶段 3:测试环境验证
# 阶段 4:关闭审计模式,启用强制执行
$ cilium config set policy-audit-mode disabledIdentity 规模管理
Identity
膨胀的常见原因:过多标签被纳入计算,或标签值组合过多(如
version=v1.2.3)。通过 labels
配置项精确控制参与 Identity 计算的标签。
$ cilium identity list | wc -l # 监控 Identity 数量监控与告警
# Prometheus 告警规则
groups:
- name: cilium-identity
rules:
- alert: CiliumIdentityAllocationFailure
expr: rate(cilium_identity_allocation_errors_total[5m]) > 0
for: 5m
annotations:
summary: "Cilium Identity 分配失败"
- alert: CiliumPolicyDeniedSpike
expr: rate(cilium_drop_count_total{reason="Policy denied"}[5m]) > 100
for: 2m
annotations:
summary: "策略拒绝流量突然增加"
- alert: CiliumL7ProxyLatencyHigh
expr: histogram_quantile(0.99, rate(cilium_proxy_upstream_reply_seconds_bucket[5m])) > 0.5
for: 5m
annotations:
summary: "L7 Proxy 延迟过高"十、深入对比:Cilium Identity vs. 传统安全模型
与 Kubernetes 标准 NetworkPolicy 的对比
| 维度 | 标准 NetworkPolicy | Cilium Identity |
|---|---|---|
| 安全原语 | IP 地址 | 数字 Identity |
| 匹配复杂度 | O(n) iptables 线性匹配 | O(1) BPF Map 哈希查找 |
| 规则更新 | 全量 iptables-restore | 原子 Map 更新 |
| L7 支持 | 无 | HTTP/gRPC/Kafka |
| mTLS | 无 | SPIFFE-based |
| 跨集群 | 无 | ClusterMesh |
| 可观测性 | 无内置 | Hubble |
与 Istio 安全模型的对比
Istio 路径:
App -> [iptables redirect] -> Envoy sidecar -> [mTLS] -> Envoy sidecar -> App
每个 Pod 两次 iptables redirect + 两次 Envoy 处理
Cilium 路径:
App -> [eBPF redirect] -> (按需) per-node Envoy -> [按需 mTLS] -> App
一次 eBPF redirect + 按需 Envoy 处理
Cilium 优势:更低资源消耗(无 per-Pod sidecar)、更低延迟(纯 L3/L4 不经 proxy)、更简单运维。Istio 优势:更成熟的 L7 流量管理(故障注入、超时重试)、更丰富的可观测性(分布式追踪)、更广泛的协议支持、与 CNI 解耦。
系列导航 - 上一篇:Network Policy - 返回目录:Kubernetes 网络深度系列 - 下一篇:eBPF vs Netfilter 安全对比
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Kubernetes 网络深度系列】Cilium 深度拆解:eBPF 原生的云原生网络
从 eBPF 数据面到 Identity 安全模型,全面拆解 Cilium 的架构与实现
【Kubernetes 网络深度系列】Network Policy 入门到精通:不只是 YAML 游戏
从默认放行到零信任白名单,NetworkPolicy 的实现原理、策略模式与 CRD 扩展
【Kubernetes 网络深度系列】容器网络加密:WireGuard、IPsec 与透明 mTLS
WireGuard、IPsec、透明 mTLS 三种容器网络加密方案的原理、性能与选型
【Kubernetes 网络深度系列】DSR(Direct Server Return):让回包绕过负载均衡器
DSR 三种实现方式、Cilium DSR 深度拆解、Maglev 一致性哈希,以及 DSR 的那些坑