PAYATHON 2026

使用 Docker 和 Kubernetes 部署 .NET Web API 时如何管理密钥配置?

数据阿明

针对这个部署场景,建议将 RSA 私钥移出 appsettings.json,通过 Kubernetes Secret 以文件形式挂载给应用。GitHub 仓库保存部署配置和 Secret 引用,Docker 镜像只包含程序和非敏感配置。需要集中管理多个环境的密钥时,再接入外部密钥管理服务。

各个环境如何选择

  • 本地开发:普通敏感配置可以使用 .NET User Secrets。RSA 私钥也可以保存在仓库之外的受限文件中,配置里只保存路径。User Secrets 不加密存储内容,只适合开发环境。Microsoft 文档
  • CI/CD:构建和推送镜像通常只需要镜像仓库凭据,不需要生产 RSA 私钥。使用 GitHub Actions 时,可以通过 Actions Secrets 提供流水线所需的凭据,但这些值不会自动成为 Kubernetes 中的运行时配置。GitHub 文档
  • Kubernetes 运行环境:通过 Secret 注入敏感配置。RSA 私钥通常包含多行内容,挂载为文件便于保留原始格式,也便于应用按路径读取。Kubernetes 文档

RabbitMQ 的密码也可以按这种方式管理。各服务应只获得自己需要的凭据。

第一步:把私钥移出仓库和镜像

appsettings.json 可以继续保存日志级别、服务地址和私钥文件路径,但应删除私钥正文。

同时检查 Dockerfile 的 COPY 范围,通过 .dockerignore 排除本地密钥文件。仅添加 .gitignore,不能阻止未跟踪的文件被放进 Docker 构建上下文。

如果真实私钥已经进入 Git 提交历史、发布镜像或构建日志,应按可能泄露处理,执行密钥轮换并排查传播范围。删除当前文件无法撤回已经发布的内容。

第二步:在 Kubernetes 中创建 Secret

下面假设目标 namespace 为已存在的 my-app,私钥文件保存在仓库之外。路径和资源名称需要按实际环境替换。

kubectl -n my-app create secret generic web-api-rsa \
  --from-file=private-key.pem=/secure/path/private-key.pem

该命令从文件创建 Secret,不会将私钥正文直接写入命令参数。执行端仍需保护原始文件,并具备创建目标 Secret 的权限。

不要把包含真实私钥的 Secret YAML 提交到 GitHub。Secret 的 data 字段使用 Base64 编码,这并不等于加密。Kubernetes Secret 文档

第三步:将 Secret 挂载给 Web API

以下是 Deployment 中 spec.template.spec 的配置片段。将其合并进现有部署文件时,需确保 Deployment 与 Secret 位于同一 namespace:

containers:
  - name: web-api
    image: your-account/your-web-api:your-tag
    env:
      - name: Rsa__PrivateKeyPath
        value: /run/secrets/rsa/private-key.pem
    volumeMounts:
      - name: rsa-key
        mountPath: /run/secrets/rsa
        readOnly: true
volumes:
  - name: rsa-key
    secret:
      secretName: web-api-rsa
      items:
        - key: private-key.pem
          path: private-key.pem

这个片段只包含 Secret 名称、文件路径和非敏感配置,可以存入 GitHub。镜像名称是占位示例,需要替换。

应结合容器运行用户设置文件权限,确保应用能够读取私钥,并限制其他进程访问。

第四步:让 .NET 从文件读取私钥

以下代码假设应用使用 ASP.NET Core 的默认配置机制和 .NET 6+ 的启动方式,且私钥是文本格式文件。可以把读取逻辑放入现有的密钥加载服务中:

var builder = WebApplication.CreateBuilder(args);

var privateKeyPath = builder.Configuration["Rsa:PrivateKeyPath"]
    ?? throw new InvalidOperationException(
        "Missing configuration: Rsa:PrivateKeyPath");

var privateKeyPem = File.ReadAllText(privateKeyPath);

// Pass privateKeyPem to the service that uses the RSA key.
// Do not write the key to logs.

默认环境变量配置提供程序会将 Rsa__PrivateKeyPath 映射为 Rsa

。如果应用自行替换了默认配置来源,需要确认仍然加载环境变量。Microsoft 配置文档

读取文件和解析 RSA 私钥是两个步骤。原问题没有说明私钥格式;PEM、加密 PEM、DER 或其他格式,需要使用对应的解析方式。示例只演示配置路径和文件读取。

CI/CD 中有哪些注意事项

生产 RSA 私钥应在部署或运行阶段提供。如果测试需要私钥,使用独立的测试密钥。

如果构建过程必须访问私有依赖源,可以使用 BuildKit secret mount 提供构建凭据。不要通过 Dockerfile 的 ARG、ENV 或 COPY 写入密钥,也不要先复制密钥,再依靠后续层删除。构建步骤同样不能把挂载的凭据复制到输出产物中。Docker 构建密钥文档

部署阶段可以由受限流程创建或更新 Kubernetes Secret,也可以由集群从外部密钥管理服务获取。应限制有权读取 Secret、创建 Pod 或修改 Deployment 的主体,并确认集群已配置 Secret 静态加密。资源类型是 Secret,并不代表存储已经加密。Kubernetes 安全实践

密钥更新后是否会自动生效

Secret 更新后,挂载的文件通常会最终同步,但应用已经加载到内存中的私钥不会自动替换。上面的代码只读取一次,轮换密钥后需要重启工作负载,或另行实现安全的重新加载逻辑。

通过环境变量注入的 Secret 不会自动更新已有进程的环境变量;使用 subPath 挂载的 Secret 文件也不会自动更新。应将应用重新加载或滚动重启纳入轮换流程。Kubernetes 更新行为说明

如果后续需要跨集群共享、集中审计或自动轮换,可以引入外部密钥管理服务。对于当前场景,先将私钥从仓库和镜像中移除,在运行时挂载并限制访问,再建立轮换流程。

备注:内容仅供参考。