Docker 生产安全指南:镜像扫描、非 root 运行、Secret 管理与 Registry

Docker 生产环境安全加固完整方案:镜像漏洞扫描(Trivy/Snyk)、非 root 用户运行、只读文件系统、Secret 管理(BuildKit)、私有 Registry(Harbor)、运行时安全(seccomp/AppArmor)。

Docker 容器不是天然安全的:默认以 root 运行、镜像可能包含漏洞、构建时 Secret 泄露。本文覆盖 Docker 生产环境的安全加固全系列方案,从镜像扫描、Secret 管理到运行时隔离与监控,构建容器安全的纵深防御体系。


一、镜像安全扫描

容器安全的起点在于镜像本身。一个基础镜像可能携带数千个已知 CVE,这些漏洞在构建阶段即被植入,若未经扫描便投入生产,相当于将攻击面直接开放给了外部威胁。

1.1 为什么镜像扫描是第一步

容器镜像本质上是一个扁平化的文件系统快照,包含了操作系统包、库文件、运行时依赖以及应用程序代码。如果基础镜像中的 glibc、OpenSSL 或 libcurl 存在已知漏洞,那么基于该镜像构建的所有服务都会继承同样的风险。2024 年的统计报告显示,超过 70% 的公开 Docker 镜像至少包含一个可被利用的高危 CVE。

1.2 Trivy — 最受欢迎的开源扫描器

Trivy 由 Aqua Security 开发,支持镜像、文件系统、Git 仓库等多种扫描目标,拥有最快的扫描速度之一。

# 安装 Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

# 扫描本地镜像
trivy image my-app:latest

# 扫描特定严重级别并输出为 JSON
trivy image --severity HIGH,CRITICAL \
            --format json \
            --output trivy-report.json \
            my-app:latest

# 扫描公开镜像仓库中的镜像
trivy image alpine:3.18

Trivy 默认扫描以下数据源:Distro 包漏洞(如 Alpine .apk、Debian .deb)、NPM / PIP / Maven 依赖漏洞、不安全的 Dockerfile 配置(如以 root 运行)、以及 secret 泄露(GitHub tokens 等)。

1.3 Snyk — 商业级安全平台

Snyk 在开源社区提供 generous free tier,适合个人项目和中小团队。

# 安装 Snyk
npm install -g snyk
snyk auth

# 容器镜像扫描
snyk container test my-app:latest --severity-threshold=high

# 监控镜像持续跟踪新漏洞
snyk container monitor my-app:latest --project-name=production-api

Snyk 的优势在于其修复建议功能,不仅能告诉你哪个包存在漏洞,还能通过自动化 PR 修复依赖。对于 Node.js 和 Python 项目尤其有用。

1.4 Docker Scout — Docker 官方方案

Docker Scout 随 Docker Desktop 和 Docker Hub 集成,无需额外安装。

# 快速查看镜像安全概要
docker scout quickview my-app:latest

# 查看 CVE 详情(含 CVSS 分数)
docker scout cves --only-packages openssh,openssl my-app:latest

# 比较两个镜像版本之间的漏洞变化
docker scout compare --to my-app:v1.0 my-app:v1.1

1.5 CI/CD 集成扫描

将镜像扫描嵌入 CI/CD 是防止漏洞进入生产环境的关键手段。以下是一个 GitHub Actions 示例:

# .github/workflows/image-scan.yml
name: Image Security Scan
on: [push]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t my-app:${{ github.sha }} .
      - name: Run Trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'my-app:${{ github.sha }}'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'
          ignore-unfixed: true

上述配置在发现严重或高危漏洞时会中断 CI 流程,确保问题在合并前解决。


二、运行时安全加固

镜像层面的安全只是第一道防线,容器运行时的配置同样关键。Docker 默认运行参数较为宽松,一个错误配置可能导致容器逃逸、资源耗尽乃至宿主机被攻陷。

2.1 非 root 运行

Docker 默认以 root(UID = 0)运行容器内的主进程,这带来极大风险:若应用程序存在命令注入漏洞,攻击者可以直接获得容器内的 root 权限。

# 正确的做法:在 Dockerfile 中创建非 root 用户
FROM node:20-alpine

# 创建用户组和用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 设置工作目录并赋予非 root 用户所有权
WORKDIR /app
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci
COPY --chown=appuser:appgroup . .

# 切换到非 root 用户
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
# 验证容器内进程不以 root 运行
docker run --rm -it my-app id
# 输出应为:uid=1000(appuser) gid=1000(appgroup) groups=1000(appgroup)

