第03章:AI生成的Dockerfile镜像运行为root用户

第03章:AI生成的Dockerfile镜像运行为root用户

“AI 帮你写了 Dockerfile,镜像构建成功,容器正常运行。安全扫描报告出来了:容器以 root(UID 0)运行,如果容器被攻破,攻击者可以以 root 权限在容器里操作,并可能通过容器逃逸获得宿主机权限。AI 不会主动给你加非 root 用户——这是最常见的容器安全遗漏。”


ℹ️ 版本说明:本章基于 Kubernetes 1.36.1 + Docker/OCI 镜像安全。

3.1 AI默认会生成什么

# AI 通常给你的 Dockerfile(以 root 运行)
FROM python:3.13-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

EXPOSE 8080
CMD ["python", "app.py"]

这个 Dockerfile 没有创建非 root 用户,容器默认以 root(UID 0)运行。


3.2 AI通常遗漏的4个坑

⚠️ 坑1:为什么 root 是问题

在容器里以 root 运行意味着:

  • 容器里的进程可以读写所有文件
  • 如果应用有 RCE(远程代码执行)漏洞,攻击者获得 root shell
  • 容器逃逸漏洞(历史上有多个)+ root 容器 = 宿主机 root 权限
  • 挂载宿主机目录时,root 容器可以修改宿主机的敏感文件

正确做法:用非 root 用户运行应用进程:

FROM python:3.13-slim

RUN useradd --create-home --shell /bin/bash appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser . .

USER appuser   # 切换到非 root 用户
EXPOSE 8080
CMD ["python", "app.py"]

⚠️ 坑2:Kubernetes SecurityContext 强制非 root

即使 Dockerfile 里有 USER appuser,也可以在 Kubernetes 里额外强制:

spec:
  securityContext:
    runAsNonRoot: true     # 拒绝以 root 运行的容器
    runAsUser: 1000        # 指定 UID
    fsGroup: 1000          # 挂载卷的 owner group
  containers:
  - name: my-app
    securityContext:
      readOnlyRootFilesystem: true   # 容器文件系统只读
      allowPrivilegeEscalation: false  # 禁止提权
      capabilities:
        drop: ["ALL"]      # 移除所有 Linux capabilities

⚠️ 坑3:端口 < 1024 需要特殊处理

非 root 用户无法绑定 1024 以下的端口(HTTP 80、HTTPS 443)。

解决方案:

  1. 应用监听高端口(如 8080),再用 Service/Ingress 做端口映射:port: 80 → targetPort: 8080(推荐)
  2. 如果必须 80:CAP_NET_BIND_SERVICE capability 允许非 root 绑定低端口(不推荐)

⚠️ 坑4:基础镜像大小和漏洞数量

AI 通常选择完整版镜像(python:3.13),包含大量开发工具和潜在漏洞:

python:3.13         → ~900MB,数百个已知 CVE
python:3.13-slim    → ~150MB,较少 CVE
python:3.13-alpine  → ~60MB,极少 CVE(但 musl libc 可能有兼容性问题)
gcr.io/distroless/python3  → 极小,无 shell(无法进入容器调试)

推荐:生产使用 slimdistroless,开发使用完整镜像(方便调试)。


3.3 更好的提示词

提示词 P01:生产级安全 Dockerfile

使用时机:为应用生成安全的容器镜像

比默认多了什么

  • 非 root 用户
  • 多阶段构建(减小镜像大小)
  • 只读文件系统(可选)
帮我为一个 [Python FastAPI / Node.js / Go / Java] 应用写一个生产级安全 Dockerfile。

应用信息:
- 语言:[Python 3.13 / Node.js 24 / 其他]
- 框架:[FastAPI / Express / 其他]
- 监听端口:[8080](避免 80/443 等低端口)

安全要求:
1. 非 root 用户:
   - 创建 appuser(UID 1000)
   - 用 USER appuser 运行应用
   
2. 多阶段构建:
   - build 阶段:安装依赖、编译
   - production 阶段:只复制运行所需文件
   
3. 最小基础镜像:
   - 推荐哪个 base image?(slim / alpine / distroless?各自权衡?)
   
4. 其他安全实践:
   - 不在镜像里放 .env 文件或密钥
   - 设置 WORKDIR
   - COPY 时用 --chown=appuser
   - 不 COPY 不需要的文件(.dockerignore 的内容)

同时给我:
- .dockerignore 文件内容
- 对应的 Kubernetes SecurityContext 配置
- 如何用 docker scout 或 trivy 扫描镜像漏洞?

