☰
Docker 安全加固清单:非 root 运行、只读文件系统、镜像漏洞扫描
2026/10/23 2:55:54 网站建设 项目流程

容器默认以 root 运行、文件系统可写、镜像可能含漏洞——这三个问题让 Docker 成为攻击者的温床。本文提供一份可直接落地的安全加固清单,覆盖镜像、容器、运行时三层。


一、容器安全的三个层面

┌─────────────────────────────────────┐ │ 应用层安全 │ │ (代码漏洞、依赖漏洞、配置错误) │ ├─────────────────────────────────────┤ │ 镜像层安全 │ │ (基础镜像、构建过程、敏感信息) │ ─────────────────────────────────────┤ │ 运行时安全 │ │ (权限、网络、资源限制) │ ─────────────────────────────────────┘

二、镜像层安全

2.1 使用官方/可信基础镜像

# 推荐:官方镜像,定期更新 FROM node:18-alpine # 不推荐:来路不明的镜像 FROM someuser/custom-node:latest # 更推荐:固定版本 + SHA256 FROM node@sha256:abc123...

2.2 最小化镜像

# 使用 Alpine 或 distroless FROM node:18-alpine # ~180MB # 而不是 FROM node:18 # ~1GB # 极致:distroless(无 shell、无包管理器) FROM gcr.io/distroless/nodejs18

distroless 的优势:

  • 没有 shell,攻击者无法 docker exec 进入
  • 没有包管理器,无法安装恶意工具
  • 镜像体积小,攻击面小

2.3 多阶段构建减少攻击面

# 阶段一:构建 FROM golang:1.21 AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 go build -o server . # 阶段二:运行(只包含二进制文件) FROM alpine:3.18 RUN adduser -D appuser USER appuser COPY --from=builder /app/server /usr/local/bin/ CMD ["server"]

2.4 不要在镜像中硬编码敏感信息

# 错误:密码写在 Dockerfile 里 ENV DB_PASSWORD=supersecret123 # 正确:运行时通过环境变量或 Secret 传入 # docker run -e DB_PASSWORD=$DB_PASSWORD myapp
# 检查镜像中的敏感信息 docker history myapp:latest docker inspect myapp:latest | grep -i password

2.5 .dockerignore 排除敏感文件

.git .env *.key *.pem secrets/ credentials.json


三、容器运行时安全

3.1 非 root 运行

为什么重要:容器内 root 虽然不等于宿主机 root,但仍有权限逃逸风险(如 CVE-2019-5736)。

# Dockerfile 中指定非 root 用户 FROM node:18-alpine # 创建用户 RUN addgroup -S appgroup && adduser -S appuser -G appgroup # 切换到非 root 用户 USER appuser WORKDIR /home/appuser/app COPY --chown=appuser:appgroup . . CMD ["node", "index.js"]
# docker run 时指定 docker run --user 1000:1000 myapp # docker-compose.yml services: app: image: myapp user: "1000:1000"

3.2 只读文件系统

# 容器文件系统只读,需要写的地方用 tmpfs 或 volume docker run --read-only \ --tmpfs /tmp \ --tmpfs /var/run \ myapp
# docker-compose.yml services: app: image: myapp read_only: true tmpfs: - /tmp - /var/run

3.3 限制 Linux Capabilities

容器默认有 14 个 Linux Capabilities,大多数应用只需要少数几个。

# 删除所有 capabilities,只保留需要的 docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp # 常见场景: # - Web 服务绑定 80/443 端口:NET_BIND_SERVICE # - 需要 ping:NET_RAW # - 需要修改系统时间:SYS_TIME
# docker-compose.yml services: app: image: myapp cap_drop: - ALL cap_add: - NET_BIND_SERVICE

3.4 禁止特权模式

# 绝对不要在生产环境使用 docker run --privileged myapp # 危险! # 如果确实需要特定权限,用 --cap-add 精确控制 docker run --cap-add=SYS_PTRACE myapp # 调试用

3.5 限制资源

# 限制 CPU 和内存 docker run --cpus=2 --memory=512m myapp # 限制 PID 数量(防 fork 炸弹) docker run --pids-limit=100 myapp
# docker-compose.yml services: app: image: myapp deploy: resources: limits: cpus: '2' memory: 512M reservations: cpus: '0.5' memory: 128M