常见错误包括创建了用户但未切换 USER 指令,或者在 COPY 时忘记赋予非 root 用户文件所有权,导致应用无法读取或写入数据。务必在构建时使用 --chown 一次性解决权限问题。

2.2 只读文件系统

许多攻击向量(如写入 webshell、修改可执行文件)依赖于文件系统的可写性。将容器根文件系统设为只读可以大幅缩小攻击面。

# 启动只读容器,同时挂载临时可写目录用于日志/缓存
docker run \
  --read-only \
  -v /tmp:/tmp \
  -v /app/logs:/app/logs \
  -e LOG_PATH=/app/logs \
  my-app:latest

应用程序需要区分两类写入需求:运行时临时文件应写入 /tmp,持久化数据通过卷挂载到外部。若应用在只读环境中崩溃,说明存在对容器内路径的非法写入,应及时修复。

2.3 资源限制(防 DoS)

未限制资源的容器可能被恶意流量或 bug 拖垮整个宿主机。

# CPU、内存、swap、PID 限制
docker run \
  --memory=512m \
  --memory-swap=512m \
  --cpus=1.0 \
  --pids-limit=100 \
  my-app:latest

--pids-limit 经常被忽略,但它能够有效防止 fork 炸弹攻击。建议对每个生产容器同时设置内存、CPU 和 PID 上限。

2.4 禁用特权模式

--privileged 授予容器对宿主设备的完全访问权限,相当于在容器内获得了实质上的宿主机 root 能力,绝大多数场景下毫无必要。

# ❌ 极度危险:容器获得宿主机 root 权限和设备访问
docker run --privileged my-app

# ✅ 正确的做法:仅授予必要的 capabilities
docker run \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --cap-add=SETUID \
  my-app

--cap-drop=ALL 先剥夺全部 capabilities,再通过 --cap-add 逐条加回真正需要的权限。这是能力最小化原则的实际应用。


三、Secret 管理

将密码、API 密钥或数据库连接字符串硬编码到 Docker 镜像或环境变量中是安全事故的高频原因。BuildKit Secret 和运行时 Secret 机制是规避这些风险的正确方式。

3.1 BuildKit Secret(构建时密钥不落入镜像层)

Docker 镜像的每一层都是可读的,曾经写入 .npmrc 或 id_rsa 的层即使后续被删除,仍然存在镜像历史中被读取的风险。BuildKit 的 Secret mount 机制能将敏感文件在构建时挂载到内存中,构建结束后不留痕迹。

# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci --prefer-offline
COPY . .
RUN npm run build
# 构建时传入 secret,不会写入任何镜像层
DOCKER_BUILDKIT=1 docker build \
  --secret id=npmrc,src=$HOME/.npmrc \
  --secret id=aws,src=$HOME/.aws/credentials \
  -t my-app:v1.0 .
# 构建后验证 secret 不在镜像中
docker run --rm my-app:v1.0 cat /root/.npmrc
# 应输出 cat: can't open '/root/.npmrc': No such file or directory

3.2 运行时 Secret(Docker Swarm / Kubernetes)

构建阶段的安全并不能替代运行时的安全。运行时密码不应以环境变量出现,而应使用 Docker Swarm Secret 或 Kubernetes Secret 机制注入。

# Docker Swarm Secret 示例
echo "my-super-secret-password" | docker secret create db_password -

# 创建服务并绑定 Secret
docker service create \
  --name my-api \
  --secret db_password \
  --secret source=ca_bundle,target=/run/secrets/ca.crt \
  my-app:latest

# 在容器内部,secret 以文件形式挂载到 /run/secrets/
docker exec <container_id> cat /run/secrets/db_password

在 Kubernetes 中,更推荐将 Secret 以卷挂载方式注入,同时配合 secrets-csi-driver 实现与外部密钥管理系统(AWS Secrets Manager、Azure Key Vault)的动态同步。


四、私有 Registry(Harbor)

将镜像推送至 Docker Hub 或其他公开仓库时,企业面临知识产权泄露、供应链污染和访问控制缺失等风险。自建私有 Registry 是隔离和安全管理镜像的必由之路。

4.1 Harbor — 企业级 Registry

Harbor 由 VMware 开源,支持漏洞扫描、镜像签名、基于角色的访问控制(RBAC)以及复制策略。

# 下载并配置 Harbor
curl -L https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz \
  -o harbor-offline-installer.tgz
