5
1

More than 1 year has passed since last update.

Cloud Run から GKE に移行する際に考えないといけない認証の話

Posted at

はじめに

Cloud Run から GKE への移行を検討するにあたり認証・認可の方法が分からなかった。
どことどこの間の認証・認可かというと、Pub/Sub をはじめとした GCP サービスと GKE の間。

調べていくと Identity-Aware Proxy という GCP の仕組みが利用できることが分かったので、
経緯と Identity-Aware Proxy の仕組みについて勉強を兼ねてまとめてみる。

導入検討中の方の参考になれば幸いです。

どういうシチュエーションだったか

Cloud Run から GKE にコンテナ基盤を移行したいというミッションがありました。
Cloud Run を利用していれば自ずと GCP サービスと連携したくなります。
ここで GCP サービスと呼んでいるのは、Pub/Sub や Tasks などです。

簡略化すると次のようなシチュエーションを想定しています。

移行前: Pub/Sub → Cloud Run
image.png

移行後: Pub/Sub → GKE
image.png

Pub/Sub のアイコンが違うのはご愛嬌。

なぜ認証を考えないといけないのか

Cloud Run は HTTP エンドポイントを公開することができます。
当然ですが誰でもアクセスできたら困ります。
なので、Pub/Sub からのアクセスのみ許可したいです。

移行前は Cloud Run の機能を使って認証を入れていました。
Terraform のコードはこんな感じです。

resource "google_cloud_run_service_iam_member" "example_api" {
  location = google_cloud_run_service.example_api.location
  project  = google_cloud_run_service.example_api.project
  service  = google_cloud_run_service.example_api.name # 認証を挟みたい Cloud Run サービス
  role     = "roles/run.invoker" # Cloud Run の呼び出しに必要なロール
  member   = "serviceAccount:${google_service_account.example_sa.email}" # 認証に使うサービスアカウント
}

Pub/Sub から送られるリクエストに example_sa を紐付けることで自動的に認証が行われます。
詳しくは ドキュメントこちらの記事 が参考になります。

resource "google_pubsub_subscription" "example_subscription" {
  ...
  push_config {
    push_endpoint = "https://cloudrun-api.com/push" # メッセージの送信先エンドポイント (Cloud Run)
    oidc_token {
      service_account_email = google_service_account.example_sa.email # 認証に使うサービスアカウント
    }
  }
  ...
}

Cloud Run ならこれで完成です。

さて、GKE でも同じようにできるかというと、答えは No です。
認証・認可は GKE の機能として備わっていないので、代替手段を検討する必要がありました。

Identity-Aware Proxy が使える

調査の結果、Identity-Aware Proxy (以下、IAP) が代替になると分かりました。

IAP は GCE や GCLB のようなサービスの前段で認証・認可のフローを提供できます。
image.png
画像: Charlie Engelke, Identity-Aware Proxy を使ったウェブサイトへのアクセス制御

これにより、認証が具備されていないサービスにも GCP のプリンシパルを用いた認証を実装できます。
なお、上図では人 (ユーザアカウント) が描かれていますが、認証対象にはサービスアカウントも含まれています。

今回のシチュエーションでは、GKE のエンドポイントは GKE Ingress Controller で作成された GCLB で公開するつもりでした。
そのため、上図と同様な構成が適用可能でした。

あとは仕組みを理解して、置き換えれば OK です。

IAP の仕組み

ドキュメント によると、認証・認可は下図のようなフローで行われます。

image.png
画像: Identity-Aware Proxy の概要

IAP が有効かチェック

まず、GCLB (App Engine や GCE も想定可) がクライアントからリクエストを受け取ります。GCLB はバックエンドサービスに対して IAP が有効になっているか確認します。バックエンドサービスは、GKE の文脈では Service オブジェクトと同義と捉えられます。

認証ステップ

IAP が有効になっている場合は、リクエストヘッダや Cookie 内の認証情報が IAP 認証サーバに送られます。認証サーバは、認証情報の有無をチェックし、有効な場合、次の認可ステップへ進みます。認証情報が無効な場合は、OAuth のログインフローにリダイレクトされ、認証が完了すれば トークンが Cookie に保存されます。

認可ステップ

認可ステップでは、認証情報から取得したユーザ ID から、そのユーザに必要な IAM Role が付与されているかチェックします。ここを PASS すればようやくアプリケーションに到達することができます。

なお、上記はユーザアカウントを利用する場合の認証フローになります。
サービスアカウントを利用する場合は ID トークンを事前に取得しておく必要があります。
詳細は、サービスアカウントからの認証 をご確認ください 。

長々書いてしまいましたが、ユーザアカウント認証、サービスアカウント認証のどちらの場合も、
トークンを持っていないと IAP で弾かれるんだなと捉えてもらえば大丈夫です。

GKE で IAP を有効化

GKE で提供するエンドポイントを IAP で保護する手順です。
これはドキュメント通りに実装して問題なく動作しました。

OAuth 同意画面の構成OAuth 認証情報の作成 は下記理由から Terraform ではなく手動で設定しています。

  • OAuth 同意画面は Terraform 対応 しているが権限問題でサポートメールアドレスを手動で設定する必要があった
  • OAuth 認証情報も Terraform 対応 していそうだが対応フィールドが少なくどちらにしろ redirect URI の手動設定が必要だった

audience を変更

ここまでで IAP の概要を把握し、GKE 上で実装することができました。
最後に Pub/Sub サブスクリプションで明示的に audience を設定して完了です。

Terrafrom のコードはこのようになります。

resource "google_pubsub_subscription" "example_subscription" {
  ...
  push_config {
    push_endpoint = "https://gke-api.com/push" # メッセージの送信先エンドポイント (GKE)
    oidc_token {
      service_account_email = google_service_account.example_sa.email # 認証に使うサービスアカウント
      audience              = "example.apps.googleusercontent.com" # 追加
    }
  }
  ...
}

audience というフィールドに前節で作成した OAuth クライアントの Client ID を記載します。

audience 未指定の場合は、 push_endpoint に記載した URL が使われます。
詳しくは、GCP ドキュメント または Terraform ドキュメント をご参照ください。

なぜ audience を変更するのか

Cloud Run では audience 未指定だった (= エンドポイント URL を指定) のに、
なぜ IAP では Client ID を記載しなければいけないのかという疑問が残ると思います。

その理由は両者の仕様の違いです。
Cloud Run は、トークン作成時に audience に target URL を要求 します。

(抜粋)
// functionURL := "https://TARGET_URL"
client, err := idtoken.NewClient(ctx, targetURL)

対して、IAP は、audience に Client ID を要求 します。

(抜粋)
// audience := "IAP_CLIENT_ID.apps.googleusercontent.com"
client, err := idtoken.NewClient(ctx, audience)

他にも書きたいことがありましたが、記事が膨張してしまうので別の機会にします。

参考

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1