Code EngineのアプリにIP制限をかけてみる

今回はCode Engine上のアプリにIP制限をかけ、特定の利用者へのみアプリ公開する方法を試してみたいと思います

IBM Cloud Code Engineのアプリはパブリックとプライベート、そしてプロジェクトと３タイプでアプリの公開範囲の設定ができますが、より細かな制御をするために今回はCloud Internet Service(CIS)と組み合わせてみます

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/f57d194c-afdf-e396-aa96-bd45e6d2d4ec.png)

## 事前準備

- 独自ドメイン
  私はIBM Cloudでドメインを購入しました
  [https://cloud.ibm.com/classic/services/domains](https://cloud.ibm.com/classic/services/domains)
- CA証明書(中間証明書を含むfullchain)とプライベートキー
  私はLet's Encryptでワイルドカードの証明書を発行しました
  参考にしたqiita：[https://qiita.com/F_clef/items/136d81223c030904523c](https://qiita.com/F_clef/items/136d81223c030904523c)
  ※自己証明書, CISのオリジン証明書は利用できません

## 設定の流れ

1. Code Engineでアプリをデプロイ
2. Code EngineでDomain Mappingを設定
3. CISでドメインを登録
4. CISでDNSレコードの登録
5. CISでIPファイアウォールの設定
6. 最終確認

## 1. Code Engineでアプリをデプロイ

まずは簡単なアプリをCode Engineにデプロイします

今回はサンプルアプリのコンテナイメージ ( [icr.io/codeengine/helloworld](http://icr.io/codeengine/helloworld) ) をそのまま使っていきます

![Untitled 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/14643648-4a67-06b3-d766-b8ff91ff04a8.png)

動作検証をスムーズにするため、1インスタンスだけで稼働し続けるようにしています

また課金を抑えるためにリソースは最低限のものを選択しました

![Untitled 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/e4257292-7eb9-8eae-bca1-0dc00cc45757.png)

デプロイが完了したので、実際にアプリにアクセスして稼働チェックしておきます

アプリのURLは、「アプリケーションのテスト」ボタンから取得できます

![Untitled 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/807de457-1030-7d6f-9a7c-9512ecd76512.png)

Hello Worldが表示され、アプリが稼働していることが確認できたので、次にすすみます

![Untitled 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/f2c27cd8-2fc3-25a8-fcab-02d3ccf09570.png)

## 2. Code EngineでDomain Mappingを設定

次に、CIS経由でアクセスできるように、カスタム・ドメイン・マッピングを設定します

**「ドメイン・マッピング」** の画面にて、 **「作成」** をクリックします

![Untitled 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/9a54202a-3df7-014e-3308-549f49eed921.png)

「ドメイン・マッピングの作成」 ダイアログが表示されるので必要事項を入力します

- TLSシークレット
  - 選択 or 作成：
    - 作成：初めての登録、証明書がワイルドカードではない場合
    - 選択：ワイルドカード証明書を利用している場合ですでに登録している場合は作成済みのSecretを選択する（**同じワイルドカード証明書は同じリージョンに１つしか登録できないようです。別プロジェクトであっても同じリージョンでは利用できません**）
  - Certificate chain：　中間証明書を含むfullchainのCA証明書の内容
    （let's encryptの場合はfullchain.pemの内容）
  - Private key：　プライベートキーの内容
    （let's encryptの場合はprivkey.pemの内容）
- ドメイン名とターゲット・アプリケーション
  - カスタム・ドメイン・ネーム：　アプリ公開に利用したいURL（私はmyapp.handson-lab.comと指定）
  - ターゲット・アプリケーション：　ターゲットのCode Engineアプリを選択
  - CNAME ターゲット：DNSの設定に使うのでコピーしておきます

![Untitled 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/169a0fbc-2f36-85ed-e601-2308b68acf12.png)

状況が「デプロイ中」から「準備完了」になったらOKです

数分で完了するはずなので、かなり待ってもデプロイ中から進まない場合は登録している証明書の内容や鍵の確認をしてみてください

またワイルドカード証明書を利用している人は、同じプロジェクトで同じワイルドカード証明書を登録済みの状況で新たにTLS Secretを作成してしまっていないかや、同じリージョンの別プロジェクトですでにワイルドカード証明書を使っていないかチェックしてみてください

![Untitled 7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/d25f7f3d-8ff8-2922-4620-7288a34b9d7a.png)

## 3. CISでドメインを登録

CISのインスタンス作成や、ドメインの登録の部分はこちらのQiitaをご参照ください

[IBM Cloud CISの動作確認(1) -初期導入編- - Qiita](https://qiita.com/khoshina/items/e9b397f498330faefdd9)

## 4. CISでDNSレコードの登録

Code Engineのドメイン・マッピングにて提供されたCNAME ターゲットを使ってDNS登録していきます

CISにて「信頼性」から「DNS」を選び、「DNSレコード」の「追加」をクリックします

![Untitled 8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/6381cef5-7ca5-1082-0fcf-83bfe49ab9d8.png)

「レコードの追加」ダイアログにて必要事項を入力します

- タイプ：CNAME
- 名前：Code Engineのカスタム・ドメインにて設定したドメイン名 
  （私の場合は[myapp.handson-lab.com](http://myapp.handson-lab.com/)）
- 別名のドメイン名：Code Engineのカスタム・ドメイン設定時に表示されたCNAME ターゲット
  （私の場合はcustom.z6qoi5aro6g.jp-tok.codeengine.appdomain.cloud）

![Untitled 9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/bead06de-37ba-0c96-d30d-48daf6746289.png)

無事にレコードが登録されました

この後IPファイアウォールを利用するので、プロキシーをONにしておきます

![Untitled 10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/6b79ee14-2628-6d97-4aad-fb970e59e2b6.png)

![Untitled 11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/65a5b3f4-61ce-321f-bd14-b42a3462c584.png)

nslookupで確認し、以下のようなCISの宛先が返ってくることを確認します

```bash
# proxy-onでの期待結果
❯ nslookup myapp.handson-lab.com
Server:		2404:1a8:7f01:b::3
Address:	2404:1a8:7f01:b::3#53

Non-authoritative answer:
Name:	myapp.handson-lab.com
Address: 172.67.31.110
Name:	myapp.handson-lab.com
Address: 104.22.62.198
Name:	myapp.handson-lab.com
Address: 104.22.63.198

# proxy-offだと以下のような結果が返ってきてしまいます
❯ nslookup myapp.handson-lab.com
Server:		2404:1a8:7f01:b::3
Address:	2404:1a8:7f01:b::3#53

Non-authoritative answer:
myapp.handson-lab.com	canonical name = custom.z6qoi5aro6g.jp-tok.codeengine.appdomain.cloud.
custom.z6qoi5aro6g.jp-tok.codeengine.appdomain.cloud	canonical name = s01.jp-tok.codeengine.appdomain.cloud.
s01.jp-tok.codeengine.appdomain.cloud	canonical name = 163f4bf89dd14529ab332f76dd35b0eb.pacloudflare.com.
Name:	163f4bf89dd14529ab332f76dd35b0eb.pacloudflare.com
Address: 172.65.200.138
```

## 5. CISでIPファイアウォールの設定

それでは最後に、特定のIPからのみアクセスできるようにIPファイアウォールの設定をしていきます

今回はドメイン・ロックダウン機能をつかっていきます

各機能の違いはこちらを参考にしました　[IBM Cloud Internet Services (CIS) IP Firewallについて - Qiita](https://qiita.com/y_tama/items/cb75efc73bda75757cb9)

![Untitled 12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/c6ba8e2a-f87e-e285-37b9-4fc86bbcbea5.png)

「ドメイン・ロックダウン・ルールの作成」ダイアログにて必要事項を入力します

- ルール名: わかりやすい名前
- URL：ファイアウォールを設定したいURL
- IPアドレスと範囲：許可したいIPアドレス（IPv4とIPv6両方書きます）

![Untitled 13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/5bf114c0-15ae-8f78-8241-8ffc6c502a3d.png)

レコードが追加され、有効がONになっていることを確認します

これですべての設定が完了です！

![Untitled 14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/d6c94f6f-0c15-0d28-f6cf-46dcd57a5293.png)

## 6. 最終確認

最後にIP制御ができているかチェックしてみます

左側が、私のLocal環境からのアクセスで許可されたIPからのアクセスです

右側が、リモートデスクトップで接続している別拠点にあるRemote環境で、許可されていないIPからのアクセスです。

期待通り、許可していないIPからのアクセスは「Access denied」とブロックされました

![Untitled 15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/5efcc53d-f59f-3ff2-e396-2d9159ee61c5.png)

## 補足-Code Engineの提供のパブリックエンドポイントは残す？残さない？

残しておくと、仮にパブリックのURLが知られた場合にダイレクトでアクセスされてしまうので、プライベートなどに変更することをおすすめします

![Untitled 16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/e0f66537-8d4a-a21b-f22e-4a2daae0c093.png)

パブリックのエンドポイントを無効化しました

左：インターネットからCode Engineが提供していたFQDNにアクセスすることができなくなりました

右：カスタムドメインマッピングで設定したドメインを使ってインターネットからアクセスできます

![Untitled 17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/a6451579-c40d-558c-628a-381ab12bfc35.png)

## 補足-２つ目以降のアプリでのカスタムドメインの設定方法

もう一つ、Helloworldアプリもカスタムドメインで公開してみます

手順はほぼ同じですが、ワイルドカード証明書を利用している場合はドメイン・マッピングの作成のTLSシークレットの部分だけ変わります

前回同様、「ドメイン・マッピング」の画面から作成をクリックします

![Untitled 18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/198bd074-063d-9a86-b279-3718fcb97628.png)

ワイルドカードの証明書の場合はすでにTLS Secretが登録済みなので「**TLSシークレット**」は作成ではなく、選択を選びます。ワイルドカードではなく、個別に証明書を設定する場合（helloworld.handson-lab.com）はTLSシークレットの作成を選んで登録してください

![Untitled 19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/1c4d4d73-786c-2410-b436-d5432a79a7a7.png)

ドメイン・マッピングの作成が完了後は初回同様に、CISからDNSレコードの追加を行います

CNAMEターゲットはCode Engineプロジェクトごとに割り振られているので、先程と同じCNAMEです

（同じCNAMEにですが、アクセスした際にヘッダー情報に含まれるアクセスURLを元にCode Engine側で適切なアプリにルーティングが行われます）

![Untitled 20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/0830288e-0dec-94bb-041b-a6bb269cb393.png)

先程作ったものと並んでDNSレコードが登録できました。

![Untitled 21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/59a80472-083d-8a4e-f6f0-f04c05db63f7.png)

そして最後に、IPファイアウォール設定を更新します

![Untitled 22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/fe3b27a6-a85c-ef2a-cba3-64cc8c081f8f.png)

最後に確認のためアクセスします

（nginxのコンテナイメージをそのままデプロイしたので、見慣れたNginxの画面が表示されました）

![Untitled 23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136580/805cae9a-9ba6-29ef-c584-f17706a5a8b5.png)

## 参考リンク

- Code Engine
  - [アプリのカスタム・ドメイン・マッピングの構成](https://cloud.ibm.com/docs/codeengine?topic=codeengine-domain-mappings&locale=ja)
- Cloud Internet Service
  - [IP ファイアウォール](