tar xvf harbor-offline-installer.tgz
cd harbor

cp harbor.yml.tmpl harbor.yml
# 编辑 harbor.yml 配置主机名和 HTTPS 证书
# hostname: harbor.example.com
# https.certificate: /your/cert/path

# 安装并启动
sudo ./install.sh --with-trivy

# 查看服务状态
docker-compose -f docker-compose.yml ps

4.2 推送镜像到 Harbor

# 登录到 Harbor Registry
docker login harbor.example.com

# 标记镜像
docker tag my-app:v1.0 harbor.example.com/project-a/my-app:v1.0

# 推送镜像
docker push harbor.example.com/project-a/my-app:v1.0

# 在 Harbor UI 上查看镜像及其扫描结果

4.3 Harbor 安全策略配置

在 Harbor 的「项目设置」中,启用以下关键安全策略:

  1. 镜像漏洞扫描:设置为推送后自动扫描,设定阻止存在高危以上漏洞的镜像被拉取
  2. 不可变标签(Immutable Tag):防止有意义的版本号被覆盖攻击
  3. 签名策略:要求所有镜像携带 Cosign 或 Notary 签名
  4. Cosign 公钥白名单:仅允许使用预先注册的公钥签署的镜像

五、Linux 安全机制详解

Docker 容器本质上是利用 Linux 内核特性(cgroups、namespaces、capabilities 等)构建的隔离环境。深入理解并正确配置这些安全原语,才能实现真正的容器加固。

5.1 seccomp — 系统调用过滤

seccomp(secure computing mode)是 Linux 内核的沙箱机制,通过白名单限制进程可使用的系统调用。Docker 默认启用一个包含约 300 个允许调用的 seccomp 配置文件,但某些场景需要自定义。

// my-seccomp.json — 自定义 seccomp 配置文件
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "syscalls": [
    {
      "names": ["read", "write", "open", "close", "exit", "exit_group"],
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "names": ["bind", "connect", "accept", "listen", "socket"],
      "action": "SCMP_ACT_ALLOW",
      "comment": "允许网络相关系统调用"
    },
    {
      "names": ["execve", "execveat"],
      "action": "SCMP_ACT_ERRNO",
      "comment": "禁止执行新程序,防止 shell 逃逸"
    }
  ]
}
# 启动容器时加载自定义 seccomp 配置
docker run \
  --security-opt seccomp=/path/to/my-seccomp.json \
  my-app:latest

5.2 AppArmor 访问控制

AppArmor 为进程定义安全配置文件,限制其文件访问和特权操作。Docker 自带 docker-default 配置文件,通常足够严密,但对于高安全要求场景可编写自定义策略。

# 查看当前容器的 AppArmor 状态
docker inspect <container_id> | grep -i apparmor

# 加载自定义 AppArmor 策略
sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-myapp

# 启动容器绑定自定义 AppArmor 策略
docker run \
  --security-opt apparmor=docker-myapp \
  my-app:latest
