Docker 安全最佳实践——从镜像到运行时的加固指南
Docker 安全最佳实践——从镜像到运行时的加固指南
作者: CaoZH
日期: 2025-10-15
本文为原创教程
Docker 极大地方便了应用部署,但「容器 ≠ 安全沙箱」。如果不注意安全配置,容器可能成为攻击者的突破口。
2025 年,云原生安全已经是运维的必修课。本文从镜像构建、容器运行、网络隔离三个维度,系统性地梳理 Docker 安全最佳实践。
一、镜像安全
1. 选择基础镜像
1 2 3 4 5 6 7 8 9 10 11
| FROM ubuntu:latest FROM node:latest
FROM node:20-alpine FROM python:3.12-alpine FROM openjdk:17-jdk-slim
FROM gcr.io/distroless/java17-debian12
|
镜像大小对比(以 Node.js 为例):
| 基础镜像 |
大小 |
漏洞数(平均) |
| node:latest |
~1GB |
200+ |
| node:slim |
~200MB |
50+ |
| node:alpine |
~120MB |
10+ |
| Distroless |
~100MB |
<5 |
2. 多阶段构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build
FROM node:20-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules USER node
EXPOSE 3000 CMD ["node", "dist/server.js"]
|
3. 镜像扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
sudo apt install -y trivy brew install trivy
trivy image node:20-alpine
trivy config .
trivy fs .
trivy image --severity CRITICAL,HIGH --exit-code 1 myapp:latest
|
4. 最小化安装
1 2 3 4 5 6 7 8
| RUN apt-get update && apt-get install -y \ curl vim git net-tools wget
RUN apt-get update && apt-get install -y \ ca-certificates \ && rm -rf /var/lib/apt/lists/*
|
二、容器运行时安全
1. 非 root 运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| FROM node:20-alpine COPY . . RUN npm install CMD ["node", "app.js"]
FROM node:20-alpine RUN addgroup -S appgroup && adduser -S appuser -G appgroup WORKDIR /app COPY --chown=appuser:appgroup . . USER appuser CMD ["node", "app.js"]
|
2. 只读文件系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| docker run --read-only \ --tmpfs /tmp \ --tmpfs /var/run \ myapp:latest
services: app: image: myapp:latest read_only: true tmpfs: - /tmp - /var/run
|
3. 资源限制
1 2 3 4 5 6 7
| docker run -d \ --memory="512m" \ --memory-swap="512m" \ --cpus="1.5" \ --pids-limit=100 \ myapp:latest
|
1 2 3 4 5 6 7 8 9 10 11 12
| services: app: image: myapp:latest deploy: resources: limits: cpus: '1.5' memory: 512M reservations: cpus: '0.5' memory: 256M
|
4. 安全配置参数
1 2 3 4 5 6 7 8 9
| docker run -d \ --security-opt=no-new-privileges:true \ --security-opt=seccomp=default.json \ --cap-drop=ALL \ --cap-add=NET_BIND_SERVICE \ --read-only \ --user 1000:1000 \ myapp:latest
|
三、网络隔离
1. 网络隔离策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| services: app: networks: - internal
web: ports: - "80:80" networks: - internal - frontend
db: networks: - internal
networks: frontend: internal: internal: true
|
2. 限制网络能力
1 2 3 4 5 6 7 8
| docker run --network none my-batch-job
docker run --network container:db my-app
docker network create --driver bridge --internal secure-net
|
四、日志与审计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| services: app: logging: driver: "json-file" options: max-size: "10m" max-file: "3"
|
五、Docker daemon 安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| { "icc": false, "live-restore": true, "log-level": "info", "userland-proxy": false, "no-new-privileges": true,
"registry-mirrors": ["..."], "insecure-registries": [],
"storage-driver": "overlay2",
"log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
|
六、安全检查清单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| ## Docker 安全检查清单
### 构建阶段 □ 使用 Alpine 或 Distroless 基础镜像 □ 多阶段构建,最小化产物 □ CI 中集成 Trivy 镜像扫描 □ 定期更新基础镜像 □ 不在镜像中硬编码密钥
### 运行阶段 □ 容器以非 root 用户运行 □ 启用 --read-only 只读文件系统 □ 限制 CPU 和内存 □ 使用 --cap-drop=ALL 移除特权 □ 启用 seccomp 系统调用过滤 □ 使用 --security-opt=no-new-privileges
### 网络 □ 数据库不对外暴露端口 □ 使用自定义网络 □ 不需要网络的容器用 --network none □ 启用 TLS 加密(远程 API)
### 监控 □ 启用日志轮转 □ 监控容器资源使用 □ 定期扫描镜像漏洞 □ 审计 Docker daemon 配置
|
七、总结
Docker 安全的核心原则:
1 2 3 4 5 6 7 8 9 10
| ## 最小权限原则
给容器刚好够用的权限,不多给一分一毫。
1. 镜像 → 最小化(Alpine / Distroless) 2. 用户 → 非 root 3. 文件系统 → 只读 4. 网络 → 最小连接 5. 能力 → 全部移除,按需添加 6. 资源 → 设置上限
|
首发于 CaoZH 的笔记