☰
微隔离+服务网格:给云原生东西向流量装上零信任闸机
2026/10/10 7:47:58 网站建设 项目流程

云原生内网横向渗透?微隔离+身份服务网格,东西向流量先过“零信任闸机”

上周帮某客户做了一次云原生环境的安全现状梳理,结果不出意料:入口防护做得很扎实,WAF、网关、认证全都有,但东西向流量基本是裸奔状态。几个业务命名空间之间可以互相直连,Nginx Pod 可以直接访问数据库 Pod,某个被拿下的边缘服务平扫一圈,几乎所有内网 IP 都能通。这种局面在云原生架构里其实是常态,因为 Kubernetes 默认的扁平网络模型天然就不信任边界,Pod IP 随手换、应用实例随意扩缩容,靠 IP 和网段做隔离的策略在动态调度面前基本失效。

微隔离和身份服务网格就是解决这个问题的组合拳。微隔离负责按身份维度收拢东西向访问面,服务网格负责在应用层建立基于身份的双向认证和细粒度授权,两者叠起来等于给东西向流量装了“零信任闸机”。这篇文章我把自己在落地过程中的思路、架构设计和踩过的坑完整理一遍,包括身份怎么编排、策略怎么下发、网关怎么设计,以及那些文档里不会写的隐藏问题。如果你正准备给云原生环境做内网安全加固,这篇可以直接照着参考。

1. 为什么传统内网防线在云原生环境里会失效

先搞清楚一个核心问题:云原生资源共享模型怎么改变了安全边界。传统架构里,内网等于安全域,机房防火墙挡住外网,内网默认互信,只要进了内网就等于通过了大半的边界防护。但在 Kubernetes 这种动态基础设施上,这套假设完全不成立。

1.1 扁平网络模型与动态调度带来的横向渗透面

Kubernetes 默认的容器网络模型是扁平化的,所有 Pod 共享一个大二层网络,Pod 与 Pod 之间默认全互联。也就是说,只要你的应用跑在集群里,任意两个 Pod 之间都能通过网络直连,不管它们在后端逻辑上有没有调用关系。

这带来的问题是:一旦攻击者突破了某个无状态前端服务——这太常见了,比如某个反序列化漏洞、某个注入点,甚至某次供应链投毒——他就拥有了一个集群内 Pod 的代码执行权限。然后攻击者开始横向移动:扫描网段、找开放端口、试弱口令、抓取其他服务的凭据。在扁平网络下,这整个过程几乎没有阻力。

更要命的是动态调度。传统环境里至少 IP 是相对固定的,你可以在防火墙上针对某个 IP 段做限制。但云原生环境里,Pod 重建一次就换个 IP,加上 HPA 自动扩缩容、故障漂移、滚动发布,IP 池是流动的。你策略里写死的 IP 可能过两天就变成别的业务的 Pod 了,基于地址的安全策略基本不可维护,更不可信。

1.2 东西向流量是“安全的盲区”

业界通常把进出数据中心的流量叫南北向流量,数据中心内部服务与服务之间的流量叫东西向流量。以前大部分安全投入都砸在南北向上,想办法把攻击挡在门外。但攻击者一旦进入内网,你会发现内部流量基本没有可信的审计和控制手段。

我在实际梳理中发现一个很普遍的现象:很多集群里连完整的网络策略都没配,甚至融合了 Istio 之后,只用了路由和灰度能力,完全没有启用安全相关的功能。CNI 自带的 NetworkPolicy 也只是粗粒度分段,比如“允许从前端命名空间访问本命名空间”,一旦服务规模增长,策略数量膨胀,效果根本看不清楚,也很难理解意图。

1.3 身份是唯一的稳定锚点

正因为 IP、网段、命名空间这些静态属性都不可靠,我们只能把信任锚点钉在“身份”上。在云原生环境里,什么最能代表一个服务的真实身份?不是它的 IP,不是它的 Pod 名字,而是它说话时携带的验证凭证——通常是 SPIFFE 标准的 SVID(SPIFFE Verifiable Identity Document),并且由某个权威端点为它签发证明身份。

后面要讲的微隔离和服务网格,本质上都是在围绕这套身份做文章:身份签发、身份校验、基于身份的授权。这样才能做到无论服务跑在哪台机器、IP 是什么、重新调度多少次,安全策略都始终跟随着它的身份走。

2. 微隔离怎么做身份编排与策略下发

