GitHub ActionsのOIDC id tokenでGCPにアクセスしてみた

巷で話題になってるGitHub Actionsのid tokenでGCPにアクセスしてみた。

AWS federation comes to GitHub Actions | Aidan Steele’s blog (usually about AWS)

これを参考に試してみた。

GCP

以下、49482415725, ryotarai-github-oidc-sampleはproject number, project ID(このprojectは削除済み)

cloud.google.com

これを参考にWorkload Identityまわりの設定をする。

まず、IAM, Resource Manager, Service Account Credentials, and Security Token Service (STS) API を有効にする。

gcloud iam workload-identity-pools create github-oidc-sample \
  --location="global" \
  --description="github-oidc-sample" \
  --display-name="github-oidc-sample"
gcloud iam workload-identity-pools providers create-oidc github-oidc \
  --workload-identity-pool="github-oidc-sample" \
  --issuer-uri="https://vstoken.actions.githubusercontent.com" \
  --location="global" \
  --attribute-mapping="google.subject=assertion.sub" \
  --allowed-audiences="https://github.com/ryotarai/github-oidc-gcp-sample"

github-oidc-sample, github-oidcは適当に名前をつけた箇所。

providerをつくるときにallowed-audiencesを指定しておくこと。デフォルトだとaudにはリポジトリのURLが入ってくるっぽいのでそれを指定しておく。

gcloud iam service-accounts add-iam-policy-binding viewer@ryotarai-github-oidc-sample.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="principal://iam.googleapis.com/projects/49482415725/locations/global/workloadIdentityPools/github-oidc-sample/subject/repo:ryotarai/github-oidc-gcp-sample:ref:refs/heads/main"

viewer@ryotarai-github-oidc-sample.iam.gserviceaccount.comは事前に作っておいたSA。このSAの権限が使えるようになる。 このmemberのフォーマットは https://cloud.google.com/iam/docs/access-resources-oidc#iam-workload-pools-create-gcloudあたりを参照。上記の場合、特定のsubject(repo:ryotarai/github-oidc-gcp-sample:ref:refs/heads/main)を指定している。

GitHub Actions

適当なAPIをつかうなにかを書いて

# client/main.go
package main

import (
    "context"
    "log"

    "cloud.google.com/go/storage"
)

func main() {
    ctx := context.Background()

    // Sets your Google Cloud Platform project ID.
    projectID := "ryotarai-github-oidc-sample"

    // Creates a client.
    client, err := storage.NewClient(ctx)
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }
    defer client.Close()

    // Creates a Bucket instance.
    iter := client.Buckets(ctx, projectID)
    attr, err := iter.Next()
    if err != nil {
        log.Fatalf("failed to iter: %s", err)
    }

    log.Printf("%+v", attr)
}

ワークフローを設定

# .github/workflows/sample.yml
name: sample
on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v2

      - run: sleep 5 # there's still a race condition for now

      - name: id token sample
        run: |
          gcloud iam workload-identity-pools create-cred-config \
            projects/49482415725/locations/global/workloadIdentityPools/github-oidc-sample/providers/github-oidc \
            --service-account=viewer@ryotarai-github-oidc-sample.iam.gserviceaccount.com \
            --output-file=cred-config.json \
            --credential-source-url="$ACTIONS_ID_TOKEN_REQUEST_URL" \
            --credential-source-headers="Authorization=bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
            --credential-source-type=json \
            --credential-source-field-name=value
          export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/cred-config.json"

          cd client
          GO111MODULE=on go run .

f:id:ryotarai:20210916014004p:plain

branchを変えるとsubjectが変わるので、権限不足で失敗することも確認

f:id:ryotarai:20210916014208p:plain