📌 本文由 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 通信
面试要点
- Docker 安全的核心理念是最小权限原则
- 非 root 用户 + 只读文件系统是最基本的安全配置
- Capabilities 是 Linux 容器安全的关键控制点
- Secret 管理(而非环境变量)是敏感信息的最佳实践
- 定期扫描和更新镜像比安全配置更重要
面试官常问:如果发现一个容器被入侵了,你如何分析和处理?
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
- 同样需要隔离但更重视启动速度
- 对性能要求不是极高
- 不需要特殊内核模块的场景
面试要点
- 传统容器共享宿主机内核,这是安全风险的根源
- Kata Containers 使用轻量级 VM 提供硬件级隔离
- gVisor 在用户态实现内核,提供应用级沙箱
- 隔离性增强必然伴随性能损失
- 选择取决于安全需求 vs 性能需求的权衡
面试官常问:Kata Containers 和 gVisor 的区别是什么?你们在什么场景用了这些技术?
网络不通排查
网络不通排查
Docker 网络问题分类
Docker 网络问题一般分为三类:
- 容器访问外部网络(例如容器不能访问互联网)
- 外部访问容器(例如宿主机浏览器不能访问容器服务)
- 容器间通信(例如 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
面试要点
- 网络排查路径:容器内 → 宿主机 → 外部
- 最常见的问题:服务监听 127.0.0.1、防火墙规则、不在同一网桥
netshoot容器是调试的瑞士军刀- 区分 DNS 问题和网络连通性问题
- 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 安全不是一劳永逸的,而是需要持续关注的系统工程。


暂无评论内容