メモ
GitHub ホステッド ランナーは、現在 GitHub Enterprise Server ではサポートされていません。
概要
OpenID Connect (OIDC) を使うと、GitHub Actions ワークフローが HashiCorp Vault で認証し、シークレットを取得できます。
このガイドでは、HashiCorp Vault が GitHub の OIDC をフェデレーション ID として信頼するように構成する方法の概要について説明します。また、この構成を hashicorp/vault-action アクションで使って HashiCorp Vault からシークレットを取得する方法を示します。
前提条件
-
GitHub が OpenID Connect (OIDC) を使用する方法の基本的な概念とそのアーキテクチャと利点については、「OpenID Connect」を参照してください。
-
先に進む前に、アクセス トークンが予測可能な方法でのみ割り当てられるようにセキュリティ戦略を計画する必要があります。 クラウド プロバイダーがアクセス トークンを発行する方法を制御するには、少なくとも 1 つの条件を定義し、信頼できないリポジトリがクラウド リソースにアクセス トークンを要求できないようにする必要があります。 詳しくは、「OpenID Connect」をご覧ください。
HashiCorp Vault への ID プロバイダーの追加
HashiCorp Vault と共に OIDC を使うには、GitHub OIDC プロバイダーの信頼構成を追加する必要があります。 詳細については、HashiCorp Vault のドキュメントを参照してください。
認証に JSON Web トークン (JWT) を受け入れるように Vault サーバーを構成します。
-
JWT
auth
メソッドを有効にし、write
を使用して Vault に構成を適用します。oidc_discovery_url
およびbound_issuer
パラメーターの場合は、https://HOSTNAME/_services/token
を使います。 これらのパラメーターを使用すると、Vault サーバーは認証プロセス中に受信した JSON Web トークン (JWT) を確認できます。Shell vault auth enable jwt
vault auth enable jwt
Shell vault write auth/jwt/config \ bound_issuer="https://HOSTNAME/_services/token" \ oidc_discovery_url="https://HOSTNAME/_services/token"
vault write auth/jwt/config \ bound_issuer="https://HOSTNAME/_services/token" \ oidc_discovery_url="https://HOSTNAME/_services/token"
-
ワークフローがシークレットの取得に使用する特定のパスへのアクセスのみを許可するポリシーを構成します。 詳細なポリシーについては、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
パラメーターがセキュリティ要件に対して定義されており、少なくとも 1 つの条件があることを確認します。 必要に応じて、bound_subject
だけでなく、bound_audiences
パラメーターも設定できます。- 受信した JWT ペイロード内の任意の要求を確認するために、
bound_claims
パラメーターには一連の要求とその必須の値が含まれています。 上記の例では、ロールは、user-or-org-name
アカウントによって所有されるrepo-name
リポジトリからの受信認証要求を受け取ります。 - GitHub の OIDC プロバイダーでサポートされているすべての可能な要求を確認するには、「OpenID Connect」を参照してください。
詳細については、HashiCorp Vault のドキュメントを参照してください。
GitHub Actions ワークフローを更新する
OIDC のワークフローを更新するには、YAML に 2 つの変更を行う必要があります。
- トークンのアクセス許可設定を追加します。
- この
hashicorp/vault-action
アクションを使って、OIDC トークン (JWT) をクラウド アクセス トークンと交換します。
独自のカスタム保護規則を有効にして、サードパーティ サービスを使ったデプロイを制御できます。 たとえば、Datadog、Honeycomb、ServiceNow などのサービスを使用し、GitHub への展開に対して自動承認を提供できます。
Vault のシークレットにアクセスできるようにワークフローに OIDC 統合を追加するには、次のコード変更を追加する必要があります。
- GitHub OIDC プロバイダーからトークンをフェッチするアクセス許可を付与します。
- ワークフローには、
id-token
の値がwrite
に設定されたpermissions:
設定が必要です。 これにより、ワークフロー内のすべてのジョブから OIDC トークンをフェッチすることができます。
- ワークフローには、
- GitHub OIDC プロバイダーに JWT を要求し、それを HashiCorp Vault に提示してアクセス トークンを受け取ります。
hashicorp/vault-action
アクションを使って、JWT をフェッチし、Vault からアクセス トークンを受け取ることができます。または、Actions ツールキットを使ってジョブのトークンをフェッチすることもできます。
この例は、HashiCorp Vault からシークレットを要求するために、公式のアクションと共に OIDC を使う方法を示しています。
アクセス許可設定の追加
GitHub の OIDC プロバイダーが実行ごとに JSON Web Token を作成できるよう、ジョブまたはワークフローの実行には id-token: write
を含む permissions
の設定が必要です。
メモ
ワークフローのアクセス許可で id-token: write
を設定しても、リソースへの変更または書き込みを行うアクセス許可はワークフローに付与されません。 そうではなく、ワークフローは、アクションまたはステップのための OIDC トークンを要求 (フェッチ) して使用 (設定) することのみが許可されます。 その後、このトークンは、有効期間の短いアクセス トークンを使って外部サービスで認証を行うために使われます。
必要なアクセス許可、構成例、高度なシナリオについて詳しくは、「OpenID Connect リファレンス」をご覧ください。
メモ
permissions
キーを使用すると、すべての未指定のアクセス許可が "アクセスなし" に設定されます。ただし、メタデータ スコープは例外であり、常に "読み取り" アクセス権を取得します。__ __ その結果、contents: read
のような他のアクセス許可を追加することが必要になる場合があります。 詳しくは、「自動トークン認証」を参照してください。
アクセス トークンの要求
hashicorp/vault-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-NAMESPACE
は、Vault Enterprise (HCP Vault を含む) デプロイに対して設定する必要があります。 詳しくは、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