容器网络安全与隔离:从 CNI 到服务网格

深入解析容器网络隔离模型(bridge/host/overlay/macvlan)与网络命名空间原理,拆解 Docker 的 iptables/nftables 规则实现,剖析常见容器网络攻击面,并给出零信任容器网络(Calico/Cilium NetworkPolicy)、加密流量与 mTLS、服务网格(Istio/Linkerd)的落地路径。

前置阅读:建议先阅读 Docker Volume 与网络 与 Rootless 模式与容器安全深度解析。

关键概念:容器的"网络隔离"本质是 Linux 网络命名空间(netns) 与 iptables/nftables 规则的组合——每个容器拥有独立的协议栈视图,宿主机通过 veth pair 和 NAT 把这些视图桥接起来。生产环境的安全目标,则是把"共享内核的扁平网络"收敛为"默认拒绝、按策略放行"的零信任网络。


1. 容器网络模型回顾

1.1 五种基础网络模式

Docker 提供 bridge / host / none / macvlan / overlay 五种内置网络模型,隔离强度与灵活度各不相同:

模式隔离级别是否跨主机典型用途安全性
none完全隔离否无网络的后台任务、安全沙箱最高
bridge(默认)每个容器独立 netns否(NAT 出网)单机多容器中
host共享宿主网络栈否高性能网络工具、legacy 应用最低
macvlan独立 netns + 独立 MAC/IP可(同 L2 域)容器直接暴露在物理网络低(依赖 VLAN 隔离)
overlay独立 netns + VXLAN 隧道是Swarm/K8s 跨主机通信中(默认明文隧道)

一句话:隔离强度与运维便利成反比——host 最省事但等于放弃网络隔离,overlay 支持跨主机但隧道默认不加密。

1.2 默认 bridge 网络如何工作

容器 eth0 (172.17.0.2) ──veth pair──> docker0 网桥 (172.17.0.1)
                                         │
                         iptables MASQUERADE ──> 物理网卡 ──> 外部网络
                         DNAT (端口发布)   <── 外部流量 <── 172.17.0.2:80

创建容器时 Docker 会自动:创建 veth pair、把一端塞进容器 netns、另一端挂到 docker0 网桥、写 iptables 规则(隔离容器间、做地址转换与端口发布)。

# 查看默认 bridge 的子网与网桥地址
docker network inspect bridge | jq '.[0].IPAM'

# 查看 veth pair(宿主机侧的名字形如 vethXXXXXX)
ip link | grep veth

# 查看某个容器的网络模式
docker inspect -f '{{.HostConfig.NetworkMode}}' myapp

2. iptables / nftables:Docker 网络的安全核心

2.1 Docker 写入了哪些规则

Docker 在宿主机 iptables 中维护两个关键链:DOCKER(端口发布/DNAT)与 DOCKER-USER(供用户自定义规则,放在最前优先匹配)。

# 查看 Docker 生成的 NAT 规则
iptables -t nat -L DOCKER -n -v

# 查看 DOCKER-USER 链(用户自定义安全规则的推荐位置)
iptables -L DOCKER-USER -n -v
端口发布的数据流(宿主机 8080 -> 容器 80):
  1. PREROUTING  -> DOCKER 链做 DNAT:目标改写为容器 IP 172.17.0.2:80
  2. FORWARD     -> 放行 docker0 与物理网卡间的转发
  3. POSTROUTING -> MASQUERADE:容器出网时源地址改写为宿主出口 IP

2.2 用 DOCKER-USER 加自己的安全规则

Docker 的规则只负责"连通",安全策略要自己加。DOCKER-USER 链在 Docker 规则之前被评估,适合做白名单:

# 只允许 10.0.0.0/8 访问暴露的 8080 端口(其余全部拒绝)
iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/8 -p tcp --dport 8080 -j ACCEPT
iptables -I DOCKER-USER -i eth0 -p tcp --dport 8080 -j DROP

# 阻止容器访问宿主机上的 169.254.169.254(云元数据服务,防 SSRF)
iptables -I DOCKER-USER -d 169.254.169.254 -j DROP

2.3 iptables 与 nftables 的选择

Docker 默认通过 iptables-legacy 或 iptables-nft 兼容层写规则。较新版本的 Docker 引擎(27.x 起)在实验模式下支持原生 nftables 后端:

{
  "iptables": true,
  "experimental": true,
  "network": { "iptables-backend": "nftables" }
}

一句话:生产环境不要直接动 DOCKER 链——用 DOCKER-USER 链追加自己的规则,重启 Docker 后自定义规则也不会被清掉。


3. 网络命名空间隔离

3.1 netns + veth:一个容器的网络全景

# 查看所有网络命名空间(容器进程的 netns 在 /var/run/docker/netns/ 下)
lsns -t net

