LayerX エンジニアブログ

LayerX の エンジニアブログです。

Github ActionからGoogle Workspaceへのキーレス化に半年間はまったのでメモっとく

この記事は、LayerX Tech Advent Calendar 2022 10日目の記事です。

@ken5scal です。CTO室やらFintech事業部やらで色々やっています。

今日は、Github ActionからGoogle WorkspaceのReports APIをキーレスで 実行する件について紹介したいと思います。 めちゃくちゃハマり半年の熟成を経て実装できたので、その喜びとともにお送りいたします。

背景

今までAPIを実行するアクセスキーといったクレデンシャルの多くは静的な値やファイルの形をとっていました。 故に取り扱いを間違えると重大な窃取や漏洩に繋がる可能性が高くなります。 そういったリスクを低減する定期的なローテーションが良いプラクティスとされていましたが、人手によるローテーションは作業漏れによる可用性の面でのリスクに繋がり兼ねません。 つまり人類は愚か

幸いなことに、OpenID ConnectなどのIdentity Federationの仕様を参照し、machine2machineにおける動的なトークン発行機能を備えるプラットフォームが急激に増えています。 (個人的な意見ですが、これをサポートしないプラットフォームは今後の検討対象に上げるのは難しいです)

特に重要なサービスやアプリケーションの構成や要件をSW化しようとするユースケースにおいては強力な助っ人になります。 特にGoogle Workspaceは、企業活動における核となるグループウェアなので活用してみました。

監査ログの取得

Google Workspaceでは、デフォルトで30日〜6ヶ月の間、レポートを保存します。

Data retention and lag times - Google Workspace Admin Help

通常こういった監査ログは1年以上保管するのが一般的(だと思う)なので、別のストレージに転送することが望ましいです。

当社では、Github Actionから日次でReport APIを叩くGo製プログラムで上記を実現しています。 この際、今までは、Report APIを叩くにあたってGoogle Projectにおけるservice accountとそれに紐づくキーJSONファイルが必要でした。 キーJSONファイルをGithubのSecretsにいれるなり、AWSのSecrets Managerなりに保存し、プログラム実行時に取得するような処理になります。

繰り返しになりますが、このキーファイルは大きなリスクです。リスクが顕在化すると、当社の様々な活動が丸裸になるためです。

これを google公式のGitHub Action「google-github-actions/auth」でキーレス化してしまいましょう。 基本的に設定方法はGithubのReadmenに書いてあるので簡単です...ただし、正確に読めるのであれば。今後、あとに続くかたのために手順を残しておきます。

 手順 in GCP

まず、Google Cloudでサービスアカウントを作成し、それをGoogle WorkspaceのDomain-Wide Delegationとして登録します。これはキーレスでもそうでなくても必要です。

次に、当該サービスアカウントにGithub Actionからフェデレーションするために以下の対応をします。 これらはgoogle-github-actions/authのReadMeにおける「Setting up Workload Identity Federation」手順に従えばOKです。

  1. Workload Identity Poolの定義
  2. 1にGithub Action(GitHub側のIdP)から発行されたID Tokenをマップするプロバイダー設定
  3. サービスアカウントとWorkload Identityの紐付け

最後にDomain-Wide Delegatio独自の設定を追加します。サービスアカウントがGoogle WorkspaceのAPIを叩くには、Google Workspace内のユーザーになりすます(Impersonate)ので、そのユーザーになりすますためのアクセストークンを発行する権限を付与します。 (なんでこんな仕組みなんでしょうね...これが一番の元凶な気すらします...)

gcloud iam service-accounts add-iam-policy-binding "my-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
  --project="${PROJECT_ID}" \
  --role="roles/iam. serviceAccountTokenCreator" \
  --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"

コード

GitHub Action

Github Actionでは次のような設定にします。access_token_subjectにはImpersonateしたいGoogle Workspaceのユーザーを指定します。

      - id: google-auth
        name: 'Authenticate to Google Cloud'
        uses: google-github-actions/auth@v0
        with:
          workload_identity_provider: projects/"${PROJECT_ID}"/locations/global/workloadIdentityPools/${REPOSITORY}/providers/github-action
          service_account:  sa@"${GCP_PROJECT}".iam.gserviceaccount.com
          token_format: access_token
          access_token_scopes: https://www.googleapis.com/auth/admin.reports.audit.readonly
          access_token_subject: sa@${GOOLE_WORKSPACE_DOMAIN}
          access_token_lifetime: 1800s
      - name: exec go bin
        run: make run-audit-log-fetcher
        env:
          GOOGLE_ACCESS_TOKEN: ${{ steps.google-auth.outputs.access_token }}

コード

ローカル実装時とは方法がことなるので、その切り分けは必要です。

 // GitHub Actionで実施するときは、"google-github-actions/auth" の設定により自動的にアクセストークン取得までされる
    credInString := os.Getenv("GOOGLE_ACCESS_TOKEN")
    if credInString == "" {
        log.Panicln("GOOGLE_ACCESS_TOKEN is not set")
    }
    config := &oauth2.Config{
        Scopes: []string{reports.AdminReportsAuditReadonlyScope},
    }
    tok := &oauth2.Token{}
    tok.AccessToken = credInString
    client := config.Client(context.Background(), tok)
    reportsSrv, err := reports.NewService(ctx, option.WithHTTPClient(client))

   //いい感じにS3にぶりこむ実装

Success!!

おわりに

LayerXおよび三井物産デジタルアセットマネジメントでは、このようにコンプライアンス要件を最新で本質的な技術を積極的に取り入れることで実現しています。このような分野を個人的にGovernance Engineerとよんでいます。今後、企業の質や信頼感を高めるためにガバナンスは重要であり、そこにチャレンジしたい方にとって、当社CTO室はピッタリと思います。興味がある方は、是非、@ken5scalまでDMください。

明日以降の LayerX Tech Advent Calendar 2022 の記事もお楽しみください!