Skip to main content

关于使用 OpenID Connect 进行安全强化

OpenID Connect 允许您的工作流程直接从云提供商交换短期令牌。

注意:GitHub Enterprise Server 目前不支持 GitHub 托管的运行器。 可以在 GitHub public roadmap 上查看有关未来支持计划的更多信息。

OpenID Connect 概述

GitHub Actions 工作流程通常设计为访问云提供商(如 AWS、Azure、GCP 或 HashiCorp Vault),以便部署软件或使用云的服务。 在工作流程可以访问这些资源之前,它将向云提供商提供凭据(如密码或令牌)。 这些凭据通常作为机密存储在 GitHub 中,工作流程在每次运行时都会将此机密呈现给云提供商。

但是,使用硬编码的机密需要在云提供商中创建凭据,然后在 GitHub 中将其复制为机密。

借助 OpenID Connect (OIDC),您可以采用不同的方法,将工作流程配置为直接从云提供商请求短期访问令牌。 您的云提供商还需要在其终端上支持 OIDC,并且您必须配置信任关系,以控制哪些工作流程能够请求访问令牌。 目前支持 OIDC 的提供商包括 Amazon Web Services、Azure、Google Cloud Platform 和 HashiCorp Vault 等。

使用 OIDC 的好处

通过更新工作流程以使用 OIDC 令牌,您可以采用以下良好的安全实践:

  • 无云机密:无需将云凭据复制为长期 GitHub 机密。 相反,您可以在云提供商上配置 OIDC 信任,然后更新您的工作流程,通过 OIDC 向云提供商请求短期访问令牌。
  • 身份验证和授权管理:可以更精细地控制工作流使用凭据的方式,使用云提供商的身份验证 (authN) 和授权 (authZ) 工具来控制对云资源的访问。
  • 轮换凭据:借助 OIDC,云提供商会颁发一个仅对单个作业有效的短期访问令牌,然后自动过期。

开始使用 OIDC

下图概述了 GitHub 的 OIDC 提供商如何与您的工作流程和云提供商集成:

OIDC 图

  1. 在云提供商中,在您的云角色和需要访问云的 GitHub 工作流程之间创建 OIDC 信任。
  2. 每次作业运行时,GitHub的 OIDC 提供商都会自动生成一个 OIDC 令牌。 此令牌包含多个声明,用于建立有关尝试进行身份验证的特定工作流程的经安全强化且可验证的身份。
  3. 您可以在作业中包含一个步骤或操作,以从 GitHub 的 OIDC 提供商请求此令牌,并将其提供给云提供商。
  4. 云提供商成功验证令牌中提供的声明后,将提供仅在作业期间可用的短期云访问令牌。

通过云配置 OIDC 信任

将云配置为信任 GitHub 的 OIDC 提供商时,必须添加筛选传入请求的条件,使不受信任的存储库或工作流无法为云资源请求访问令牌:

  • 在授予访问令牌之前,云提供商会检查用于在其信任设置中设置条件的 subject 和其他声明是否与请求的 JSON Web 令牌 (JWT) 中的声明匹配。 因此,必须注意正确定义云提供商中的主题和其他条件。
  • OIDC 信任配置步骤和为云角色设置条件的语法(使用主题和其他声明)会因所使用的云提供商而异。 有关一些示例,请参阅“示例主题声明”。

了解 OIDC 令牌

每个作业都从 GitHub 的 OIDC 提供商请求一个 OIDC 令牌,提供商使用自动生成的 JSON Web 令牌 (JWT) 进行响应,该令牌对于生成它的每个工作流程作业都是唯一的。 当作业运行时,OIDC 令牌将呈现给云提供商。 要验证令牌,云提供商会检查 OIDC 令牌的主题和其他声明是否与云角色的 OIDC 信任定义上预配置的条件匹配。

以下示例 OIDC 令牌使用主题 (sub),该主题引用 octo-org/octo-repo 存储库中名为 prod 的作业环境。

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "example-thumbprint",
  "kid": "example-key-id"
}
{
  "jti": "example-id",
  "sub": "repo:octo-org/octo-repo:environment:prod",
  "environment": "prod",
  "aud": "https://HOSTNAME/octo-org",
  "ref": "refs/heads/main",
  "sha": "example-sha",
  "repository": "octo-org/octo-repo",
  "repository_owner": "octo-org",
  "actor_id": "12",
  "repository_visibility": private,
  "repository_id": "74",
  "repository_owner_id": "65",
  "run_id": "example-run-id",
  "run_number": "10",
  "run_attempt": "2",
  "actor": "octocat",
  "workflow": "example-workflow",
  "head_ref": "",
  "base_ref": "",
  "event_name": "workflow_dispatch",
  "ref_type": "branch",
  "job_workflow_ref": "octo-org/octo-automation/.github/workflows/oidc.yml@refs/heads/main",
  "iss": "https://HOSTNAME/_services/token",
  "nbf": 1632492967,
  "exp": 1632493867,
  "iat": 1632493567
}

