概述
OpenID Connect (OIDC) 允许您的 GitHub Actions 工作流程使用 HashiCorp Vault 进行身份验证以检索机密。
本指南概述如何将 HashiCorp Vault 配置为信任作为联合标识的 GitHub 的 OIDC,并演示如何在 hashicorp/vault-action 操作中使用此配置从 HashiCorp Vault 检索机密。
先决条件
-
若要了解 GitHub 如何使用 OpenID Connect (OIDC) 及其体系结构和优势的基本概念,请参阅“关于使用 OpenID Connect 进行安全强化”。
-
在继续之前,必须规划安全策略,以确保仅以可预测的方式分配访问令牌。 要控制云提供商颁发访问令牌的方式,必须至少定义一个条件,以便不受信任的存储库无法为云资源请求访问令牌。 有关详细信息,请参阅“关于使用 OpenID Connect 进行安全强化”。
将身份提供商添加到 HashiCorp Vault
要将 OIDC 与 HashiCorp Vault 配合使用,您需要为 GitHub OIDC 提供商添加信任配置。 有关详细信息,请参阅 HashiCorp Vault 文档。
将 Vault 服务器配置为接受 JSON Web 令牌 (JWT) 进行身份验证:
-
启用 JWT
auth
方法,并使用write
将配置应用于 Vault。 对于oidc_discovery_url
和bound_issuer
参数,请使用https://token.actions.githubusercontent.com
。 这些参数使 Vault 服务器可以在身份验证过程中验证收到的 JSON Web 令牌 (JWT)。Shell vault auth enable jwt
vault auth enable jwt
Shell vault write auth/jwt/config \ bound_issuer="https://token.actions.githubusercontent.com" \ oidc_discovery_url="https://token.actions.githubusercontent.com"
vault write auth/jwt/config \ bound_issuer="https://token.actions.githubusercontent.com" \ oidc_discovery_url="https://token.actions.githubusercontent.com"
-
配置策略以便仅授予对工作流将用于检索机密的特定路径的访问权限。 有关更高级的策略,请参阅 HashiCorp Vault 策略文档。
Shell vault policy write myproject-production - <<EOF # Read-only permission on 'secret/data/production/*' path path "secret/data/production/*" { capabilities = [ "read" ] } EOF
vault policy write myproject-production - <<EOF # Read-only permission on 'secret/data/production/*' path path "secret/data/production/*" { capabilities = [ "read" ] } EOF
-
配置角色以将不同策略分组在一起。 如果身份验证成功,这些策略会附加到生成的 Vault 访问令牌。
Shell vault write auth/jwt/role/myproject-production -<<EOF { "role_type": "jwt", "user_claim": "actor", "bound_claims": { "repository": "user-or-org-name/repo-name" }, "policies": ["myproject-production"], "ttl": "10m" } EOF
vault write auth/jwt/role/myproject-production -<<EOF { "role_type": "jwt", "user_claim": "actor", "bound_claims": { "repository": "user-or-org-name/repo-name" }, "policies": ["myproject-production"], "ttl": "10m" } EOF
ttl
定义所生成的访问令牌的有效性。- 确保针对安全要求定义
bound_claims
参数,并且该参数至少有一个条件。 (可选)还可以设置bound_subject
和bound_audiences
参数。 - 为了检查收到的 JWT 有效负载中的任意声明,
bound_claims
参数包含一组声明及其所需值。 在上面的示例中,角色会接受来自user-or-org-name
帐户拥有的repo-name
存储库的任何传入身份验证请求。 - 若要查看 GitHub 的 OIDC 提供商支持的所有可用声明,请参阅“关于使用 OpenID Connect 进行安全强化”。
有关详细信息,请参阅 HashiCorp Vault 文档。
更新 GitHub Actions 工作流程
要更新 OIDC 的工作流程,您需要对 YAML 进行两项更改:
- 为令牌添加权限设置。
- 使用操作
hashicorp/vault-action
将 OIDC 令牌 (JWT) 交换为云访问令牌。
要将 OIDC 集成添加到您的工作流程中,以允许他们访问 Vault 中的密钥,您需要添加以下代码更改:
- 授予从 GitHub OIDC 提供程序提取令牌的权限:
- 工作流需要将
id-token
值设置为write
的permissions:
设置。 这样,便可以从工作流中的每个作业中提取 OIDC 令牌。
- 工作流需要将
- 向 GitHub OIDC 提供商请求 JWT,并将其提供给 HashiCorp Vault 以接收访问令牌:
- 可以使用
hashicorp/vault-action
操作提取 JWT 并从 Vault 接收访问令牌,也可以使用操作工具包 提取作业的令牌。
- 可以使用
此示例演示如何将 OIDC 与官方操作结合使用,以向 HashiCorp Vault 请求机密。
添加权限设置
作业或工作流运行需要具有 id-token: write
的 permissions
设置。 如果 id-token
的 permissions
设置已设置为 read
或 none
,则无法请求 OIDC JWT ID 令牌。
id-token: write
设置允许使用下列方法之一从 GitHub 的 OIDC 提供程序请求 JWT:
- 在运行器上使用环境变量(
ACTIONS_ID_TOKEN_REQUEST_URL
和ACTIONS_ID_TOKEN_REQUEST_TOKEN
)。 - 使用“操作”工具包中的
getIDToken()
。
如果需要为工作流提取 OIDC 令牌,则可以在工作流级别设置权限。 例如:
permissions: id-token: write # This is required for requesting the JWT contents: read # This is required for actions/checkout
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
如果只需要为单个作业提取 OIDC 令牌,则可在该作业中设置此权限。 例如:
permissions: id-token: write # This is required for requesting the JWT
permissions:
id-token: write # This is required for requesting the JWT
可能需要在此处指定额外权限,具体取决于你的工作流要求。
对于与调用方工作流属于同一用户、组织或企业的可重用工作流,可以从调用方的上下文访问在可重用工作流中生成的 OIDC 令牌。
对于企业或组织外部的可重用工作流,应在调用方工作流级别或在调用可重用工作流的特定作业中将 id-token
的 permissions
设置显式设置为 write
。
这可确保仅允许可重用工作流中生成的 OIDC 令牌按预期在调用方工作流中使用。
有关详细信息,请参阅“重新使用工作流”。
注意:
使用 permissions
密钥时,所有未指定的权限都设置为无访问权限,但元数据范围除外,它始终拥有读取访问权限 。 因此,可能需要添加其他权限,例如 contents: read
。 有关详细信息,请参阅自动令牌身份验证。
请求访问令牌
hashicorp/vault-action
操作从 GitHub OIDC 提供程序接收 JWT,然后从 HashiCorp Vault 实例请求访问令牌以检索机密。 有关详细信息,请参阅 HashiCorp Vault GitHub 操作文档。
此示例演示如何创建从 HashiCorp Vault请求机密的作业。
<Vault URL>
:将此替换为 HashiCorp Vault 的 URL。<Vault Namespace>
:将此值替换为在 HashiCorp Vault 中设置的命名空间。 例如:admin
。<Role name>
:将此值替换为在 HashiCorp Vault 信任关系中设置的角色。<Secret-Path>
:将此值替换为从 HashiCorp Vault 检索的机密的路径。 例如:secret/data/production/ci npmToken
。
jobs: retrieve-secret: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: Retrieve secret from Vault uses: hashicorp/vault-action@v2.4.0 with: method: jwt url: <Vault URL> namespace: <Vault Namespace - HCP Vault and Vault Enterprise only> role: <Role name> secrets: <Secret-Path> - name: Use secret from Vault run: | # This step has access to the secret retrieved above; see hashicorp/vault-action for more details.
jobs:
retrieve-secret:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Retrieve secret from Vault
uses: hashicorp/vault-action@v2.4.0
with:
method: jwt
url: <Vault URL>
namespace: <Vault Namespace - HCP Vault and Vault Enterprise only>
role: <Role name>
secrets: <Secret-Path>
- name: Use secret from Vault
run: |
# This step has access to the secret retrieved above; see hashicorp/vault-action for more details.
注意:
- 如果无法从公共网络访问 Vault 服务器,请考虑将自承载运行程序与其他可用 Vault 身份验证方法配合使用。 有关详细信息,请参阅“关于自托管运行程序”。
- 必须针对 Vault Enterprise(包括 HCP Vault)部署设置
<Vault Namespace>
。 有关详细信息,请参阅 Vault 命名空间。
撤销访问令牌
默认情况下,Vault 服务器会在 TTL 过期时自动撤销访问令牌,因此无需手动撤销访问令牌。 但是,如果确实要在作业完成或失败后立即撤销访问令牌,则可以使用 Vault API 手动撤销颁发的令牌。
- 将
exportToken
选项设置为true
(默认值:false
)。 这会将颁发的 Vault 访问令牌导出为环境变量:VAULT_TOKEN
。 - 添加一个步骤以调用撤销令牌(自行) Vault API 来撤销访问令牌。
jobs: retrieve-secret: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: Retrieve secret from Vault uses: hashicorp/vault-action@v2.4.0 with: exportToken: true method: jwt url: <Vault URL> role: <Role name> secrets: <Secret-Path> - name: Use secret from Vault run: | # This step has access to the secret retrieved above; see hashicorp/vault-action for more details. - name: Revoke token # This step always runs at the end regardless of the previous steps result if: always() run: | curl -X POST -sv -H "X-Vault-Token: ${{ env.VAULT_TOKEN }}" \ <Vault URL>/v1/auth/token/revoke-self
jobs:
retrieve-secret:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Retrieve secret from Vault
uses: hashicorp/vault-action@v2.4.0
with:
exportToken: true
method: jwt
url: <Vault URL>
role: <Role name>
secrets: <Secret-Path>
- name: Use secret from Vault
run: |
# This step has access to the secret retrieved above; see hashicorp/vault-action for more details.
- name: Revoke token
# This step always runs at the end regardless of the previous steps result
if: always()
run: |
curl -X POST -sv -H "X-Vault-Token: ${{ env.VAULT_TOKEN }}" \
<Vault URL>/v1/auth/token/revoke-self