envoy の CORS Filter を試してみた。

# 概要
公式サイトにおける [Sandboxes の CORS Filter](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/cors) を試してみたので、メモがてら記事を投稿します。

# 検証環境
- macOS - High Sierra 10.13.6

- Docker - 18.06.1-ce

- Docker Machine - 0.15.0

- Docker Compose - 1.22.0

# 事前準備
[envoy のリポジトリ](https://github.com/envoyproxy/envoy)をクローンしておく必要があります。

# Sandbox の構築
基本的にドキュメント通りです。

ターミナルを2つ起動した後、それぞれのターミナルで次のコマンドを実行します。

```bash:ターミナル1
$ docker-machine create --driver virtualbox frontend
$ eval $(docker-machine env frontend)
```

```bash:ターミナル2
$ docker-machine create --driver virtualbox backend
$ eval $(docker-machine env backend)
```

クローンした envoy リポジトリの examples/cors/frontend ディレクトリと examples/cors/backend ディレクトリに格納されている各 docker-compose.yml からサービスを開始します。

```bash:ターミナル1
$ cd envoy/examples/cors/frontend
$ docker-compose up --build -d
```

```bash:ターミナル2
$ cd envoy/examples/cors/backend
$ docker-compose up --build -d
```

これで Sandbox の構築は完了です。

# frontend を通じて backend へリクエストを送信する。
Sandbox を作成すると仮想マシンの IP とサービスへ割り当てられている IP を用いることで frontend のサービスへアクセスできます。

まず、仮想マシンの IP 確認します。

```bash:ターミナル1
$ docker-machine ip frontend
192.168.99.100
```

frontend のアプリ動作に backend の仮想マシンのIPも必要となるため、このタイミングで調べておきます。

```bash:ターミナル2
$ docker-machine ip frontend
192.168.99.101
```

次にサービスへ割り当てられているポートを確認します。

```bash:ターミナル1
$ docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                                     NAMES
897e22a5cec3        frontend_frontend-service   "/bin/sh -c /usr/loc…"   2 hours ago         Up 2hours          80/tcp, 10000/tcp                                         frontend_frontend-service_1
c07e94bee417        frontend_front-envoy        "/docker-entrypoint.…"   2 hours ago         Up 2hours          0.0.0.0:8001->8001/tcp, 10000/tcp, 0.0.0.0:8000->80/tcp   frontend_front-envoy_1
```

私の環境では frontend アプリのURLは `http://192.168.99.100:8000/` となっていたため、ブラウザからアクセスしてみます。すると次のような画面が表示されます。ちなみに 8001 番ポートは envoy の admin へアクセスすることができました。

<img width="931" alt="スクリーンショット 2019-01-04 23.48.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/333750/6d78af1e-bdb4-1624-095f-c87e4b605b6f.png">

あとは `Remote IP` となっている箇所へ backend が動作する仮想マシンの IP を入力した後、`Fetch asset` を押すだけです。`CORS Enforcement` を切り替えることにより、`CORS Filter が無効な URL`、`あらゆる　origin　が有効な URL`、そして`特定の origin のみを許可する URL` とリクエストの送信先を切り替えることができます。

# curl を用いて backend へリクエストを送信する。

前述の通り、frontend のアプリは backend の URL を切り替えることにより、CORS Filter の設定値が異なる URL へリクエストを送信しています。従って、 `curl` により直接リクエストを送ることにより、レスポンスヘッダーの内容を確認することも可能です。

backend における各 URL とそれぞれのCORSの設定はenvoyリポジトリの examples/cors/backend/front-envoy.yaml から確認できます。

```bash
$ yq -y '.static_resources.listeners[].filter_chains[].filters[].config.route_config' front-envoy.yaml
name: local_route
virtual_hosts:
- name: services
  domains:
  - '*'
  cors:
    allow_origin:
    - '*'
    allow_methods: GET
  routes:
  - match:
      prefix: /cors/open
    route:
      cluster: backend_service
  - match:
      prefix: /cors/disabled
    route:
      cluster: backend_service
      cors:
        enabled: false
  - match:
      prefix: /cors/restricted
    route:
      cluster: backend_service
      cors:
        allow_origin:
        - envoyproxy.io
        allow_methods: GET
  - match:
      prefix: /
    route:
      cluster: backend_service
```

[API ドキュメント](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route.proto#envoy-api-msg-route-corspolicy)から各設定値を確認すると CORS Filter が有効となっているパスは `/cors/open`　と `/cors/restricted` であるとわかります。そして CORS Filter が無効となっているパスは `/cors/disabled` だとわかります。

`/cors/open` へリクエストを送信してみます。

```bash
$ curl -I http://192.168.99.101:8000/cors/open -H 'Origin: https://foo.com'
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 8
server: envoy
date: Fri, 04 Jan 2019 15:04:03 GMT
x-envoy-upstream-service-time: 1
access-control-allow-origin: https://foo.com
```

レスポンスヘッダへ `access-control-allow-origin` が付加されていることが確認できました。 

次に `/cors/disabled` へリクエストを送信してみます。

```bash
$ curl -I http://192.168.99.101:8000/cors/disabled -H 'Origin: https
://foo.com'
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 8
server: envoy
date: Fri, 04 Jan 2019 15:05:44 GMT
x-envoy-upstream-service-time: 2
```

レスポンスヘッダへ `access-control-allow-origin` が付加されていないことが確認できます。