CloudRunのサービスとタグ毎に独自ドメインのURLを割り当てる(CertificateManager編)

## 目的
GCPのマネージド証明書では扱えなかったワイルドカード証明書が[Certificate Manager](https://cloud.google.com/blog/ja/products/identity-security/simplify-saas-scale-tls-certificate-management)では扱えるようになったそうなのでCloudRunのサービスごとに独自ドメインを割り当てます。

## 注意!
- この記事は2022/06/11時点でのCertificate Manager(Preview)を取り扱っています。
- 必要なコマンドやコンソール操作の手順だけを記しており、gcloudのインストール・設定やAPIの有効化等は記載していません。
- 簡単な動作しか確認していないため設定やセキュリティに不備が　あるかもしれませんので利用の際はお気をつけください。

## 事前に必要なもの
- 独自ドメイン（この記事ではexample.comとしているので読み替えてください）
- DNS(Cloud DNS,Route53等)
- 課金が有効なGCPプロジェクト

## CloudRunの用意
CloudRunはサービス・リビジョンタグごとにURLが割り振られるので、サンプルとして以下を構成します。自動で割り振られたURLも例として記載します。(xxxxxxxxxxはプロジェクト独自のランダム文字列)

- サービス: main https://main-xxxxxxxxxx-an.a.run.app/
  - タグ: rev01 https://rev01---main-xxxxxxxxxx-an.a.run.app/
  - タグ: rev02 https://rev02---main-xxxxxxxxxx-an.a.run.app/
- サービス: sub  https://sub-xxxxxxxxxx-an.a.run.app/
  - タグ: rev01 https://rev01---main-xxxxxxxxxx-an.a.run.app/
  - タグ: rev02 https://rev02---main-xxxxxxxxxx-an.a.run.app/

今回はこのサービスを `https://rev01-main.example.com/` のようなURLでは `サービス:main　/　タグ:rev01` 、 `https://rev02-sub.example.com/` では `サービス:sub　/　タグ:rev02` に振り分けられるロードバランサーを構築します。 

## ロードバランサの作成
まずはコンソールからHTTPSロードバランサーを作成します。注意点として、Classic（従来型）ではなく新しいグローバル外部HTTP（S）ロードバランサー（2022/06/11時点preview）を作成する必要があります。新しいロードバランサーしかCertificateManagerで作成する証明書に対応していないためです。


### バックエンドサービスの作成
新たにバックエンドサービスを作成します。バックエンドタイプにサーバーレスネットワークエンドポイントグループを指定します。(ServerlessNEG)

### ServerlessNEGの作成
バックエンドサービスにのバックエンドに指定するサーバーレスネットワークエンドポイントグループ(ServerlessNEG)を以下の設定で作成します。

- リージョン: `任意のリージョン`
- サーバーレス ネットワーク エンドポイント グループの種類: `Cloud Run`
  - URLマスクを使用: `<tag>-<service>.example.com`

ここで設定したURLマスクに応じてCloudRunへの振り分け方が決まります。タグでの振り分けを行わない場合は `<service>.example.com` となります。`*.example.com` のサブドメインである必要があるので タグとサービスを `.` で区切ることができません。
※試してはいませんが、タグやサービス自体に`-`を含むことはできるので、混ざるとパースがおかしくなる可能性があります。


バックエンドを作成したところで、フロントエンドはデフォルトのままロードバランサーを作成します。
CertificateManager関連の操作にコンソールが対応していないため以降はgcloudコマンドによる操作が必要です。
gcloudでのフロントエンド操作後、コンソールではCertificateManagerが行われたロードバランサーは設定が異常とみなされコンソールから設定を変更することができなくなるためバックエンドの設定はここまでに終えておきましょう。

### DNS認証の作成
参考: [Certificate Manager の導入による SaaS 規模の TLS と証明書管理の簡素化](https://cloud.google.com/blog/ja/products/identity-security/simplify-saas-scale-tls-certificate-management)

CertificateManagerでまず特定のドメインに対するDNS認証を作成します。
```
gcloud beta certificate-manager dns-authorizations create runsample-auth --domain="example.com"
```

作成が生成したらDNSで認証に必要な情報を設定します。設定に必要な内容はlistで取得できます。この場合、example.comを管理しているDNSで `_acme-challenge.example.com.`のCNAMEに指定の文字列を設定します。

```
gcloud beta certificate-manager dns-authorizations list
NAME       DOMAIN                DNS_RECORD                             RECORD_TYPE  DNS_VALUE
runsample-auth  example.com  _acme-challenge.example.com.  CNAME        (ドメインの所有権確認用の文字列)
```

DNS認証を作成したら、証明書を作成します。domainsに `*.example.com` を指定することでサブドメインを使用することができます。

```
gcloud alpha certificate-manager certificates create runsample-crt --domains="example.com,*.example.com" --dns-authorizations="runsample-auth"
```

### 証明書マップの作成
参考: [GCPにおけるロードバランサ、CDN、Certificate Managerの流れを理解する](https://qiita.com/ku_suke/items/25e9e7c2daee9ee02991)

まずはロードバランサーで使用するための証明書マップを作成します。

```
gcloud beta certificate-manager maps create crt-map-runsample
```

#### エントリ作成
証明書マップに設定となるエントリを追加します。

```
gcloud beta certificate-manager maps entries create entry-1-runsample \
    --map="crt-map-runsample" \
    --certificates="runsample-crt" \
    --hostname="example.com"
```

設定後、エントリの状態がアクティブか確認してください。
```
gcloud beta certificate-manager maps entries describe entry-1-runsample  --map="crt-map-runsample"
# 以下結果
certificates:
- projects/xxxxxxxx/locations/global/certificates/runsample-crt
createTime: '2022-06-11T04:19:35.431834662Z'
hostname: 'example.copm'
name: projects/xxxxxxxxxxxxx/locations/global/certificateMaps/crt-map-runsample/certificateMapEntries/entry-1-runsample
state: ACTIVE
updateTime: '2022-06-11T04:55:00.547144846Z'
```

### ロードバランサーへ適用
ロードバランサにHTTPSプロキシを作成し証明書マップを設定します。
```
gcloud beta compute target-https-proxies create lb-runsample-proxy  --url-map=lb-runsample --certificate-map="crt-map-runsample"
```

転送ルールを作成します。この時点でロードバランサーにフロントエンドが設定されます。（コンソールからは証明書が空で設定不備に見えます）
```
gcloud beta compute forwarding-rules create lb-runsample-https-forwarding-rule \
 --load-balancing-scheme=EXTERNAL_MANAGED \
 --network-tier=PREMIUM \
 --global \
 --target-https-proxy=lb-runsample-proxy \
 --ports=443
```

### DNSにワイルドカードのドメインを設定
コンソールでロードバランサーの443が開放されているIPを確認して、DNSで`*.example.com`のAレコードに設定します。


## URLで接続を確認

設定が正しく行えていると以下のようなURLのパターンで各サービスのタグがつけられたインスタンスへアクセスができるようになります。

- サービス: main （割当なし)
  - タグ: rev01 https://rev01-main.example.com/
  - タグ: rev02 https://rev02-main.example.com/
- サービス: sub  (割当なし)
  - タグ: rev01 https://rev01-sub.example.com/
  - タグ: rev02 https://rev02-sub.example.com/


## まとめ
GCPユーザー待望のマネージドなワイルドカード証明書がようやく実現されました。ただしまだまだ設定が手間で、コンソールにも対応していません。
Certificate Managerも新しいロードバランサーもpreviewなのですが、GAになるころにはコンソールだけで完結できそうな気もするので今無理してやる必要はないんじゃあないかなとは思います。