云多租户网络隔离全景:从 Hypervisor 到 VNI,一层层看懂租户是怎么被隔开的
云多租户网络隔离全景:从 Hypervisor 到 VNI,一层层看懂租户是怎么被隔开的
多租户是云计算的立身之本——成千上万个互不信任的租户共享同一批物理机、同一批交换机、同一批存储盘,却要求彼此"看不见、摸不着"。这篇文章从计算、网络、数据、管理面四个维度拆解隔离体系,然后聚焦最核心也最容易被误解的一环:VPC 逻辑隔离为什么真的能隔离。我们会用一个"故意撞 IP、故意共宿主机"的例子逐跳追踪报文,再回答两个高频疑问:subnet 能不能做租户隔离?subnet 在路由表和交换机里的真实拓扑长什么样?
一、多租户隔离体系总览
隔离的本质命题是:在共享物理资源的前提下,为每个租户构建一个"逻辑上独立、必要时可物理隔离"的运行环境,同时兼顾安全性与资源利用率。
不同云服务模型的隔离锚点不同:IaaS 靠 Hypervisor 和网络虚拟化,PaaS 靠容器沙箱与命名空间,SaaS 靠应用层的 Tenant-ID 与数据权限策略。
| 隔离维度 | 共享程度 | 核心实现机制 | 典型技术/产品 |
|---|---|---|---|
| 计算隔离 | 共享硬件,独立内核 | Hypervisor 虚拟机、安全容器、机密计算 | KVM/Xen、Kata Containers、Firecracker、gVisor、AMD SEV/Intel TDX/SGX |
| 网络隔离 | 共享物理网络,独立逻辑网络 | VPC + VXLAN Overlay、安全组、网络 ACL | VPC、VNI(24 位标识,约 1600 万租户) |
| 存储隔离 | 共享存储池,独立卷/桶 | 计算存储分离、QoS 限速、数据擦除、透明加密 | 云硬盘、对象存储 Bucket、KMS |
| 数据隔离 | 共享实例/表,逻辑分片 | 独立实例 / 独立 Schema / 共享表+RLS | PostgreSQL RLS、tenant_id 过滤 |
| 管理面隔离 | 共享控制平面 | IAM 多账户、最小权限、审计日志 | RBAC/ABAC、CloudTrail、操作审计 |
1.1 计算隔离:从 Hypervisor 到机密计算
计算隔离的核心是让租户的工作负载无法访问彼此的内存与 CPU 资源,实现强度由弱到强分三档:
Hypervisor 虚拟机隔离(IaaS 主流):每个租户运行在独立 VM 中,由 KVM/Xen 等虚拟化管理程序在硬件层面做地址空间隔离。云厂商还会配合虚拟机布局算法防止恶意租户"探测"自身所在物理机,并对虚拟化层做热补丁修复和逃逸检测。
容器/沙箱隔离(PaaS 主流):通过 Linux namespaces + cgroups 做轻量隔离,多个租户共享宿主机内核,隔离强度依赖内核安全性。为弥补共享内核的风险,业界引入了三类增强方案:
- gVisor:用户态拦截 syscall,开销约 45MB 内存、启动约 85ms;
- Kata Containers:每个 Pod 运行在独立轻量 VM 中,具备完整内核隔离,适合多租户不可信代码与金融/政务场景;
- Firecracker microVM:AWS Lambda/Fargate 采用的极致轻量 VMM,启动 <125ms、内存约 28MB,禁用多余设备模拟,攻击面最小。
机密计算隔离(高合规场景):基于 CPU TEE(AMD SEV-ES、Intel SGX/TDX)对租户内存做硬件加密,连云厂商的 Hypervisor 和管理员都无法窥视运行中的数据。
1.2 网络隔离:VPC + VXLAN Overlay
网络隔离的核心思想是:在共享的物理网络上,通过 Overlay 封装为每个租户构建专属的虚拟网络,让租户之间的流量在二/三层都无法互通。
- VPC 逻辑隔离:每个租户分配独立 VPC,拥有自定义 CIDR 网段、子网、路由表,不同 VPC 之间默认完全隔离,互访必须通过显式的对等连接、专线或 VPN;
- VXLAN 封装实现多租户标识:传统 VLAN 只有 12 位标签(4094 个),无法满足大规模多租户;VXLAN 在原始以太网帧外新增 8 字节头部(含 24 位 VNI),理论支持 2²⁴ ≈ 1600 万个租户网络;
- 安全组与网络 ACL:作为 VPC 内的 L4 状态防火墙,安全组以 ENI 为对象控制实例级出入流量,网络 ACL 以子网为对象做无状态访问控制,两者组合实现细粒度"微分段";
- 网络加密(可选):高合规租户可开启 VPC 内加密,计算节点与网关之间的流量全程加密,对云厂商也保持不透明。
1.3 存储与数据隔离
存储层隔离有两个目标:性能上防"吵闹邻居",安全上防数据越权访问。
- 存储卷隔离:计算与存储分离架构下,虚拟机只能访问分配给它的磁盘空间;实例释放时对原存储介质做可靠的数据擦除,防止跨租户数据残留;
- QoS 性能隔离:对云硬盘、对象存储 Bucket、消息队列等设置每租户的 IOPS/吞吐/QPS 上限;
- 数据加密隔离:通过 KMS 为每个租户分配独立密钥(BYOK),对静态数据做服务端透明加密;部分高安全方案甚至实现"加密隔离"——即使集群管理员也无法解密租户数据;
SaaS 数据隔离的三种模式(应用层最关键的选型问题):
| 模式 | 隔离性 | 成本 | 适用规模 |
|---|---|---|---|
| 独立实例(一租户一 DB 实例) | 最高(物理/进程级) | 最高 | <50 租户,金融/政务 |
| 独立 Schema(一租户一库) | 高(逻辑库级) | 中等 | 50–500 租户 |
| 共享库 + tenant_id + RLS | 依赖应用层 + 行级策略 | 最低 | 500+ 租户 |
共享表方案最大的风险是应用层 SQL 漏写 WHERE 条件导致串数据,因此推荐把访问控制下沉到数据库引擎层的行级安全(PostgreSQL RLS):在查询执行器阶段自动为每条 SQL 注入租户过滤条件,即使绕过应用直连数据库也不会泄露跨租户数据。
1.4 管理面隔离
共享的控制平面是横向渗透的高危路径:
- 身份与权限隔离:每个租户对应独立 IAM 账户体系,通过 RBAC/ABAC 实现最小权限;所有 API 请求必须携带合法 TenantID,在接口权限、数据权限、操作权限三层做分层校验;
- 物理运维通道隔离:云厂商内部运维通过堡垒机 + 多因素认证进入生产网,与租户网络完全隔离;
- 审计与溯源:全量记录租户操作日志与控制面调用日志,通过 eBPF tracepoint 等手段做零侵入式审计;
- 元数据隔离(SaaS 层):Salesforce 等多租户 SaaS 通过租户专属 metadata 实现功能差异化,避免代码分叉。
1.5 选型原则
隔离方案的选择本质是合规强度、性能隔离需求与成本三者之间的权衡:
- 金融、政务、医疗等强合规行业倾向于"物理/加密隔离"路线:裸金属、独立 VPC、独立 DB 实例、机密计算、专属 KMS——用较高成本换取清晰的责任边界与审计路径;
- 互联网 SaaS、AI 推理平台等规模型业务倾向于"逻辑隔离"路线:共享硬件 + Kata 安全容器 + 共享表 + RLS + 严格的配额与审计——通过把隔离机制从"人肉纪律"升级为"平台强制"来取得平衡。
二、VPC 逻辑隔离为什么就能隔离租户网络?
"逻辑隔离"听起来很虚:明明所有租户的报文都在同一批交换机、同一批光纤上跑,为什么 A 租户的虚拟机就"够不着"B 租户的虚拟机?
关键在于:物理网络搬运的从来不是租户的原始报文,而是被封装后打了租户标签的"包裹",而解封、转发、隔离的决策全部发生在宿主机的虚拟交换机上。
2.1 物理网络上跑的到底是什么
假设租户 A 的 VM1(10.0.0.5)要 ping 租户 B 的 VM2(192.168.1.5),报文离开 VM 后的第一站不是物理交换机,而是宿主机上的 vSwitch(虚拟交换机,如 OVS)。vSwitch 会做一件事:
1 | 原始报文(租户 A 的 VM 发出,源 10.0.0.5 → 目的 B 的 IP) |
物理交换机看到的是"宿主机 → 宿主机"的普通 UDP 流量,它根本不知道、也不需要知道里面装的是哪个租户的包。物理网络(underlay)只负责把包裹送到正确的宿主机,租户网络(overlay)的寻址、隔离都在两端解封装时完成。
2.2 隔离真正发生的三个关卡
关卡 1:VM 入网时的"门禁"——端口绑定 VNI
每台 VM 的虚拟网卡接入 vSwitch 时,云平台控制面就已经把这条端口和一个 VNI 绑死了。这个绑定是平台下发的,租户无法修改。VM 就算被完全攻破、root 权限拿到手,它发出的报文进入 vSwitch 时仍会被强制打上 VNI=100 的标签——租户没有"冒充别的租户"的通道。
关卡 2:vSwitch 转发时的"查无此路"
隔离的核心机制其实简单到只有一句话:vSwitch 的转发表里,不同 VNI 是完全独立的命名空间,转发查询永远在同一个 VNI 内进行。
- 目的 MAC 在本机、同 VNI → 本地二层直接交付;
- 目的 MAC 不在本机、同 VNI → 封装 VXLAN,发给目标宿主机的 VTEP;
- 目的 MAC/IP 不在本 VNI 的表里 → 直接丢弃。
A 租户的 VM 发往 B 租户 IP 的报文,在 VNI=100 的转发表里查不到任何匹配项——不是因为"禁止",而是因为"根本不存在这条路由"。
关卡 3:跨 VNI 通信必须过网关
如果两个租户确实需要通信,报文必须送到分布式网关/VPC Router。网关是唯一"能看见多个 VNI"的组件;是否放行,取决于控制面有没有下发对等连接、专线、VPN 等显式规则;默认没有规则 = 默认拒绝。
所以隔离模型是:数据面(vSwitch)无差别执行"VNI 之间不通",控制面(SDN 控制器)显式开通例外。
2.3 容易被忽略但同样关键的旁路封堵
| 机制 | 防的是什么 |
|---|---|
| MAC/IP 反欺骗 | 租户在 VM 里把 IP 改成 B 租户的 IP 冒名访问;vSwitch 校验源 MAC/IP 与端口绑定不一致即丢弃 |
| ARP 域收窄 | ARP 请求只在同 VNI 内广播/代答,A 租户永远 ARP 不出 B 租户的 MAC |
| 隔离的默认路由表 | 每个 VPC 有独立虚拟路由表,B 租户的网段在 A 的路由表里压根不存在 |
| 网关上的安全组/ACL | 即使开通了对等连接,流量还要过状态防火墙 |
| VTEP 白名单 | 防止恶意租户伪造外层 IP 直接注入伪造 VNI 的报文 |
2.4 一句话总结隔离的本质
VPC 的"逻辑隔离" = 把每个租户的网络身份(VNI)固化在租户无法触碰的宿主机数据面里,让跨租户流量不是因为被拦截而失败,而是因为"查无此路"而根本无法产生。
物理层完全共享,但租户能操控的边界止步于自己的虚拟网卡;从 vNIC 往外的第一跳开始,打标、查表、封装、路由的每一个决策都在云平台控制的组件里完成。
2.5 诚实的补充:它依赖什么前提
逻辑隔离不是魔法,它的安全性建立在几个前提上,这也是它和物理隔离的真正差距:
- vSwitch/Hypervisor 无漏洞——历史上确实出过 VXLAN VNI 校验漏洞、虚拟化逃逸漏洞,云厂商靠快速热补丁和逃逸检测兜底;
- 控制面不可被租户渗透——SDN 控制器、宿主机管理通道一旦失守,所有 VNI 都会暴露;
- 硬件资源侧信道——网络带宽、宿主机缓存这类共享资源仍存在"吵闹邻居"问题,逻辑隔离不解决性能隔离。
正因为这些残余风险,强合规场景会在逻辑隔离之上再叠加:裸金属/专属宿主机、VPC 内流量加密(连云厂商的网关都看不到明文)、以及基于 TEE 的机密计算——把信任边界从"相信云平台的实现正确"收紧到"只相信硬件加密"。
三、实战推演:故意让两个租户撞 IP、共宿主机
为了真正看清楚隔离发生在哪里,我们故意设计一个最恶劣的场景:两个租户使用完全相同的网段,两台分属不同租户的虚机落在同一台物理宿主机上。
3.1 场景设定
flowchart LR
A1[VM-A1
172.16.0.5] -- vNIC p1 --> VS1
A2[VM-A2
172.16.0.6] -- vNIC p7 --> VS2
B1[VM-B1
172.16.0.6
与A2同IP!] -- vNIC p9 --> VS2
subgraph H1[宿主机 H1 / 10.10.0.11]
VS1[vSwitch + VTEP1
按VNI分转发表]
end
subgraph H2[宿主机 H2 / 10.10.0.12]
VS2[vSwitch + VTEP2
按VNI分转发表]
end
VS1 -- 物理网络 UDP 4789
只看到 H1→H2 --> VS2
| 角色 | 属性 |
|---|---|
| 租户 A | VPC-A,网段 172.16.0.0/16,VNI = 10001 |
| VM-A1 | 172.16.0.5,MAC 02:11:22:33:44:55,宿主机 H1 |
| VM-A2 | 172.16.0.6,MAC 02:aa:bb:cc:dd:ee,宿主机 H2 |
| 租户 B | VPC-B,网段 172.16.0.0/16(与 A 撞网段),VNI = 20002 |
| VM-B1 | 172.16.0.6(与 A2 完全同 IP),宿主机 H2(与 A2 同一台物理机) |
| H1 / H2 | 物理网卡 IP 10.10.0.11 / 10.10.0.12,各跑一个 vSwitch,充当 VTEP |
动作:VM-A1 ping 172.16.0.6。 这个目标 IP 同时是 A2 和 B1 的地址,网络必须准确知道"该给谁、不该给谁"。
3.2 正向流程:A1 → A2 报文一步步怎么走
第 0 步:A1 发 ARP 查询(隔离第一关卡)
A1 内核构造 ARP Request(目的 MAC = ff:ff:ff:ff:ff:ff):“谁是 172.16.0.6?” 这个广播不会走物理网络。vSwitch 查询控制面下发的租户 ARP/端口映射表:
1 | 端口 p1 (VM-A1) → VNI=10001 |
vSwitch 直接代答(proxy ARP),把 A2 的 MAC 回给 A1。ARP 广播域被收窄到 VNI=10001 内部,永远"波及"不到 B 租户。
第 1 步:ICMP 帧从 A1 的 vNIC 发出
原始(内层)以太网帧:
1 | 源 MAC : 02:11:22:33:44:55 (VM-A1) |
第 2 步:vSwitch 打标 + 查表(隔离真正发生的第一站)
vSwitch 在入口处做三件事,全部由平台侧执行,租户无法干预:
- 按端口绑定强制打 VNI:p1 绑定了 VNI=10001,这帧报文被强制标记为租户 A;
- MAC/IP 反欺骗校验:源 MAC、源 IP 与控制面下发的绑定表比对,不一致直接丢弃;
- 查转发位置:在 VNI=10001 的专属转发表里查目的 MAC → 命中远端表项,对应 VTEP 地址 10.10.0.12。
这一步是整个隔离体系的根:vSwitch 的所有转发表按 VNI 分命名空间,查询永远发生在本租户那张表里。
第 3 步:VXLAN 封装(打包裹)
1 | 外层以太网头:源/目的 MAC = H1 物理网卡 ↔ 物理交换机下一跳 |
从这一刻起,物理网络只看到"H1→H2 的普通 UDP 流量"。
第 4 步:物理网络转发(不做租户判断)
物理交换机按外层目的 IP 做普通三层转发。这层不做任何隔离判断——隔离已经在两端 vSwitch 完成,underlay 只负责"送快递"。
第 5 步:H2 vSwitch 解封装(验身份证)
- 剥外层头,取出 VNI=10001;
- 合法性校验:来源 VTEP 是否在白名单、VNI 是否在本机合法集合内——不合法直接丢弃;
- 在 VNI=10001 的本机转发表里查目的 MAC → 命中本地端口 p7(VM-A2 的 vNIC)。
第 6 步:交付
vSwitch 把剥干净的原始帧过一道安全组(L3/L4 状态过滤)后,从 p7 发给 VM-A2。回程反向走同样的路。
整个流程中,报文从未"裸奔"在物理网络上,租户身份始终由 VNI 标记、由平台侧 vSwitch 把关——即使 A2 和 B1 同宿主机、同 IP,各自的流量在 vSwitch 的不同 VNI 表里走完全独立的路径。
3.3 反例:A1 恶意尝试访问 B1 会发生什么
假设 A1 被攻破,攻击者直接 ping 172.16.0.6 想试试能不能串到 B 租户:
- 卡在 ARP:ARP 广播被限定在 VNI=10001 内,vSwitch 只会用 A2 的 MAC 代答,永远 ARP 不出 B1 的 MAC;
- 伪造目的 MAC:即使猜到 B1 的真实 MAC 手工构帧,vSwitch 在 VNI=10001 的表里查不到 → 丢弃;
- 绕过 vSwitch 直接注入伪造 VXLAN 包(外层伪装成 VTEP、VNI 填 20002):H2 vSwitch 校验 VTEP 白名单,发现不合法 → 丢弃;
- 从 A 的 VPC 路由表找路:控制面从未下发指向 B 的路由,查表 miss → 丢弃。
每条路都是死胡同,原因高度一致:跨租户流量不是被"拦截",而是"查无此路"。
3.4 逐跳对照表
| 步骤 | 发生位置 | 动作 | 隔离判断 | 为什么必须在这层做 |
|---|---|---|---|---|
| 0 | A1 内核 → vSwitch p1 | ARP 广播 | 广播域限定 VNI=10001 | 防跨租户 ARP 泛洪/欺骗 |
| 1 | vSwitch (H1) 入口 | 强制打 VNI=10001 | 端口身份固化 | 攻破 VM 也改不了租户归属 |
| 2 | vSwitch (H1) 查表 | VNI=10001 表内查目的 MAC | 按 VNI 分命名空间 | "查无此路"式硬隔离 |
| 3 | vSwitch (H1) 封装 | 外层 IP + UDP 4789 + VNI | VNI 由平台打上不可篡改 | 物理网络可区分身份但不暴露拓扑 |
| 4 | 物理交换机 | 按外层 IP 转发 | 不判断(不需要) | underlay 保持通用 |
| 5 | vSwitch (H2) 入口 | VTEP 白名单 + VNI 合法性 | 伪造来源丢弃 | 防注入绕过 |
| 6 | vSwitch (H2) 查表 | VNI=10001 表查目的 MAC | 查不到 → 丢弃 | 双向对称隔离 |
| 7 | 交付 vNIC | 剥净后送入 | 安全组 L4 过滤 | 兜底细粒度控制 |
3.5 精确校准:四个容易忽略的实现细节
上面的流程是主干,四个细节需要精确化:
1. ARP 的处理方式取决于控制面实现,不总是"代答"
公有云 VPC 里普遍是 vSwitch 代答——广播根本不出宿主机;传统 EVPN-VXLAN 部署里更多是 ARP Suppression(抑制)——本地表命中就代答,未命中才把 ARP 作为 BUM 流量在 VNI 内泛洪(泛洪范围仍被 VNI 截断)。两种形式隔离效果一致,区别只是广播是否"漏出"本机。
2. 同宿主机的流量根本不封装 VXLAN
如果源 VM 和目的 VM 在同一台宿主机,vSwitch 在 VNI=10001 的本地转发表里直接命中本地端口,做的是本地二层交换——不封装、不出物理网卡、不经过 VTEP。VXLAN 只在跨宿主机时才登场。例子里 A2 和 B1 同宿主机同 IP,隔离靠的就是本地转发表的 VNI 命名空间,跟 VXLAN 封装无关。
3. 源 VTEP 校验发生在解封装一侧
校验由收包方的 vSwitch 执行:封装一侧只负责打标,不校验自己。OVS 里校验的形式通常是隧道表里登记的合法远端 VTEP IP 列表——来源 IP 不在表内则无法映射到合法隧道,直接丢弃。
4. 交付前的最后一道:安全组
剥离成原始帧后、送进 vNIC 前,vSwitch 还会按端口上挂的安全组规则做 L3/L4 状态过滤——这是租户自己定义的策略,属于授权后的细粒度控制,与 VNI 的"硬隔离"是叠加关系。
修正后的完整心智模型:
1 | VM 发包 |
3.6 隔离层次总结
1 | L1 物理层 :所有租户共享交换机/光纤 —— 不隔离(也不需要) |
最关键的认知:L3 是隔离的根——不是靠防火墙"拦截",而是靠"不存在那条路";L4 控制面决定要不要修路,L3 数据面决定有没有路。
四、那么,subnet 能不能做租户隔离?
答案:不能。 VNI + vSwitch 按租户分命名空间的转发表,才是 VPC 隔离租户的"根";subnet 回答的是另一个维度的问题——VPC 内部的分区控制。
subnet 在云里的真实角色:VPC 内的一段 IP 地址规划(CIDR),附属于一张路由表,本质上只是"地址分配和路由的记账单位",不是隔离边界。四个原因,一个比一个致命:
4.1 IP 是"租户自报的身份",不是平台担保的身份
subnet 隔离依赖路由器/防火墙按 IP 做判断,但 VM 里的 IP 是租户自己配置的:
1 | ifconfig eth0 172.16.0.6 # 伪装成别的子网/别的机器的 IP |
如果隔离只靠"目的 IP 属于哪个网段"来判断,源 IP 伪造就能绕过。对比 VNI:VNI 绑定在 vSwitch 端口上,由平台写入、租户改不了。这就是"逻辑地址"与"物理身份锚点"的差别——隔离强度取决于 enforcement point 在哪一层:越靠近租户触碰不到的地方(vSwitch 端口、VNI)越硬,越靠近租户可配置的层面(IP、路由)越软。
4.2 subnet 隔离是"有路但设卡",VNI 隔离是"根本没有路"
- VNI 模式:租户 B 的 MAC 表项只存在于 VNI=20002 的转发表里,租户 A 的报文查询的是 VNI=10001 那张表,查不到就是查不到——那条路径在数据面上不存在;
- subnet 模式:路由器上两张子网的路由都在同一张全局路由表里,隔离靠中间挂 ACL/防火墙规则"禁止转发"。一旦规则配错一条、防火墙被绕过一条路径,隔离就破了。
安全设计上,前者叫 deny by absence(默认无路),后者叫 deny by policy(有路设卡)。前者不依赖策略的正确性,后者完全依赖——而策略是会出错的。
4.3 撞网段问题:subnet 方案直接崩溃
公有云几百万租户,一定有大量租户都想用 172.16.0.0/16 或 10.0.0.0/8 这类私网段:
- 路由器上同一个目的网段只能有一个下一跳——两个租户都用 172.16.0.0/16 时,全局路由表直接冲突;
- 所以 subnet 方案要求所有租户网段全局唯一,这在租户规模上不可行。
而 VNI 模式下,报文的"归属"由 VNI 决定、内层 IP 原样保留,每个租户拥有独立的虚拟路由表和独立的 MAC 地址空间,撞网段完全合法。第三章那个 A2/B1 同 IP 同宿主机的例子,在纯 subnet 世界里根本不可能运转。
4.4 二层广播域拦不住
VNI 模式下广播域被 VNI 硬截断;而同一物理网络里的两台 subnet 机器,如果二层连通(没有 VLAN),ARP 广播双方都收得到——攻击者可以通过 ARP 泛洪/欺骗持续探测、投毒。
4.5 对比表
| 维度 | VNI 隔离(VPC 根机制) | subnet 隔离 |
|---|---|---|
| 身份锚点 | vSwitch 端口绑定的 VNI,租户不可篡改 | IP 地址,租户自配可伪造 |
| 隔离方式 | 转发表按 VNI 分命名空间,“查无此路” | 路由表/ACL 策略拒绝,“有路设卡” |
| 失效条件 | 需要 vSwitch 实现有 bug | 任何一条策略配错即穿透 |
| 撞网段 | 天然支持,每租户独立地址空间 | 全局路由冲突,无法共存 |
| 广播域 | 硬截断在 VNI 内 | 取决于 VLAN 配置,易泛洪 |
| 隔离的层级 | L2 虚拟化层(数据面) | L3 路由策略层(控制面) |
4.6 subnet 的正确战场:VPC 内部微分段
公道地说,subnet 并非无用,它的正确用法是在 VNI 已把租户硬隔离之后,做租户内部的子网微分段,机制是三层叠加:
- 路由表切分:把子网关联到不同路由表,去掉指向对方子网的路由——这是"收窄路径"的 subnet 版本;
- 网络 ACL:子网边界的无状态 L3/L4 过滤;
- 安全组:实例级有状态过滤,作用在 vNIC 上。
典型分层架构:public subnet 放对外服务,private subnet 放应用,隔离的 data subnet 放数据库且不放通往 IGW 的路由——通过"不给路由"实现数据库子网无法出网,这其实就是缩小版的 deny by absence。注意安全组在这个体系里反而最强——因为它同样下沉到了 vNIC/vSwitch 端口层执行。
历史上这也是真实演进路径:数据中心早期靠"VLAN + subnet + 防火墙分区"做隔离,撞上了 4094 个 VLAN 上限、网段全局唯一、策略人工维护出错这些墙,才发展出 VXLAN/VNI + SDN 控制面这套体系——把隔离从"运维纪律"升级成了"平台机制"。
五、subnet 在路由表和交换机中的真实拓扑
subnet 有两层拓扑:一层是租户在控制台上看到的逻辑拓扑(VPC → 子网 → 实例),另一层是数据面真实存在的实现拓扑(子网 ↔ 二层 VNI/Bridge Domain ↔ 虚拟路由器 ↔ 底层 Leaf-Spine)。两层的错位正是困惑的根源。
5.1 层次全景
| 层级 | 组件 | 与 subnet 的关系 |
|---|---|---|
| L0 物理层 | Leaf(TOR)→ Spine 交换机,underlay IP/BGP | 不感知 subnet:跨宿主机的子网流量只是一条宿主机间的 UDP 4789 普通流量 |
| L1 Overlay 隧道层 | VTEP + VXLAN 隧道 | 按隧道转发到目标宿主机,不管隧道里装的是哪个子网的帧 |
| L2 二层虚拟网络层 | 二层 VNI ↔ Bridge Domain(BD),每个 subnet 对应一个 BD/VSI | subnet 在这层第一次"实体化":同子网 = 同 BD = 二层互通;不同子网 = 二层隔离 |
| L3 虚拟路由层 | 路由表(VPC 级)+ 分布式虚拟路由器 | 跨子网通信的唯一通道:出子网必须查本子网关联的路由表 |
| L4 租户网络层 | VPC 整体边界(三层 VNI / VPN 实例) | subnet 的"天花板":所有子网都在同一个 VPC 命名空间内 |
| L5 逻辑视图层 | 控制台上的 VPC → subnet → ENI → VM | 只是地址记账和策略挂载点,不是转发实体 |
两个重要"错位":
- subnet 与 AZ 没有物理绑定:公有云的 subnet 是区域级逻辑对象,同一子网的实例可以分布在多个 AZ 的不同宿主机上;控制面保证"subnet ID → VNI"的映射在区域内全局一致,但底层物理路径每个 AZ 各自独立;
- subnet 与物理交换机没有绑定:一个子网的流量可能横跨几百台宿主机、几十台 Leaf 交换机;一台 Leaf 上的隧道里同时跑着上千个不同子网(不同 VNI)的流量。
5.2 具体例子:一个 VPC,2 个 AZ,3 类 subnet
flowchart TB
subgraph VPC[租户 A 的 VPC / 172.16.0.0/16]
subgraph AZ1[可用区 1]
PUB1[Public-Subnet-AZ1
172.16.1.0/24
关联 RT-Public]
PRIV1[Private-Subnet-AZ1
172.16.2.0/24
关联 RT-Private]
end
subgraph AZ2[可用区 2]
PUB2[Public-Subnet-AZ2
172.16.3.0/24
关联 RT-Public]
PRIV2[Private-Subnet-AZ2
172.16.4.0/24
关联 RT-Private]
end
DB[DB-Subnet / 172.16.5.0/24
关联 RT-DB]
RT-Public[RT-Public]
RT-Private[RT-Private]
RT-DB[RT-DB]
end
IGW[Internet 网关] --- RT-Public
NAT[NAT 网关] --- RT-Private
RT-DB -.仅含 local 路由.- VPC
每张路由表的内容:
| 路由表 | 关联子网 | 路由条目 |
|---|---|---|
| RT-Public | 172.16.1.0/24、172.16.3.0/24 | 172.16.0.0/16 → local;0.0.0.0/0 → IGW |
| RT-Private | 172.16.2.0/24、172.16.4.0/24 | 172.16.0.0/16 → local;0.0.0.0/0 → NAT 网关 |
| RT-DB | 172.16.5.0/24 | 172.16.0.0/16 → local(刻意不配出网路由) |
三个结构细节:
- local 路由是隐式自动生成的,指向整个 VPC 网段,删不掉——它是"子网间互通"的物理基础;
- 0.0.0.0/0 是默认路由,决定子网的"出网属性"(public/private/DB 的差别就在这一条);
- 一个子网同一时刻只关联一张路由表(显式关联优先;没显式关联就吃 VPC 主路由表)。多子网可共享一张表——例子中 AZ1/AZ2 的 public subnet 共享 RT-Public,这是把"同策略子网"归类的常规做法。
5.3 数据面逐跳追踪:subnet 在转发中"实体化"在哪
部署:Web-VM(172.16.2.10,宿主机 H1,AZ1)→ DB-VM(172.16.5.20,宿主机 H2,AZ2)。
第一跳:Web-VM 判断目标不在本子网
VM 内核发现目的 IP 172.16.5.20 不在 172.16.2.0/24 内 → 关键分叉:同子网走二层(直接 ARP + 同 BD 的 VXLAN 转发),跨子网必须走三层(发给网关)。VM 把帧发给虚拟网关 MAC(SDN 控制器写入每个 VM 的默认网关,实际是分布式虚拟路由器在各宿主机上的接口 MAC)。
第二跳:vSwitch 识别"这是发给路由器的包"
H1 的 vSwitch 解析目的 MAC = 虚拟路由器接口 → 触发三层转发:剥离以太网头,按 172.16.5.0/24 查 RT-Private → 命中 local → 换成出接口,重新封装以太网头(源 MAC = 路由器,目的 MAC = ARP 查到的 DB-VM MAC)。公有云把这个路由功能分布到了每个宿主机 vSwitch 上(分布式路由)。
第三步:VXLAN 封装(换 VNI)
vSwitch 把"路由后"的帧封装进 VNI=BD(DB-Subnet)——注意:不是原子网的 VNI,而是目的子网的 VNI,外层 IP 打 H2 的地址,送进 underlay。
第四步:Leaf/Spine 转发(完全不看 subnet)
物理交换机按外层 IP 做普通转发——对里面装的子网、VPC、租户全部无感。
第五步:H2 vSwitch 解封装交付
剥外层头、验 VNI/VTEP、在 BD(DB-Subnet) 的表里查 DB-VM MAC、过安全组,交付。
整个路径说明一个要点:"子网"在物理网络上从未出现过,它只以 VNI(BD) 的形式存在于宿主机 vSwitch 的转发表里,以路由条目的形式存在于虚拟路由器里。物理网络是纯粹的信使。
5.4 与传统物理网络(VLAN 模式)对照
| 结构点 | 传统数据中心(VLAN+SVI) | 公有云(VXLAN overlay) |
|---|---|---|
| 子网的二层实体 | 一段 VLAN(12bit,全局 4094 个) | 一个 BD/二层 VNI(24bit,1600 万) |
| 子网间的路由点 | 核心交换机上的 SVI(VLAN 接口) | 分布式虚拟路由器 + VPC 路由表 |
| 子网跨机柜/跨楼 | 受物理二层延伸(Trunk/堆叠)限制 | underlay IP 路由,无二层延伸限制 |
| 子网跨 AZ | 基本做不到(二层跨 DC 很脆) | 逻辑上同一个 subnet(区域级对象),物理上每 AZ 独立 leaf-spine,靠控制面统一映射 |
| 谁决定"可达" | 交换机配置 + STP/VLAN 剪枝 | 路由表条目 + VNI 命名空间 |
一句话归纳:传统网络里 subnet 是"物理绑定的 VLAN",云网络里 subnet 是"逻辑映射的 VNI + 路由表条目"——所有实体化都发生在宿主机 vSwitch 和虚拟路由器上,物理交换机退化为纯粹的 IP 信使。
5.5 按子网内 / 跨子网区分查表行为
- 同子网两 VM:纯二层流程,vSwitch 在 BD(Private-Subnet) 的 MAC 表里查目的,不查路由表;
- 跨子网两 VM(Web → DB):必须经虚拟路由器,两次查表(VM 出子网查路由表,路由后进入目的子网查 BD MAC 表);
- 出 VPC(Web → 互联网):同跨子网,但出接口指向 IGW,由 IGW 做 NAT 后送进外部网络。
这就是为什么 RT-DB 不配出网路由就够了——子网内互访走 local,出网路径因为"路由表里没有那条"而不存在。路由表的"没有"决定"没有路径",与 VNI 的"查无此路"是一脉相承的设计哲学。
六、总结:贯穿全文的三条设计哲学
把全文收拢到三个可迁移的原则上:
1. 身份要锚定在租户触碰不到的层。
租户隔离的强度不取决于隔离机制多复杂,而取决于 enforcement point 的位置:VNI 绑死在 vSwitch 端口(硬)、安全组挂在 vNIC(硬)、tenant_id 过滤靠应用自觉(软)、subnet 划分靠 IP(最软,可伪造)。凡是租户能改的参数,都不能作为安全身份的依据。
2. 优先 deny by absence,而不是 deny by policy。
VNI 命名空间让跨租户路径"不存在",local 路由让子网间互通"天然有",IGW 路由的缺席让数据子网"出不了网"。相比之下,靠防火墙规则"有路设卡"的方案,安全性等于策略配置的零失误率——这在人身上是奢求,在平台上是纪律。
3. 物理层共享、逻辑层独立,是隔离与成本的帕累托解。
Leaf-Spine 上跑着所有租户的 UDP 包,宿主机上住着互相撞 IP 的邻居虚机,存储池里混着大家的加密数据——共享换来了云的成本曲线,而 VNI、Hypervisor、KMS、TEE 把逻辑边界守住了。残余风险(Hypervisor 漏洞、控制面失守、侧信道)不是被忽略,而是被强合规场景用裸金属、VPC 加密、机密计算逐级买断。
理解了这三条,再看云上任何隔离设计——不管是容器沙箱、数据库 RLS,还是对象存储的桶策略——你都能快速定位同一个问题:它的 enforcement point 在哪一层?租户的手能不能伸到那一层?答案是"够不着"的,就是可靠的隔离。