Docker网络与安全

📌 本文由 4 篇相关文章智能合并整理而成

Docker 安全最佳实践

Docker 安全最佳实践

安全原则

Docker 安全的核心原则是最小权限——容器不应该拥有不需要的权限,不应该暴露不需要的端口,不应该使用不需要的系统调用。

镜像安全

1. 使用最小化基础镜像

# ❌ 大体积、多漏洞
FROM ubuntu:22.04

# ✅ 更小更安全
FROM alpine:3.19
FROM gcr.io/distroless/base:latest
FROM scratch

2. 使用指定版本

# ❌ 不可控的 latest
FROM node:latest

# ✅ 固定版本
FROM node:18.19.0-slim

3. 定期更新和扫描

# 更新基础镜像
docker pull ubuntu:22.04

# 扫描漏洞
trivy image myapp:latest
docker scout quickview myapp:latest

容器运行时安全

1. 以非 root 用户运行

# Dockerfile 中
FROM node:18-slim
RUN useradd -m -u 1000 appuser
USER appuser
# 运行时指定
docker run --user 1000:1000 myapp

2. 只读根文件系统

docker run --read-only myapp

# 如果需要临时写入
docker run --read-only --tmpfs /tmp:rw,noexec,nosuid myapp

3. 删除不需要的权限

# 删除所有非必需能力
docker run \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  myapp

# 常见安全能力
--security-opt=no-new-privileges:true
--security-opt seccomp=/path/to/seccomp-profile.json
--security-opt apparmor=myapp-profile

4. 资源限制

docker run \
  --memory=512m \
  --cpus=0.5 \
  --pids-limit=100 \
  --ulimit nofile=1024:2048 \
  myapp

网络安全

1. 最小化端口暴露

# ❌ 暴露所有端口
docker run -p 80:80 -p 8080:8080 -p 3000:3000 myapp

# ✅ 只暴露必要端口
docker run -p 80:80 myapp

2. 使用内部网络

version: '3'
services:
  db:
    image: postgres:15
    # 不对外暴露端口
    expose:
      - "5432"
    networks:
      - internal

  app:
    image: myapp
    ports:
      - "80:80"
    networks:
      - internal

networks:
  internal:
    internal: true  # 不能访问外部网络

3. 网络隔离

# 自定义网络隔离
docker network create --internal secure-net

# 只加入安全网络
docker run --network secure-net myapp

配置安全

1. 敏感信息管理

# ❌ 使用环境变量传递密钥
docker run -e DB_PASSWORD=secret123 myapp

# ✅ 使用 Docker Secrets
echo "secret123" | docker secret create db_password -
docker service create --secret db_password myapp

# ✅ 使用 BuildKit secrets
docker build --secret id=db_password,src=./db_password.txt -t myapp .

2. 配置验证

# 检查 daemon 配置
docker info | grep -i "Security"

# 检查容器配置
docker inspect  | jq '.[].HostConfig'

Docker Daemon 安全

daemon.json 安全配置

{
  "icc": false,
  "live-restore": true,
  "userland-proxy": false,
  "userns-remap": "default",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "authorization-plugins": [],
  "tls": true,
  "tlsverify": true,
  "tlscacert": "/etc/docker/ca.pem",
  "tlscert": "/etc/docker/server-cert.pem",
  "tlskey": "/etc/docker/server-key.pem"
}

审计和监控

日志审计

# 审计 Docker 事件
docker events --filter 'type=container' --filter 'event=kill' \
  > /var/log/docker-events.log &

# 监控容器变化
docker diff 

运行时安全工具

# Falco - 容器运行时安全
docker run -d \
  --name falco \
  --privileged \
  -v /var/run/docker.sock:/host/var/run/docker.sock \
  falcosecurity/falco

安全清单

  • [ ] 使用最小化基础镜像(alpine/distroless)
  • [ ] 固定镜像版本标签,不使用 latest
  • [ ] 以非 root 用户运行容器
  • [ ] 使用只读根文件系统
  • [ ] 删除不必要的 Linux Capabilities
  • [ ] 限制资源(CPU、内存、PIDs)
  • [ ] 不暴露不需要的端口
  • [ ] 使用内部网络隔离敏感服务
  • [ ] 使用 Secret 管理敏感信息
  • [ ] 定期扫描镜像漏洞
  • [ ] 使用镜像签名验证
  • [ ] 配置 TLS 加密 Docker daemon 通信

