GCP上のKibanaにTCP80でアクセスさせる方法

## はじめに
会社のネットワークからインターネット越しにKibanaへアクセスしようとするとファイアウォールで
ブロックされることが多いです。
KibanaのデフォルトポートであるTCP5601のまま、会社ネットワークからGCP上に構築したKibanaに
アクセスできるようにした際にCloud Load Balancingでハマったので、備忘録的に投稿します。

## 利用環境
・Kibana 7.1.1

※ 構成は以下のようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/d9c3230a-d2e4-ae07-763e-f450965f0b77.png)

## 前提
やり方は色々あると思っていますが、ちょっとワガママを言いました。

- AWSではなくGCPで構築したかった
- KibanaのポートはデフォルトのTCP5601から変えたくなかった
- KibanaのGCEにはNGINXを入れたくなかった
- TCP443でSSL証明書の発行はしたくなかった
- 送信元IPアドレスを会社ネットワークからに限定したかった

上記のワガママを実現しようとすると

- `Cloud Load Balancing`でTCP80をTCP5601にポートフォワーディングする
- `Cloud Load Balancing`にファイアウォールルールの適用は出来ないため、`Cloud Armor`でIP制御を行う 
 
ということになります。

**【参考】**
・ [Google Cloud Load Balancing documentation][00]
・ [Google Cloud Armor documentation][01]

## 実施内容
以下のステップで設定を実施しました。
1. VMインスタンスの作成
2. インスタンスグループの作成
3. ヘルスチェックの作成
4. ファイアウォールルールの作成
5. HTTP Load Balancingの作成
6. セキュリティポリシーの作成

#### 1. VMインスタンスの作成
[GCPメニュー] > [Compute Engine] > [VMインスタンス]
`リージョン:us-west1 (オレゴン)`、`ゾーン:us-west1-b`でインスタンスを`CentOS7`で構築しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/90f0914b-4b7e-bc0d-b595-694fb4aae0ff.png)

**【gcloudコマンド】**

```console
$ gcloud compute instances create kibana \
   --boot-disk-auto-delete \
   --image "centos-7" \
   --maintenance-policy TERMINATE \
   --preemptible \
   --zone "us-west1-b"
```

※Kibanaの構築手順は割愛しています。

**【参考】**
・ [Install Kibana with RPM][02]

#### 2. インスタンスグループの作成
[GCPメニュー] > [Compute Engine] > [インスタンスグループ]
上記で作成したVMと同じロケーションとし、`VMインスタンス`に`kibana`をしてします。
(**非マネージドインスタンスグループ**とします)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/34a9f756-e80d-af1c-5a6a-bb9b94f65159.png)

**【gcloudコマンド】**

```console
$ gcloud compute instance-groups unmanaged create kibana-group \
   --zone "us-west1-b"
$ gcloud compute instance-groups unmanaged add-instances kibana-group \
   --instances "kibana"
```

#### 3. ヘルスチェックの作成
[GCPメニュー] > [Compute Engine]  > [ヘルスチェック]
`プロトコル:HTTP`、`ポート:5601`、`リクエストパス:/app/kibana`とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/b9cc01fa-3b82-b241-e3b2-9c934244308f.png)

**【gcloudコマンド】**

```console
$ gcloud compute http-health-checks create kibana-healthcheck \
   --port "5601" \
   --request-path "/app/kibana" \
```

#### 4. ファイアウォールルールの作成
[GCPメニュー] > [VPCネットワーク] > [ファイアウォールルール]
`Cloud Load Balancing`からの通信を許可する必要があります。
`35.191.0.0/16`と`130.211.0.0/22`からの`TCP5601`のみ許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/601963e0-f68c-42a1-4352-e28c6e8b1b8d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/5792a16f-29bc-7c75-ffa5-43399ce2bfee.png)

>Traffic from the load balancer to your instances has an IP address in the ranges of 130.211.0.0/22 and 35.191.0.0/16. 
>When viewing logs on your load balanced instances, you will not see the source address of the original client. Instead, you will see source addresses from this range.

**【gcloudコマンド】**

```console
$ gcloud compute firewall-rules create kibana-firewall \
   --source-ranges 130.211.0.0/22,35.191.0.0/16 \
   --target-tags kibana \
   --allow tcp:5601
```

VMインスタンスに作成したファイアウォールルールの`ネットワークタグ:kibana`を付与します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/bc8750d3-fc92-24be-26c9-ef66de329130.png)

#### 5. HTTP Load Balancingの作成
設定画面では、`HTTP(S)負荷分散`、`TCP負荷分散`、`UDP負荷分散`という表現がされてますが
実際には以下の5つのパターンがあり、ユースケースに応じて非常に細かく複雑になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/3a132e63-c45c-d97f-5abe-f93d4c27f6a7.png)
※今回は要件的に`HTTP(S) Load Balancing`を利用しています。

