在传统的数据中心安全模型里,防火墙负责把网络切成不同的区域,区域之间严格控制访问。但到了Kubernetes环境,这套思路遇到了挑战:Pod的IP地址是动态分配的,节点也是经常增减的,传统的IP防火墙规则根本跟不上这种变化。于是很多团队干脆放任集群内部网络全通,结果一旦某个应用被注入恶意代码,攻击者就能在集群内横向移动,轻松访问数据库、消息队列甚至etcd。网络分段与微隔离就是针对这个问题提出的解决方案,它把安全边界缩小到单个Pod或者一组工作负载级别,按身份标签而非IP地址来控制流量。

网络分段与微隔离到底是什么关系
这两个词经常被混用,但严格来说它们是两个层面的概念。网络分段是更宏观的做法,指把一个大的网络平面切分成若干个相对独立的子网或安全域,比如按业务线划分命名空间、按环境划分集群、按敏感程度划分网段。分段的目标是控制爆炸半径,让某个区域出问题时不会波及全局。
微隔离则是分段的进一步细化和落地手段,它的粒度可以精确到单个工作负载。在Kubernetes语境下,微隔离主要通过NetworkPolicy实现:用标签选择器挑选出一组Pod,明确声明谁可以访问它们、它们又可以访问谁。与传统的基于IP的五元组规则不同,NetworkPolicy跟随Pod的生命周期自动生效,Pod重建、漂移、扩缩容都不需要人工调整规则,这正是它适合容器环境的关键原因。
两者的关系可以总结为:分段提供架构层面的隔离框架,微隔离提供运行时的流量管控能力。一个常见的落地路径是先用命名空间和CNI的网络插件能力做粗粒度分段,再在命名空间内部用NetworkPolicy做细粒度的微隔离,层层收紧。
NetworkPolicy核心概念与基础配置
NetworkPolicy是Kubernetes内置的API资源,但要注意,它只是规则的声明标准,真正执行靠的是CNI插件。Calico、Cilium、Weave等主流插件都支持,而Flannel原生不支持NetworkPolicy,如果集群用的是Flannel又需要微隔离,通常要额外部署Calico作为网络策略层,或者直接换掉CNI。这一点在做方案选型时必须提前确认,否则写了一堆策略却发现完全不生效。
NetworkPolicy有几个关键特性需要理解。第一,它是白名单模型:一旦某个Pod被任何一条NetworkPolicy选中,那么所有未在规则中明确允许的流量都会被拒绝,这和防火墙默认放行的直觉相反。第二,策略之间是叠加关系,多条策略对同一个Pod生效时,只要任意一条允许了某流量,该流量就是通的。第三,策略是定向的,需要分别声明ingress和egress规则。
先看一个默认拒绝所有入站流量的基础策略,这是微隔离的第一步:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 空选择器表示选中命名空间内所有Pod
policyTypes:
- Ingress
# 没有写ingress规则,意味着全部拒绝入站
这条策略生效后,production命名空间内的所有Pod都无法被任何来源访问,包括集群内部的DNS解析请求响应也会受影响(DNS是Pod主动发起的出站查询加返回流量,返回流量属于egress策略建立的连接,一般不受ingress拒绝影响,但如果同时做了egress默认拒绝就必须放行DNS)。所以实践中常见的做法是先只做ingress默认拒绝,观察业务后再逐步补白名单。
接下来针对具体应用放行流量,比如只允许前端调用后端API:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
env: production
podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
这里同时使用了namespaceSelector和podSelector,注意写在同一个from列表项里表示并且的关系,即必须同时满足两个条件。如果写成两个列表项则是或者的关系,这是配置时最容易踩的坑之一。
多租户与命名空间级别的分段实践
在多租户集群里,租户之间的隔离是最基本的要求。推荐的分层做法是:每个租户独立命名空间,命名空间打上租户标签,然后给每个命名空间应用默认拒绝策略,最后再按需放行跨租户的必要调用。配套地,还应该在RBAC层面限制租户只能操作自己的命名空间,配合ResourceQuota和LimitRange做资源隔离,网络层面配合NetworkPolicy,形成立体的分段体系。
下面是一个租户命名空间默认互相隔离、只允许访问公共服务的组合策略示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-isolation
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-a
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-a
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: shared-services
这条策略实现了三件事:租户内部自由通信、DNS查询放行、跨租户只允许访问共享服务命名空间。其中kubernetes.io/metadata.name标签是Kubernetes自动打在命名空间上的,从1.21版本开始稳定可用,不需要手动维护标签,非常适合做这类基于命名空间名字的选择。对于egress控制,如果业务需要访问集群外的外部API,还需要额外放行IP段块,比如用ipBlock指定外部服务的网段。
策略不生效的排查思路与进阶工具
NetworkPolicy配置完成后最头疼的问题就是不知道为什么还不通。排查可以按这个顺序来:首先确认CNI插件是否支持并正确部署了策略组件,比如Calico需要calico-node和控制器正常运行;其次检查Pod是否真的被podSelector选中,可以用kubectl get networkpolicy -o yaml检查策略定义;再次确认对端Pod是否也被自己的策略锁住了,很多不通的情况其实是目标端有默认拒绝策略而调用方规则没写对。
抓包和连通性测试工具能大幅提升排查效率。Calico提供的calicoctl工具可以查看策略在节点上的实际下发状态,Cilium有强大的hubble observe命令实时观察被拒绝的连接及拒绝原因。也可以用一个带网络工具的调试Pod做连通性验证:
# 启动一个调试Pod并进入
kubectl run nettool --image=nicolaka/netshoot -n production --rm -it -- bash
# 在Pod内测试到目标的连通性
curl -v http://api-server.production.svc.cluster.local:8080/healthz
# 查看目标Pod被哪些策略选中
kubectl get pod api-server-7d9c -n production -o jsonpath='{.metadata.labels}'
在策略治理层面,建议把所有NetworkPolicy纳入GitOps流程管理,通过CI校验策略的合法性和重叠情况,避免有人在线上手改导致规则漂移。对于规模较大的集群,手写YAML容易出错,可以考虑Cilium的CiliumNetworkPolicy扩展资源,它支持DNS规则匹配和FQDN过滤,能直接按域名放行外部访问,比原生ipBlock灵活得多;商业方案如Tigera的零信任工作流还能根据真实流量自动生成最小化策略,先以观察模式运行收集流量画像,再一键转成白名单规则,落地成本低很多。
最后要强调,微隔离不是一次性工程。应用迭代会带来新的调用关系,策略需要持续维护。比较稳妥的节奏是:新命名空间上线即应用默认拒绝,观察期内通过日志或hubble收集真实流量,随后固化成显式规则,并把策略文件与应用代码放在同一个仓库里随版本演进。这样网络分段与微隔离才能真正成为集群安全的常态化防线,而不是一堵随时会被绕开的墙。
网络分段微隔离Kubernetes网络策略修改时间:2026-09-05 19:14:56