K8s NetworkPolicy 落地:从全通模式到最小网络权限的迁移
·
K8s NetworkPolicy 落地:从全通模式到最小网络权限的迁移
一、集群里每个 Pod 都能访问任何其他 Pod,你的数据库也是一样
默认情况下,K8s 集群内的网络是全通模式——任何 Pod 可以访问任何其他 Pod 的任何端口。安全团队关心的是:如果攻击者拿到了一个前端 Pod 的 shell,他能直接连上你的数据库 Pod。
NetworkPolicy 的价值在于将默认的"全通"改为"默认拒绝 + 白名单放行"。但迁移过程充满挑战:你不可能在一天之内梳理完所有服务间的调用关系。
合理策略是渐进式收紧:先观察 → 再标记 → 最后阻断。
flowchart TD
A[阶段1: 流量观察] --> B[阶段2: 策略设计]
B --> C[阶段3: 审计模式]
C --> D[阶段4: 逐步收紧]
A --> A1[部署网络流量监控<br/>Hubble / Cilium Monitor]
A1 --> A2[收集 1-2 周流量数据]
A2 --> A3[生成服务间调用图]
B --> B1[按 namespace 划分信任域]
B1 --> B2[定义 app 级别策略]
B2 --> B3[review 异常调用]
C --> C1[NetworkPolicy + 日志记录]
C1 --> C2[不阻断, 只审计]
C2 --> C3[验证无误]
D --> D1[先收紧核心 namespace<br/>如 production/database]
D1 --> D2[监控异常]
D2 --> D3[逐步扩展到全集群]
二、NetworkPolicy 的核心模型
NetworkPolicy 基于三层选择器:podSelector(谁应用)→ 流量方向(ingress/egress)→ 匹配规则(哪些来源/目标/端口)。
关键概念:
- 空 podSelector:匹配 namespace 内所有 Pod
- namespaceSelector:跨 namespace 的选择
- ipBlock:CIDR 范围的 IP 规则(用于集群外流量)
- 不设置 egress 规则 = 允许所有出站流量
三、生产级 NetworkPolicy 配置
# 第一步:默认拒绝所有入站流量
# 这是安全基线——先封闭再打开,而不是先开放再封堵
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 空选择器 = 本 namespace 所有 Pod
policyTypes:
- Ingress
# 没有 ingress 规则 = 拒绝所有入站
---
# 第二步:允许同 namespace 内服务间通信
# 大多数微服务需要同 namespace 内互相调用
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
ingress:
- from:
- podSelector: {} # 同 namespace 所有 Pod
policyTypes:
- Ingress
---
# 第三步:允许 monitoring namespace 采集指标
# 可观测性是生产必需的——Prometheus 必须能 scrape
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
namespace: production
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- port: 9090 # metrics port
protocol: TCP
policyTypes:
- Ingress
---
# 第四步:仅允许特定服务访问数据库
# 最小权限原则的落地——只有 order-service 能连接 PostgreSQL
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-access-control
namespace: production
spec:
podSelector:
matchLabels:
app: postgresql
ingress:
# 规则1: order-service 读写
- from:
- podSelector:
matchLabels:
app: order-service
ports:
- port: 5432
protocol: TCP
# 规则2: 备份 Job(在 backup namespace)
- from:
- namespaceSelector:
matchLabels:
name: backup
podSelector:
matchLabels:
job-type: db-backup
ports:
- port: 5432
protocol: TCP
policyTypes:
- Ingress
---
# 第五步:出站流量控制
# 限制 Pod 只能访问必要的外部服务
# 防止被攻破的 Pod 成为跳板机
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-control
namespace: production
spec:
podSelector:
matchLabels:
app: order-service
egress:
# 允许 DNS 查询——这是几乎所有服务的基础依赖
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- port: 53
protocol: UDP
# 允许访问 PostgreSQL
- to:
- podSelector:
matchLabels:
app: postgresql
ports:
- port: 5432
protocol: TCP
# 允许访问外部支付 API(通过 CIDR)
- to:
- ipBlock:
cidr: 203.0.113.0/24 # 支付服务商的 IP 段
except:
- 203.0.113.5/32 # 排除已知的测试 IP
ports:
- port: 443
protocol: TCP
policyTypes:
- Egress
四、渐进式迁移策略
第一步:流量可视化(1-2 周)
先用 Cilium Hubble 或 Calico 的流量日志收集所有的网络流。不要直接写策略——你写出来的策略大概率漏掉几个关键的调用。
# 用 Cilium 监控流量
cilium monitor --type drop -v
# 或导出 Hubble Flow
hubble observe --namespace production -o json > flows.json
第二步:审计模式(1 周)
创建 NetworkPolicy 但不做 deny-all。先加允许规则,观察是不是有流量被错误拦截。
第三步:核心 namespace 收紧(逐步)
从数据库、消息队列等基础设施 namespace 开始收紧。这些 namespace 的调用关系相对明确。稳定后再扩展到业务 namespace。
第四步:全集群基线
最终状态:每个 namespace 都有 default-deny-ingress + 精确的允许规则。
迁移检查清单
- 是否所有监控/日志采集器的流量都被允许?
- ingress controller 到后端服务的流量是否畅通?
- DNS 解析(UDP 53)是否被允许?
- K8s 的 liveness/readiness probe 是否会触发网络策略?
- StatefulSet 的 Pod 间通信是否需要特殊规则?
五、总结
NetworkPolicy 落地的核心难点不是写 YAML,是在不破坏现有服务的前提下逐步收紧。从观察流量开始、在审计模式下验证、按 namespace 优先级逐步收紧——这个策略保证每一步都可逆、每个变更都有监控覆盖。全通模式是火灾隐患,最小权限是消防规范。迁移过程就是你从前者走向后者的道路。
更多推荐



所有评论(0)