Skip to main content

HashiCorp Vault での OpenID Connect の構成

ワークフロー内で OpenID Connect を使用して HashiCorp Vault で認証します。

概要

OpenID Connect (OIDC) を使うと、GitHub Actions ワークフローが HashiCorp Vault で認証し、シークレットを取得できます。

このガイドでは、HashiCorp Vault が GitHub の OIDC をフェデレーション ID として信頼するように構成する方法の概要について説明します。また、この構成を hashicorp/vault-action アクションで使って HashiCorp Vault からシークレットを取得する方法を示します。

前提条件

  • GitHub が OpenID Connect (OIDC) を使用する方法の基本的な概念とそのアーキテクチャと利点については、「OpenID Connect を使用したセキュリティ強化について」を参照してください。

  • 先に進む前に、アクセス トークンが予測可能な方法でのみ割り当てられるようにセキュリティ戦略を計画する必要があります。 クラウド プロバイダーがアクセス トークンを発行する方法を制御するには、少なくとも 1 つの条件を定義し、信頼できないリポジトリがクラウド リソースにアクセス トークンを要求できないようにする 必要があります。 詳細については、「クラウドを使った OIDC 信頼の構成」を参照してください。

HashiCorp Vault への ID プロバイダーの追加

HashiCorp Vault と共に OIDC を使うには、GitHub OIDC プロバイダーの信頼構成を追加する必要があります。 詳細については、HashiCorp Vault のドキュメントを参照してください。

認証に JSON Web トークン (JWT) を受け入れるように Vault サーバーを構成します。

  1. JWT auth メソッドを有効にし、write を使用して Vault に構成を適用します。 oidc_discovery_url および bound_issuer パラメーターの場合は、https://token.actions.githubusercontent.com を使います。 これらのパラメーターを使用すると、Vault サーバーは認証プロセス中に受信した JSON Web トークン (JWT) を確認できます。

    Shell
    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"
  2. ワークフローがシークレットの取得に使用する特定のパスへのアクセスのみを許可するポリシーを構成します。 詳細なポリシーについては、HashiCorp Vault の 「ポリシー」のドキュメントを参照してください。

    Shell
    vault policy write myproject-production - <<EOF
    # Read-only permission on 'secret/data/production/*' path
    
    path "secret/data/production/*" {
      capabilities = [ "read" ]
    }
    EOF
  3. 異なるポリシーをグループ化するようにロールを構成します。 認証が成功した場合、これらのポリシーは結果の 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
  • ttl によって、結果のアクセス トークンの有効性が定義されます。
  • bound_claims パラメーターがセキュリティ要件に対して定義されており、少なくとも 1 つの条件があることを確認します。 必要に応じて、bound_subject だけでなく、bound_audiences パラメーターも設定できます。
  • 受信した JWT ペイロード内の任意の要求を確認するために、bound_claims パラメーターには一連の要求とその必須の値が含まれています。 上記の例では、ロールは、user-or-org-name アカウントによって所有される repo-name リポジトリからの受信認証要求を受け取ります。
  • GitHub の OIDC プロバイダーでサポートされている使用可能なすべての要求を確認するには、「クラウドを使った OIDC 信頼の構成」を参照してください。

詳細については、HashiCorp Vault のドキュメントを参照してください。

GitHub Actions ワークフローを更新する

OIDC のワークフローを更新するには、YAML に 2 つの変更を行う必要があります。

  1. トークンのアクセス許可設定を追加します。
  2. この hashicorp/vault-action アクションを使って、OIDC トークン (JWT) をクラウド アクセス トークンと交換します。

Vault のシークレットにアクセスできるようにワークフローに OIDC 統合を追加するには、次のコード変更を追加する必要があります。

  • GitHub OIDC プロバイダーからトークンをフェッチするアクセス許可を付与します。
    • ワークフローには、id-token の値が write に設定された permissions: 設定が必要です。 これにより、ワークフロー内のすべてのジョブから OIDC トークンをフェッチすることができます。
  • GitHub OIDC プロバイダーに JWT を要求し、それを HashiCorp Vault に提示してアクセス トークンを受け取ります。
    • hashicorp/vault-action アクションを使って、JWT をフェッチし、Vault からアクセス トークンを受け取ることができます。または、Actions ツールキットを使ってジョブのトークンをフェッチすることもできます。

この例は、HashiCorp Vault からシークレットを要求するために、公式のアクションと共に OIDC を使う方法を示しています。

アクセス許可設定の追加

ジョブまたはワークフローの実行には、id-token: writepermissions 設定が必要です。 id-tokenpermissions 設定が read または none の場合、OIDC JWT ID トークンを要求することはできません。

この id-token: write 設定により、次のいずれかの方法を使用して、GitHub の OIDC プロバイダーから JWT を要求できます。

  • ランナーで環境変数を使用する (ACTIONS_ID_TOKEN_REQUEST_URL および ACTIONS_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

1 つのジョブに対して OIDC トークンのみをフェッチする必要がある場合は、そのジョブ内でこのアクセス許可を設定できます。 次に例を示します。

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

ワークフローの要件に応じて、ここで追加のアクセス許可を指定する必要がある場合があります。

:

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」のように入力します。
YAML
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 Namespace> は、Vault Enterprise (HCP Vault を含む) デプロイに対して設定する必要があります。 詳しくは、Vault 名前空間に関するページを参照してください。

アクセス トークンの取り消し

既定で、Vault サーバーでは TTL の有効期限が切れたときにアクセス トークンを自動的に取り消します。そのため、アクセス トークンを手動で取り消す必要はありません。 ただし、ジョブが完了または失敗した直後にアクセス トークンを取り消す場合は、Vault API を使用して発行されたトークンを手動で取り消すことができます。

  1. exportToken オプションを true (既定値: false) に設定します。 これにより、発行された Vault アクセス トークンが環境変数としてエクスポートされます: VAULT_TOKEN
  2. トークンの取り消し (自己) Vault API を呼び出してアクセス トークンを取り消すステップを追加します。
YAML
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