要查看 GitHub 的 OIDC 提供商支持的所有声明,请查看 https://HOSTNAME/_services/token/.well-known/openid-configuration 处的 claims_supported 条目。

令牌包括标准受众、颁发者和主题声明:

声明说明
aud(受众)默认情况下,这是存储库所有者(例如拥有存储库的组织)的 URL。 这是唯一可以自定义的声明。 可以使用工具包命令设置自定义受众:core.getIDToken(audience)
iss(颁发者)OIDC 令牌的颁发者:https://HOSTNAME/_services/token
sub(主题)定义要由云提供商验证的主题声明。 此设置对于确保仅以可预测的方式分配访问令牌至关重要。

OIDC 令牌还包括其他标准声明:

声明说明
alg(算法)OIDC 提供商使用的算法。
exp(过期时间)标识 JWT 的过期时间。
iat(发布时间)JWT 的发布时间。
jti(JWT 令牌标识符)OIDC 令牌的唯一标识符。
kid(密钥标识符)OIDC 令牌的唯一密钥。
nbf(生效时间)JWT 在此时间之前不可使用。
typ(类型)描述令牌的类型。 这是 JSON Web 令牌 (JWT)。

令牌还包括 GitHub 提供的自定义声明:

声明说明
actor发起工作流运行的个人帐户。
actor_id发起工作流运行的个人帐户的 ID。
base_ref工作流程运行中拉取请求的目标分支。
environment作业使用的环境的名称。
event_name触发工作流程运行的事件的名称。
head_ref工作流程运行中拉取请求的来源分支。
job_workflow_ref这是此作业使用的可重用工作流程的引用路径。 有关详细信息,请参阅“将 OpenID Connect 与可重用工作流结合使用’”。
ref(参考)触发工作流运行的 git ref。
ref_typeref 的类型,例如:“branch”。
repository_visibility运行工作流的存储库的可见性。 可接受以下值:internalprivatepublic
repository运行工作流程的存储库。
repository_id运行工作流的存储库的 ID。
repository_owner存储 repository 的组织的名称。
repository_owner_id存储 repository 的组织的 ID。
run_id触发工作流程的工作流程运行的 ID。
run_number此工作流程已运行的次数。
run_attempt此工作流程运行的重试次数。
workflow工作流的名称。

使用 OIDC 声明定义云角色的信任条件

借助 OIDC,GitHub Actions 工作流程需要令牌才能访问云提供商中的资源。 工作流程从云提供商请求访问令牌,以检查 JWT 提供的详细信息。 如果 JWT 中的信任配置匹配,则云提供商将通过向工作流程颁发临时令牌来做出响应,然后可以使用该令牌访问云提供商中的资源。 您可以将云提供商配置为仅响应来自特定组织的存储库的请求;您还可以指定其他条件,如下所述。

在云角色/资源上设置条件以限定其对 GitHub 工作流程的访问范围时,受众和主题声明通常结合使用。

  • 受众:此值默认使用组织或存储库所有者的 URL。 这可用于设置只有特定组织中的工作流程才能访问云角色的条件。
  • 主题:默认情况下具有预定义格式,是有关工作流的一些关键元数据的串联,例如 GitHub 组织、存储库、分支或关联的 job 环境。 请参阅主题声明示例,了解主题声明是如何从连接的元数据中组合而成的。

如果需要更精细的信任条件,可以自定义 JWT 中包含的颁发者 (iss) 和主题 (sub) 声明。 有关详细信息,请参阅“自定义令牌声明”。

OIDC 令牌中还支持许多其他声明,这些声明可用于设置这些条件。 此外,云提供商可以允许你为访问令牌分配角色,从而允许你指定更精细的权限。

注意:要控制云提供商颁发访问令牌的方式,必须至少定义一个条件,使不受信任的存储库无法为云资源请求访问令牌 。

示例主题声明

以下示例演示如何使用“主题”作为条件,并说明如何从串联的元数据汇编“主题”。 主题使用来自 job 上下文的信息,并指示云提供商只能为来自特定分支、环境中运行的工作流的请求授予访问令牌请求。 以下各节介绍了您可以使用的一些常见主题。

筛选特定环境

当作业引用环境时,主题声明包括环境名称。

