容器默认以 root 运行、文件系统可写、镜像可能含漏洞——这三个问题让 Docker 成为攻击者的温床。本文提供一份可直接落地的安全加固清单覆盖镜像、容器、运行时三层。一、容器安全的三个层面┌─────────────────────────────────────┐ │ 应用层安全 │ │ (代码漏洞、依赖漏洞、配置错误) │ ├─────────────────────────────────────┤ │ 镜像层安全 │ │ (基础镜像、构建过程、敏感信息) │ ─────────────────────────────────────┤ │ 运行时安全 │ │ (权限、网络、资源限制) │ ─────────────────────────────────────┘二、镜像层安全2.1 使用官方/可信基础镜像# 推荐官方镜像定期更新 FROM node:18-alpine # 不推荐来路不明的镜像 FROM someuser/custom-node:latest # 更推荐固定版本 SHA256 FROM nodesha256:abc123...2.2 最小化镜像# 使用 Alpine 或 distroless FROM node:18-alpine # ~180MB # 而不是 FROM node:18 # ~1GB # 极致distroless无 shell、无包管理器 FROM gcr.io/distroless/nodejs18distroless 的优势没有 shell攻击者无法 docker exec 进入没有包管理器无法安装恶意工具镜像体积小攻击面小2.3 多阶段构建减少攻击面# 阶段一构建 FROM golang:1.21 AS builder WORKDIR /app COPY . . RUN CGO_ENABLED0 go build -o server . # 阶段二运行只包含二进制文件 FROM alpine:3.18 RUN adduser -D appuser USER appuser COPY --frombuilder /app/server /usr/local/bin/ CMD [server]2.4 不要在镜像中硬编码敏感信息# 错误密码写在 Dockerfile 里 ENV DB_PASSWORDsupersecret123 # 正确运行时通过环境变量或 Secret 传入 # docker run -e DB_PASSWORD$DB_PASSWORD myapp# 检查镜像中的敏感信息 docker history myapp:latest docker inspect myapp:latest | grep -i password2.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 --chownappuser:appgroup . . CMD [node, index.js]# docker run 时指定 docker run --user 1000:1000 myapp # docker-compose.yml services: app: image: myapp user: 1000:10003.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/run3.3 限制 Linux Capabilities容器默认有 14 个 Linux Capabilities大多数应用只需要少数几个。# 删除所有 capabilities只保留需要的 docker run --cap-dropALL --cap-addNET_BIND_SERVICE myapp # 常见场景 # - Web 服务绑定 80/443 端口NET_BIND_SERVICE # - 需要 pingNET_RAW # - 需要修改系统时间SYS_TIME# docker-compose.yml services: app: image: myapp cap_drop: - ALL cap_add: - NET_BIND_SERVICE3.4 禁止特权模式# 绝对不要在生产环境使用 docker run --privileged myapp # 危险 # 如果确实需要特定权限用 --cap-add 精确控制 docker run --cap-addSYS_PTRACE myapp # 调试用3.5 限制资源# 限制 CPU 和内存 docker run --cpus2 --memory512m myapp # 限制 PID 数量防 fork 炸弹 docker run --pids-limit100 myapp# docker-compose.yml services: app: image: myapp deploy: resources: limits: cpus: 2 memory: 512M reservations: cpus: 0.5 memory: 128M3.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 High4.2 TrivyAqua 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:latest4.3 GrypeAnchore# 安装 brew install grype # 扫描镜像 grype myapp:latest # 只扫描指定严重级别 grype --only-fixed myapp:latest4.4 CI/CD 集成示例# GitHub Actions name: Security Scan on: push: branches: [main] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-actionmaster 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-sarifv2 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.sock5.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 真正安全地跑在生产环境。
阅读完成 · 觉得有帮助?