阻断DNS的防火墙与扩大访问范围的允许规则
目标
在真正的 Cilium 环境中区分策略方向、namespace 选择器、DNS 依赖、允许规则的并集以及显式拒绝。
为什么这很重要
安全配置变更后出现 timeout 时,如果立刻重启服务器,可能会抹掉问题原因。请通过对比 IP 对照请求和名称请求来定位依赖关系,并同时检查正常请求与被拒绝的请求。要验证的是实际访问范围,而不是策略数量。对照对象会一直保留到最后,因此最终评分也会重新检查当前状态。
只使用 VM 内的个人 k3s。新环境使用 Cilium 1.20.1 和 k3s 1.35.8+k3s1,启动可能需要数分钟。仅完成步骤的准备工作并不等于解决了当前步骤。策略传播完成前,观测结果可能会暂时不同,请在观测后再次评分。会话结束时工作文件会消失,如有需要请先导出。
步骤
- 使用工具的 inventory 命令,将 11 个 Pod 的 namespace、name、uid、ip、identity 保存到 /root/cca-policy/inventory.json。cca-blue/client 和 cca-red/client 的 role 标签相同,但 namespace 标签和 identity 不同。请读取并比较输出中的实际值。如果 Pod 已被重新创建,也必须更新记录。
- 在 /root/cca-policy/native.yaml 中编写并应用 cca-blue 的 native-only NetworkPolicy。podSelector.matchLabels 为 target=native,policyTypes 为 [Ingress];唯一一条 ingress 中的唯一 from 只设置 podSelector.matchLabels.role=client。对于 native,只有蓝方 client 应返回 200,蓝方 stranger 和红方 client 应 timeout。无策略的 baseline 中三者都应返回 200。
- 在 /root/cca-policy/ingress.yaml 中编写并应用 cca-blue 的 blue-ingress CiliumNetworkPolicy。endpointSelector.matchLabels.target=ingress;唯一一条 ingress 中的唯一 fromEndpoints 只设置 matchLabels.role=client。只有蓝方 client 应返回 200,stranger 和红方 client 应 timeout。不要删除 native 策略。
- 在 /root/cca-policy/dns-blocked.yaml 中编写并应用 cca-blue 的 dns-blocked CNP。endpointSelector.matchLabels.client-mode=blocked。在唯一一条 egress 中,只设置 toEndpoints.matchLabels={role: api, target: egress} 和 toPorts.ports=[{port: "8080", protocol: TCP}]。不要添加 DNS 允许规则。dns-blocked 客户端通过 egress 服务器 IP 发出的请求应返回 200,通过 Service 名称发出的请求应 timeout。
- 在 /root/cca-policy/dns-open.yaml 中编写并应用 cca-blue 的 dns-open CNP。选择 client-mode=open。第一条 egress 项与上一步保持一致,使用同一个 API 目标和 TCP 8080。第二条的 toEndpoints.matchLabels 为 k8s:io.kubernetes.pod.namespace=kube-system 和 k8s:k8s-app=kube-dns,toPorts.ports 包含字符串 53 的 UDP 和 TCP 两项。dns-open 通过 IP 和名称访问都应返回 200。保留 dns-blocked 的限制。
- 保留初始 blue-union CNP。在 /root/cca-policy/union.yaml 中编写并应用 cca-blue 的 red-union NetworkPolicy。选择 target=union,并设置 policyTypes=[Ingress]。在唯一一条 ingress 的唯一 from 中,同时设置 namespaceSelector.matchLabels.team=cca-red 和 podSelector.matchLabels.role=client。蓝方 client 和红方 client 应返回 200,stranger 应 timeout。
- 保留初始 blue-deny CNP 和 red-deny NetworkPolicy。在 /root/cca-policy/deny.yaml 中编写并应用 cca-blue 的 deny-red CNP。选择 target=deny;在唯一一条 ingressDeny 的唯一 fromEndpoints 中,同时设置 matchLabels 的 k8s:io.kubernetes.pod.namespace=cca-red 和 k8s:role=client。蓝方 client 应返回 200,stranger 和红方 client 应 timeout。
- 将工具的 report 命令结果保存到 /root/cca-policy/report.json。红方 client 向 baseline、union、deny 发出的三个请求应分别为 200、200、timeout。请在输出中对照当前 Pod 的 UID/IP/identity、策略 UID/spec 哈希、请求 source port,以及同一节点和时间的 Hubble FORWARDED/DROPPED 流量。如果修改了策略或 Pod,请重新生成报告。最终完整评分时,前面各步骤也必须全部保持有效。
参考
- 观测工具:python3 /opt/fixtures/cca-policy/runtime.py observe 案例名。案例名包括 baseline、native、ingress、dns-blocked、dns-open、union、deny。
- 身份:kubectl get cep -A。策略:kubectl get cnp,netpol -A -o yaml。
- Hubble:hubble observe --server 127.0.0.1:4245 --namespace cca-blue --last 50。
- 作业文件可以保存为 JSON 或单个 YAML 对象。除了值之外,也要检查列表的分组结构。
- HTTP 000 不是服务器响应码。未收到响应时,也要检查实际退出码和流量。
记录两个团队的实际 Pod 和安全身份
使用工具的 inventory 命令,将 11 个 Pod 的 namespace、name、uid、ip、identity 保存到 /root/cca-policy/inventory.json。cca-blue/client 和 cca-red/client 的 role 标签相同,但 namespace 标签和 identity 不同。请读取并比较输出中的实际值。如果 Pod 已被重新创建,也必须更新记录。
名称相同并不意味着是同一个端点。请同时查看 UID 和安全标签集合。
标准 NetworkPolicy 也通过标签进行选择
在 /root/cca-policy/native.yaml 中编写并应用 cca-blue 的 native-only NetworkPolicy。podSelector.matchLabels 为 target=native,policyTypes 为 [Ingress];唯一一条 ingress 中的唯一 from 只设置 podSelector.matchLabels.role=client。对于 native,只有蓝方 client 应返回 200,蓝方 stranger 和红方 client 应 timeout。无策略的 baseline 中三者都应返回 200。
不要把策略的目标选择器和入站对端选择器颠倒理解。请确认 peer 未设置 namespaceSelector 时的作用范围。
在 CNP 中也确认两个团队的边界
在 /root/cca-policy/ingress.yaml 中编写并应用 cca-blue 的 blue-ingress CiliumNetworkPolicy。endpointSelector.matchLabels.target=ingress;唯一一条 ingress 中的唯一 fromEndpoints 只设置 matchLabels.role=client。只有蓝方 client 应返回 200,stranger 和红方 client 应 timeout。不要删除 native 策略。
并不会仅仅因为名称是 CNP,就自动连接所有 namespace。也要保留另一个团队中具有相同 role 的对象作为对照请求来源。
复现 API 正常而只有名称解析被阻断的故障
在 /root/cca-policy/dns-blocked.yaml 中编写并应用 cca-blue 的 dns-blocked CNP。endpointSelector.matchLabels.client-mode=blocked。在唯一一条 egress 中,只设置 toEndpoints.matchLabels={role: api, target: egress} 和 toPorts.ports=[{port: "8080", protocol: TCP}]。不要添加 DNS 允许规则。dns-blocked 客户端通过 egress 服务器 IP 发出的请求应返回 200,通过 Service 名称发出的请求应 timeout。
服务器 egress Pod 在端口 8080 上充当对照组。如果缺少 DNS 时连直接使用 IP 的路径也被阻止,还需要检查选择器或方向。
在另一个对照客户端上仅添加 DNS 以恢复访问
在 /root/cca-policy/dns-open.yaml 中编写并应用 cca-blue 的 dns-open CNP。选择 client-mode=open。第一条 egress 项与上一步保持一致,使用同一个 API 目标和 TCP 8080。第二条的 toEndpoints.matchLabels 为 k8s:io.kubernetes.pod.namespace=kube-system 和 k8s:k8s-app=kube-dns,toPorts.ports 包含字符串 53 的 UDP 和 TCP 两项。dns-open 通过 IP 和名称访问都应返回 200。保留 dns-blocked 的限制。
不要开放所有外部连接,只允许名称解析端点和相应端口。请检查恢复用客户端的选择器。
新增允许规则后,另一个团队也获得访问权限
保留初始 blue-union CNP。在 /root/cca-policy/union.yaml 中编写并应用 cca-blue 的 red-union NetworkPolicy。选择 target=union,并设置 policyTypes=[Ingress]。在唯一一条 ingress 的唯一 from 中,同时设置 namespaceSelector.matchLabels.team=cca-red 和 podSelector.matchLabels.role=client。蓝方 client 和红方 client 应返回 200,stranger 应 timeout。
两个条件应放在同一个 peer 中,但已有 CNP 与新 NP 的允许规则会作为不同路径合并。
让显式拒绝优先于允许策略
保留初始 blue-deny CNP 和 red-deny NetworkPolicy。在 /root/cca-policy/deny.yaml 中编写并应用 cca-blue 的 deny-red CNP。选择 target=deny;在唯一一条 ingressDeny 的唯一 fromEndpoints 中,同时设置 matchLabels 的 k8s:io.kubernetes.pod.namespace=cca-red 和 k8s:role=client。蓝方 client 应返回 200,stranger 和红方 client 应 timeout。
如果通过删除允许策略来阻止红方团队,就无法再比较显式 deny 的优先级。请保留最初的两条允许规则。
使用当前策略和同一请求的流量编写故障报告
将工具的 report 命令结果保存到 /root/cca-policy/report.json。红方 client 向 baseline、union、deny 发出的三个请求应分别为 200、200、timeout。请在输出中对照当前 Pod 的 UID/IP/identity、策略 UID/spec 哈希、请求 source port,以及同一节点和时间的 Hubble FORWARDED/DROPPED 流量。如果修改了策略或 Pod,请重新生成报告。最终完整评分时,前面各步骤也必须全部保持有效。
不要随意附上一行 DROPPED。请匹配 TCP 源端口和两端的端点,并区分 HTTP 结果与数据包转发观测。