微隔离的核心理念是“按身份建组,按身份放行”,它不关心你的拓扑,不关心你的网段,只认定一个东西:你是谁。在云原生环境里落微隔离,实际操作起来主要是两条路线:一种是靠 CNI 的网络策略扩展,比如 Cilium 的 CiliumNetworkPolicy;另一种是部署偏安全厂商的 Agent,这类产品通常有统一管理面。

2.1 微隔离里“身份”具体长什么样

对于 Kubernetes 原生工作负载,微隔离系统通常把一组 workload 定义为身份组。比如“所有带有 app=user-service 标签的 Pod”就是一个身份,也可以结合命名空间、Deployment 名字、自定义标签来构造更细粒度的身份。

落地的时候,我们一般会先梳理业务的调用关系,画一张调用矩阵,把所有业务按职责划分成几个安全组:前端接入组、业务逻辑组、数据存储组、中间件组。然后给每个工作负载打上统一的标识标签。这里有一个非常容易犯的错误:直接用纯逻辑的标签来划分身份含义,比如简单地写role: web和role: db,粒度太粗,后面策略没法覆盖到具体业务交流。

经验做法是用三元组来建身份:namespace + app + secure-group。namespace表达环境边界,app指向具体服务,secure-group用于聚合安全等级相同的多组服务。这样设计的好处是,安全策略可以分三级精细化:第一级按secure-group打通全局粗粒度策略,第二级按namespace折叠到环境边界里,第三级再按app做一对一细粒度放行。

2.2 策略下发与执行机制的选型对比

我用两个维度去对比方案,一个是“在哪执行策略”,一个是“网络层透明性”。CNI 方案里,策略执行发生在数据路径的节点上,强制在网络驱动层面生效,内核通过 eBPF/iptables 落地规则;Service Mesh 方案里,策略主要落在每个 Pod 的 Sidecar 上,控制链路较多。对比表格如下:

能力维度Cilium CNI 微隔离服务网格注入 Sidecar 方案
执行点节点内核态 eBPF用户态 Sidecar 代理
支持 L3/L4 策略高效直接依赖透明劫持实现
支持 L7 策略可基于协议解析做,但生态较新天然支持,对 REST/gRPC 尤其友好
改造侵入性低,业务无感知需要向 Pod 注入 Sidecar,占内存/CPU
适合场景追求强制边界和安全基线以灰度、安全观测、认证为主的微服务环境

我实测做了一个简化测试,CNI 方案在纯 L3/L4 策略下的数据包处理延迟增量可以稳定控制在 3% 以内,Sidecar 方案通常会在 8~15% 左右,经过协议解析和授权之后会更高。但反过来,Sidecar 方案可以提供 L7 层面的协议感知和双向 mTLS,这对微服务架构来说又是非常有价值的能力。

所以我一贯的建议是:如果架构已经是微服务,两者不是二选一,而是配合使用。给集群先铺一套 CNI 微隔离打底,再在核心业务链路叠加服务网格身份认证。底层的定位是虽大但稳,上层的认证做细粒度控制,但前提是你可以接受额外的性能开销。

2.3 策略设计要有“默认拒绝”的落地姿态

很多微隔离项目失败,不是因为技术不行,而是因为策略太宽松。最初的配置往往是从现有流量学习来的,学习过程中如果允许了所有历史流量,那等于没隔离。

正确做法是分三个阶段渐进收敛。第一阶段全观测不阻断,所有告警只看不看,先把全网调用关系摸出来;第二阶段针对高危路径,比如接入层到数据层的大端口放开,先收紧一批明显不合规的直连;第三阶段默认拒绝,只通过显式策略放行业务依赖。

我们当时的收敛路径是先解除数据存储层的任意访问,把 Redis、Kafka、MySQL 这些关键组件的触达面限制到核心调用方。这一步做完,攻击者登录一个普通 Web Pod 后的渗透半径立刻缩小一个大数量级。蛮多团队第一步总是想对所有服务一刀切,结果业务联调一片哀嚎,时间都浪费在处理策略遗漏上了。

2.4 网络策略的名字与注释管理

过一段时间策略数量上来以后,你会发现最痛苦的不是写策略,而是清理策略。曾有段时间我们策略数量涨到几百个,谁也不敢删旧的,怕一删就断网。后来我们建立了硬性规定:每条策略必须有明确的所有者标签、业务来源、创建时间、过期时间。就连临时开的一次性排障策略,也必须标注有效期并纳入定时回收,到期自动生成删除提醒。

一个常见做法:策略命名用编号体系。POL-APP-001这种格式,备注注明关联的 service 和调用组,并在 GitOps 仓库里维护策略的 YAML,审批流对每个 diff 人工确认。策略即代码的好处不仅是可审计,更重要的是你可以回溯——出问题的时候能知道这条策略是谁加进来的,为什么加。

3. 身份服务网格在零信任体系里的定位

讲完微隔离,再单独看身份服务网格。服务网格的价值远不止流量管理,它在零信任里的核心贡献是提供了一种标准化的身份通信模型。只要是网格内的服务,双方都会先验证对端身份,并且通信全程加密,从架构上掐死了中间人攻击和身份伪装。

3.1 双向 TLS 为什么是零信任的“闸机”

零信任总强调“先认证,再连接”。服务网格落地这套模型的抓手是 mTLS。在未启用 mTLS 前,服务之间经常还是明文 HTTP,数据库密码可能直接写在配置中心或者环境变量里,任何一个 Pod 只要能连通就能直接拉取数据。

启用 mTLS 后,任何连接请求在应用数据发送之前,双方都要先在传输层完成证书校验。客户端验证服务端的身份,服务端同样验证客户端的身份,两边都确认之后才建立安全通道。这就像两个人在进入会议室之前,各自掏出工作证让门卫核对,核不完不放行,而且对讲机还是加密的。

这样攻击者即使拿下了某个应用 Pod,想以这个 Pod 的身份去访问数据服务,也要先过数据服务的身份校验,而证书对不上就直接拒绝连接,完全绕不开。

3.2 身份签发全流程:从认证到授权

服务网格里身份签发的链路大致是这样的:控制面有一个证书权威,负责为每个工作负载签发短期证书;数据面的 Envoy 代理启动时,通过 SDS 协议向控制面请求自己的身份证书;证书里携带 SPIFFE 格式的身份标识,比如spiffe://trust-domain/ns/namespace/sa/service-account这种形式。

当服务 A 想连服务 B 时,Envoy 会做这几步:第一,和 B 的 Envoy 建立 TLS 连接,出示 A 的证书;第二,验证 B 的证书链,确认 B 的 SPIFFE ID 合法;第三,把 A 的 SPIFFE ID 传给 B 的授权策略引擎;第四,授权策略根据预先配置的方式,比如“只允许来自 finance 命名空间的 GET 请求”,决定放行或拒绝。

这个体系里最需要关注的是证书信任域设计。信任域决定了整个网格信任边界,我见过某些团队直接把生产信任域和测试环境统一,结果测试环境的证书也能在生产里被合法识别,瞬间绕过了环境隔离。正确做法是不同环境用不同 trustDomain,跨环境访问必须走专门的网关策略。

3.3 服务网格策略的优先级:认证与授权不一样

服务网格里有两类策略,前者是 PeerAuthentication,管的是“对方能不能连过来、要不要加密”,后者是 AuthorizationPolicy,管的是“对方连上来之后具体能做什么”。很多人把这两个搞混,导致配置了一堆东西但安全效果几乎没有。

打个比方,PeerAuthentication 是小区门禁,能进不能进;AuthorizationPolicy 是进了小区之后,能不能进某个单元门,以及进了单元门能不能开某个房间。如果只配置了认证,所有合法进入网格的服务还是可以互相访问,安全面并没有被收窄。所以我的顺序是先统一开启严格 mTLS,把明文流量全部禁掉,让“冒名顶替”消失;再针对关键业务链路配 AuthorizationPolicy,逐步细化到路径级别、方法级别甚至 header 级别。

3.4 网格性能开销不能拍脑袋,必须量化

服务网格的代价主要体现在数据路径上。每个 Pod 注入 Sidecar 后,流量都会经过用户态代理转发,带来 CPU 和内存开销以及额外的延迟。在真实业务场景里,这种性能影响有多大,取决于链路长度、连接复用程度和协议类型。

我在一个压测环境里试过:同样一个服务,纯直连的时候 P99 延迟大概是 8ms,挂上 Sidecar 之后提升到 11ms,再叠加 L7 授权策略后变成了 13ms 左右。绝对数值不大,但如果你链路上要过四五跳服务,每个服务都是网格代理,延迟就是乘数级累计。另外 Sidecar 对连接复用的收益非常依赖业务场景,短连接高频次调用场景的性能下降会更明显。

量化手段最简单的是做一次压测基准:同负载条件下跑开启网格和不开启的两组数据,把差异记下来交给业务方共同决策。另一个实用优化是给非关键路径的 Pod 打上不被注入的标记,让它们绕过网格直接直连。不是所有服务都需要网格保护,头精神的服务优先进网格,边角料服务保持轻量就行。

4. 东西向流量过“零信任闸机”的完整链路

