4. CiliumNetworkPolicy 实战:创建允许特定微服务通信的策略、Deny 策略、基于 FQDN 的策略

本章通过三个实战场景,演示如何利用 CiliumNetworkPolicy (CNP) 实现微服务间的精细化访问控制。你将掌握从“允许特定通信”到“显式拒绝”再到“基于域名出口”的完整策略编写与验证流程。

4.1 实战场景与集群环境准备

假设我们有一个运行在 Kubernetes 上的电商应用,包含以下微服务:

微服务 标签 (Labels) 说明
frontend app=frontend 前端 Web 服务,接收用户请求
checkout app=checkout 订单结算服务
inventory app=inventory 库存查询服务
payment app=payment 支付网关服务(仅内部调用)
monitoring app=monitoring 监控采集器(需访问外部 API)
前提条件:确保集群已安装 Cilium 并启用 Hubble 可观测性组件。使用 kubectl get pods -n kube-system -l k8s-app=cilium 验证 Cilium 代理运行正常。

4.2 实战一:允许特定微服务通信的策略

目标:只允许 frontend 访问 checkout 的 8080 端口,拒绝其他所有流量。

策略定义:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-checkout
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: checkout
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP

关键字段解析:

  • endpointSelector:策略作用的目标 Pod(checkout)。
  • ingress.fromEndpoints:允许的源 Pod(frontend)。
  • toPorts:限制目标端口为 8080/TCP。

验证方法:

  1. 进入 frontend Pod:kubectl exec -it deploy/frontend -- sh
  2. 测试允许的访问:curl http://checkout:8080/health(应返回 200)。
  3. 测试拒绝的访问:curl http://checkout:8081/health(应超时或拒绝)。
  4. 从 inventory Pod 测试:curl http://checkout:8080/health(应被拒绝)。
策略生效验证:使用 hubble observe --from-pod default/frontend-xxx --to-pod default/checkout-yyy 查看 Hubble 流量日志,确认策略命中情况。

4.3 实战二:Deny 策略——显式拒绝特定通信

Cilium 支持 Deny 策略,优先级高于 Allow 策略。当同时存在 Allow 和 Deny 规则时,Deny 规则优先生效。

场景:禁止 monitoring 服务访问 payment 服务,即使其他策略允许。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-monitoring-to-payment
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: payment
  ingressDeny:
  - fromEndpoints:
    - matchLabels:
        app: monitoring

Deny 策略与 Allow 策略的对比:

特性 Allow 策略 Deny 策略
默认行为 未匹配则拒绝(白名单模式) 未匹配则允许(黑名单模式)
优先级 低 高(覆盖 Allow)
适用场景 最小权限原则 紧急阻断、合规隔离
语法字段 ingress / egress ingressDeny / egressDeny
注意:Deny 策略的 endpointSelector 指向的是被拒绝的目标 Pod(payment),而不是发起方。这与直觉相反,请务必确认方向。

验证 Deny 策略:

  1. 进入 monitoring Pod:kubectl exec -it deploy/monitoring -- sh
  2. 尝试访问 payment:curl http://payment:9090/metrics(应被拒绝)。
  3. 从其他 Pod(如 frontend)访问 payment:应正常(前提是有 Allow 策略)。

4.4 实战三:基于 FQDN 的策略——安全的外部出口

场景:monitoring 服务需要访问外部监控 API(例如 api.example.com),但禁止访问其他外部地址。

FQDN 策略使用 toFQDNs 字段,基于 DNS 解析结果动态生成网络规则。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: fqdn-egress-monitoring
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: monitoring
  egress:
  - toFQDNs:
    - matchName: "api.example.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
      matchLabels:
        k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP

策略说明:

  • 第一条规则:允许访问 api.example.com 的 443 端口。
  • 第二条规则:允许访问集群 DNS(CoreDNS),这是 FQDN 策略工作的前提——Cilium 需要拦截 DNS 请求来学习域名与 IP 的映射。
FQDN 策略工作原理:Cilium 通过 eBPF 在节点上拦截 Pod 发出的 DNS 查询,将解析到的 IP 地址动态注入到网络策略的允许列表中。DNS TTL 过期后,IP 映射自动更新。

4.5 三种策略的协同关系与架构图

下图展示了三种策略在集群中的协同工作方式:

CiliumNetworkPolicy 三种策略协同架构 Kubernetes 集群 frontend app=frontend checkout app=checkout payment app=payment monitoring app=monitoring inventory app=inventory api.example.com 外部服务 Allow :8080 Deny 所有端口 FQDN :443 默认拒绝 Allow 策略 Deny 策略 FQDN 策略 默认拒绝

4.6 策略编写最佳实践

  • 先 Deny 后 Allow:先部署 Deny 策略阻断高风险流量,再逐步开放 Allow 策略。
  • FQDN 策略必须放行 DNS:缺少 DNS 规则会导致域名解析失败,FQDN 策略无法生效。
  • 使用标签而非 IP:始终基于 Kubernetes 标签选择端点,避免硬编码 IP 导致策略漂移。
  • 启用 Hubble 监控:通过 hubble observe --verdict DROPPED 快速定位被拒绝的流量。
  • 策略命名规范:建议格式 <action>-<source>-to-<target>,例如 allow-frontend-to-checkout。
生产环境建议:在 CI/CD 流水线中集成 cilium connectivity test 命令,自动验证策略变更不会破坏现有通信链路。