はじめに

現在(2020 年 9 月 14 日) cloud run には Identity-Aware Proxy(以後 IAP)が google cloud の機能として追加されていません。IAP を使いたいけど使えない、cloud run を使っている人なら一度は思ったことがあるはずです。 しかし、先日 pomerium というオープンソースの IAP プロバイダーを使い cloud run で IAP を使う記事が公開されました。試してみて思ったより詰まったので、知見として記事を書いて行きます。

Pomerium とは

Pomerium is an identity-aware proxy that enables secure access to internal applications. Pomerium provides a standardized interface to add access control to applications regardless of whether the application itself has authorization or authentication baked-in. Pomerium gateways both internal and external requests, and can be used in situations where you’d typically reach for a VPN.

詳しくはドキュメントを呼んで欲しいですが、簡単にいうと、内部アプリへのアクセスコントロールを行えるアプリケーションです。DDD 的な感じだと認証コンテキストって感じです(この説明大丈夫か不安。。。)。 GCP の IAP はリクエストに対して、勝手にプロキシを挟んで認証を行うカットインって感じですが、この pomeirum は pomerium を入り口としてアプリケーションを構築していく感じです。

cloudrun + pomerium

御託はいいのでさっさと作成していきます。今回はドメインを一つ使ってサブドメインを3つ作成するので、事前に準備をしておきます。 この後の説明では example.com を用意したドメインとして説明していきます。因みに割り当てるサブドメインは以下のような対応です。

  • authn.pomerium.example.com : 認証で使用するドメイン
  • app.pomerium.example.com : アプリケーションへのアクセスで使用するドメイン
  • httpbin.pomerium.example.com: api 定義の閲覧用

client の作成

google 認証を行うためにまずは、OAuth client を作成していきます。この URLをクリックして以下の画像のように作成していきます。認証で使用するドメインをリダイレクト先の URL に入れる所が大切です。

clientの作成

client 作成後生成されるClient IDClient Secretをメモしておきます。

設定ファイルの作成

これを行う前に、IAP で保護したい cloud run のサービスを-no-allow-unauthenticatedオプションを付けてデプロイしておきます(以後 protect サービスとする)。デプロイ後 URL が作成されていることを確認してから作業を行っていきます。 まずは認証設定を記載したconfig.yamlを作成します。

# config.yaml
authenticate_service_url: https://authn.pomerium.example.com
# https://www.pomerium.com/reference/#shared-secret
shared_secret: XXXXXX # head -c32 /dev/urandom | base64 で適当に生成した値
# https://www.pomerium.com/reference/#cookie-options
cookie_secret: XXXXXX # head -c32 /dev/urandom | base64 で適当に生成した値
idp_provider: "google"
idp_client_id: XXXXXX # さっきメモした Client ID
idp_client_secret: "XXXXXX" # さっきメモした Client Secret

次に IAP の設定を記載したpolicy.yamlを記載します。

# policy.template.yaml
# see https://www.pomerium.com/reference/#policy
- from: https://app.pomerium.example.com # アクセス元となる
  to: # deploy した protect サービスの URL。ドメインを割り振っているなら、それを記述
  allowed_domains:
    - gmail.com
  enable_google_cloud_serverless_authentication: true
- from: https://httpbin.pomerium.example.com # api定義用
  to: https://httpbin.org
  pass_identity_headers: true
  allowed_domains:
    - gmail.com

IAM 権限の設定

まず、pomerium を実行する予定のサービスアカウントに先程デプロイした protect の実行権限を付与します。

$ PROJECT=$(gcloud projects describe $(gcloud config get-value project) --format='get(projectNumber)')
$ gcloud run services add-iam-policy-binding protect --platform managed --region us-central1 \
       --member=serviceAccount:${PROJECT}-compute@developer.gserviceaccount.com \
       --role=roles/run.invoker

上記のコマンドはデフォルトのサービスアカウントを指定していますが、任意のサービスアカウントで pomerium を起動する場合は、そちらに変更して権限を付与します。

