Appearance
安全实践
容器安全是生产环境中不可忽视的重要环节,本节介绍 Docker 安全的最佳实践。
镜像安全
使用官方或可信镜像
bash
# 优先使用官方镜像
FROM node:20-alpine # 官方镜像
FROM nginx:alpine # 官方镜像
# 固定版本,避免引入不可控变更
FROM node:20.11.0-alpine3.19 # 固定完整版本扫描镜像漏洞
bash
# 使用 docker scout(Docker Desktop 内置)
docker scout cves nginx:alpine
# 使用 Trivy(开源,推荐)
# 安装
brew install trivy # macOS
apt-get install trivy # Ubuntu
# 扫描本地镜像
trivy image nginx:alpine
# 扫描 Dockerfile(构建前检查)
trivy config ./Dockerfile
# 在 CI/CD 中扫描(失败则阻断)
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest最小化基础镜像
dockerfile
# 减少攻击面:使用最小化镜像
FROM alpine:3.19 # 约 5MB
FROM gcr.io/distroless/static # 约 2MB,无 shell
FROM scratch # 0MB,仅适合静态二进制容器运行安全
以非 root 用户运行
dockerfile
# 方式一:创建专用用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 方式二:使用镜像内置用户
USER node # node 官方镜像内置
USER nginx # nginx 官方镜像内置bash
# 运行时指定用户
docker run --user 1000:1000 myapp
# 验证容器内用户
docker exec mycontainer id禁止 root 用户运行
bash
# 运行时限制不允许提权到 root
docker run --security-opt no-new-privileges myapp
# 只读根文件系统
docker run --read-only myapp
# 只读 + 临时写入目录
docker run --read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
myapp限制 Linux 能力(Capabilities)
bash
# 删除所有能力,只添加必要的
docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \ # 允许绑定低端口
nginx
# 常见需要的能力
# NET_BIND_SERVICE - 绑定 1024 以下端口
# CHOWN - 修改文件所有者
# SETUID/SETGID - 切换用户/组避免特权模式
bash
# 绝对避免(除非必须,如 Docker-in-Docker)
docker run --privileged myapp # ⚠️ 危险!
# 使用最小权限替代
docker run --cap-add SYS_PTRACE myapp # 只需要 ptrace 时网络安全
最小化端口暴露
bash
# 只暴露必要端口
docker run -p 80:80 nginx # 只暴露 HTTP
# 绑定到本地(只允许本机访问)
docker run -p 127.0.0.1:3306:3306 mysql
# 内部服务不暴露端口(通过自定义网络通信)
docker run --network app-net mysql # 不加 -p,只在网络内可访问隔离网络
bash
# 每个应用使用独立网络
docker network create app1-net
docker network create app2-net
# 不同应用的容器在不同网络,互相隔离
docker run --network app1-net service-a
docker run --network app2-net service-bSecrets 管理
不要在镜像中存储密钥
dockerfile
# 错误做法
ENV DB_PASSWORD=secret123 # ⚠️ 会被记录到镜像层中
# 正确做法:运行时通过环境变量传入
# docker run -e DB_PASSWORD=$DB_PASSWORD myapp使用 Docker Secrets(Swarm 模式)
bash
# 创建 secret
echo "secure_password" | docker secret create db_password -
# 在服务中使用
docker service create \
--secret db_password \
-e DB_PASSWORD_FILE=/run/secrets/db_password \
myapp使用环境变量文件(开发)
bash
# .env 文件不提交到 Git
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
# 运行时加载
docker run --env-file .env myapp日志安全审计
bash
# 开启 Docker 审计日志
sudo auditctl -w /usr/bin/docker -p rwxa -k docker
# 查看容器操作历史
docker events --since 24h
# 监控特权操作
docker events --filter event=exec_start定期更新
bash
# 定期更新基础镜像
docker pull node:20-alpine
docker pull nginx:alpine
# 检查哪些容器在使用过时的镜像
docker ps --format "table {{.Names}}\t{{.Image}}"
# 在 CI/CD 中自动构建最新镜像安全扫描集成到 CI/CD
yaml
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: HIGH,CRITICAL
exit-code: 1
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: trivy-results.sarif安全检查清单
- [ ] 使用非 root 用户运行容器
- [ ] 基础镜像固定版本,定期更新
- [ ] 使用漏洞扫描工具定期扫描
- [ ] 只暴露必要端口
- [ ] 内部服务不映射到公网端口
- [ ] 密钥通过环境变量或 Secrets 管理,不硬编码
- [ ] 使用只读文件系统(
--read-only) - [ ] 丢弃不必要的 Linux 能力(
--cap-drop ALL) - [ ] 避免使用
--privileged - [ ] 在 CI/CD 中集成安全扫描
- [ ] 定期审查容器和镜像的安全状态
总结
Docker 安全的核心原则:
- 最小权限:只给容器所需的最小权限
- 最小攻击面:使用最小化镜像,不暴露不必要的端口
- 密钥管理:不在镜像中存储密钥
- 定期更新:保持镜像和依赖的最新安全补丁
- 持续扫描:在 CI/CD 中集成漏洞扫描