面试要点

  1. Docker 安全的核心理念是最小权限原则
  2. 非 root 用户 + 只读文件系统是最基本的安全配置
  3. Capabilities 是 Linux 容器安全的关键控制点
  4. Secret 管理(而非环境变量)是敏感信息的最佳实践
  5. 定期扫描和更新镜像比安全配置更重要

面试官常问:如果发现一个容器被入侵了,你如何分析和处理?


Kata Containers 与 gVisor

Kata Containers 与 gVisor

传统容器的安全隐患

传统容器共享宿主机的内核,这意味着容器逃逸(Container Escape)攻击可能会影响整个宿主机。

传统容器
[App A]  [App B]  [App C]     共享内核
[       Linux Kernel        ]
[        Hardware            ]

Kata Containers

概述

Kata Containers 使用轻量级虚拟机替代传统的容器沙箱,每个容器运行在独立的 VM 中。

Kata Containers
[App A]       [App B]        每个容器有自己的内核
[Guest Kernel][Guest Kernel]
[  VM A  ]    [  VM B  ]     轻量级虚拟机
[       Hypervisor          ]
[       Hardware            ]

特点

  • 更高的隔离性:每个容器有自己的内核,即使容器逃逸也无法影响宿主机
  • 兼容性:兼容 OCI 标准,可以用 Docker CLI 直接启动
  • 性能接近原生:使用 KVM 虚拟化,开销小

安装和配置

# 安装 Kata Containers
sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/katacontainers:/releases:/x86_64:/master/xUbuntu_$(lsb_release -rs)/ /' > /etc/apt/sources.list.d/kata.list"
sudo apt-get update && sudo apt-get install -y kata-runtime kata-proxy kata-shim

# 配置 Docker 使用 Kata
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <
{
  "runtimes": {
    "kata": {
      "path": "/usr/bin/kata-runtime"
    }
  }
}
EOF

# 使用 Kata 运行容器
docker run --runtime kata -it ubuntu uname -r

gVisor

概述

gVisor 是 Google 开源的容器沙箱,在用户态实现了一个内核层(Sentry)。

gVisor
[App A]          [App B]
[Sentry Kernel]  [Sentry Kernel]   用户态内核
[       Host Linux Kernel        ]
[           Hardware             ]

特点

  • 应用级沙箱:拦截系统调用,在用户态处理
  • 兼容性好:支持大多数 Linux 系统调用
  • 启动快:比 Kata Containers 启动更快(无需启动 VM)

安装和配置

# 安装 gVisor
wget https://storage.googleapis.com/gvisor/releases/release/latest/runsc
chmod +x runsc
sudo mv runsc /usr/local/bin/

# 配置 Docker
sudo tee /etc/docker/daemon.json <
{
  "runtimes": {
    "runsc": {
      "path": "/usr/local/bin/runsc"
    }
  }
}
EOF

# 使用 gVisor 运行容器
docker run --runtime runsc -it ubuntu uname -r

对比分析

特性 Kata Containers gVisor 传统 Docker
隔离级别 VM 级别 应用沙箱 内核共享
安全等级 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
性能 ~95% 原生 ~70-80% 原生 ~99% 原生
启动速度 较慢(秒级) 快(毫秒级) 最快
兼容性 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
系统调用 完整 部分 完整
适用场景 多租户、高安全 多租户、边界安全 通用

性能对比场景

# 测试网络性能
docker run --runtime runsc alpine wget -O /dev/null https://example.com

# 测试 I/O
docker run --runtime kata alpine dd if=/dev/zero of=/tmp/test bs=1M count=100

适用场景

使用 Kata Containers

  • 多租户环境(SaaS、PaaS)
  • 需要极高隔离性的场景
  • 不确定信任的第三方镜像

使用 gVisor

  • 同样需要隔离但更重视启动速度
  • 对性能要求不是极高
  • 不需要特殊内核模块的场景

