网络策略
网络策略
NetworkPolicy 是 Kubernetes 的网络安全机制,用于控制 Pod 之间的流量。
核心概念
┌─────────────────────────────────────────┐
│ NetworkPolicy │
├─────────────────────────────────────────┤
│ podSelector: 选择要应用策略的 Pod │
│ policyTypes: [Ingress, Egress] │
│ ingress: 入站规则 │
│ egress: 出站规则 │
└─────────────────────────────────────────┘
关键点:
- NetworkPolicy 是白名单机制
- 需要 CNI 插件支持(Calico、Cilium、Weave)
- 多个策略叠加(OR 逻辑)
默认拒绝策略
拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 选择所有 Pod
policyTypes:
- Ingress
拒绝所有出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
拒绝所有流量(入站+出站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
允许特定流量
允许来自特定 Pod 的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
允许来自特定 Namespace 的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
允许特定 IP 段的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ip-range
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24 # 排除特定子网
ports:
- protocol: TCP
port: 443
出站流量控制
允许访问特定服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-database
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
# 允许访问数据库
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
# 允许 DNS 查询(必需!)
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
允许访问外部 API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-api
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Egress
egress:
# 允许访问外部 API
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8 # 内网
- 172.16.0.0/12 # 内网
- 192.168.0.0/16 # 内网
ports:
- protocol: TCP
port: 443
# 允许 DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
跨命名空间访问
场景:允许 Ingress 访问应用
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
podSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
ports:
- protocol: TCP
port: 8080
场景:允许 Prometheus 采集指标
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-prometheus-scraping
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 8080
# 假设 /metrics 在 8080 端口
完整的三层应用网络策略
Frontend 策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: frontend
policyTypes:
- Ingress
- Egress
ingress:
# 允许来自 Ingress Controller 的流量
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
# 允许访问 Backend
- to:
- podSelector:
matchLabels:
tier: backend
ports:
- protocol: TCP
port: 8080
# 允许 DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
Backend 策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes:
- Ingress
- Egress
ingress:
# 只允许来自 Frontend 的流量
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- protocol: TCP
port: 8080
# 允许 Prometheus 监控
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 8080
egress:
# 允许访问 Database
- to:
- podSelector:
matchLabels:
tier: database
ports:
- protocol: TCP
port: 5432
# 允许访问 Redis
- to:
- podSelector:
matchLabels:
tier: cache
ports:
- protocol: TCP
port: 6379
# 允许 DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
Database 策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
- Egress
ingress:
# 只允许来自 Backend 的流量
- from:
- podSelector:
matchLabels:
tier: backend
ports:
- protocol: TCP
port: 5432
egress:
# 数据库通常不需要出站流量
# 但可能需要访问外部备份服务
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
# DNS(如果需要)
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
高级用法
使用多个选择器(AND 逻辑)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-specific-namespace-and-pod
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- from:
# 必须同时满足两个条件
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 8080
使用多个规则(OR 逻辑)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-multiple-sources
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
# 规则1:来自 frontend
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
# 规则2:来自 admin namespace
- from:
- namespaceSelector:
matchLabels:
name: admin
ports:
- protocol: TCP
port: 8080
调试 NetworkPolicy
检查策略是否生效
# 查看 NetworkPolicy
kubectl get networkpolicy -n production
# 查看详细信息
kubectl describe networkpolicy <policy-name> -n production
# 检查 Pod 标签
kubectl get pods --show-labels -n production
测试连通性
# 从 Pod A 测试访问 Pod B
kubectl exec -it pod-a -n production -- curl http://pod-b-ip:8080
# 使用 netshoot 调试
kubectl run netshoot --rm -it --image=nicolaka/netshoot -n production -- /bin/bash
# 在 netshoot 中测试
curl http://backend-service:8080
nc -zv backend-service 8080
常见问题
问题 1:策略不生效
# 检查 CNI 插件是否支持 NetworkPolicy
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave'
# 如果使用 Flannel,需要额外配置
# Flannel 默认不支持 NetworkPolicy
问题 2:DNS 无法解析
# 确保允许 DNS 流量
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53 # 某些情况下也需要 TCP
问题 3:忘记允许内部服务发现
# 允许访问 Kubernetes API(Service 发现)
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
NetworkPolicy 生成器
使用工具自动生成策略:
# 使用 kubepug 生成建议
kubectl run policy-advisor --rm -it --image=quay.io/fairwinds/polaris:latest -- sh
# 使用 Cilium Editor
# https://editor.cilium.io/
# 使用 Network Policy Editor
# https://networkpolicy.io/
最佳实践
1. 默认拒绝 + 白名单
# 第一步:默认拒绝所有
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 第二步:逐个开放必要的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-specific-traffic
spec:
podSelector:
matchLabels:
app: myapp
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
2. 分层隔离
┌─────────────────┐
│ Frontend │ ← 允许来自 Ingress
└────────┬────────┘
│
┌────────▼────────┐
│ Backend │ ← 只允许来自 Frontend
└────────┬────────┘
│
┌────────▼────────┐
│ Database │ ← 只允许来自 Backend
└─────────────────┘
3. 测试驱动
# 1. 先部署应用(不加 NetworkPolicy)
# 2. 确认应用正常工作
# 3. 添加默认拒绝策略
# 4. 测试(预期失败)
# 5. 逐步添加允许规则
# 6. 每次添加后测试
4. 文档化
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
annotations:
description: "Backend 层网络策略"
purpose: "只允许来自 Frontend 的流量访问 Backend"
owner: "platform-team"
reviewed: "2024-01-08"
小结
本节介绍了网络策略:
✅ 默认拒绝:默认拒绝所有流量,白名单机制
✅ 入站控制:podSelector、namespaceSelector、ipBlock
✅ 出站控制:DNS、数据库、外部 API
✅ 跨命名空间:Ingress、Prometheus 访问
✅ 三层架构:Frontend、Backend、Database 完整策略
✅ 调试方法:测试连通性、常见问题
✅ 最佳实践:分层隔离、测试驱动
下一节:Pod 和镜像安全。