3.6 网络隔离

# 不暴露不必要的端口 docker run -p 8080:80 myapp # 只暴露 8080 # 使用自定义网络 docker network create isolated-net docker run --network isolated-net myapp
# docker-compose.yml services: app: image: myapp ports: - "8080:80" networks: - frontend db: image: postgres ports: [] # 不暴露到宿主机 networks: - backend networks: frontend: backend:

四、镜像漏洞扫描

4.1 Docker Scout(官方)

# 登录 Docker Hub docker scout login # 扫描本地镜像 docker scout cves myapp:latest # 扫描远程镜像 docker scout cves docker.io/library/nginx:latest # 生成报告 docker scout cves myapp:latest --format json > report.json

输出示例:

✓ Image stored for indexing ✓ Indexed 142 packages ✗ 3 vulnerabilities found - 1 Critical - 2 High

4.2 Trivy(Aqua Security)

# 安装 brew install trivy # macOS apt-get install trivy # Debian/Ubuntu # 扫描镜像 trivy image myapp:latest # 扫描文件系统 trivy fs /path/to/project # 只扫描高危及以上 trivy image --severity HIGH,CRITICAL myapp:latest # 输出为表格 trivy image --format table myapp:latest # 输出为 JSON(用于 CI/CD) trivy image --format json --output report.json myapp:latest

4.3 Grype(Anchore)

# 安装 brew install grype # 扫描镜像 grype myapp:latest # 只扫描指定严重级别 grype --only-fixed myapp:latest

4.4 CI/CD 集成示例

# GitHub Actions name: Security Scan on: push: branches: [main] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: 'myapp:${{ github.sha }}' format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH' - name: Upload Trivy scan results uses: github/codeql-action/upload-sarif@v2 with: sarif_file: 'trivy-results.sarif'

五、Docker 守护进程安全

5.1 启用 TLS 认证

# 生成 CA 证书 openssl genrsa -aes256 -out ca-key.pem 4096 openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem # 生成服务器证书 openssl genrsa -out server-key.pem 4096 openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem # 配置 Docker 守护进程 # /etc/docker/daemon.json { "tls": true, "tlscert": "/path/to/server-cert.pem", "tlskey": "/path/to/server-key.pem", "tlscacert": "/path/to/ca.pem" }

5.2 限制 API 访问

# 不要直接暴露 Docker API 到公网 # 错误 dockerd -H tcp://0.0.0.0:2375 # 正确:使用 Unix socket 或 TLS dockerd -H unix:///var/run/docker.sock

5.3 启用审计日志

# 配置 Docker 审计 # /etc/docker/daemon.json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

六、安全加固检查清单

镜像构建阶段

  • 使用官方/可信基础镜像
  • 固定基础镜像版本(不用 latest)
  • 多阶段构建,减少最终镜像大小
  • 不在镜像中硬编码密码/密钥
  • 使用 .dockerignore 排除敏感文件
  • 定期扫描镜像漏洞(Trivy/Docker Scout)

容器运行阶段

  • 非 root 用户运行
  • 只读文件系统(--read-only)
  • 删除不必要的 Linux Capabilities
  • 不使用 --privileged
  • 限制 CPU、内存、PID 数量
  • 不暴露不必要的端口
  • 使用自定义网络隔离

守护进程配置

  • 启用 TLS 认证(远程访问时)
  • 不暴露 Docker API 到公网
  • 配置日志轮转
  • 定期更新 Docker 版本

七、常见误区

误区 1:容器 = 虚拟机,很安全

事实:容器共享宿主机内核,权限逃逸风险真实存在。2019 年的 CVE-2019-5736 允许容器内 root 逃逸到宿主机。

误区 2:非 root 运行就没风险

事实:非 root 降低了风险,但不能完全消除。配合只读文件系统、capabilities 限制才能形成纵深防御。

误区 3:扫描没漏洞就安全

事实:漏洞扫描只检查已知 CVE。配置错误(如暴露敏感端口、硬编码密码)需要人工审查。


八、总结

Docker 安全不是单一措施,而是纵深防御:

镜像安全 → 运行时安全 → 网络隔离 → 监控审计

把本文的检查清单融入 CI/CD 流程,每次构建自动扫描漏洞,每次部署自动检查配置,才能让 Docker 真正安全地跑在生产环境。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询