可以配置用于筛选特定环境名称的主题。 在此示例中,工作流运行必须源自 octo-org 组织拥有的名为 octo-repo 的存储库中,一个具有名为 Production 的环境的作业:

语法:repo:<orgName/repoName>:environment:<environmentName>
例如:repo:octo-org/octo-repo:environment:Production

筛选 pull_request 事件

当工作流由拉取请求事件触发时,主题声明包含 pull_request 字符串,但前提是作业未引用环境。

可以配置筛选 pull_request 事件的主题。 在此示例中,工作流运行必须由 octo-org 组织拥有的名为 octo-repo 的存储库中的 pull_request 事件触发:

语法:repo:<orgName/repoName>:pull_request
例如:repo:octo-org/octo-repo:pull_request

筛选特定分支

主题声明包括工作流程的分支名称,但前提是作业未引用环境,并且工作流程不是由拉取请求事件触发的。

您可以配置筛选特定分支名称的主题。 在此示例中,工作流运行必须源自 octo-org 组织拥有的名为 octo-repo 的存储库中,一个名为 demo-branch 的分支:

语法:repo:<orgName/repoName>:ref:refs/heads/branchName
例如:repo:octo-org/octo-repo:ref:refs/heads/demo-branch

筛选特定标记

主题声明包括工作流程的标记名称,但前提是作业未引用环境,并且工作流程不是由拉取请求事件触发的。

您可以创建筛选特定标记的主题。 在此示例中,工作流运行必须源自 octo-org 组织拥有的名为 octo-repo 的存储库中,一个名为 demo-tag 的标记:

语法:repo:<orgName/repoName>:ref:refs/tags/<tagName>
例如:repo:octo-org/octo-repo:ref:refs/tags/demo-tag

在云提供商中配置主题

要在云提供商的信任关系中配置主题,必须将主题字符串添加到其信任配置中。 以下示例演示了不同的云提供商如何以不同的方式接受同一 repo:octo-org/octo-repo:ref:refs/heads/demo-branch 主题:

Amazon Web Services"HOSTNAME/_services/token:sub": "repo:octo-org/octo-repo:ref:refs/heads/demo-branch"
Azurerepo:octo-org/octo-repo:ref:refs/heads/demo-branch
Google Cloud Platform(assertion.sub=='repo:octo-org/octo-repo:ref:refs/heads/demo-branch')
HashiCorp Vaultbound_subject="repo:octo-org/octo-repo:ref:refs/heads/demo-branch"

有关详细信息,请参阅“为云提供商启用 OpenID Connect”中列出的指南。

更新用于 OIDC 的操作

要更新自定义操作以使用 OIDC 进行身份验证,可以使用 Actions 工具包中的 getIDToken() 从 GitHub 的 OIDC 提供商请求 JWT。 有关详细信息,请参阅 npm 包文档中的“OIDC 令牌”。

还可以使用 curl 命令通过以下环境变量请求 JWT:

ACTIONS_ID_TOKEN_REQUEST_URLGitHub 的 OIDC 提供商的 URL。
ACTIONS_ID_TOKEN_REQUEST_TOKEN向 OIDC 提供商发出请求的持有者令牌。

例如:

Shell
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange"

添加权限设置

作业或工作流运行需要具有 id-token: writepermissions 设置。 如果 id-tokenpermissions 设置已设置为 readnone,则无法请求 OIDC JWT ID 令牌。

id-token: write 设置允许使用下列方法之一从 GitHub 的 OIDC 提供程序请求 JWT:

  • 在运行器上使用环境变量(ACTIONS_ID_TOKEN_REQUEST_URLACTIONS_ID_TOKEN_REQUEST_TOKEN)。
  • 使用“操作”工具包中的 getIDToken()

如果需要为工作流提取 OIDC 令牌,则可以在工作流级别设置权限。 例如:

YAML
permissions:
  id-token: write # This is required for requesting the JWT
  contents: read  # This is required for actions/checkout

如果只需要为单个作业提取 OIDC 令牌,则可在该作业中设置此权限。 例如:

YAML
permissions:
  id-token: write # This is required for requesting the JWT

可能需要在此处指定额外权限,具体取决于你的工作流要求。

更新 OIDC 的工作流程

现在,您可以更新 YAML 工作流程,以使用 OIDC 访问令牌而不是机密。 常用的云提供商已发布其官方登录操作,使您可以轻松开始使用 OIDC。 有关更新工作流的详细信息,请参阅下面“为云提供商启用 OpenID Connect”中列出的特定于云的指南。

为云提供商启用 OpenID Connect

要为您的特定云提供商启用和配置 OIDC,请参阅以下指南:

要为其他云提供商启用和配置 OIDC,请参阅以下指南: