Code Engineへのアクセスを制御するため、Squidによるリバースプロキシ（Reverse Proxy）を立てる



IBM CloudのCode Engineを使用してWeb Applicationを構築する際、安全性を考慮してアクセスを制限したいと希望するお客様が多くいらっしゃいます。

一般的な解決策としては、Code Engine上のWeb Applicationをプライベートエンドポイントのみで公開し、ユーザーがプロキシサーバーやVPNを介して接続する方法や、パブリックエンドポイントを使用しながらファイアウォールで保護する方法などがあります。

本記事の説明は、プロキシサーバーを使用する方法に関するものです。特に、フォワードプロキシ（ForwardProxy）ではなく、リバースプロキシ（ReverseProxy）の設定方法について取り上げています。

### 実現したいこと

構成はこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/1e958990-0b55-dbe8-a622-5e5cfd66addc.png)
- Web App on Code Engine：Httpsのみ、Private Endpointで公開する
- Proxy on Virtual Server：Proxy softwareがSquidです。まだ、Security Groupによる、送信元IP Addressや、Protocol、PortNoを制御する

最初はForward Proxyで試しました。次の記事は大変参考になりました。
By @egawaaa: SquidによるフォワードプロキシでCode Engineへのアクセスを制御する。
https://qiita.com/egawaaa/items/79176404ba91270981a9


その後、Reverse Proxyの要件が出てきて、変更があったのはSquidの設定部分のみです。そのため、Squidの設定方法について重点的に説明します。

### Forward ProxyとReverse Proxyについて

#### Forward Proxyであれば
 @egawaaaさんの記事に説明して頂いたように、Forward Proxyを使用する場合、Webアプリケーションを訪問するためユーザーは自分のパソコンでプロキシサーバーを設定する必要があります。具体的には、

- curl コマンドを使用する場合は、--proxy <proxy VM IP> を指定し、宛先アドレスとしてWeb AppのURLを指定する必要があります。
```ctr:
curl --proxy http://<proxy server IP>:8080 https://<application-specific-url>.xxxxxx.private.jp-tok.codeengine.appdomain.cloud
```
- ブラウザを使用する場合は、ブラウザのプロキシ設定を行う必要があり、Web Appを訪問する際にWeb AppのURLままに入力します。
下記の二つのスクリーンショットは@egawaaaさんの記事からのものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/5425aab8-5d50-dbd1-45f2-9006ebe63e02.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/ba9ae0c5-b68e-7528-fb2e-a2e942cd539d.png)

#### Reverse Proxyであれば

Reverse Proxyを使用すると、curlまたはブラウザーは、実はProxy Serverのアドレスを宛先として接続します。つまり、ユーザーはProxy Serverの存在を意識せずにWeb Appにアクセスできます。詳細の接続方法については、この記事の後半の手順の部分で説明します。

どのようなメリットがあるかといいますと：
- Web Appの一般的なユーザーにとって、常にブラウザのプロキシ設定が必要となるのは不便です。また、会社のPCを使用しているユーザーの中には、ブラウザのプロキシ設定を自由に変更できない場合もあります。
- Code EngineのWeb App URLは固定の形式になっており、たとえば、codeengine.appdomain.cloudというDomainが使用されます。もし、Web Appに独自のDomainを使用したい場合は、リバースプロキシを通じて実現可能です。


### 手順

全体の流れ：
1. Code EngineでAppを作成する
1. VSI for VPCを作成する
1. Squidの導入と設定、接続効果を確認する

#### Step 1. Code EngineでAppを作成する

詳細手順を割愛しますが、「Domain Mappings」で「Private」をご選択ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/428ecb1b-02fc-816b-18d6-3c17a2df6701.png)

Appの構築が出来たら、Domain mappingsタブでURLを確認できます。
私の環境ではWeb AppのURLがこうなります：https://application-xxx.1xxxe.private.jp-tok.codeengine.appdomain.cloud

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/eec68822-abff-e695-144d-1d9bb1662452.png)

#### Step 2. VSI for VPCを作成する

