Windows Server容器化已经不是新鲜事,但真正上生产时,网络配置这块翻车的人依然不少。问题大多集中在一点:容器网络和主机网络的安全边界到底怎么划。很多人直接把宿主机的NSG规则套用到容器上,结果要么端口全开,要么容器间通信完全中断。核心矛盾在于,Windows容器的网络模式决定了流量路径,而NSG的生效位置必须匹配这个路径。

Windows容器主要有五种网络驱动:NAT、Transparent、Overlay、L2Bridge、L2Tunnel。生产环境里真正高频使用的是NAT和Transparent两种,Overlay在Kubernetes场景下也会涉及。每种模式下,数据包从容器发出到抵达物理网络设备的过程完全不同,NSG该挂载在哪里、规则该怎么写,差别巨大。

NAT模式下的NSG配置要点

NAT模式是Windows容器默认的网络模式。容器会获得一个由内部虚拟交换机分配的私有IP,通常是172.16.0.0/12或192.168.0.0/16范围内的地址。容器访问外部网络时,通过宿主机IP做源地址转换。这意味着外部流量看到的源IP永远是宿主机IP,而不是容器IP。

在这个前提下,如果你需要从外部访问容器提供的服务,必须做端口映射。使用docker run -p或Podman的端口绑定参数,将宿主机端口映射到容器端口。此时NSG规则应该应用在宿主机网络接口上,目标端口填写宿主机映射端口,而不是容器内部端口。

举个例子,容器内运行IIS监听80端口,映射到宿主机8080端口。NSG入站规则应该允许目标端口8080,而不是80。很多管理员在这里犯错,在NSG里开放了80端口却发现外部根本访问不到容器,原因就是流量到达宿主机时目标端口是8080,80端口根本没有监听。

# 正确的端口映射命令
docker run -d -p 8080:80 --name iis-container mcr.microsoft.com/windows/servercore/iis

容器间通信在NAT模式下走的是内部虚拟交换机,流量不经过宿主机物理网卡,因此宿主机层面的NSG无法管控容器间的东西向流量。如果需要隔离,必须在容器内部使用Windows防火墙,或者在Hyper-V虚拟交换机层面配置端口ACL。这个细节在安全审计时经常被忽略,导致合规风险。

Transparent模式下的NSG配置

Transparent模式直接把容器挂载到物理网络,容器通过DHCP或静态配置获得与宿主机同网段的IP地址。这种模式下容器在网络层面完全等同于一台独立物理机,流量直接经过物理交换机,不经过宿主机NAT转换。

NSG的配置位置在这里出现了分支。如果你使用Azure虚拟机运行Windows容器,NSG可以关联到虚拟机网卡,也可以关联到子网。Transparent模式下的容器IP与宿主机IP在同一子网,因此关联到子网的NSG规则会同时作用于宿主机和容器。这意味着你可以用同一套NSG策略管理所有流量,但必须精确区分哪些规则针对宿主机,哪些针对容器。

一个常见的生产实践是:在NSG规则中使用源IP或目标IP来区分流量范围。例如,数据库容器IP为10.0.1.50,只允许来自应用容器10.0.1.30的1433端口访问。这条规则直接写在子网NSG上,目标IP填10.0.1.50,端口1433,源IP填10.0.1.30。这种方式比在容器内部配置防火墙更易于集中管理和审计。

但Transparent模式有个坑:容器的网络堆栈直接暴露在物理网络中,如果容器本身存在漏洞,攻击面比NAT模式大得多。此时NSG必须承担起第一道防线的作用,不能只依赖容器内部防护。建议在子网NSG上对每个容器IP实施最小权限原则,只开放业务必需的端口,默认拒绝所有其他流量。

Overlay模式与Kubernetes场景

在Kubernetes集群中运行Windows容器时,网络插件通常使用Overlay模式,例如Flannel的VXLAN后端或Calico的IPIP模式。容器获得一个Overlay网络中的IP,Pod间通信通过隧道封装,底层物理网络只看到节点之间的封装流量。

这种场景下NSG的配置思路完全不同。物理网络设备看到的都是节点IP之间的UDP封装流量,无法识别具体Pod的IP和端口。因此NSG策略应该聚焦在节点层面:允许集群节点之间的VXLAN端口(通常是4789)通信,允许节点到外部服务的出站流量,严格限制从外部直接访问节点的端口。

