概述
OpenID Connect (OIDC) 允许您的 GitHub Actions 工作流程使用 HashiCorp Vault 来验证并检索密钥。
本指南概述了如何配置 HashiCorp Vault 以信任 GitHub 的 OIDC 作为联合身份,并演示了如何在 hashicorp/vault-action 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
action 将 OIDC 令牌 (JWT) 交换为云访问令牌。
注意
当在工作流程或 OIDC 策略中使用环境时,我们建议为环境添加保护规则以增强安全性。例如,您可以配置环境上的部署规则,以限制哪些分支和标签可以部署到环境或访问环境密钥。更多信息,请参阅“管理部署环境”。
要将 OIDC 集成添加到允许它们访问 Vault 中的密钥的工作流程,您需要添加以下代码更改
- 授予从 GitHub OIDC 提供程序获取令牌的权限
- 工作流程需要
permissions:
设置,其中id-token
值设置为write
。这允许您从工作流程中的每个作业中获取 OIDC 令牌。
- 工作流程需要
- 从 GitHub OIDC 提供程序请求 JWT,并将其呈现给 HashiCorp Vault 以接收访问令牌
- 您可以使用
hashicorp/vault-action
action 获取 JWT 并从 Vault 接收访问令牌,或者您可以使用 Actions 工具包 获取作业的令牌。
- 您可以使用
此示例演示了如何使用官方 action 将 OIDC 与 HashiCorp Vault 请求密钥一起使用。
添加权限设置
作业或工作流程运行需要一个 permissions
设置,其中包含 id-token: write
,以允许 GitHub 的 OIDC 提供程序为每次运行创建一个 JSON Web 令牌。如果 id-token
的 permissions
未设置为 write
,则您将无法请求 OIDC JWT ID 令牌,但是此值并不意味着授予对任何资源的写入访问权限,而只是能够为 action 或步骤获取和设置 OIDC 令牌,以启用使用短期访问令牌进行身份验证。任何实际的信任设置都是使用 OIDC 声明定义的,有关更多信息,请参阅“关于使用 OpenID Connect 加强安全性”。
id-token: write
设置允许使用以下方法之一从 GitHub 的 OIDC 提供程序请求 JWT
- 在运行程序上使用环境变量 (
ACTIONS_ID_TOKEN_REQUEST_URL
和ACTIONS_ID_TOKEN_REQUEST_TOKEN
)。 - 使用 Actions 工具包中的
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
action 从 GitHub OIDC 提供程序接收 JWT,然后从您的 HashiCorp Vault 实例请求访问令牌以检索密钥。更多信息,请参阅 HashiCorp Vault GitHub Action 文档。
此示例演示了如何创建一个从 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@9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b 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@9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b
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@9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b 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@9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b
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