VSIのプロビジョニングやSecurity Groupの設定に関する手順を割愛します。
OSがCentOSにしました。

#### Step 3. Squidの導入と設定、接続確認

Squidのインストール
```ctr:
dnf -y install squid
```
Squidのバージョンを確認します。
```ctr:
[root@xxx-centos9 ~]# squid --version
Squid Cache: Version 5.5
Service Name: squid
```

squid.confを編集します。
```ctr:
vi /etc/squid/squid.conf
```

##### Client PCとProxy Serverの間でHttpで接続する場合、
構成ファイルの**最後**に下記の内容を追加します：
```ctr:
http_port 3128 accel defaultsite=application-xxx.1xxxe.private.jp-tok.codeengine.appdomain.cloud no-vhost
cache_peer  application-xxx.1xxxe.private.jp-tok.codeengine.appdomain.cloud parent 443 0 no-query originserver ssl name=myAccel
cache_peer_access myAccel allow all
http_access allow all
```
一部のパラメータを説明します：
- http_portの行：
    - **3128**：HTTPで接続する場合、Port 3128を使います。
    - **accel**：Squidは、HTTPリクエストのHostヘッダーに関係なく、すべての受信リクエストを指定された defaultsite宛てのものとして扱います。
    - **defaultsite**：Code EngineでのWeb AppのURLを'https://'なしで設定します。
    - **no-vhost**：Squid 3.2以降では、HTTP/1.1のドメインベースのVirtual Hosting Supportが無効になっています。古いバージョンのSquidを使用する場合は、このオプションを省略してください。今回はSquid 5.5なので、**このオプションが必要**です。

-　cache_peerの行：
    -　Code EngineのWeb AppのURLを'https://'なしで設定します。
    -　**443**：Code EngineのWeb AppのPort No
    -　**ssl**：Proxy ServerとWeb Appの間にHttpsを使います。

この設定を保存してから、Squidを起動します。
```ctr:
systemctl restart squid
```
Web Appを接続できるか、Curlやブラウザで確認します。
```ctr:
curl http://<Proxy Server IP>:3128
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/10fdc8f4-226a-62b8-9701-bac9845e2c40.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/d5cc27c5-ac81-2255-c79c-0da8c1356d14.png)

##### Client PCとProxy Serverの間でHttpsで接続する場合、
構成ファイルの**最後**に下記の内容を追加します：
```ctr:
https_port 443 accel defaultsite=application-xxx.1xxxee.private.jp-tok.codeengine.appdomain.cloud cert=/etc/squid/ssl_certificates/proxy.test.com.crt key=/etc/squid/ssl_certificates/proxy.test.com.key no-vhost
cache_peer application-xxx.1xxxe.private.jp-tok.codeengine.appdomain.cloud parent 443 0 no-query originserver ssl name=myAccel
cache_peer_access myAccel allow all
http_access allow all
```
お気づきのように、今回は：
- Httpsで443を使います
- Proxy Server用のSSL Certificateの準備が必要になります。
私の検証環境でEasyRSAを使って自己証明書を作成しました。手順はこちら：
```ctr:
git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa build-server-full proxy.test.com nopass
```
作成した **./pki/issued/proxy.test.com.crt**と **./pki/private/proxy.test.com.key**を　**/etc/squid/ssl_certificates/**に移動してから、Squidをスタートします。

```ctr:
systemctl restart squid
```

HttpsでWeb Appを接続できるか、Curlやブラウザで確認します。自己証明書なので、Curl -kが必要、ブラウザで証明書に関するWarningを無視します。

```ctr:
curl https://<Proxy Server IP>:443 -k
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/73cb3350-7a8a-48e0-09ef-660cfce784ad.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/8cbb813a-bc34-e4ab-5424-57a647bcf45a.png)

更に、Local PCのHost Fileを編集すれば、FQDNでも訪問でき、独自のDomainを使うことが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2075462/7398ead0-f5d9-7a74-e1a1-0d8401360438.png)

### 最後に
手順が以上です。
今回の検証は @egawaaaさんの記事は大変参考になりまして、感謝致します。