Docker 安全
安全威胁概览
镜像安全
使用可信基础镜像
# ✅ 使用官方镜像 + 固定版本
FROM node:20.11-alpine3.19
# ❌ 使用 latest(不可控)
FROM node:latest
# ❌ 使用来路不明的镜像
FROM someone/random-image
镜像漏洞扫描
# Docker Scout(官方工具)
docker scout cves myimage:latest
docker scout quickview myimage:latest
# Trivy(推荐,开源免费)
trivy image myimage:latest
trivy image --severity HIGH,CRITICAL myimage:latest
# Grype
grype myimage:latest
CI/CD 集成扫描
在流水线中加入镜像扫描步骤,阻止包含高危漏洞的镜像发布:
.github/workflows/scan.yml
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: myimage:latest
severity: HIGH,CRITICAL
exit-code: 1 # 发现高危漏洞时构建失败
避免泄露敏感信息
# ❌ 密钥写入镜像层(即使后续删除也能恢复)
COPY .env /app/.env
RUN rm /app/.env # 仍然存在于历史层中!
# ✅ 使用 BuildKit secret mount(构建时使用,不写入镜像层)
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret > /dev/null
# 构建时传入 secret
docker build --secret id=mysecret,src=./secret.txt .
容器运行时安全
非 root 用户运行
# 创建非 root 用户
RUN addgroup -g 1000 appgroup && \
adduser -D -u 1000 -G appgroup appuser
# 切换到非 root 用户
USER appuser
# 运行时指定用户
docker run -u 1000:1000 myimage
只读文件系统
# 容器文件系统只读 + tmpfs 可写
docker run -d \
--read-only \
--tmpfs /tmp:size=100m \
--tmpfs /var/run \
-v app-data:/app/data \
myimage
限制 Linux Capabilities
# 删除所有 capabilities,只添加需要的
docker run -d \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \ # 绑定低端口
myimage
# 禁止获取新权限
docker run -d \
--security-opt no-new-privileges \
myimage
常用 Capabilities:
| Capability | 说明 |
|---|---|
NET_BIND_SERVICE | 绑定 1024 以下端口 |
CHOWN | 修改文件所有者 |
SYS_TIME | 修改系统时间 |
NET_RAW | 原始套接字(ping) |
资源限制
docker run -d \
--memory 512m \
--memory-swap 512m \ # 禁用 swap
--cpus 1.0 \
--pids-limit 100 \ # 限制进程数(防 fork 炸弹)
--ulimit nofile=1024:1024 \
myimage
Seccomp 和 AppArmor
# 自定义 Seccomp 配置
docker run -d \
--security-opt seccomp=./seccomp-profile.json \
myimage
# 使用默认 AppArmor
docker run -d \
--security-opt apparmor=docker-default \
myimage
Docker Daemon 安全
保护 Docker Socket
# docker.sock 只允许 docker 组访问
ls -la /var/run/docker.sock
# srw-rw---- 1 root docker 0 Jan 1 00:00 /var/run/docker.sock
# ❌ 绝对不要把 docker.sock 挂载到不可信容器
docker run -v /var/run/docker.sock:/var/run/docker.sock untrusted
Docker Socket = root 权限
能访问 Docker Socket 就等于拥有宿主机 root 权限。可以通过创建特权容器逃逸到宿主机。
TLS 远程访问
# 生成 CA 和证书
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# 配置 Docker Daemon 使用 TLS
cat /etc/docker/daemon.json
{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
"tls": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem",
"tlsverify": true
}
网络安全
# 创建内部网络(不能访问外网)
docker network create --internal secure-net
# 绑定端口到 localhost
docker run -p 127.0.0.1:8080:80 myapp
# 禁止容器间通信
docker network create --opt com.docker.network.bridge.enable_icc=false isolated-net
Docker Bench Security
Docker Bench for Security 根据 CIS Docker Benchmark 自动检查安全配置:
# 运行安全基线检查
docker run --rm --net host --pid host --userns host \
--cap-add audit_control \
-v /etc:/etc:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
docker/docker-bench-security
安全最佳实践清单
# 镜像层面
- [ ] 使用官方/可信基础镜像
- [ ] 固定镜像版本标签(不用 latest)
- [ ] 多阶段构建,最小化最终镜像
- [ ] CI/CD 镜像漏洞扫描
- [ ] 不在镜像中存储密钥/密码
# 容器层面
- [ ] 非 root 用户运行
- [ ] 只读文件系统 + tmpfs
- [ ] 删除不需要的 Capabilities
- [ ] 设置资源限制(内存、CPU、进程数)
- [ ] 启用 no-new-privileges
# 主机层面
- [ ] 保护 Docker Socket
- [ ] 启用 TLS 远程访问
- [ ] 定期更新 Docker Engine
- [ ] 启用审计日志
# 网络层面
- [ ] 使用自定义网络隔离
- [ ] 端口只绑定 localhost
- [ ] 内部服务用 internal 网络
常见面试问题
Q1: Docker 容器逃逸有哪些途径?如何防御?
答案:
常见逃逸途径:
- 特权容器(
--privileged):可访问所有设备 - 挂载 docker.sock:可创建特权容器
- 内核漏洞(如 Dirty Pipe):利用内核漏洞逃逸
- 挂载宿主机敏感目录(
/、/etc)
防御措施:
- 不使用
--privileged - 不挂载 docker.sock 到不可信容器
- 使用非 root 用户 +
--cap-drop ALL - 启用 Seccomp/AppArmor
- 及时更新内核和 Docker 版本
Q2: 如何安全管理容器中的敏感信息?
答案:
- 环境变量:通过运行时注入,不硬编码在镜像中
- Docker Secrets(Swarm):
docker secret create - BuildKit secret mount:构建时使用,不存入镜像层
- 外部密钥管理:HashiCorp Vault、AWS Secrets Manager
- Kubernetes Secrets + 加密存储
Q3: 如何在 CI/CD 中保障镜像安全?
答案:
- 构建后用 Trivy/Grype 扫描漏洞
- 设置策略:HIGH/CRITICAL 漏洞阻止发布
- 使用私有镜像仓库(Harbor)+ 镜像签名
- 定期重建基础镜像获取安全补丁
- 使用 Cosign 进行镜像签名和验证