次に先程作成したconfig.yamlをシークレットマネージャーに登録します。シークレットマネージャーの API が有効になっていない場合は有効にしてから行って下さい。

$ gcloud secrets create --data-file config.yaml pomerium-config --replication-policy automatic ## secret の名前は大切

pomerium を実行するサービスアカウントに対して、シークレットに対してのアクセス権限を付与します。任意のサービスアカウントを使う場合は、適宜サービスアカウント名を変更して下さい。

$ PROJECT=$(gcloud projects describe $(gcloud config get-value project) --format='get(projectNumber)')
$ gcloud secrets add-iam-policy-binding pomerium-config \
       --member=serviceAccount:${PROJECT}-compute@developer.gserviceaccount.com \
       --role=roles/secretmanager.secretAccessor

deploy

以下のコマンドで pomerium をデプロイします。リージョンは東京にしていますが、近場に適宜変更して下さい。

$ PROJECT=$(gcloud projects describe $(gcloud config get-value project) --format='get(projectNumber)')
$ gcloud run deploy pomerium --region asia-northeast1 --platform managed --allow-unauthenticated --max-instances 1 \
       --image=gcr.io/pomerium-io/pomerium:v0.10.0-rc2-cloudrun \
       --set-env-vars VALS_FILES="/pomerium/config.yaml:ref+gcpsecrets://${PROJECT}/pomerium-config" \
       --set-env-vars POLICY="$(base64 policy.yaml)"

DNS の設定

最後に DNS の設定を行います。ドキュメントにはコマンドも用意されていますが、beta コマンドなので、GCP コンソールから行う方法でやりました。

cloud run のサービス一覧からManager Custom Domainsをクリックします。

サービス一覧

その後、Add Mapping をクリックして、domain のマッピングを追加します。

サービス一覧

pomeriumサービスに、設定で使用している以下の3つのドメインを追加していきます。 ドメインのプロバイダーに DNS レコードを追加する必要があるなど、少し面倒なため、こちらの手順を参考に行うと良いと思います。

  • authn.pomerium.example.com : 認証で使用するドメイン
  • app.pomerium.example.com : アプリケーションへのアクセスで使用するドメイン
  • httpbin.pomerium.example.com: api 定義の閲覧用

動作確認

動作確認は簡単です。アプリケーションのアクセスで使用する予定だったapp.pomerium.example.comにアクセスすれば google 認証を行うようになっていることが確認できます。 そして、google 認証後にアプリケーションにアクセスできるかと思います。また、httpbin.pomerium.example.comなどのドメインにアクセスすれば api 定義を見ることができるので面白いです。

しかし気づくと思います。これでは google 認証さえすれば誰でもアプリケーションにアクセスできることを。。。

そこで、最後に IAP っぽくメールアドレスの filter を追加していきます。

メールアドレスのフィルター設定

設定するのはすごい簡単です。pomerium のドキュメントを読めばすぐ見つかりますが、以下のように対象のドメイン設定を変更してあげるだけです。(設定の追加後は再デプロイを忘れずに。)

# policy.template.yaml
# see https://www.pomerium.com/reference/#policy
- from: https://app.pomerium.example.com # アクセス元となる
  to: # deploy した protect サービスの URL。ドメインを割り振っているなら、それを記述
  allowed_domains:
    - gmail.com
  # 追加行
  allowed_users:
    - allowed_mail@example.com # 許可するメールアドレス

こうすると、対象のメールアドレス以外で google 認証を行うと、弾かれることが確認できます。

アクセス拒否

まとめ

手順は多いですが、GCP の IAP に近いことができる pomeirum の追加手順でした。 ドメインが必要なことや、GCP コンソール上でポチポチっと許可ユーザーの設定を行なえませんが、幅広い設定が可能なので現状の選択肢としては全然有りなんじゃないかなって思いました。
また、管理ユーザの管理だけでなく、ユーザの認証サービスとしても全然使えそうなので、色々と試しがいがありそうで面白そうなサービスです。