现在把微隔离和服务网格串起来,看一次完整的东向流量的访问从发起、认证到放行,究竟经过了哪些环节、由谁做判定。这部分的架构设计直接决定你零信任落地的可靠性。

4.1 一次连接的完整“过闸”过程

假设现在有个合法请求,从前端服务 user-service 要访问数据服务 order-db。请求发出后,出 Pod 先进入本地的 Sidecar Envoy。Envoy 检查目标服务的 SPIFFE ID,查找服务发现数据,然后与目标 Envoy 建立 TLS 连接。建立连接时,双方互相出示身份证书,并完成 CA 校验。

连接建立成功之后,目标 Envoy 会把请求的完整信息——来源身份、目标身份、路径、方法、甚至 JWT 里的 Claims——交给授权引擎,与 AuthorizationPolicy 匹配。命中放行规则后被转发给应用容器。如果匹配到拒绝规则,请求直接返回 403,应用容器连请求包都看不到。

与此同时,底层 Cilium 的微隔离策略也在工作。即使 Sidecar 层已经判定放行,如果底层网络策略没有显式放行这对身份组合的流量,数据包依然会被 eBPF 拦截丢弃。这就是我之前说的两层配合:CNI 策略是强兜底,就算 Sidecar 被绕过或者恶意配置导致控制面失效,底层的网络隔离还是存在的。

4.2 从内核到应用:四层纵深拦截结构

数据被真正处理前,最少要过三层关卡:第一层节点内核态 eBPF 策略,基于 L3/L4 筛选身份组合,执行默认拒绝;第二层 Pod 内 Sidecar 入站策略,做 L7 解析和路径级授权;第三层应用本身的安全逻辑,比如接口鉴权、参数校验。有些场景还会有第四层,比如你在应用前面放 API 网关,在网关层做一次令牌校验,这就变成四层了。

这三层缺一不可,我的实际经验是,只有 Sidecar 没有底层兜底,风险在于攻破控制面或 Sidecar 配置被篡改后,隔离子盾直接没了;只有底层没有 Sidecar,L7 的语义感知识别不到,靠 IP 段区分是否敏保服务会漏成筛子。两层配合的逻辑是:底层负责“包的放行”,上层负责“语义的判定”;底层是门禁,上层是审讯室。

4.3 身份感知的网关:跨网格与外网流量怎么过闸

不是所有流量都发生在网格内部。外部已认证用户访问某业务的 API,或者一个跨集群调用。这时候需要单独处理身份感知的入口网关。

我采用的方案是在集群边缘部署独立的入口网关,这个网关自身加入网格控制面,它对外终结 TLS、校验 OIDC/JWT 令牌,对内向网格内转发请求时,以自己的服务身份重放请求,让链路全程保持加密和身份可验证。这样一来,外部请求最终的授权判定还是基于从 JWT 里提取出的用户身份与业务逻辑,而服务到服务的身份安全交由网格管理,两层身份模型并不冲突。

跨集群调用也是一样,只要两个集群加入了同一个信任域,证书签发体系共用,服务就可以用 SPIFFE ID 互相识别。但跨集群的微隔离策略,需要在两个集群各自维护,不然本地策略管不住远端流量。

4.4 大流量下的网关瓶颈与优化思路

身份网关是东西向安全链路的关键汇聚点,高并发下面临的连接数和加解密量非常可观。我在线上遇到过 CPU 被 TLS 握手干爆的情况,后来总结了几条优化手段:

  • 启用 TLS 会话缓存复用,减少重复握手开销
  • 对内部长连接做连接池配置,避免频繁建立新连接
  • 把 mTLS 的私钥加载放到硬件加速卡里,减轻 CPU 负担
  • 合理分配 Sidecar 实例规格,避免单实例内存拥挤形成热点

另一个容易忽略的问题是 DNS 与线程池参数。Envoy 的默认线程数不一定匹配你机器的核数,在大型机器上可能出现线程数不足或超额的现象。我们会在压测底层就测量吞吐与 P99 的关系,找出最优的 worker 线程数并固定住,不加干预反而容易在突发流量下打满连接队列。

5. 落地过程中的三大隐藏坑

这部分是我最想写的——你按文档搭起来的架构看起来很好看,但真正跑起业务来,总是会有各种预想不到的事情冒出来打乱节奏。这里挑三个比较普遍的坑分享。

5.1 时钟漂移导致证书校验失败

mTLS 里面有一项检查:证书有效期校验。如果节点时钟漂移,比真实时间慢几分钟,而证书恰好是刚刚签发的短时证书,校验方就认为证书还未生效或者已经过期,直接拒绝连接。这个坑特别隐蔽,因为集群内部所有监控都正常,但服务之间就是会间歇性互相拒连。

