Docker 已为 GitHub Actions 与 Docker Hub 之间启用 OpenID Connect 身份认证,允许工作流使用签名的每轮运行身份令牌换取短生命周期的 Docker 凭证,而非从仓库密钥中读取 Personal Access Token。根据 Docker 官方博客,该功能面向 Docker Team、Docker Business 及 Docker Hardened Images 方案的组织开放。对于平台团队而言,这把注册表凭证从「每 90 天轮换一次,祈祷不出事」堆栈中移除,纳入与 AWS、GCP、Azure 和 HashiCorp Vault 相同的联合身份模式。
机制简述
该模式是标准的 Actions OIDC 交换流程。当工作流声明 permissions: id-token: write 时,GitHub 会为本次运行签发 JWT,其中包含仓库、分支或环境、工作流名称等声明。工作流将该 JWT 提交给 Docker,Docker 使用 GitHub 的公钥验证签名,并根据 Docker 端配置的信任策略检查声明,之后返回本次运行可用的短生命周期凭证。任务结束后凭证即失效。仓库、环境密钥或 Actions 缓存中均不再留存长期 Docker 令牌。Docker 将这一变更定位为消除 CI/CD 流水线中的静态凭证,前提是用户随后确实删除了 PAT。
信任策略有两点需要注意。首先,作用域在 Docker 侧定义,而非 GitHub。如果策略允许信任 my-org/* 下的任意工作流,攻击者只要能向任意仓库推送分支即可请求 Docker 凭证。更安全的做法是将策略限定在特定仓库和特定环境(environment:prod),并在 GitHub 侧对该环境设置必需的审核者。其次,OIDC 移除了凭证本身,但并未移除授权边界:令牌虽已短生命周期,但信任策略本身成为需要长期审计的对象。
凭证为何重要
静态注册表令牌已成为今年多起供应链事件的根源。能从被攻陷分支推送公共标签的 PAT 或 OAT,只需一次 API 调用即可完成供应链劫持,且不像云 IAM 密钥那样通常受工作负载身份边界保护。轮换虽有帮助,但并非免费:轮换后的 Docker 令牌需重新分发到每个推送镜像的 Actions 仓库和自托管运行器,这也是团队实际轮换频率低于策略要求的原因。
OIDC 并未改变受攻陷工作流在单次运行内能做的事,而是改变了残留痕迹。任务结束后,密钥存储中不再有任何可窃取内容。泄露令牌的影响半径从「直到下一次轮换周期」缩短为「直到本次任务结束」,对大多数 Actions 任务而言即几分钟。这在运维角度意味着:更少需要轮换、更少需要盘点、在事件中更少需要撤销。
工作流集成示例
Actions 侧的交换流程与其他 OIDC 集成一致。以下为示意代码,占位符需替换为正式版本:
permissions:
id-token: write
contents: read
jobs:
push:
runs-on: ubuntu-latest
environment: prod
steps:
- uses: actions/checkout@<full-40-char-sha>
- name: Log in to Docker Hub via OIDC
uses: docker/login-action@<full-40-char-sha>
with:
# OIDC-mode inputs per the Docker docs for this feature;
# no username or password is stored in the repo.
registry: docker.io
# ...OIDC-specific parameters go here...
- name: Build and push
run: |
docker buildx build \
--tag docker.io/$REGISTRY_NAMESPACE/app:${{ github.sha }} \
--push .
Enter fullscreen mode Exit fullscreen mode
来自运维侧的两点提醒:将登录 Action 固定到完整提交 SHA,而非浮动标签——你交给该步骤的凭证虽有时限,但其内部代码没有;同时在 Docker 侧将信任策略收窄:限定仓库、分支或环境,以及工作流文件路径。通配符策略相当于你原本想要淘汰的 read_write PAT。
该方案未解决的问题
OIDC 联合身份认证仅改变凭证管道。「运行已获得有效令牌」之后的所有下游环节仍需常规关注。
镜像来源不变。经 OIDC 认证的工作流仍是按你配置运行的工作流,仍受触发器允许的分支限制。若策略信任 main,自批合并到 main 的 PR 仍可获取 Docker 凭证。分支保护、部署环境必需的审核者,以及 Actions 对疑似恶意工作流的「等待批准」控制,均位于此功能的上游。
自托管运行器是另一处隐性限制。GitHub 托管运行器按文档方式签发 OIDC 令牌;自托管运行器也可签发,但信任边界变为「控制运行器主机的人可请求与信任策略匹配的 Docker 凭证」。若自托管集群未按仓库或环境完全隔离,Docker 信任策略的管控需至少与运行器注册令牌同等严格。
签名是独立环节。OIDC 移除推送凭证,但未添加签名摘要。若需拉取端验证推送端生成内容,仍需使用 Cosign 或平台自身的证明流程。
其他 CI 平台如何处理注册表认证
Docker Hub 虽晚于其他平台推出此集成,但模式本身已成熟。注册表认证策略因流水线运行位置而异。
GitHub Actions → GHCR。 若注册表为 ghcr.io,GitHub Actions 早已提供最简方案:内置 GITHUB_TOKEN 作用域限定在仓库,可直接推送到组织的容器注册表,无需额外联合配置。若 Docker Hub 并非硬性需求,GHCR 对 GitHub 原生团队仍是更简答案,此次 Docker OIDC 变更并未消除这一差距。
GitLab CI ID tokens。 GitLab 自有的 OIDC(流水线中的 id_tokens:)可联合 AWS、GCP、Vault,并通过注册表自身的 OIDC 提供者原生接入 GitLab Container Registry。对已使用 GitLab 的团队,ID-token 流程比任何外部注册表集成更原生;若从零选型,GitLab 方案更优。
CircleCI OIDC。 CircleCI 对作业签发 OIDC 令牌,主要用于云 IAM(AWS、GCP)。大多数团队在 CircleCI 上的 Docker Hub 注册表登录仍依赖存储的上下文密钥,这正是 Docker 在 GitHub 侧此次变更所解决的问题。
Buildkite agent OIDC。 Buildkite 的 agent 签名 OIDC 令牌已广泛用于 AWS 和 Vault。注册表认证模式因集群而异;agent 集群的信任边界比令牌类型更关键。
Buddy。 Buddy 是一款托管 CI/CD 平台,其 Docker 流水线 Action 包含从 Buddy 作用域密钥和每条流水线短生命周期凭证读取的注册表登录步骤。若你希望在同一 UI 中完成 Docker 推送与环境门禁,而非在 Actions 与外部策略间拼装,Buddy 是一种选择。若你的注册表需求全部在 Docker Hub,且 CI 已全部使用 GitHub,Docker 的新 OIDC 流程可让你留在现有工具链内。
贯穿全文的结论:联合身份认证已成为注册表认证的默认假设,而非可选功能。CI 中的长期注册表令牌已成为例外,每一例剩余令牌都应列入平台团队的待办轮换清单。
后续观察要点
值得跟踪的两件事。首先,Docker 侧信任策略表面是否会重现早期 AWS-to-Actions OIDC 策略的错误配置影响半径,即过于宽泛的 aud 和 sub 声明允许组织内任意工作流扮演生产角色。补救措施是收紧声明,此处亦需从第一天起严格执行。其次,Docker 是否会将 OIDC 流程扩展到 GitHub Actions 之外的其他 CI 平台。目前公告仅覆盖 GitHub Actions 和付费 Docker 组织层级;其他平台仍需继续轮换 PAT。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.