# 进入容器网络命名空间执行 ip 命令(利用 nsenter,与 nsenter 等价)
nsenter -t $(docker inspect -f '{{.State.Pid}}' myapp) -n ip addr

# 查看 netns 中路由表
nsenter -t $(docker inspect -f '{{.State.Pid}}' myapp) -n ip route
每个容器 netns 隔离以下内容:
  - 网卡 / IP / 路由表        (网络层)
  - iptables/nftables 规则     (包过滤,容器内默认空)
  - 邻居表 ARP / 连接跟踪      (L2/L4 状态)
  - 但不隔离 socket 中的抽象命名空间(UNIX socket 需配权限)

隔离的意义:容器 A 抓不到容器 B 的包,
  攻击者拿到容器 root 也无法直接嗅探兄弟容器流量。

3.2 共享 netns 的两种常见形态

  • Kubernetes Pod:pause 容器持有 netns,业务容器共享之(--net=container:pause),所以 Pod 内容器共享 localhost。
  • Docker 边车模式:docker run --network container:main 让辅助容器复用主容器的网络栈。
# 让 log-agent 复用 web 容器的网络栈
docker run -d --network container:web --name log-agent logshipper:1.0

# 查看两个容器是否共享 netns(Inode 相同即共享)
lsns -t net -o NS,NPROCS,COMMAND | grep -E "web|log-agent"

4. 常见容器网络攻击面

4.1 攻击面清单

攻击向量成因缓解手段
端口暴露过宽-p 0.0.0.0:port 把服务暴露全网只绑定 127.0.0.1 或按需白名单
横向移动bridge 上容器间默认互通NetworkPolicy / 自定义 iptables
调试端口裸奔9090/2375/2376 等未加密不暴露 dockerd,走 TLS 或 ssh 隧道
元数据 SSRF容器可访问云 metadata IPDOCKER-USER 链 DROP 169.254.169.254
host 网络误用容器与宿主共享 netns禁止 host 模式(准入控制)
DNS 劫持 / rebinding容器内 DNS 与外部服务固定 DNS、校验 SNI
内网扫描容器被攻破后做资产探测默认拒绝的出站 egress 策略

4.2 一次真实的横向移动路径

1. 攻击者拿到 web 容器 RCE(例如旧版本 ImageMagick 漏洞)
2. web 容器扫描 172.18.0.0/16,发现 db 容器开放 5432
3. 因 bridge 网络默认互通,攻击者直连 db:5432
4. db 密码弱口令 -> 数据泄露

防御关键:
  - 默认禁止同网络容器互通(zero-trust)
  - db 只对 web 开放 5432,不对全网开放
  - 出站默认 deny

5. 零信任容器网络:NetworkPolicy

5.1 Kubernetes NetworkPolicy 与 CNI

Kubernetes 原生 NetworkPolicy 只定义意图,落地靠 CNI 插件。两大主流实现:

CNI数据面优势劣势
Calicoiptables/eBPF纯三层、与云环境兼容性好、Felix 成熟复杂拓扑下规则数多
CiliumeBPF高性能、可观测性、L7 策略与透明加密依赖内核(5.8+ 体验佳)

5.2 Calico 网络策略示例

# 默认拒绝:该命名空间下没有命中策略的流量一律丢弃
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: payments
spec:
  selector: all()
  types:
    - Ingress
    - Egress
# 只允许 frontend 访问 payments 服务的 8080
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-payments
  namespace: payments
spec:
  selector: app == "payments"
  types: [Ingress]
  ingress:
    - action: Allow
      source:
        selector: app == "frontend"
      destination:
        ports:
          - 8080

5.3 Cilium 网络策略与可观测性

# CiliumNetworkPolicy:L3/L4 白名单
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-server
  namespace: api
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: nginx-ingress
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP

Cilium 的优势在于同一数据面还能做 L7(HTTP 方法、路径)策略与流日志:

# 查看 Cilium 状态与监控面板
cilium status
cilium monitor --type drop

# Hubble 流日志(已随 Cilium 安装)
hubble observe --from-namespace api --port 8080

一句话:NetworkPolicy 是零信任落地的第一步——先全局默认拒绝,再按"调用方 → 端口"逐步放开,横向移动就没了通道。


6. 加密流量与 mTLS

6.1 传输加密:WireGuard 与 IPsec

容器隧道默认明文(overlay VXLAN、Calico 默认 IPIP),跨宿主机流量可能被物理网络嗅探:

# Calico 用 WireGuard 加密节点间流量(v3.15+)
calicoctl patch felixconfiguration default \
  --patch='{"spec":{"wireguardEnabled":true}}'

# 校验节点间是否走 WireGuard 隧道
ip link show wireguard.cali
方案加密方式密钥管理性能开销适用
Calico WireGuard每节点 WireGuard 隧道自动生成/轮换低节点间加密
Calico IPsecESP 隧道依赖密钥库中合规审计要求
Cilium Transparent EncryptionWireGuard/IPsec 透明自动低K8s 全链路

