LabHub
学习 学习路径 课程

CCA — Cilium 认证助理

挂上一条策略的那一瞬间发生的事

在 LabHub 中继续学习

一句话总结

只要有一条选择某个 endpoint 的策略生效,该方向就会立即切换为白名单模式。 两个方向彼此独立,而且 deny 永远优先于 allow。

概念图: 该方向就会立即切换为白名单模式。 · 无法看到被拒绝的流量。 · 第一,各方向彼此独立。 · 第二,deny 永远优先于 allow。

为什么需要它

Kubernetes 的默认状态是“所有 Pod 都能与所有 Pod 通信”。支付服务可以连接公司 wiki,被攻陷的 frontend 也能直接访问数据库。零信任的起点,就是颠覆这一默认值。

标准 NetworkPolicy 可以作为起点,但在实际工作中很快会遇到限制:无法按 HTTP 路径控制,无法按域名允许外部 API,没有显式拒绝规则来表达“无论如何都必须阻止”的对象,最重要的是,无法看到被拒绝的流量。 CiliumNetworkPolicy 填补了这些空白。

工作原理

其思维模型如下。

        ingress 정책                       egress 정책
  "누가 나에게 올 수 있나"            "나는 어디로 갈 수 있나"

  [소스 아이덴티티] --> (엔드포인트) --> [목적지 아이덴티티/CIDR/FQDN]
                            |
              per-endpoint 정책 맵에서 O(1) 판정
              key: (아이덴티티, 포트, 프로토콜, 방향)

由此可以得到两条最容易在实际工作中引发事故的规则。

第一,各方向彼此独立。 为某个 Pod 添加一条 ingress 策略后,该 Pod 的 ingress 会变成白名单,但在添加 egress 策略之前,egress 仍然全部放行。“已经应用策略,所以安全了”的错觉正是由此而来。

第二,deny 永远优先于 allow。 如果同一流量同时匹配 allow 和 deny,结果就是拒绝。因此,对于阻止云 metadata endpoint 这类绝不能放行的对象,应再使用 egressDeny 增加一道防线。

selector 的细微差异也是考试常见内容。

ingress:
  - fromEndpoints:
      - {}        # 같은 네임스페이스의 모든 엔드포인트 = 허용
ingress:
  - fromEndpoints: []   # 아무것도 매칭되지 않음 = 명시적 기본 거부

包含一个空对象的数组,与空数组的含义完全相反。

添加 L7 策略后,流量路径会发生变化。eBPF 只挑选相应 flow,转交给节点上的 Envoy;Envoy 解析 HTTP,如果不符合规则,就返回 403。与 L4 阻断不同,连接本身已经建立,因此应用日志中会表现为“能够连接,但返回 403”。如果不了解这项差异,就可能误认为是 firewall 问题,并在错误方向上排查。

最常见的配置失误则是:使用 toFQDNs,却没有同时配置 DNS 规则。 toFQDNs 并不是检查 packet 的 SNI。它的工作方式是由 Cilium DNS proxy 截获该 Pod 的 DNS 响应,学习“此 Pod 已经得知 api.example.com 对应 54.x.x.x”,再把该 IP 注册到 ipcache,按 IP 放行。因此,如果没有允许 DNS query 并让 proxy 能够观察的规则,toFQDNs 将永远无法匹配。 症状可能表现为“DNS 正常但连接被拒绝”,也可能恰好相反。

生产切换分四个阶段:观察(用 Hubble 收集真实通信矩阵)→ 先只发布 allow 策略 → 使用 policy-audit-mode 仅记录“原本会被阻止的流量”→ 按 namespace 逐步强制执行。为了避免遗漏 batch job 等很少运行的流量,观察期最好至少覆盖一个月的周期。

最后,标准 NetworkPolicy 与 CNP 会在同一个 eBPF datapath 中评估,并按任意一方允许即允许的方式合并。如果混用两种资源,就必须在两个地方查找“为什么这里是开放的?”,因此最好由团队统一选定一种标准资源。

现场会遇到的情况

作者在家庭实验室中实际测量了这一行为。部署 nginx 后,在没有策略的情况下调用,GET 与 POST 都返回 200。随后应用只包含 rules.http: [{method: GET}] 的 CiliumNetworkPolicy,结果出现了如下差异。

GET  /  -> 200
POST /  -> 403

IP 和端口完全相同,却按方法进行了区分。 Pod 没有注入 sidecar,应用代码也未做任何修改。iptables 在 L3/L4 工作,从原理上就无法实现这种区分。

更有意思的是 Hubble 日志的形态。

client:47918 -> api:80  http-request  FORWARDED (HTTP/1.1 GET  http://api/)
client:47932 -> api:80  http-request  DROPPED   (HTTP/1.1 POST http://api/)
client:47932 <- api:80  http-response FORWARDED (HTTP/1.1 403 0ms POST)

请求是 DROPPED,响应却是 FORWARDED。这是因为 proxy 生成的 403 作为正常响应流了出去。 如果是 L4 drop,连响应行本身都不会存在。这种日志形态差异,是区分“被策略阻止”与“网络中断”最快的线索。

下一项实验要做什么

首先真正 apply 标准 NetworkPolicy,练习默认拒绝以及通过 Pod/namespace selector 允许流量;然后把使用 CiliumNetworkPolicy 的 HTTP 方法与路径限制、与 toFQDNs 配套的 DNS 规则,以及 metadata endpoint 阻断写入文件。