GitHub ActionsでCloud Runにデプロイする

# はじめに
GitHub Actionsからトリガーして、CloudRunにデプロイする際のワークフローを作成しました。
特に、GCPへの認証部分(Workload Identity)や、実行時のGitHubリポジトリの制限など含め、記載します。


# 設定
以下完成形となります。
mainブランチへのpushをトリガーとして動作するように設定しました。

```yml
name: deploy

on:
  push:
    branches:
      - main

env:
  GCP_SERVICE: sample
  GCP_IMAGE: gcr.io/sample_project/sample:latest #　なければ作成される

jobs:
  deploy:
    runs-on: ubuntu-latest

    permissions:
      contents: 'read'
      id-token: 'write'

    steps:
      - name: Checkout sources
        uses: actions/checkout@v3

      - name: 'gcloud Auth'
        uses: 'google-github-actions/auth@v0'
        with:
          workload_identity_provider: {workload_identity_provider}
          service_account: {service_account}

      - name: 'Set up gcloud SDK'
        uses: 'google-github-actions/setup-gcloud@v0'

      - name: Init docker for gcloud
        run: gcloud auth configure-docker --quiet

      - name: Build docker image
        run: docker build -t ${{ env.GCP_IMAGE }} .

      - name: Push docker image for container registory
        run: docker push ${{ env.GCP_IMAGE }}

      - name: Deploy CloudRun Service
        uses: google-github-actions/deploy-cloudrun@v0
        with:
          service: ${{ env.GCP_SERVICE }}
          image: ${{ env.GCP_IMAGE }}
          region: asia-northeast1
          env_vars: |
            ENV=production
          secrets: |
            GOOGLE_APPLICATION_CREDENTIALS=credentials:latest
```

使用したActionは
- https://github.com/google-github-actions/auth
    - 認証に使用
- https://github.com/google-github-actions/setup-gcloud　
    - gcloud CLIのセットアップ
- https://github.com/google-github-actions/deploy-cloudrun
    - CloudRunへデプロイ

となります。
細かい使い方などは、上記ドキュメントを参照いただければと思います。

今回特に、認証部分の設定について[setting-up-workload-identity-federation](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation)をベースに解説していきます。

↓この部分
```yml
      - name: 'gcloud Auth'
        uses: 'google-github-actions/auth@v0'
        with:
          workload_identity_provider: {workload_identity_provider}
          service_account: {service_account}
```

## 1. サービスアカウント作成

こちらのサービスアカウントでContainer RegistryへのPushやCloudRunへのデプロイを行うので、`ストレージ管理者`、`CloudRunデベロッパー`、`サービスアカウントユーザー`のロールを追加しておく必要があります。また必要に応じて、`Secret Manager のシークレット アクセサー`等のロールも追加しておいてください。

```
$ export PROJECT_ID="my-project"
$ gcloud iam service-accounts create "github-action-cd" \
  --project "${PROJECT_ID}"
```

作成した、サービスアカウントを workflowファイルの`{service_account}`に設定します。


## 2. 認証情報API有効化
すでに有効化済みであれば省略
```
$ gcloud services enable iamcredentials.googleapis.com \
  --project "${PROJECT_ID}"
```

## 3. Workload Identityプール作成
WorkloadIdentityプールを作成します。
今回は、GitHubから利用するため、`github-pool`として作成しました。

```
$ gcloud iam workload-identity-pools create "github-pool" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --display-name="pool for github"
```

## 4. プールIDの取得
上記作成したプールIDを取得します。
projects/~ のIDが取得できると思います。

```
$ gcloud iam workload-identity-pools describe "github-pool" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --format="value(name)"

projects/xxxxxx/locations/global/workloadIdentityPools/github-pool

$ export WORKLOAD_IDENTITY_POOL_ID="projects/xxxxxx/locations/global/workloadIdentityPools/github-pool"
```

## 5. Workload Identity Provider作成
githubからIDトークンを取得するためのOIDCプロバイダを作成します。
特定のGitHubオーナー配下でのみ、IDトークンを発行して、GCPを操作可能にするため、`attribute-condition`に`assertion.repository_owner=='{target_repository_owner}'`を追加しています。
※`{target_repository_owner}`はそれぞれのリポジトリ
※その他のGitHubのOIDCトークンは[こちら](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token)を参照してください。

```
$ gcloud iam workload-identity-pools providers create-oidc "oidc-provider" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --workload-identity-pool="github-pool" \
  --display-name="oidc provider" \
  --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-condition="assertion.repository_owner=='{target_repository_owner}'"
```

## 6. サービスアカウントに対して、リポジトリからのWorkload Identity Providerからの認証許可
対象リポジトリからの認証を許可するために設定します。
※こちらの設定をして、制限されると思ったのですが、対象外のリポジトリからも操作できてしまったので、5.で制限をかけています。

```
$ export REPO="repository_owner/repository"

$ gcloud iam service-accounts add-iam-policy-binding "github-action-cd@${PROJECT_ID}.iam.gserviceaccount.com" \
  --project="${PROJECT_ID}" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
```

## 7. Workload Identity Providerリソース名の取得
workflowに記載するためのリソース名を取得します。

```
$ gcloud iam workload-identity-pools providers describe "oidc-provider" \
  --project="${PROJECT_ID}" \
  --location="global" \
  --workload-identity-pool="github-pool" \
  --format="value(name)"

projects/xxxxxx/locations/global/workloadIdentityPools/github-pool/providers/oidc-provider
```
取得した、リソース名を workflowファイルの`{workload_identity_provider}`に設定します。


# 参考
https://cloud.google.com/iam/docs/configuring-workload-identity-federation#mappings-and-conditions
https://cloud.google.com/blog/ja/products/identity-security/enable-keyless-access-to-gcp-with-workload-identity-federation