Docker 容器安全加固实战:镜像与运行时防护

Docker 容器安全加固是云原生应用部署前必须完成的基线工作:容器共享宿主机内核,默认配置下容器内进程以 root 运行、拥有完整 capabilities,一旦应用被攻破或存在逃逸漏洞(如 CVE-2022-0492、CVE-2026 系列内核漏洞),攻击者可直达宿主机。本文从镜像构建、运行时权限、资源限制三个层面给出可复制的容器安全加固方案。

适用场景

  • 使用 Docker / Docker Compose 部署生产服务的团队
  • 容器环境通过等保或云安全基线检查、需完成加固整改
  • 面临容器逃逸、权限提升或资源耗尽攻击风险的业务
  • 从虚拟机迁移到容器化架构、需要建立安全规范的组织

前置条件

  • 宿主机 Docker 20.10+,docker info 可正常输出
  • 具备构建镜像与修改 docker-compose.yml / Dockerfile 的权限
  • 熟悉基础 Linux 命令(chmod、useradd)与容器基本操作

原理说明

容器安全风险集中在四个层面:

  • 镜像层:镜像携带多余工具链、以 root 运行、包含已知漏洞的基础镜像(如旧版 Ubuntu),扩大攻击面。
  • 内核共享:容器与宿主机共享内核,容器内 root 若拥有完整 capabilities(如 CAP_SYS_ADMIN),可尝试 mount 宿主机文件系统实现逃逸。
  • 写权限:默认文件系统可写,攻击者可植入持久化后门;挂载了 //etc、Docker socket 等敏感路径时风险剧增。
  • 资源滥用:无 CPU/内存限制的容器可耗尽宿主机资源,形成容器内 DoS。

加固思路遵循「最小权限、最小镜像、最小能力」:非 root 运行、收窄 capabilities、只读文件系统、资源限额,并用镜像扫描拦截带漏洞的基础镜像。

操作步骤

1. 最小化镜像构建(多阶段构建)

# Dockerfile 示例:多阶段构建 + 非 root 用户
# 阶段一:构建(包含完整工具链)
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 阶段二:运行(仅保留产物与运行时)
FROM node:20-alpine
# 创建非 root 用户,禁止以 root 运行
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
RUN npm ci --omit=dev --ignore-scripts && chown -R appuser:appgroup /app
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]

关键点:USER appuser 指定非 root 用户;–omit=dev 不安装开发依赖;alpine 基础镜像体积小、工具链少。构建后立即用 docker scan 或 Trivy 扫描。

2. 镜像安全扫描

# 安装 Trivy(轻量级漏洞扫描器)
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# 扫描本地镜像(含基础镜像与依赖漏洞)
trivy image your-image:latest
# 只输出高危及以上,JSON 格式供 CI 解析
trivy image --severity HIGH,CRITICAL --format json your-image:latest
# CI 中高危漏洞即失败
trivy image --exit-code 1 --severity HIGH,CRITICAL your-image:latest

3. 运行时收窄 capabilities 与权限

# docker run 示例:去掉全部 capabilities 再按需添加
docker run -d --name app   --cap-drop=ALL   --cap-add=NET_BIND_SERVICE   --security-opt=no-new-privileges   --read-only   --tmpfs /tmp   -p 3000:3000   your-image:latest
# docker-compose.yml 对应配置
services:
  app:
    image: your-image:latest
    cap_drop: [ALL]
    cap_add: [NET_BIND_SERVICE]
    security_opt:
      - no-new-privileges:true
    read_only: true
    tmpfs: [/tmp]

参数说明:–cap-drop=ALL 移除全部内核能力,NET_BIND_SERVICE 允许绑定 80/443 等低端口;–read-only 只读根文件系统,写入走 --tmpfsno-new-privileges 禁止进程提升权限(setuid 失效)。

4. 资源限制与安全参数

docker run -d --name app   --memory=512m --memory-swap=512m   --cpus=1.0 --pids-limit=256   --restart=on-failure:5   your-image:latest
# compose 对应配置
services:
  app:
    image: your-image:latest
    mem_limit: 512m
    memswap_limit: 512m
    cpus: 1.0
    pids_limit: 256

–memory-swap–memory 相等可禁用 swap 防逃逸;–pids-limit 限制进程数防 fork 炸弹。

5. 严禁挂载敏感路径

# 错误示例(绝对禁止):
# docker run -v /:/host your-image        # 挂载宿主机根目录
# docker run -v /var/run/docker.sock:/var/run/docker.sock your-image  # 挂载 Docker socket 可直接控制宿主机
# 正确做法:只挂载业务需要的目录,并设置为只读
docker run -d --name app   -v /data/config:/app/config:ro   your-image:latest

6. 启用 seccomp 与 AppArmor 默认配置

# Docker 默认已附带 seccomp 配置文件,确认未被禁用
docker run -d --name app   --security-opt seccomp=default.json   your-image:latest
# 查看默认 seccomp 配置
docker info --format '{{.SecurityOptions}}'
# 期望输出包含 name=seccomp 与 name=apparmor

配置验证

# 1. 验证容器内用户为非 root
docker exec app id
# 期望输出 uid=1000(appuser) 而非 uid=0(root)
# 2. 验证 capabilities 已收窄
docker exec app capsh --print 2>/dev/null | grep Current
# 期望仅包含 net_bind_service 等白名单能力
# 3. 验证只读文件系统
docker exec app touch /root-test.txt
# 期望报错 read-only file system
# 4. 验证资源限制生效
docker inspect app --format '{{.HostConfig.Memory}}'  # 536870912 (512m)
# 5. 镜像漏洞扫描
trivy image --severity HIGH,CRITICAL your-image:latest

常见问题(FAQ)

Q1:–cap-drop=ALL 后容器启动失败或功能异常?

常见原因是缺少必要能力。按错误信息逐步补充:绑定低端口需要 NET_BIND_SERVICE,涉及网络抓包/诊断工具需要 NET_RAW,写系统日志需要 SYS_ADMIN 之外的 CHOWN/DAC_OVERRIDE。建议在测试环境逐个 cap-add 直到功能恢复,并记录最终白名单。若应用需要完整能力,考虑拆分服务或换用 sysbox 等运行时方案。

Q2:–read-only 后应用无法写日志/缓存?

将可写路径挂载为 tmpfs 或卷:日志目录 --tmpfs /var/log、缓存目录 --tmpfs /tmp;需要持久化的数据用命名卷 -v appdata:/data。注意 --tmpfs 数据不持久,重启即清空,适合日志缓存类场景。

Q3:如何检测已运行的容器是否安全合规?

使用 Docker Bench for Security(官方安全基线检查工具):

# 在宿主机运行(需 docker.sock 访问权限)
docker run -it --net host --pid host --userns host   --cap-add audit_control   -e DOCKER_CONTENT_TRUST=1   -v /var/lib:/var/lib -v /var/run/docker.sock:/var/run/docker.sock   docker/docker-bench-security
# 输出包含各检查项的 PASS/WARN/FAIL 结果,按 WARN/FAIL 项逐一整改

总结

Docker 容器安全加固的核心是「最小镜像、非 root 运行、能力收窄、资源限额」:多阶段构建产出精简镜像并扫描漏洞,USER 非 root 用户消除提权通道,--cap-drop=ALL + --read-only 收窄内核能力与写面,内存/CPU/PID 限制防资源滥用,并严禁挂载 Docker socket 等敏感路径。建议将以上配置固化为组织级镜像模板与 compose 规范,配合 Docker Bench 定期巡检。容器安全没有银弹,纵深防御 + 持续扫描才是正解。