# /etc/apparmor.d/containers/docker-myapp 示例
profile docker-myapp flags=(attach_disconnected,mediate_deleted) {
  #include <tunables/global>
  capability chown,
  capability setuid,
  deny /proc/sys/** w,
  deny /etc/shadow r,
  /app/** rw,
  /tmp/ rw,
}

deny /proc/sys/** w 阻止写入内核参数,deny /etc/shadow r 阻止读取密码哈希,这些都是防止容器逃逸的典型措施。

5.3 SELinux 强制访问控制

在 RHEL / CentOS / Fedora 环境中,SELinux 提供比 AppArmor 更细粒度的强制访问控制。

# 检查 SELinux 状态
getenforce
# 输出 Expected: Enforcing

# 启动容器时启用 SELinux 标记
docker run \
  -v /host/data:/data:Z \
  --security-opt label=disable:false \
  my-app:latest

:Z 标签让 Docker 自动设置 SELinux 上下文为 container_file_t,确保容器内进程只能访问被明确允许的卷目录。

5.4 Linux Capabilities 精细控制

Linux capabilities 将 root 的传统特权拆分为 40 多项独立权限。通过 --cap-drop=ALL 和 --cap-add 的组合,可实现对容器能力的精确削减。

# 完整示例:Web 服务容器仅需网络绑定能力
docker run \
  --cap-drop=ALL \
  --cap-add=CHOWN \
  --cap-add=SETGID \
  --cap-add=SETUID \
  --cap-add=NET_BIND_SERVICE \
  --security-opt no-new-privileges:true \
  -p 8080:8080 \
  my-nginx
Capabilities用途风险等级
NET_ADMIN配置网络接口高,可启用伪造流量
SYS_ADMIN执行挂载等管理操作极高,常被用于容器逃逸
SYS_PTRACE附加到其他进程高,可读取其他容器内存
SYS_MODULE加载内核模块极高,直接威胁宿主机
NET_BIND_SERVICE监听 1024 以下端口低,Web 服务必要
DAC_OVERRIDE绕过文件权限检查高,可读取任意文件

安全原则是:绝不授予 SYS_ADMIN、SYS_MODULE、CAP_BPF 等特权能力,这些与宿主机边界仅一步之遥。


六、Rootless Docker

传统 Docker 守护进程以 root 运行,一旦守护进程本身出现漏洞,整个宿主机都将暴露。Rootless Docker 模式将守护进程迁移到普通用户命名空间下运行,实现了真正的「无 root」容器管理。

6.1 Rootless 模式工作原理

Rootless Docker 利用 Linux 用户命名空间(User Namespace),将容器内的 root(UID 0)映射宿主机上一个普通用户(如 UID 1000)。这意味着即使容器进程认为自己拥有 root 权限,在宿主机内核看来它只是一个非特权进程。

# 安装 rootless Docker 工具包
curl -fsSL https://get.docker.com/rootless | sh

# 验证安装
dockerd-rootless-setuptool.sh check

# 启动 rootless Docker 守护进程
export PATH=$HOME/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
dockerd-rootless.sh &

6.2 uidmap 配置

用户命名空间的映射关系需通过 newuidmap 和 newgidmap 配置,写入 /etc/subuid 和 /etc/subgid。以用户 app 为例:

# /etc/subuid 配置
echo "app:100000:65536" | sudo tee -a /etc/subuid

# /etc/subgid 配置
echo "app:100000:65536" | sudo tee -a /etc/subgid

这表示用户 app 可以在用户命名空间中将容器内 UID 0-65535 映射到宿主机的 100000-165535 范围。容器 root 在宿主机上实际对应 UID 100000,彻底脱离了宿主机 root 的概念。

6.3 Rootless 与 Rootfull 对比

维度Rootfull DockerRootless Docker
守护进程运行身份root普通用户
容器逃逸影响范围宿主 root 沦陷仅影响普通用户
能否运行特权容器可以不支持 --privileged
编排工具兼容性完全兼容部分限制
存储驱动选择全部推荐 overlay2 + fuse-overlayfs

对于生产环境的安全关键型部署,Rootless Docker 是消除单点特权风险的最佳实践之一。


七、镜像签名与供应链安全

即使有漏洞扫描和安全加固,镜像供应链本身也可能被攻击:攻击者可能替换 Registry 中的镜像为植入后门的版本。镜像签名和供应链安全机制确保你运行的镜像确实来自可信的来源,并且未被篡改。

7.1 Cosign / Sigstore 密钥less签名

Sigstore 是由 Linux 基金会支持的开源项目,提供无需管理私钥的镜像签名方案。Cosign 是其实现工具。

# 安装 Cosign
wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign

# 使用 OIDC(如 GitHub Actions)进行密钥less签名
cosign sign --yes harbor.example.com/my-app:v1.0

# 验证签名(无需手动分发公钥)
cosign verify \
  --certificate-identity=your-ci@example.com \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  harbor.example.com/my-app:v1.0

cosign sign --yes 在 CI/CD 环境中通过 OIDC 身份自动获取临时密钥对进行签名,签名证书和透明日志条目自动发布到 Rekor 公共日志中,行为透明可审计。

7.2 Notary v2

Docker Content Trust v1 的继任者 Notary v2 提供了与 OCI 仓库原生集成的签名规范,支持按 Tag 或按 Digest 签名。

# 使用 Notary v2 (notation) 签名镜像
notation sign harbor.example.com/my-app:v1.0

# 验证镜像签名
notation verify harbor.example.com/my-app:v1.0

Harbor 2.9+ 版本已原生支持 Notary v2 验证,可以在项目级别要求所有镜像必须携带有效签名,否则拒绝部署。

7.3 SBOM 生成与 SLSA 合规

SBOM(Software Bill of Materials)是一份完整的软件成分清单,记录镜像中每个包的来源和版本。欧盟《网络韧性法案》和美国 Wiz 备忘录都要求关键软件提供 SBOM。

# 使用 Syft 生成 SBOM
syft my-app:latest -o spdx-json=sbom.spdx.json

# 使用 Trivy 生成 SBOM
trivy image --format cyclonedx --output sbom.json my-app:latest

# 将 SBOM 作为制品伴随镜像推送
cosign attest \
  --predicate sbom.spdx.json \
  --type spdxjson \
  harbor.example.com/my-app:v1.0

SLSA(Supply-chain Levels for Software Artifacts)是一个分级标准,强调从源码到工件的全程可追溯。要做到 SLSA Level 3,必须满足:构建环境隔离、构建脚本代码化、构建产物签名且支持可验证的追溯链。


八、网络隔离与安全

默认 bridge 网络下所有容器处于同一二层网络,可以直接相互访问。在多租户或微服务架构中,这显然不符合最小权限原则,必须通过自定义网络和 iptables 规则实现隔离。

8.1 自定义隔离网络

# 创建自定义 bridge 网络
docker network create --driver bridge isolated-net

# 启动服务时加入自定义网络
docker run -d --name frontend --network isolated-net frontend:latest
docker run -d --name backend --network isolated-net backend:latest

# 限制边界网络接入,只有前端可暴露端口到外网
docker run -d --name db --network isolated-net \
  --network-alias postgres \
  postgres:15

数据库服务 db 不映射任何宿主机端口,仅允许在同一 isolated-net 中的其他容器通过内部 DNS 解析进行访问,天然屏蔽了外部直接访问的可能。

8.2 禁用 ICC(容器间通信)

在需要进一步隔离的场景下,可以关闭同一网络内容器之间的直接通信,使其仅允许通过显式端口映射进行交互。

# 创建禁用 ICC 的桥接网络
docker network create \
  --driver bridge \
  --opt com.docker.network.bridge.enable_icc=false \
  high-secure-net

启用此选项后,即使两个容器在同一网络中,也无法直接访问对方的端口,除非通过外部负载均衡或代理转发。

8.3 iptables 规则加固

Docker 默认通过 DOCKER-USER 链将 iptables 规则暴露给用户自定义,所有用户规则均插入到此链中。

# 阻止容器访问特定 IP(例如元数据服务)
iptables -I DOCKER-USER -d 169.254.169.254 -j DROP

# 仅允许容器访问外部 HTTPS 端口
iptables -I DOCKER-USER -p tcp ! --dport 443 -j DROP

# 持久化规则
apt-get install -y iptables-persistent
netfilter-persistent save

169.254.169.254 是云厂商常见的实例元数据服务地址,历史上多次发生容器通过 SSRF 窃取 IAM 凭证的事件,通过 iptables 阻断是最有效的防护措施之一。


九、运行时安全监控

事前加固可以减少攻击面,但无法保证绝对安全。运行时监控和审计日志是发现异常行为和事后取证的关键技术手段。

9.1 Falco — 云原生安全监控

Falco 由 Sysdig 开源,通过内核模块或 eBPF 探针监控系统调用,以规则引擎检测异常行为。它在检测到可疑事件时输出高保真告警日志。

# 使用 Helm 安装 Falco
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
  --set driver.kind=modern_ebpf \
  --set tty=true

# 查看内核触发的 Falco 告警
kubectl logs -l app.kubernetes.io/name=falco | grep Warning

以下是一个自定义 Falco 规则,检测容器内是否出现了反弹 shell 连接行为:

# /etc/falco/rules.d/custom.yaml
- rule: Reverse Shell Detected
  desc: Detect spawn of a shell with an established network connection
  condition: >
    spawned_process and
    shell_procs and
    (inbound_outbound or
     fd.name in ("127.0.0.1", "0.0.0.0"))
  output: >
    Reverse shell connection detected
    user=%user.name command=%proc.cmdline parent=%proc.pname
    connection=%fd.name
  priority: CRITICAL

9.2 Sysdig 容器取证

Sysdig 是一个轻量级的系统级信息收集工具,能够在不修改应用的情况下捕获容器内的全部系统调用和 I/O 活动,生成 .scap 抓包文件用于事后分析。

# 安装 Sysdig
sudo apt-get install -y sysdig

# 抓取特定容器的全部系统调用(用于事后分析)
sudo sysdig -pc -c echo_fds \
  container.name=my-app > /tmp/container-forensics.scap &

# 读取抓包文件
sudo sysdig -r /tmp/container-forensics.scap \
  "proc.aname contains curl and evt.type=connect"

Sysdig 特别适用于「某容器曾被入侵但当前不可复现」的场景,通过有限的抓包数据可以还原攻击链全过程。

9.3 审计日志集成(auditd)

Docker 的 dockerd 守护进程支持向 auditd 输出关键事件日志。

# 在 daemon.json 中启用审计日志
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "labels": ["environment", "service"],
  "live-restore": true
}
EOF

sudo systemctl restart docker

# 查看审计日志
cat /var/log/audit/audit.log | grep docker

建议通过 auditd 规则监控对 Docker 守护进程 socket 文件 /var/run/docker.sock 的访问,因为拥有 socket 访问权限等同于拥有 root 权限。


十、CVE 响应与镜像更新策略

安全加固不是一次性的工作,持续跟进漏洞情报和及时更新镜像,是保持安全态的核心运营环节。

10.1 Distroless / Chiseled 最小化攻击面

Google 的 Distroless 镜像和 Canonical 的 Chiseled 镜像通过移除系统包管理器、shell 和冗余库文件,将攻击面压缩到绝对最小。

# Distroless 示例:静态编译 Go 应用
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o main .

# 运行时镜像仅包含 scratch + CA certs
gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/main /main
USER nonroot:nonroot
ENTRYPOINT ["/main"]
# Chiseled 示例:最小化 Ubuntu 基础镜像
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates

FROM ubuntu:22.04
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY my-app /usr/local/bin/my-app
ENTRYPOINT ["my-app"]

Distroless 镜像内部没有 sh、bash、apt、curl 等工具,即使攻击者获得执行权,也无法继续横向移动或下载恶意载荷。

10.2 Dependabot / Renovate 自动更新

依赖漏洞通常比操作系统漏洞更多,手动跟踪每个包的更新是不现实的。Dependabot 和 Renovate 是两款流行的自动依赖更新工具。

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    ignore:
      - dependency-name: "node"
        update-types: ["version-update:semver-major"]

  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    commit-message:
      prefix: "security"

Renovate 功能更为强大,支持分支式配置、定时批量合并、以及自动修复 lockfile 冲突。推荐在 CI 中配置 Renovate 且关闭自动合并,要求所有依赖更新 PR 通过回归测试和人工审查后再合并。

10.3 漏洞优先级评估

并非所有 CVE 都需要立即修复,有效的漏洞管理应基于可利用性进行优先级排序。

# 使用 Trivy 的漏洞数据库评估可利用性
trivy image --vuln-type os \
            --severity HIGH,CRITICAL \
            --ignore-unfixed \
            my-app:latest

业界广泛采用 EPSS(Exploit Prediction Scoring System)和 CISA KEV(Known Exploited Vulnerabilities Catalog)作为漏洞优先级判断依据。一个漏洞虽然被评为 Critical,但如果 EPSS 分数低于 0.1 且不在 KEV 目录中,可以延后至下一个维护窗口修复。反之,即使一个漏洞被评为 Medium,如果 KEV 目录中已有野外利用记录,应作为最高优先级立即处理。


常见问题(FAQ)

Docker 容器会被黑客攻击吗?

会。如果容器以 root 运行且应用程序存在漏洞,攻击者可能首先获得容器内 root 权限。虽然从容器突破到宿主机通常需要额外的内核漏洞(容器逃逸),但不应轻视容器安全。历史上,Docker 的 runc 和 Linux 内核的 dirty cow、 privilege escalation 漏洞都曾被利用实现容器逃逸。正确的做法是将容器视为一个可被破坏的边界,通过纵深防御策略降低逃逸后的影响面。

扫描出漏洞怎么办?

  1. 更新基础镜像:运行 docker pull node:20-alpine 拉取最新版本,重新构建后再次扫描
  2. 更新应用依赖:使用 npm audit fix、pip-audit --fix 或 cargo audit 修复已知依赖漏洞
  3. 评估风险:如果漏洞无修复版本,结合 CVSS 评分、EPSS 分数和实际利用场景进行风险评估
  4. 临时缓解:通过 WAF 规则、网络微分段或运行时策略暂时阻止利用路径,等待上游修复
  5. 记录与跟踪:在漏洞管理系统中归档该 CVE,设定修复时间表并安排复查

相关阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「saas」更多文章

  1. 短链接对 SEO 的影响与优化最佳实践
  2. UTM 参数 + 短链接:追踪每一条营销链路
  3. 私域流量运营中的短链接策略:从引流到转化