CloudRun への IAP 追加手順

## はじめに

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

## 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.

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

## cloudrun + pomerium

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

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

### client の作成

google 認証を行うためにまずは、OAuth client を作成していきます。この [URL](https://console.developers.google.com/apis/credentials/oauthclient)をクリックして以下の画像のように作成していきます。認証で使用するドメインをリダイレクト先の URL に入れる所が大切です。

![create_client.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488897/0cb28124-f406-345d-ead6-999531ae0afe.png)


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

### 設定ファイルの作成

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

```yml
# 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`を記載します。

```yml
# 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 の実行権限を付与します。

```bash
$ 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`をシークレットマネージャーに登録します。[シークレットマネージャー](https://console.cloud.google.com/security/secret-manager)の API が有効になっていない場合は有効にしてから行って下さい。

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

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

```bash
$ 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 をデプロイします。リージョンは東京にしていますが、近場に適宜変更して下さい。

```bash
$ 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 の[サービス一覧](https://console.cloud.google.com/run)から`Manager Custom Domains`をクリックします。

![service_list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488897/f6f9292e-66d3-fe1e-9561-6c0af1e6beac.png)

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

![domain_mapping.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488897/1e57eef2-f3a5-f580-d943-8cf02fa36527.png)


`pomerium`サービスに、設定で使用している以下の３つのドメインを追加していきます。
ドメインのプロバイダーに DNS レコードを追加する必要があるなど、少し面倒なため、こちらの[手順](https://cloud.google.com/run/docs/mapping-custom-domains?_ga=2.24128506.-1940196106.1586675382)を参考に行うと良いと思います。

- `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 のドキュメント](https://www.pomerium.com/reference/#policy)を読めばすぐ見つかりますが、以下のように対象のドメイン設定を変更してあげるだけです。（設定の追加後は再デプロイを忘れずに。）

```yml
# 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 認証を行うと、弾かれることが確認できます。

![forbidden.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488897/05eb59b8-3e56-4eb5-e557-13a847bf5605.png)


## まとめ

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