排查方式是先检查每个节点的时钟同步状态。解决方案很简单:所有节点统一接入同一时间源,并启动持续校时服务。注意,云上托管的 Kubernetes 节点通常默认就有时间同步,但自建集群经常疏漏。我甚至遇到过某自建机房里所有节点漂移了将近一分钟,导致连接成功率直线下降。

5.2 mTLS 开启之后 DNS 解析顺序的变化

服务网格流量劫持原理决定了 Envoy 会优先接管解析流程。当开启严格 mTLS 后,部分服务会对“域名”做直连解析,绕过网格,导致流量没有经过身份验证就和后端建立通信。

表现特别诡异:策略全开着,业务大部分正常,少数请求会超时或直接失败。排查后发现是业务代码里某些库用了 IP 直连方式,绕过 Sidecar,结果被底层微隔离策略拦截。解决方案是要么让业务代码统一走服务域名,要么给这些特殊 Pod 单独出绕过清单。最彻底的做法,是把此现象视为安全设计的一部分——既然你要零信任,就不允许 IP 直连的存在。

我在落地时甚至加了启动检查:扫描所有 Deployment 的启动命令和配置里有没有硬编码内部 IP,发现一个修一个。可能有点过度,但就是这样推理未知的坑才少。

5.3 策略先行还是身份先行

我见过不少团队一上来就把精力花在写策略上,结果策略写了一堆,发现服务身份标签还没打全,后面的工作全部返工。正确的顺序是:先把身份编排搞定。

第一步梳理工作负载,给所有命名空间补全标签规范,确保每个工作负载能映射到一个清晰的 SPIFFE ID;第二步再基于身份组合写策略。身份编排跟不上,策略写得再细也会因为标签缺失打不了补丁。我们当时发生过服务身份标签漏打,导致新上线的服务直接被默认拒绝策略拦掉业务全部不可用的悲惨案例,教训特别深刻。

6. 从现状到零信任的落地路径规划

回到最初,云原生内网的安全建设不是买一个产品就行,它本质上是对你现有网络模型、身份模型和运维体系的一次系统性调整。

6.1 第一步:资产梳理与依赖关系可视化

你无法加固你看不见的东西。落地前先要做几件事:把集群里的所有命名空间、工作负载、服务、负载均衡摸清;把服务间的调用关系通过可观测性平台拉出来,弄清谁是数据入口、谁持有敏感数据;把当前已存在的网络策略、网格策略全部归拢,清理失效规则。

我建议把所有调用关系保存成文档或图谱,这是后续安全策略的输入。没有这一步,策略设计就是拍脑袋。

6.2 第二步:由敏感数据链路向内扩展试点

选择一条最敏感的业务链路作为第一个试点。典型的对象是“核心库 -> 业务服务”这条链路。先在这条链路上启用严格 mTLS,再配置默认拒绝策略,只显式放行来源合法、协议合法的通信。

这条链路跑通之后,总结经验,形成可复制的策略模板,再逐步部署到其他链路。不要一上来就全网铺开,试点期排障节奏会让你自己崩溃。

6.3 第三步:基于威胁建模设计策略

策略不能唯调用关系图是从,还要结合威胁建模。如果某条链路虽然当前没有正常调用,但攻击者有可能利用某个暴露面横向靠近它,这类连接直接用默认拒绝拦截。安全策略的目标不是照抄正常通信图,而是在允许合法通信的同时封住威胁路径。

一份好的策略体系应该是白名单逻辑的,每条允许策略都有具体的业务解释,同时包含一条兜底拒绝所有未显式放行流量的规则。

6.4 第四步:策略生命周期与日常运营机制

微隔离策略不是配置完就结束的,它和业务研发一样有生命周期。我落地了策略需求单制度——所有策略变更都必须通过工单流程,注明业务线路、申请理由、有效期、责任人,再经过技术评审后合入 Git,通过 GitOps 流水线推送。到期自动巡检提醒,没有人认领就进入清理清单。

这种运营机制其实比技术实现更能决定项目的长期效果。机会主义的“谁要谁开”模式,用不了三个月策略列表就会失控,安全体系又重新变回一锅粥。

最后分享一个实操技巧:在开启任何全局默认拒绝前,先把变更窗口通知业务方,准备好一键回滚开关,比如通过集群标签临时关闭策略模块。建议先小范围放量测试,再逐步扩大到全集群。真出了事故,宁可先短暂放开,也不要让业务长时间中断——毕竟安全的根目标,是在保障业务可用性的前提下提高攻击成本,而不是反过来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询