对于需要暴露到集群外部的服务,Kubernetes通过NodePort或LoadBalancer类型的Service实现。NodePort在节点上开放一个高端口(30000-32767),NSG需要允许这个端口的入站流量。LoadBalancer则依赖云提供商的负载均衡器,NSG规则应配置在负载均衡器后端池所在的子网上,允许来自负载均衡器健康探测和客户端访问的流量。

# 示例:允许NodePort范围的入站流量
# Azure NSG规则
# 优先级: 200
# 源: Internet或特定IP范围
# 目标: 节点子网
# 目标端口: 30000-32767
# 协议: TCP
# 操作: 允许

Windows节点本身还需要额外注意一些端口。Kubelet API使用10250端口,Windows节点加入域时可能需要LDAP的389和636端口,SMB文件共享需要445端口。这些端口在NSG上必须对管理网络开放,但不能暴露到公网。

Windows防火墙与NSG的协同

很多人认为有了NSG就可以关闭Windows防火墙,这是错误认知。NSG工作在Azure或云平台的软件定义网络层,Windows防火墙工作在操作系统层,两者是纵深防御的关系。特别是NAT模式下容器间流量不经过物理网卡,NSG完全看不见,此时Windows防火墙是唯一能控制容器间东西向流量的手段。

Windows容器的防火墙配置可以通过Dockerfile在构建镜像时预设规则,也可以通过容器运行时的启动脚本动态配置。推荐的做法是使用Group Policy或Desired State Configuration在宿主机层面统一管理防火墙策略,然后让容器继承或适配这些策略。

# 在Dockerfile中预设防火墙规则
RUN netsh advfirewall firewall add rule name="Allow-App-Port" dir=in action=allow protocol=TCP localport=8080

对于Transparent模式,容器拥有独立IP,Windows防火墙可以基于IP地址精确控制。建议在容器启动脚本中获取自身IP,然后动态添加仅允许特定源IP访问的防火墙规则,与子网NSG形成双重防护。

NSG规则设计与最佳实践

无论使用哪种网络模式,NSG规则的设计都应遵循几个基本原则。第一,优先级规划要合理。把最常用的允许规则放在高优先级(数字小),拒绝规则放在低优先级,但默认拒绝规则应放在最后。第二,使用服务标签和应用安全组简化管理。Azure的服务标签如VirtualNetwork、AzureLoadBalancer可以避免硬编码IP地址,应用安全组可以将多个容器或虚拟机编组,在NSG规则中直接引用。

第三,日志和监控必须到位。NSG的流日志能记录每条规则的命中情况,这是排查网络问题和安全事件的基础。Windows容器的网络诊断相对复杂,建议在宿主机上启用ETW跟踪,结合NSG流日志形成完整的流量视图。

第四,定期审计规则。容器环境变化快,今天开放的端口明天可能就不再使用。过期的允许规则是安全风险,应建立定期审查机制,结合实际流量日志清理无用规则。

常见问题与排错思路

容器网络不通时,先别急着改NSG。按这个顺序排查:确认容器网络模式是否正确,确认端口映射或IP分配是否生效,在宿主机上测试目标端口连通性,检查Windows防火墙日志,最后再看NSG流日志。大部分问题其实出在容器网络配置本身,而不是NSG。

一个典型场景:NAT模式下容器可以访问外网,但外网无法访问容器映射的端口。检查docker port命令输出,确认映射关系是否正确。然后检查宿主机上netstat -ano是否在监听映射端口。如果宿主机监听正常但外部仍不通,再检查NSG是否允许该端口。如果宿主机都没有监听,问题一定在容器运行时或应用本身。

另一个高频问题是Transparent模式下容器获取不到IP或IP冲突。这通常与DHCP服务器配置或IP地址池耗尽有关,与NSG无关。但一旦IP分配出问题,之前基于IP的NSG规则就会失效,需要同步更新。

总结

Windows Server容器化部署的NSG配置没有一刀切的方案。NAT模式下重点管好宿主机端口映射,Transparent模式下用IP粒度规则精确控制,Overlay模式下聚焦节点间隧道端口和NodePort范围。Windows防火墙与NSG必须协同工作,不能互相替代。规则设计遵循最小权限原则,配合日志审计形成闭环。理解每种网络模式的流量路径,是写出正确NSG规则的前提。