文章

Cilium 网络策略与零信任

Cilium 网络策略与零信任

为什么 Cilium 的策略更强

K8s 原生 NetworkPolicy 只能做到 L3/L4(IP/namespace/port/proto),且依赖底层 CNI 实现。Cilium 在 eBPF 上实现了 L7 感知 策略:

原生 NetworkPolicy:
  allow frontend → api-server : 8080/TCP      # 只到端口,看不到 HTTP 内容

CiliumNetworkPolicy (CNP):
  allow frontend → api-server : 8080/TCP
    http:
      - method: GET
        path: "/api/health"                     # 连 HTTP method/path 都能控

L7 之所以能实现,是因为 Cilium 在 eBPF 里把匹配 L7 的流量重定向给本节点的 envoy(见 Cilium 架构与数据面组件),由 envoy 解析协议后裁决。

策略资源类型

类型作用域说明
CiliumNetworkPolicy (CNP)命名空间内类似 NetworkPolicy,但支持 L7
CiliumClusterwideNetworkPolicy (CCNP)集群级跨 namespace,常用于 Host Firewall、全局默认拒绝
CiliumEgressGatewayPolicy出网网关指定 Pod 出网走特定节点/地址(合规/审计出口)
原生 NetworkPolicy命名空间内Cilium 完全兼容,照常生效

L3/L4 策略示例

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-allow-frontend
spec:
  endpointSelector:
    matchLabels: { app: api-server }
  ingress:
    - fromEndpoints:
        - matchLabels: { app: frontend }
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
  egress:
    - toEndpoints:
        - matchLabels: { io.kubernetes.pod.namespace: kube-system, k8s-app: kube-dns }
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP

endpointSelector / fromEndpoints标签而非 IP——这正是 eBPF identity 模型的优势:Pod IP 变了策略依然有效。

L7 策略(HTTP / gRPC / Kafka)

# 只允许 GET /api/health,其余 8080 流量全部拒绝
ingress:
  - fromEndpoints:
      - matchLabels: { app: frontend }
    toPorts:
      - ports:
          - port: "8080"
            protocol: TCP
        rules:
          http:
            - method: GET
              path: "/api/health"
---
# gRPC:按 method 控(service/method)
        rules:
          grpc:
            - method: "/helloworld.Greeter/SayHello"
---
# Kafka:按 topic + 操作
        rules:
          kafka:
            - topic: "orders"
              apiVersions: ["2"]
              operations: ["produce"]

支持 L7 的协议:HTTP/1.1、HTTP/2、gRPC、Kafka。注意 L7 策略会触发 envoy 注入(节点级共享,非 per-pod sidecar)。

FQDN / DNS 策略(零信任出网)

不用写死 IP,按域名放行——Cilium 自己维护 DNS 响应到 identity 的映射:

egress:
  - toFQDNs:
      - matchName: "api.stripe.com"
      - matchPattern: "*.github.com"
    toPorts:
      - ports:
          - port: "443"
            protocol: TCP

这解决了”出网白名单按 IP 很难维护”的痛点。前提:Pod 的 DNS 必须走 Cilium 能观测的路径(CoreDNS 或 Cilium 的 DNS 代理)。

Policy 模式(默认行为)

Cilium 对一个 Endpoint 的默认策略由 policyMode 决定:

模式行为
default未显式指定策略的 Endpoint,沿用 K8s 原生语义(无策略=全通)
always该 Endpoint 强制启用策略引擎(配合默认拒绝更安全)
never该 Endpoint 跳过策略(排障时临时关)

全局默认拒绝(零信任基础)用 CCNP:

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  endpointSelector: {}     # 匹配所有 endpoint
  ingress: []              # 空 ingress = 默认拒绝所有入向

Host Firewall(保护节点本身)

开启后,节点的 host 命名空间流量也受 Cilium 策略管制(SSH/API Server/节点组件):

# values.yaml
hostFirewall:
  enabled: true
---
# 只允许特定来源 SSH 到节点
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: host-ssh
spec:
  nodeSelector: {}
  ingress:
    - toPorts:
        - ports:
            - port: "22"
              protocol: TCP
      fromEntities:
        - "192.0.2.0/24"   # 跳板机网段

注意:Host Firewall 配错可能把自己锁在外面。先开 policyAuditMode 观察再 enforcement

策略可观测(验证策略是否生效)

# 看某个 endpoint 的生效策略
cilium endpoint policy get <endpoint-id>

# Hubble 看被 DROP 的流(验证默认拒绝生效)
hubble observe --verdict DROPPED --protocol http

# 策略审计模式:只记录不拦截
cilium config set policy-audit-mode true

与零信任架构的关系

传统:边界防火墙(南北向) + 内网全通(东西向裸奔)
零信任:每个 workload 间默认拒绝,按身份显式授权(东西向也控)

Cilium 的落地路径:
  1. CCNP 默认拒绝(东西向零信任地基)
  2. CNP 按身份(标签)授权 L3/L4
  3. 敏感服务加 L7(HTTP method/path、gRPC、Kafka)
  4. 出网走 FQDN + Egress Gateway(审计出口)
  5. Host Firewall 收口节点

关联知识

学习时间

阶段时间备注
网络策略2026-07-16完成:CNP/CCNP、L3/L4/L7、FQDN、policyMode、Host Firewall、零信任路径