Workload Identityを使ってJSONキーなしでGitHubActionsからGCPにアクセスする

GitHubActionsを使ってCI/CDパイプラインを構築する際には、以下のようにService AccountのJSONキーを使用して認証を行うことが多いです。


```yaml
- name: Set up Cloud SDK
  uses: google-github-actions/setup-gcloud@master
  with:
    service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_JSON }}
    export_default_credentials: true
```

しかし、この方法は既に非推奨になっており、代わりにWorkload Identityを使うように案内されています。

> The following inputs are for authenticating to Google Cloud via a Service Account Key JSON. We recommend using Workload Identity Federation instead as exporting a long-lived Service Account Key JSON credential poses a security risk.

https://github.com/google-github-actions/auth#authenticating-via-service-account-key-json

そのため、Workload Identityを使ってGitHub ActionsからGCPへアクセスできるように設定してみます。
なお、サービスアカウントは事前に作成し、適切な権限を付与してあるものとします。

# APIの有効化
最初にWorkload Identityに関するAPIを有効化します。
この作業はGCPプロジェクト毎に1回だけ実行するだけでOKです。

```sh
gcloud services enable iamcredentials.googleapis.com --project="${PROJECT_ID}"
```

# Workload Identity Poolの作成
次にWorkload Identity Poolを作成します。
これはこの後に作成するWorkload Identity Providerをまとまるための論理的な入れ物です。
ファイルシステムにおけるディレクトにみたいなものです。

```sh
gcloud iam workload-identity-pools create "gh-oidc-pool" \
  --project="${PROJECT_ID}" \
  --location="global"

# この後の作業で使うので、IDを変数に入れておく
WORKLOAD_IDENTITY_POOL_ID=$(gcloud iam workload-identity-pools describe "gh-oidc-pool" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --format="value(name)")
```

# Workload Identity Providerの作成
Workload Identity Providerを作成します。
これがGitHub ActionsとGCPとの間をOIDCで連携するための設定の本体です。
Attribute Mapping機能を使ってGitHubから渡されるリポジトリ名の情報をattribute.repositoryという名前で参照できるようにしておきます。

```sh
gcloud iam workload-identity-pools providers create-oidc "gh-oidc-pool" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --workload-identity-pool="gh-oidc-pool" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
  --issuer-uri="https://token.actions.githubusercontent.com"
```

# 権限借用の設定
最後にWorkload Identity ProviderがService Accountの権限借用(impersonate)をできるように設定を行います。
この時にattribute.repositoryでどのGitHubリポジトリ上で動いているGitHubActionsに対して権限を与えるかを決定します。

```sh
gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT}" \
  --project="${PROJECT_ID}" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${GitHubユーザー名}/${リポジトリ名}"
```

# GitHubActions側の設定
上記の手順で作成した設定をGitHub Actionsから使うためには以下のようなYAMLを書けばOKです。

```yaml
permissions:
  contents: 'read'
  id-token: 'write'
 
jobs:
  job_id:
    steps: 
    ...
    - name: Authenticate to Google Cloud
      id: 'google-cloud-auth'
      uses: 'google-github-actions/auth@v0.4.1'
      with:
        create_credentials_file: true
        workload_identity_provider: 'projects/${YOUR_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${YOUR_POOL_ID}/providers/${YOUR_PROVIDER_ID}'
        service_account: 'YOUR_SERVICE_ACCOUNT'

    - name: Google Cloud login
      run: gcloud auth login --brief --cred-file="${{ steps.google-cloud-auth.outputs.credentials_file_path }}"
```

参考:

https://cloud.google.com/iam/docs/configuring-workload-identity-federation


https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform