一句话总结
K8s 默认所有 Pod 之间网络全通, 任何 Pod 可以访问任何其他 Pod.
NetworkPolicy 实现"默认拒绝 + 白名单放行", 限制攻击者在集群内的横向移动能力.
配合 mTLS 实现零信任: 不信任任何网络位置, 每个请求都需要身份验证.
K8s 默认网络: 全平面互通
K8s 网络模型的设计原则: 每个 Pod 有独立 IP, 所有 Pod 之间直接可达(无 NAT). 这对开发者很方便, 但对安全是灾难:
|
默认网络 = 开放式办公室, 任何人都能走到任何工位.
NetworkPolicy = 门禁系统, 每个区域需要刷对应的门禁卡.
零信任 = 不仅要刷卡, 进门后每次操作还要验证身份证(mTLS).
NetworkPolicy 基础
基本结构
|
关键逻辑
- 没有 NetworkPolicy → 全通(默认允许)
- 一旦有 NetworkPolicy 选中了 Pod → 该方向默认拒绝, 只有规则里列出的才放行
- 多条 NetworkPolicy 是累加关系(OR), 不是覆盖
- 如果只写了 Ingress 规则没写 Egress → Egress 仍然全通(反之亦然)
必须先确认 CNI 支持 NetworkPolicy
NetworkPolicy 只是 K8s API 对象, 实际执行靠 CNI 插件. 并非所有 CNI 都支持: Flannel 不支持, Calico / Cilium / Weave 支持.
如果集群用 Flannel, 写了 NetworkPolicy 不会报错, 但也不会生效, 这是最危险的"安全错觉".
默认拒绝策略
安全的第一步: 先全部拒绝, 再按需放行.
|
默认拒绝 Egress 会断 DNS
Pod 连 DNS 查询都做不了, 服务发现直接瘫痪. 部署 default-deny-egress 后必须立刻添加允许 DNS 出站的规则(如上面 backend-policy 中的 DNS egress 规则).
建议先在非生产环境验证.
Namespace 隔离
典型的微服务集群有多个 Namespace: production / staging / monitoring / istio-system. 不同 Namespace 之间应该限制互访.
|
常见网络策略模式
| 场景 | 策略 |
|---|---|
| 数据库只接受后端访问 | Ingress: from podSelector app=backend, port 5432 |
| 前端只能访问后端和外部 CDN | Egress: to podSelector app=backend + to ipBlock CDN 地址段 |
| 禁止 Pod 访问云 Metadata API | Egress: deny to ipBlock 169.254.169.254/32 |
| 允许 Ingress Controller 访问所有后端 | Ingress: from namespaceSelector ingress-nginx |
务必阻止访问云 Metadata API
AWS/GCP/Azure 的 Instance Metadata API(169.254.169.254)包含 IAM 临时凭证. 如果 Pod 被攻破且未限制出站 → 攻击者直接获取云平台权限, 这是真实攻击中最常见的提权路径.
|
零信任网络
NetworkPolicy 基于网络层(IP/Port)控制, 但攻击者可能冒充 Pod IP. 零信任要求每个请求都验证身份, 不信任网络位置.
mTLS(Service Mesh)
在微服务 08 篇中讲过, Istio 自动为每个 Pod 签发证书, 服务间通信全部 mTLS 加密:
- 通信加密(防窃听)
- 双向身份认证(我知道对方是谁, 对方知道我是谁)
- 配合 AuthorizationPolicy 实现身份级别的访问控制
网络安全分层
|
NetworkPolicy vs Service Mesh AuthorizationPolicy
两者不冲突, 而是互补.
NetworkPolicy 是网络层防火墙, 即使没有 Service Mesh 也能用, 但粒度只到 IP/Port.
AuthorizationPolicy 是应用层策略, 基于服务身份(ServiceAccount)和 HTTP 属性(路径/方法), 但需要 Mesh.
最安全的做法: 两者都配置.
快速回顾
- K8s 默认全通: 任何 Pod 可以访问任何 Pod, 必须主动限制
- 默认拒绝 + 白名单: 先 default-deny, 再按需放行, 是安全基本原则
- CNI 支持: 确认集群 CNI 支持 NetworkPolicy(Calico/Cilium), Flannel 不支持
- DNS 出站: 默认拒绝 Egress 后必须单独放行 DNS(53/UDP)
- 阻止 Metadata API: 169.254.169.254 是云平台最高风险的提权路径
- 零信任: NetworkPolicy + mTLS + AuthorizationPolicy 三层叠加
动手练习
- 验证默认全通: 在测试 Namespace 部署 3 个 Pod(frontend/backend/database), 验证默认可以互相 curl
- 默认拒绝策略: 部署 default-deny-ingress + default-deny-egress, 验证所有通信断开
- 白名单放行: 逐步添加 NetworkPolicy 只允许 frontend → backend → database 的链路, 验证前端无法直连数据库
- 阻止 Metadata API: 添加阻止 169.254.169.254 的 Egress 规则, 从 Pod 内 curl metadata API 验证被拒绝