アプリケーションのHTTPプロキシのテスト環境を作る


## やりたいこと〜

ツール類やデスクトップアプリケーションを作る際に HTTP プロキシ対応をしたりしますが、テストする際に環境がなくて困ったりします。

この記事では [docker-compose] を使って、テスト用の HTTP プロキシ環境をいつでも再現できるようにします。

> UNIX 系 OS ベースの話になります。
> NTLM はしません。

## コード

本記事のすぐ動くコードは ↓ にあります。

* https://github.com/megmogmog1965/squid-for-http-proxy-testing

## 単に HTTP プロキシを立てる

以下のコードを書きます。

* ``docker-compose.yml``
* ``Dockerfile``
* ``squid.conf.template``  (envsubst 用のテンプレートファイル)
* ``.env``  (環境変数 = 変更可能なパラメータ)

まず ``.env`` ファイルで [Squid] HTTP Proxy の待受ポートと、BASIC 認証の有無を、環境変数として指定できるようにします。

```shell
# 待受ポート
HTTP_PORT=3128

# BASIC 認証の設定 (default ではコメントアウト → "#" で OFF)
BASIC_AUTH_COMMENT_OUT=#
BASIC_AUTH_USERNAME=squid
BASIC_AUTH_PASSWORD=password
```

オーケストレーションファイル ``docker-compose.yml`` でコンテナの起動方法を定義します。

```yaml
version: '3.1'
services:
  squid:
    build: ./squid
    expose:
      - "${HTTP_PORT}"
    ports:
      - "${HTTP_PORT}:${HTTP_PORT}"
    environment:
      - HTTP_PORT
      - BASIC_AUTH_COMMENT_OUT
      - BASIC_AUTH_USERNAME
      - BASIC_AUTH_PASSWORD
```

コンテナイメージ定義 ``Dockerfile`` で [Squid] HTTP Proxy の構築をします。

```docker
FROM alpine:3.10

# Set correct environment variables.
ENV HOME /root
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8

# install PKGs.
RUN apk update && \
    apk --no-cache add squid libintl apache2-utils && \
    apk --no-cache add --virtual .gettext gettext && \
    cp /usr/bin/envsubst /usr/local/bin/envsubst && \
    apk del .gettext

# edit squid settings.
COPY squid.conf.template /etc/squid/squid.conf.template

# user.
RUN chown -R squid:squid /etc/squid/ /var/run/
USER squid

# entrypoint.
ENTRYPOINT /bin/sh -c " \
    /bin/touch /etc/squid/passwd && \
    /usr/bin/htpasswd -b /etc/squid/passwd ${BASIC_AUTH_USERNAME} ${BASIC_AUTH_PASSWORD} && \
    /usr/local/bin/envsubst < /etc/squid/squid.conf.template > /etc/squid/squid.conf && \
    /usr/sbin/squid -N -d 1 -f /etc/squid/squid.conf "
```

最後に ``squid.conf.template`` です。 長いので [設定ファイルのリンク](https://github.com/megmogmog1965/squid-for-http-proxy-testing/blob/master/squid/squid.conf.template) だけ。
標準の ``squid.conf`` に、以下の設定と ``envsubst`` 用の変数を埋め込んでいます。

* [BASIC 認証](https://github.com/megmogmog1965/squid-for-http-proxy-testing/blob/master/squid/squid.conf.template#L54) の設定を追加しました
* [待受ポート](https://github.com/megmogmog1965/squid-for-http-proxy-testing/blob/master/squid/squid.conf.template#L69) は環境変数で変更できるようにしました
* [キャッシュは OFF](https://github.com/megmogmog1965/squid-for-http-proxy-testing/blob/master/squid/squid.conf.template#L86) にしました
* [ログは stdout に出す](https://github.com/megmogmog1965/squid-for-http-proxy-testing/blob/master/squid/squid.conf.template#L93) 様にしました  (コンテナ化の流儀)

あとはビルドして起動します。

```shell
docker-compose build
docker-compose up -d
```

待受ポートをホストにフォワードしているので、ローカルアクセスできます。

* http://localhost:3128


## [面倒] HTTP プロキシを経由しないとインターネットに出れない環境を作る

実際にテストする際に、Default Gateway からインターネットに出れちゃう環境だと、ちゃんとプロキシ経由してるか (漏れてて直接インターネットアクセスしてるのあるかも) 保証できないので、そういう環境を作りたいと思います。

> 作業用の OS イメージは、比較的ユーザーが多いであろう ``ubuntu:18.04`` でいきます。

先程の ``docker-compose.yml`` を修正します。

```yaml
version: '3.1'
services:
  # ↓ここを足しました。
  app:
    image: ubuntu:18.04
    entrypoint:
      - tail
      - -f
      - /dev/null
    privileged: true

  squid:
    build: ./squid
    expose:
      - "${HTTP_PORT}"
    ports:
      - "${HTTP_PORT}:${HTTP_PORT}"
    environment:
      - HTTP_PORT
      - BASIC_AUTH_COMMENT_OUT
      - BASIC_AUTH_USERNAME
      - BASIC_AUTH_PASSWORD
```

コンテナ起動しなおします。

```shell
docker-compose down
docker-compose up -d
```

コンテナ ``app`` に入ります。

```shell
docker exec -it squid-for-http-proxy-testing_app_1 bash
```

ネットワークをいじる為に必要なコマンドを入れます。　

```shell
apt update
apt install -y net-tools iputils-ping curl
```

> アプリケーションを動作させる為に必要な物があれば、このタイミングで一緒にインストールしておきます。

この時点ではインターネットにアクセスできます。

```shell
curl google.com

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
```

ルーティングテーブルを見てみます。
① Default Gateway と ② Docker ネットワーク (他のコンテナ) へのルーティングがあります。

```shell
route

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.23.0.1      0.0.0.0         UG    0      0        0 eth0
172.23.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
```

① Default Gateway のルーティングを消します。 (かなり荒っぽい方法ですが...)

```shell
route delete default
```

```shell
route

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.23.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
```

インターネットにアクセスできなくなりました。

```shell
curl google.com

curl: (6) Could not resolve host: google.com
```

プロキシ設定をします。

```shell
export http_proxy=http://squid:3128
export https_proxy=${http_proxy}
```

> * ホスト名 ``squid`` は、Squid Proxy コンテナの IP ``172.xx.xx.xx`` を指してします。
> * 当然ですが、上記の設定は、この bash プロセス上だけで有効です。

HTTP プロキシを経由してインターネットに出れました。

```shell
curl google.com

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
```

あとは ``docker cp {ローカルファイル} {コンテナ名}:/root/`` 等を使って、この環境にアプリケーションを送信し、アプリケーションの動作・テストします。


[docker-compose]:https://docs.docker.com/compose/
[Squid]:http://www.squid-cache.org/