[GCPメニュー] > [ネットワーキング] > [負荷分散]
`HTTP(S)負荷分散`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/a488e157-fbed-51e1-1fda-225913def7a0.png)

`バックエンドの設定`で`バックエンドサービスの作成`を行います。
(ロードバランサがどのVMインスタンスのグループに負荷分散をするのかを定義)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/2dc03dd5-d5df-55e9-1cb0-6045e0bae67e.png)

事前に作成した`インスタンスグループ:kibana-group`に対して、`ポート番号:5601`で負荷分散します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/986fbf3f-9792-57ea-676e-e598e4b51270.png)

事前に作成した`ヘルスチェック:kibana-healthcheck`を設定し、作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/0fa1e32c-bca0-d073-5aa3-faf3cef07b86.png)

`ホストとパスのルール`として、作成したバックエンドサービスが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/3025d7ed-aa0c-00cc-00b0-9fa472c547f1.png)

`フロントエンドの設定`でクライアントからの受信設定を行います。
`HTTP(80)`で`シングルリージョン`となるので、以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/a7d29f08-5e6f-f831-7ba8-0cff89343ad5.png)

内容に間違いがなければ、[作成]をします。これで`kibana-lb`に完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/76234f88-d03c-9721-daf2-d13eab76a96d.png)

**【gcloudコマンド】**

```console
$ gcloud compute backend-services create kibana-back \
   --protocol HTTP \
   --http-health-checks kibana-healthcheck \
   --global
$ gcloud compute backend-services add-backend kibana-back \
   --instance-group kibana-group \
   --global
$ gcloud compute url-maps create kibana-lb \
   --default-service kibana-back
$ gcloud compute forwarding-rules create kibana-front \
   --target-http-proxy kibana-lb-target-proxy \
   --ports 80
```

#### 6. セキュリティポリシーの作成
[GCPメニュー] > [ネットワークセキュリティ] > [Cloud Armor]
`ポリシーの作成`を行います。(デフォルト動作は**全て拒否**です。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/4a6b83e5-66cd-7411-9a91-963eae075b6a.png)

`条件`の`一致`に会社ネットワークのグローバルIPをセットし、`アクション:許可`、`優先度:0`とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/a496653f-4a93-35ca-7a8c-29363b7d663f.png)

`ターゲットへのポリシーの適用`に`タイプ:ロードバランサバックエンドサービス`、`ターゲット:kibana-back`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/b8925b80-a19b-926b-27b4-1baff101aa7c.png)

`ポリシーを作成`で作成されれば、完了です。
会社ネットワーク以外からKibanaにアクセスすると以下の画面となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/d1cbc666-a6dd-33bb-43cd-14f2e3e560ce.png)

**【gcloudコマンド】**

```console
$ gcloud compute security-policies create kibana-waf
$ gcloud compute security-policies rules update 2147483647 \
   --security-policy kibana-waf \
   --action "deny-403"
$ gcloud compute security-policies rules create 0 \
   --security-policy kibana-waf \
   --src-ip-ranges "xxx.xxx.xxx.xxx/32" \
   --action "allow"
$ gcloud compute backend-services update kibana-back \
   --security-policy kibana-waf
```

**【参考】**
・ [Setting Up HTTP(S) Load Balancing][03]

## まとめ
今回ハマったポイントは、要件を満たす最適なロードバランサのタイプの選び間違いでした。
最初は、`HTTP(S)負荷分散`ではなく、`TCP負荷分散`を選択してしまいました。
TCP80をTCP5601にポートフォワーディングするので、それでOKだと思ったんですが
`TCP負荷分散`ではポートフォワーディングが出来ませんでした。

公式サイトを読んでいると漠然と「HTTP/HTTPSの場合は、`HTTP(S)負荷分散`を推奨します」
と記載されていますが、ポートフォワーディングするだけならL7じゃなくてL4でいいじゃんと
考えたのが失敗でした。。。

あとはLoad Balancingの設定をするだけなのに、色々な箇所に設定を作らないと機能せず
どことどこがどう関連しているのか初学者には考え方が掴みにくく、AWS ELBのほうが敷居が低いなと
感じました。画面を行ったり来たりしないと設定できないので、Cloud Shell前提なんですかね、、

[00]:https://cloud.google.com/load-balancing/docs/?hl=ja "Google Cloud Load Balancing documentation"
[01]:https://cloud.google.com/armor/docs/?authuser=19&hl=ja "Google Cloud Armor documentation"
[02]:https://www.elastic.co/guide/en/kibana/current/rpm.html "Install Kibana with RPM"
[03]:https://cloud.google.com/load-balancing/docs/https/setting-up-https?hl=ja "Setting Up HTTP(S) Load Balancing"