6.2 mTLS:服务到服务之间也加密互认

传输加密只防"偷听",不防"伪装"。**mTLS(双向 TLS)**让每个服务携带证书,双方互验身份后再建连。三条落地路线:

  • 服务网格(Istio/Linkerd):边车自动签发、轮换证书,应用零改动;
  • Cilium:encryption: type: wireguard 直接对 Pod 流量加密,配合 SPIFFE 身份;
  • 应用层:gRPC/gRPC-Web 用 Java/Go 客户端库手工配置 CA。
# Istio 启用全网格 mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT
# 验证流量已加密(从 sidecar 抓包应看到 TLS 握手而非明文 HTTP)
kubectl exec -it frontend-xxx -c istio-proxy -- \
  tcpdump -i eth0 -A 'tcp port 8080 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

7. 服务网格:从网络策略到应用层安全

7.1 为什么需要服务网格

NetworkPolicy 管到 L3/L4,但业务安全的很多需求在 L7:限流、熔断、灰度、审计、按请求身份授权。服务网格在 Pod 边注入 sidecar 代理,接管南北/东西向流量。

能力IstioLinkerdCilium
数据面Envoy自研 Rust proxyeBPF + Envoy
mTLS自动自动自动
L7 策略强(VirtualService)中强(Cilium L7)
性能开销中(Envoy 较重)低最低
上手复杂度高低中

7.2 Istio 最小启用

# 安装 Istio
istioctl install --set profile=default -y

# 给命名空间注入边车
kubectl label namespace payments istio-injection=enabled

# 强制全链路 mTLS(上文 PeerAuthentication)
kubectl apply -f mtls-default.yaml

7.3 渐进式安全:按阶段收紧

阶段一:全链路 mTLS(机密性)      —— 证书自动轮换,应用无感
阶段二:AuthorizationPolicy         —— 按身份/方法授权,替代网络 ACL
阶段三:审计与可观测               —— 请求级 trace 与审计日志

一句话:NetworkPolicy 解决"谁能连通",服务网格解决"谁被允许调用、调用是否被加密与审计"——两者是零信任的两个层次,不是二选一。


8. 网络排查与加固清单

8.1 排查工具箱

# 容器内网络连通性(推荐带 nmap/curl 的排障镜像)
docker run -it --network container:web nicolaka/netshoot

# 看容器端口映射是否生效
docker port web

# 检查 iptables 中是否有冲突规则(容器不通时的第一排查点)
iptables -S | grep -i docker

# 抓容器流量(-c 用容器名,nc 输出 pcap 到宿主机)
docker run -it --privileged --pid=host nicolaka/netshoot \
  sh -c "tcpdump -i any -w /tmp/cap.pcap && docker cp /tmp/cap.pcap ."

8.2 生产加固清单

□ 默认用 bridge/overlay,禁用 host 网络(用准入策略强制)
□ 端口只绑 127.0.0.1 或按来源白名单(DOCKER-USER 链)
□ DOCKER-USER 链 DROP 云元数据地址 169.254.169.254
□ 节点间流量启用 WireGuard/IPsec 加密
□ K8s 环境先做默认拒绝 NetworkPolicy 再逐步放行
□ 敏感服务(db/redis)不与公网服务同网络
□ 服务间用 mTLS,关键路径接入服务网格审计
□ 定期用 nmap/trivy 网络栈扫描与规则 review

9. 总结

层次要解决的问题核心工具/机制落地优先级
隔离容器间互不可见netns + veth + bridge/overlayP0
出网/暴露端口与 NAT 可管可控iptables DOCKER-USER / -p 127.0.0.1P0
横向移动默认拒绝连通NetworkPolicy(Calico/Cilium)P0
偷听节点间与 Pod 间加密WireGuard / IPsec / 透明加密P1
伪装身份互认mTLS(服务网格/Cilium)P1
审计谁调用了谁服务网格 + 流日志(Hubble)P2

容器网络的本质是"内核隔离 + 规则放行"。安全上记住一条主线:默认拒绝一切,再按最小白名单逐步放开——先把 netns 和 iptables 规则看得一清二楚,再用 NetworkPolicy 锁横向移动,最后用加密与服务网格处理传输与身份。当你能在一张网络拓扑图上标出"哪些流量被允许、哪些被加密、哪些被审计",容器网络就从"能用"变成了"可信"。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「docker」更多文章

  1. Docker 容器排障与调试实战:退出码、OOM、exec 与调试工具链
  2. Docker 镜像供应链安全:SBOM、签名、扫描与 SLSA 合规
  3. Docker 容器监控与日志实践:cgroups 资源限制、Prometheus 与日志驱动