LabHub
学习 学习路径 课程

Kubernetes 网络 — 在真集群上

亲眼看策略真的挡住了什么

在 LabHub 中继续学习

本实验在真正的 Kubernetes 中进行

VM 内实际运行着一台 k3s,并有强制执行 NetworkPolicy 的控制器。 因此,添加策略后流量会真正被阻断。 评分器也不会只查看文件, 而是每次都实际尝试连接并确认结果。

首次启动大约需要 2 分钟。

目标

逐层构建采用允许列表方式的网络策略,并在此过程中亲手制造、修复一个 实际工作中最常发生的事故

为什么重要

Kubernetes 的默认行为是全部允许。任何命名空间中的任何 Pod 都能访问 其他所有 Pod。攻击者只要攻陷一个 Web Pod,就能从那里看到数据库。

但策略的工作方式并不直观。如果 Pod 没有应用任何策略,则全部允许; 一旦应用至少一个策略,该 Pod 就会转为允许列表方式。 因此,我们编写的 不是“阻止某项流量的策略”,而是“允许某项流量的策略”。如果不了解这种转换, 添加的策略越多,越容易意外中断其他通信。

最常见的事故出现在第 5 步。默认阻止 egress 的瞬间,DNS 也会一起中断。 因为通往 CoreDNS 的 53 端口同样属于 egress。症状表现为“无法解析名称”, 所以没人会怀疑刚刚添加的网络策略。

步骤

预置内容:shop 命名空间中有 apiapp=api)和 dbapp=db,nginx)Pod,另外还有 ops 命名空间。如不存在,请在第 1 步创建。

  1. 确认在没有任何策略时,从任意 Pod 都能访问 db,并保存到 /root/k8snp/baseline.txt。必须看到响应码 200。
  2. shop 中创建 default-deny 策略。其 podSelector: {}policyTypes: [Ingress]。然后把现在已被阻止的结果记录到 /root/k8snp/deny.txt
  3. 使用 allow-api 策略,只允许 app=api Pod 访问 db。将结果保存到 /root/k8snp/allow-pod.txt。策略应用于接收方app=db)。
  4. 使用 allow-ops 策略允许整个 ops 命名空间,并保存到 /root/k8snp/namespace.txt。通过 kubernetes.io/metadata.name 标签选择命名空间。
  5. shop 中添加 deny-egresspolicyTypes: [Egress],空 selector),观察发生了什么。然后在 /root/k8snp/incident.md 中编写事故报告,必须包含原因是 DNS、53 端口以及 CoreDNS 所在的命名空间。
  6. 使用 allow-dns 策略只开放 DNS,使其恢复。将结果保存到 /root/k8snp/fixed.txt。53 端口必须同时开放 UDP 和 TCP
  7. allow-api 添加端口限制(80),并将结果保存到 /root/k8snp/ports.txt
  8. /root/k8snp/report.md 中写两行:policies=(策略数量)和 dns_fix_policy=allow-dns,并说明从默认允许切换为允许列表的时点。

参考

默认行为是全部允许

确认在没有任何策略时,从任意 Pod 都能访问 db,并保存到 /root/k8snp/baseline.txt。必须看到响应码 200。

创建策略前先测量当前状态。要知道改变了什么,必须先了解改变之前的情况。

只要添加一个策略,方式就会改变

shop 中创建 default-deny 策略。其 podSelector: {}policyTypes: [Ingress]。然后把现在已被阻止的结果记录到 /root/k8snp/deny.txt

podSelector: {} 表示“该命名空间中的所有 Pod”。不提供任何规则,就表示“没有允许的流量”。

将策略应用于接收方

使用 allow-api 策略,只允许 app=api Pod 访问 db。将结果保存到 /root/k8snp/allow-pod.txt。策略应用于接收方app=db)。

策略的 podSelector 选择受保护的 Pod(db),ingress.from 选择允许的来源(api)。如果把方向写反,将不会产生效果。

按命名空间允许访问

使用 allow-ops 策略允许整个 ops 命名空间,并保存到 /root/k8snp/namespace.txt。通过 kubernetes.io/metadata.name 标签选择命名空间。

namespaceSelector 通过 kubernetes.io/metadata.name 标签进行选择。该标签由 Kubernetes 自动添加到所有命名空间。

阻止 egress 后名称无法解析

shop 中添加 deny-egresspolicyTypes: [Egress],空 selector),观察发生了什么。然后在 /root/k8snp/incident.md 中编写事故报告,必须包含原因是 DNS、53 端口以及 CoreDNS 所在的命名空间。

默认阻止 egress 后,通往 CoreDNS 的 53 端口也会一起被阻止。在事故报告中写明原因、端口和 CoreDNS 的位置。

只开放 DNS 使其恢复

使用 allow-dns 策略只开放 DNS,使其恢复。将结果保存到 /root/k8snp/fixed.txt。53 端口必须同时开放 UDP 和 TCP

to 中选择 kube-system 命名空间,并在 ports 中同时加入 UDP 53 和 TCP 53。

只选择来源还只完成了一半

allow-api 添加端口限制(80),并将结果保存到 /root/k8snp/ports.txt

ingress 条目中添加 ports。如果留空,该来源就能访问目标 Pod 的所有端口。

学到了什么

/root/k8snp/report.md 中写两行:policies=(策略数量)和 dns_fix_policy=allow-dns,并说明从默认允许切换为允许列表的时点。

写入 policies=dns_fix_policy= 两行,并说明默认允许何时转为允许列表。