面试要点

  1. 传统容器共享宿主机内核,这是安全风险的根源
  2. Kata Containers 使用轻量级 VM 提供硬件级隔离
  3. gVisor 在用户态实现内核,提供应用级沙箱
  4. 隔离性增强必然伴随性能损失
  5. 选择取决于安全需求 vs 性能需求的权衡

面试官常问:Kata Containers 和 gVisor 的区别是什么?你们在什么场景用了这些技术?


网络不通排查

网络不通排查

Docker 网络问题分类

Docker 网络问题一般分为三类:

  1. 容器访问外部网络(例如容器不能访问互联网)
  2. 外部访问容器(例如宿主机浏览器不能访问容器服务)
  3. 容器间通信(例如 app 容器不能连接数据库容器)

排查工具

# 进入容器交互式排查
docker exec -it  /bin/bash

# 容器内常用命令(如果不存在则先安装)
docker exec  apt-get update && apt-get install -y iputils-ping curl netcat

场景一:容器无法访问外部网络

排查步骤

# 1. 检查 DNS
docker exec  cat /etc/resolv.conf
docker exec  nslookup google.com

# 2. 测试公网连通性
docker exec  ping 8.8.8.8
docker exec  curl -v https://google.com

# 3. 检查 iptables 规则
iptables -L -n -t nat | grep -i docker

# 4. 检查网络模式
docker inspect  | jq '.[].NetworkSettings'

常见原因

原因 解决方法
DNS 配置错误 修改 daemon.json 的 dns 配置
iptables 转发被禁用 sysctl net.ipv4.ip_forward=1
公司代理限制 传递 HTTP_PROXY 环境变量
MTU 问题 调整 Docker 网络 MTU 值
防火墙规则 检查宿主机的 ufw/iptables

场景二:外部无法访问容器服务

排查步骤

# 1. 确认端口映射
docker port 
docker inspect  | jq '.[].NetworkSettings.Ports'

# 2. 确认容器内服务在监听
docker exec  netstat -tulpn
docker exec  ss -tulpn

# 3. 在容器内测试本地访问
docker exec  curl -v http://localhost:8080/health

# 4. 在宿主机上测试
curl -v http://localhost:<映射端口>/health

# 5. 检查防火墙
sudo ufw status
sudo iptables -L -n | grep 8080

常见原因

# 容器内服务只监听了 127.0.0.1
# ❌ 错误
docker exec  netstat -tulpn | grep 8080
# tcp  0  0  127.0.0.1:8080  0.0.0.0:*  LISTEN

# ✅ 正确应该监听 0.0.0.0
# tcp  0  0  0.0.0.0:8080  0.0.0.0:*  LISTEN

场景三:容器间无法通信

排查步骤

# 1. 确认是否在同一网络
docker network ls
docker inspect  | jq '.[].NetworkSettings.Networks'

# 2. 使用容器名通信
docker exec app ping db
docker exec app curl http://db:3306

# 3. 使用 IP 通信
docker exec app ping 

# 4. 检查网络隔离
docker network inspect 

连通性测试脚本

#!/bin/bash
# test_connectivity.sh

CONTAINER_A=$1
CONTAINER_B=$2

echo "Testing connectivity from $CONTAINER_A to $CONTAINER_B..."

# 获取 IP
IP_B=$(docker inspect $CONTAINER_B -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}')

# 测试 DNS 解析
docker exec $CONTAINER_A ping -c 2 $CONTAINER_B && echo "✅ DNS OK" || echo "❌ DNS Failed"

# 测试 IP 连通性
docker exec $CONTAINER_A ping -c 2 $IP_B && echo "✅ IP OK" || echo "❌ IP Failed"

# 快速端口测试
docker exec $CONTAINER_A nc -zv $CONTAINER_B 3306 && echo "✅ Port 3306 open" || echo "❌ Port 3306 closed"

网络调试容器

# 使用 nicolaka/netshoot 调试容器
docker run -it --rm --network container: nicolaka/netshoot

# netshoot 内置了 curl、tcpdump、iftop、nmap 等强大工具
# 在这个容器内可以调试 target_container 的网络

宿主机网络排查

# 检查 iptables
iptables -t nat -L -n
iptables -t filter -L -n

