概要
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 を使ったセキュリティ強化について」を参照してください。
-
GHE.com に関するこのガイドに従っている場合は、次のドキュメントの特定の値を置き換える必要があることを理解してください。 「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://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"
Note
Enterprise に対して一意の発行者 URL が REST API を使って設定されていた場合 (「OpenID Connect を使ったセキュリティ強化について」で説明されています)、
bound_issuer
とoidc_discover_url
の値はその URL と一致している必要があります。 たとえば、その一意の issuer URL が使われているoctocat
という名前の Enterprise の場合、bound_issuer
とoidc_discovery_url
はhttps://token.actions.githubusercontent.com/octocat
に設定されていなくてはなりません。 -
ワークフローがシークレットの取得に使用する特定のパスへのアクセスのみを許可するポリシーを構成します。 詳細なポリシーについては、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
の permissions
が write
に設定されていない場合、OIDC JWT ID トークンを要求することはできません。ただし、この値はリソースへの書き込みアクセスを許可することを意味せず、アクションまたはステップの OIDC トークンをフェッチして設定し、有効期間の短いアクセス トークンを使用して認証を有効にできるだけです。 実際の信頼の設定は OIDC 要求を使用して定義されます。詳細については、「OpenID Connect を使ったセキュリティ強化について」を参照してください。
この 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
1 つのジョブに対して OIDC トークンのみをフェッチする必要がある場合は、そのジョブ内でこのアクセス許可を設定できます。 次に例を示します。
permissions: id-token: write # This is required for requesting the JWT
permissions:
id-token: write # This is required for requesting the JWT
ワークフローの要件に応じて、ここで追加のアクセス許可を指定する必要がある場合があります。
呼び出し元ワークフローと同じユーザー、Organization、または Enterprise が所有する再利用可能なワークフローの場合、再利用可能なワークフローで生成された OIDC トークンに呼び出し元のコンテキストからアクセスできます。
Enterprise または Organization 外部の再利用可能なワークフローについては、id-token
の permissions
設定を、呼び出し元ワークフロー レベル、または再利用可能ワークフローを呼び出す特定のジョブで write
に設定してください。
これにより、再利用可能なワークフローで生成された OIDC トークンは、意図した場合にのみ呼び出し元ワークフローで使用できるようになります。
詳しくは、「ワークフローの再利用」を参照してください。
Note
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.
Note
- 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