4. Calico网络策略实战:创建租户A与租户B的隔离策略
在多租户Kubernetes集群中,网络隔离是保障租户安全的第一道防线。Calico作为CNI插件,通过其强大的网络策略引擎,能够实现基于Kubernetes原生NetworkPolicy的细粒度隔离,同时支持更高级的全局网络策略(GlobalNetworkPolicy)。本节将实战演示如何为租户A和租户B创建隔离策略,确保租户之间的流量完全隔离,而同一租户内的Pod可以正常通信。
4.1 隔离模型设计
在开始创建策略之前,我们需要明确隔离的边界。本实战采用“默认拒绝,按需放行”的原则,为每个租户的命名空间设置独立的网络策略。
| 租户 | 命名空间 | 隔离要求 | 策略类型 |
|---|---|---|---|
| 租户A | tenant-a |
禁止所有入站流量(除同命名空间外);允许出站到集群DNS | 默认拒绝入站 + 允许同命名空间 |
| 租户B | tenant-b |
禁止所有入站流量(除同命名空间外);允许出站到集群DNS | 默认拒绝入站 + 允许同命名空间 |
| 跨租户 | — | 租户A与租户B之间完全隔离,禁止任何流量互通 | 由命名空间级别的默认拒绝策略实现 |
设计要点: 隔离策略的核心在于“默认拒绝”策略的部署。一旦为命名空间应用了拒绝所有入站流量的策略,任何未显式允许的入站连接都会被Calico的iptables规则丢弃。这比依赖应用层认证更底层、更安全。
4.2 创建租户A的隔离策略
首先,为租户A的命名空间 tenant-a 创建网络策略。该策略包含两部分:拒绝所有入站流量(默认行为)和允许同命名空间内的所有流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
ingress: []
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-a
应用策略后,验证租户A内的Pod是否可以互相通信,以及租户B的Pod是否无法访问租户A。
# 在租户A的Pod中测试同命名空间通信
kubectl exec -n tenant-a deploy/app-a-1 -- curl -s --connect-timeout 3 http://app-a-2.tenant-a.svc.cluster.local:8080
# 在租户B的Pod中测试跨租户通信(预期失败)
kubectl exec -n tenant-b deploy/app-b-1 -- curl -s --connect-timeout 3 http://app-a-1.tenant-a.svc.cluster.local:8080
验证结果: 第一个命令应返回HTTP响应(如200 OK),第二个命令应超时或返回连接拒绝。这表明入站隔离策略已生效。
4.3 创建租户B的隔离策略
租户B的策略与租户A完全对称,确保两个租户的隔离策略一致,避免出现策略漏洞。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: tenant-b
spec:
podSelector: {}
policyTypes:
- Ingress
ingress: []
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: tenant-b
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-b
同样,验证租户B内部的连通性以及跨租户的隔离性。
4.4 隔离策略的流量拓扑
下图展示了策略生效后的网络流量拓扑。租户A和租户B各自形成一个独立的通信域,所有跨域流量被Calico的eBPF或iptables规则在节点层面阻断。
4.5 策略生效的底层机制
Calico网络策略的生效依赖于其数据平面组件(如Felix)将Kubernetes资源转换为节点上的iptables或eBPF规则。理解这一机制有助于排查策略不生效的问题。
- Felix代理: 运行在每个Kubernetes节点上,监听API Server中的NetworkPolicy变化。
- 规则编排: Felix根据策略中的
podSelector、namespaceSelector和ipBlock生成对应的iptables链。 - 数据包处理: 当Pod发送或接收数据包时,内核根据iptables规则进行匹配。匹配到“拒绝”规则则丢弃,匹配到“允许”规则则放行。
- 性能优化: 在支持eBPF的内核上,Calico可以使用eBPF模式,绕过iptables,实现更高的吞吐量和更低的延迟。
常见陷阱: 如果策略中使用了
ipBlock 来允许特定外部IP,请确保该IP不在Pod的子网范围内,否则可能导致策略冲突。另外,policyTypes 字段必须显式声明 Ingress 或 Egress,否则策略可能不会按预期生效。
4.6 策略验证与回滚准备
在生产窗口内进行回滚验证前,必须确认当前策略的正确性。建议执行以下验证步骤:
- 连通性测试: 使用
kubectl exec或部署专用的测试Pod,验证同命名空间和跨命名空间的连通性是否符合预期。 - 策略审计: 使用
calicoctl get networkpolicy -n tenant-a -o yaml检查策略的YAML定义是否与预期一致。 - 日志检查: 查看Calico Felix的日志(
kubectl logs -n calico-system daemonset/calico-node),确认没有策略同步错误。 - 备份策略: 在回滚前,使用
kubectl get networkpolicy -n tenant-a -o yaml > tenant-a-policy-backup.yaml备份当前策略,以便快速恢复。
回滚准备要点: 由于网络策略是声明式资源,回滚操作本质上是重新应用旧的策略YAML。因此,确保备份文件完整且与当前集群版本兼容至关重要。建议将备份文件存储在版本控制系统中,并附带时间戳和变更说明。