# 检查 Docker 网桥
ip addr show docker0
brctl show docker0

# 检查网络接口
ip link show

面试要点

  1. 网络排查路径:容器内 → 宿主机 → 外部
  2. 最常见的问题:服务监听 127.0.0.1、防火墙规则、不在同一网桥
  3. netshoot 容器是调试的瑞士军刀
  4. 区分 DNS 问题和网络连通性问题
  5. Docker 默认 bridge 网络不支持容器名解析,自定义网络支持

面试官常问:两个容器之间网络不通,你如何一步步排查?自定义网络和默认 bridge 有什么区别?


Docker 安全挑战

Docker 安全挑战

什么是容器安全挑战

Docker 容器共享宿主机的操作系统内核,这种设计带来高效的资源利用,但也引入了独特的安全风险。”容器不是轻量级虚拟机”——这句话的核心含义是,容器并没有虚拟机的硬件隔离屏障。

核心安全挑战

1. 共享内核风险

容器与宿主机共享内核,这意味着:
– 容器中的内核漏洞可能影响宿主机
– 例如:CVE-2016-5195(脏牛)可以在容器中提权到宿主机
– 如果存在内核漏洞,攻击者可以从容器内部逃逸到宿主机

2. 默认 root 用户

默认情况下,容器内是 root 用户。容器 root 在宿主机上仍有部分权限,可能被利用。

3. 权限滥用

# 不安全的实践
docker run --privileged myapp        # 给予几乎所有权限
docker run --cap-add=ALL myapp       # 添加所有 cap

过多的权限增加了攻击面。

4. 镜像安全

# 基础镜像可能包含漏洞
docker pull nginx:latest
# 该镜像可能包含已知 CVE

基础镜像中的漏洞会传递给所有使用它的容器。

历史安全事件

年份 事件 影响
2019 runC 漏洞(CVE-2019-5736) 容器逃逸到宿主机
2020 Docker API 未授权访问 数据泄露、挖矿
2021 供应链攻击(镜像投毒) 恶意代码传播
2022 CVE-2022-0492 cgroup v1 提权

攻击面分析

从内到外(容器逃逸)

攻击者 → 容器 → 内核漏洞/配置漏洞 → 宿主机

常见逃逸路径:
– 内核漏洞利用
– –privileged 滥用
– Docker socket 挂载
– mount 系统调用滥用

从外到内(外部攻击)

外部 → 暴露端口 → 应用漏洞 → 容器

常见攻击路径:
– Web 应用漏洞
– 弱密码/默认凭据
– 未打补丁的软件
– API 未授权访问

安全分层模型

┌─────────────────────────────┐
│ 第 6 层:访问控制(RBAC)    │
│ 第 5 层:运行时安全          │
│ 第 4 层:网络安全            │
│ 第 3 层:镜像安全            │
│ 第 2 层:守护进程安全        │
│ 第 1 层:内核安全            │
└─────────────────────────────┘

各层防护措施

  • 第 1 层(内核安全):保持内核更新,启用 seccomp、AppArmor/SELinux
  • 第 2 层(守护进程):限制 Docker API 访问,使用 TLS 加密通信
  • 第 3 层(镜像安全):镜像签名和验证,漏洞扫描
  • 第 4 层(网络安全):网络分段,防火墙规则
  • 第 5 层(运行时):非 root 用户,只读文件系统
  • 第 6 层(访问控制):RBAC 权限控制,审计日志

常见安全误区

误区:容器 = 虚拟机
容器共享内核,隔离性弱于虚拟机。

误区:Alpine 镜像绝对安全
减小了攻击面,但 musl libc 也有 CVE。

误区:Docker Hub 镜像都安全
官方镜像相对可信,但仍有漏洞可能。

安全评估清单

  • Docker 守护进程是否安全配置?
  • 容器是否以非 root 用户运行?
  • 是否删除了不必要的 capabilities?
  • 是否启用了 seccomp 配置文件?
  • 是否对镜像进行漏洞扫描?
  • 是否限制了资源使用?
  • 是否使用只读文件系统?
  • 敏感信息是否通过 secret 管理?

Docker 安全不是一劳永逸的,而是需要持续关注的系统工程。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容