hamakou108 blog

プロキシサーバを介した HTTPS 通信を Docker 環境下で試してみる

October 20, 2019

その1 の続き。 今回はクライアントとサーバの間にフォワードプロキシやリバースプロキシが存在するケースについて動作検証する。

環境は以下の通り。

  • MacOS 10.14.3
  • Docker Desktop Community 2.0.0.3
  • Docker Compose 1.23.2

フォワードプロキシを使った HTTPS 通信

フォワードプロキシで HTTPS メソッドを扱うために CONNECT メソッドを利用する。 CONNECT メソッドに関しては以下を参照する。

基本的な設定は以下の通り。 今回は HTTP と HTTPS のそれぞれに対応できるように設定した。

# forward proxy settings
ProxyRequests On
ProxyVia On
AllowCONNECT 443

# for HTTP connections
<Proxy http://my-server/*>
    Order deny,allow
    Deny from all
    Allow from 172.16.1.2
</Proxy>

# for HTTPS connections
<Proxy https://my-server:443/*>
    Order deny,allow
    Deny from all
    Allow from 172.16.1.2
</Proxy>

以下コマンドを Docker ホストで実行して動作確認する。

$ docker exec -it docker-httpd-proxy_client_1 curl https://my-server --cert ./ssl/client-cert-dec.pem --key ./ssl/client-key-dec.pem --cacert ./ssl/cacert.pem -x my-forward-proxy:8080

curl の -x オプションでフォワードプロキシに指定したサーバが ProxyRequests On を設定していない場合、そのプロキシからレスポンスが返却されてしまうので注意。

$ docker exec docker-httpd-proxy_forward_proxy_1 cat /usr/local/apache2/htdocs/index.html
<html><body><h1>It works!</h1></body></html>
I'm forward proxy!
$ docker exec -it docker-httpd-proxy_client_1 curl http://my-server -x my-forward-proxy:8080
<html><body><h1>It works!</h1></body></html>
I'm forward proxy!

<Proxy> の各設定の前に以下の記述を忘れた場合、設定した <Proxy> を除く全ての通信が許可されてしまうので注意。

<Proxy *>
    Order deny,allow
    Deny from all
</Proxy>

リバースプロキシを使った HTTPS 通信

その1 の手順に従ってリバースプロキシ用のサーバ証明書を作成する。 リモートサーバ用に作成した証明書を流用しようとすると Common Name が異なるためエラーが発生する(ただ Apache の設定で避けることもできそう)。

基本的な設定は以下の通り。 今回はリバースプロキシとサーバ間の通信も暗号化するため SSLProxy の設定も行ったが、通常の負荷分散用途では不要。

# reverse proxy settings
<Proxy *>
    Order deny,allow
    Deny from all
    Allow from 172.16.1.2
</Proxy>

ProxyPass /proxy https://my-server/
ProxyPassReverse /proxy https://my-server/

SSLProxyEngine On
SSLProxyMachineCertificateFile "/usr/local/apache2/conf/ssl/client-certkey-dec.pem"
SSLProxyCACertificateFile "/usr/local/apache2/conf/ssl/cacert.pem"

client-certkey-dec.pem は以下のようにメタ情報を取り除いたクライアント証明書と復号化した秘密鍵を 結合して作成 する。

$ cat client-cert-dec.pem client-key-dec.pem > client-certkey-dec.pem

SSLProxyMachineCertificateFile は同一コンテキスト内に一つしか定義できない(複数定義した場合は最後の定義のみ有効になる)。 複数の証明書を使い分ける場合は VirtualHost でコンテキストを分割する。

クライアントからの通信をリバースプロキシで復号化するには以下の設定も行う。 これはプロキシサーバを介さない場合と同じ。

SSLCertificateFile "/usr/local/apache2/conf/server-cert-dec.pem"
SSLCertificateKeyFile "/usr/local/apache2/conf/server-key-dec.pem"

以下コマンドを Docker ホストで実行して動作確認する。

$ docker exec -it docker-httpd-proxy_client_1 curl https://my-server --cert ./ssl/client-cert-dec.pem --key ./ssl/client-key-dec.pem --cacert ./ssl/cacert.pem -x my-forward-proxy:8080