基于 Kubernetes 1.36.1。

提示词 P02:Kubernetes Pod Security Standards 配置

使用时机:为集群配置 Pod 安全策略,强制所有 Pod 遵守安全标准

比默认多了什么

  • PSS(Pod Security Standards)的三种级别
  • 如何在 Namespace 级别强制执行
帮我配置 Kubernetes 1.36.1 的 Pod Security Standards(PSS),强制所有 Pod 遵守安全规则。

背景:K8s 1.25+ 废弃了 PodSecurityPolicy,改用 PSS。

三种安全级别(给我每种的详细说明):
1. Privileged(宽松):几乎没有限制
2. Baseline(基础):防止明显的特权提升
3. Restricted(严格):最佳实践,包含非 root、只读文件系统等

我的需求:
- production Namespace:Restricted 级别
- staging Namespace:Baseline 级别
- kube-system Namespace:不限制(系统组件需要特权)

配置步骤:
1. 在 Namespace 上添加 PSS label:
   - enforce(强制,违规 Pod 被拒绝)
   - warn(只警告,不拒绝)
   - audit(记录日志,不拒绝)
   
2. 如果我有已有的 Pod 不符合 Restricted 标准:
   - 如何检查哪些 Pod 不符合?
   - 先用 warn 模式,再升级到 enforce?

3. SecurityContext 的最佳实践配置(满足 Restricted 标准):
   - runAsNonRoot: true
   - readOnlyRootFilesystem: true
   - capabilities: drop ALL
   - allowPrivilegeEscalation: false

给我完整的 Namespace YAML 和 SecurityContext 模板。

基于 Kubernetes 1.36.1。

提示词 P03:镜像漏洞扫描和修复流程

使用时机:建立 CI/CD 里的镜像安全扫描流程

比默认多了什么

  • 集成 trivy 到 CI
  • 漏洞严重级别的处理策略
帮我在 CI/CD 中集成 Docker 镜像安全扫描流程。

扫描工具:trivy(开源,被广泛使用)
CI 平台:GitHub Actions

需要的功能:

1. GitHub Actions workflow(每次构建镜像后自动扫描):
   - 扫描 HIGH 和 CRITICAL 级别的 CVE
   - 有 HIGH/CRITICAL CVE 时 CI 失败(阻止部署)
   - 扫描结果上传到 GitHub Security Alerts

2. 漏洞处理策略:
   - CRITICAL:立刻修复,不能部署
   - HIGH:48小时内修复
   - MEDIUM/LOW:记录,下个迭代修复
   - 如何对特定 CVE 设置例外(已知无法修复的漏洞)?

3. 如何快速修复漏洞:
   - 更新基础镜像版本(`python:3.13.X-slim` 的最新补丁版)
   - 更新依赖包版本
   - 使用 `pip-audit` 或 `npm audit` 检查应用依赖

4. .github/workflows/security-scan.yml 完整内容

基于 GitHub Actions + trivy 最新版。

3.4 验收清单

检查项 验证方法 AI辅助
容器以非 root 运行 kubectl exec <pod> -- id 输出不是 root 用 P01 修改 Dockerfile
SecurityContext 有 runAsNonRoot YAML 中有 runAsNonRoot: true 用 P02 添加 SecurityContext
capabilities: drop ALL YAML 中有 capabilities.drop: [“ALL”] 用 P02 配置
镜像无 HIGH/CRITICAL CVE trivy 扫描结果干净 用 P03 配置扫描 CI
基础镜像用 slim 或更小 docker images 检查镜像大小 让 AI 优化 Dockerfile
CI 有镜像安全扫描 PR 里有 trivy 扫描 job 运行 用 P03 配置 CI

3.5 本章小结

如果你只记一件事:在 Dockerfile 的最后 CMDENTRYPOINT 之前加两行:

RUN useradd --create-home --uid 1000 appuser
USER appuser

这两行让你的容器从 root 切换到非 root 用户,是容器安全最基础的实践。同时在 K8s 的 SecurityContext 里加 runAsNonRoot: true,防止镜像里没有设置 USER 时意外以 root 运行。

容器安全的三个层次

  1. 非 root 用户(Dockerfile USER + SecurityContext runAsNonRoot):最基础的防御,限制容器内进程权限
  2. 能力最小化(drop ALL capabilities + readOnlyRootFilesystem):减少攻击面
  3. 无漏洞基础镜像(slim/distroless + 定期 trivy 扫描):从源头减少已知漏洞

→ 第4章:AI帮我配置了ConfigMap但secrets没有加密