内容提要
本文介绍在AWS VPC中利用ENI的IPv6前缀委派,为每个Firecracker沙盒分配公网可直接访问的IPv6 /128地址。方案采用双ENI分离管理面与沙盒流量,由宿主dnsmasq通过DHCPv6自动下发地址,无需调用AWS API;沙盒另配私网IPv4经宿主NAT出站。防火墙阻止沙盒访问宿主本机与IMDS,保障隔离安全。
延伸解读
IPv6前缀委派的关键网络行为
文章指出,委派的/80前缀是ENI合法拥有的地址空间,因此无需关闭源/目标检查或修改子网路由表;但源地址属于该前缀的报文必须从该ENI发出,否则会被丢弃。VPC路由器不对委派前缀做邻居发现,报文直接投递到ENI,省去了ndppd代答。前缀长度固定为/80,SLAAC不可用,需用DHCPv6有状态模式逐个下发/128,同时仍需发送RA通告默认路由。这些行为直接决定了宿主上的网桥、策略路由和dnsmasq配置方式。
双ENI与防火墙构成安全边界
方案用两个ENI分离管理面与沙盒流量:主ENI安全组只放行管理端口,专用ENI入站放开但不分配IPv6地址。文章特别提醒,专用ENI不分配IPv6地址不等于宿主在该ENI上不可达,prefix::1仍是本机地址,sshd默认监听所有地址,因此宿主防火墙才是保护宿主的主防线。nftables规则只放行沙盒到宿主的NDP、ping、DHCP和DNS,并丢弃沙盒访问IMDS的流量,防止沙盒内代码获取实例角色凭证。
策略路由与DUID配置是易错点
宿主有两个ENI时,main路由表中eth0的默认路由优先级更高,沙盒回复报文若从eth0发出会因源/目标检查被丢弃,导致外部连接超时。文章通过为源自/80的流量建立独立路由表并指向eth1来解决,且强调不要手工用ip rule/ip route添加规则,因为systemd-networkd会管理外来规则,一次重配或续租就可能清除。另一个易错点是所有沙盒从同一镜像复制,machine-id相同会导致DHCPv6 DUID冲突,需改用link-layer派生DUID,确保每个MAC获得唯一且稳定的/128。
隔离范围与规模化限制
文章讨论部分指出,RA通告的/80和IPv4 /24在沙盒中都是直连网段,默认沙盒之间可直接二层互访,不经过宿主FORWARD链,适合同一用户协作,但多租户场景需开启TAP端口隔离并添加br0到br0的丢弃规则。规模化方面,一个/80含2⁴⁸个地址,创建沙盒只是本地建TAP和一次DHCP,瓶颈在宿主CPU和内存而非地址;如需更多前缀可为ENI委派多个/80,并同步调整网桥地址、地址池、策略路由和防火墙规则。
Q&A
如何让每个 Firecracker 沙盒都获得一个公网可直接访问的 IPv6 地址?
利用 AWS VPC 中 ENI 的 IPv6 前缀委派功能,为专用 ENI 委派一个 /80 前缀,然后在宿主机上通过 dnsmasq 以 DHCPv6 有状态模式从该 /80 中为每个沙盒分配一个 /128 地址。沙盒的 MAC 地址唯一,因此每次启动都会获得相同的 /128,且无需调用 AWS API。
为什么方案中要为 EC2 实例配置两个 ENI?各自的作用是什么?
双 ENI 用于分离管理面和沙盒流量:主 ENI(eth0)承载宿主管理面,安全组只放行管理端口;专用 ENI(eth1)承载委派的 /80 前缀,安全组入站放开以允许外部访问沙盒,但该 ENI 自身不分配 IPv6 地址。这样沙盒流量的放开不会波及宿主管理面。
沙盒的 IPv4 出站流量是如何实现的?
沙盒配置一个私网 IPv4 地址(来自 172.16.0.0/24),其出站流量经宿主主 ENI(eth0)做 NAT masquerade 后访问互联网。宿主本身需要具备 IPv4 出网能力(公有子网或 NAT 网关)。
如何防止沙盒中的代码访问宿主本机或实例元数据服务(IMDS)?
在宿主上使用 nftables 配置防火墙:对于来自沙盒网桥 br0 的流量,只放行 NDP、ping、DHCP 和 DNS,其余丢弃;对于来自专用 ENI 的流量,只放行 NDP/RA 和 DHCPv4 回包;在 forward 链中丢弃沙盒访问 IMDS 地址(169.254.169.254 和 fd00:ec2::254)的流量。这样沙盒无法访问宿主本机(包括 prefix::1)和 IMDS。
为什么需要配置策略路由?不配置会有什么问题?
因为宿主有两个 ENI,main 路由表中 eth0 的默认路由优先级更高。如果不配置策略路由,沙盒回复外部访问的报文会按 main 表从 eth0 发出,但源地址属于 eth1 的委派前缀,会被源/目标检查丢弃,导致外部连接超时。解决方法是为源自 /80 的流量建立独立路由表(表 100),让其默认路由经 eth1 发出。
沙盒之间默认可以互访吗?如果需要隔离不同租户的沙盒应该怎么做?
默认情况下沙盒之间可以直接互访,因为 RA 通告的 /80 和 IPv4 /24 在沙盒中都是直连网段,流量在网桥内二层转发。如果需要隔离不同租户的沙盒,需要在二层和三层同时隔离:为 TAP 设备开启端口隔离(bridge link set dev $TAP isolated on),并在防火墙 forward 链中添加规则丢弃从 br0 进入且从 br0 发出的流量(iifname "$BR" oifname "$BR" counter drop)。
这个方案支持规模化部署大量沙盒吗?瓶颈在哪里?
支持。一个 /80 前缀包含 2^48 个地址,创建沙盒只是在本地创建 TAP 设备并完成一次 DHCP,瓶颈在于宿主机的 CPU 和内存,而不是地址数量。如果需要更多地址,可以为 ENI 委派更多的 /80 前缀,并相应增加 br0 地址、dnsmasq 地址池、策略路由规则和防火墙放行规则。