https リバースプロキシーサーバの作り方
はじめに
ひょんなことからhttpsを使うリバースプロキシーサーバを作ることになりました.個人情報を含んだ通信は暗号化すべき,なんて世の中の流れに乗ったわけです.で今回はそのメモ.今回作ったプロキシーはクライアントとの間をhttpsで通信しますが,サーバとの間はhttpsを使うものと,httpを使うものの2種類を実現します.ざっと絵に描くとこんな感じ.数字はポート番号です.
--- https ---> 443 --- https ---> 443 サーバA クライアント リバースプロキシー --- https ---> 8443 --- http ---> 80 サーバB
apacheをコンパイル
今回は,リバースプロキシーをnetbsd3.0上で作ってみました.netbsdを選んだ理由は特にありません.以前使っていたので他のOSより慣れてる,というぐらいでしょうか.まぁ,それはともかく,apache2.2をダウンロードして展開,configureを以下の引数で実行してからmake, make installしました.
./configure --prefix=/usr/local/http_proxy --enabe-rewreite \ --enable-proxy --with-mpm=prefork --enable-ssl --with-ssl=/usr/local/ssl
httpd.confでの設定
昔からimport文なんてあったかなぁ,と思いつつ書いてみたのが以下の設定になります.実際にはコメント文なんかが沢山あるんですが,ここでは一切省いています.
ServerRoot "/usr/local/http_proxy" User daemon Group daemon <Directory /> Options FollowSymLinks AllowOverride None Order deny,allow Deny from all </Directory> ErrorLog logs/error_log LogLevel warn Include conf/extra/httpd-mpm.conf Include conf/extra/httpd-default.conf Include conf/extra/httpd-ssl.conf
やろうとしているのは,
- このサーバにはコンテンツを何も置かない
- エラーログのフォーマットはCommon Log Format(CLF)
の2点です.CLFのフォーマットは以下のようになっています.
Format | 意味 |
---|---|
%h | リモートホストIPアドレス |
%l | identで得たクライアントアイデンティティ |
%u | http認証で得たリモートユーザ名 |
%t | 受付時刻 |
%r | リクエストの最初の行 |
%>s | status |
%b | httpヘッダを除くレスポンスのバイト数 |
httpd-default.confとhttpd-mpm.confはデフォルトをそのまま使ったので,個々では説明を省略します.
httpd-ssl.conでの設定
ここが本題の設定になります.間違ってる箇所があったら指摘していただけるとうれしいです.ちなみにIPアドレスを明示しているのは,デフォルトの設定ではIPv6用のポートも開いてしまうので,それを防ごうとしているからです.
SSLRandomSeed startup file:/dev/urandom 1024 Listen 10.10.10.10:443 Listen 10.10.10.10:8443 AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl SSLPassPhraseDialog exec:/usr/local/http_proxy/conf/pp-filter SSLSessionCache shmcb:/usr/local/http_proxy/logs/ssl_scache(512000) SSLSessionCacheTimeout 300 SSLMutex file:/usr/local/http_proxy/logs/ssl_mutex <VirtualHost 10.10.10.10:443> DocumentRoot "/usr/local/http_proxy/htdocs" ServerName proxy.foo.co.jp:443 ServerAdmin proxymaster@foo.co.jp ErrorLog /usr/local/http_proxy/logs/error443_log SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP SSLCertificateFile /usr/local/http_proxy/conf/server.crt SSLCertificateKeyFile /usr/local/http_proxy/conf/private_key.pem BrowserMatch ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 CustomLog /usr/local/http_proxy/logs/ssl_request443_log \ "%t %h %{SSL_PROTOCOL}x %{Cookie}i \"%r\" %b" SSLProxyEngine On RewriteEngine On RewriteRule ^(.*) https://serverA.foo.co.jp$1 [P] </VirtualHost> <VirtualHost 10.10.10.10:8443> DocumentRoot "/usr/local/http_proxy/htdocs" ServerName proxy.foo.co.jp:8443 ServerAdmin proxymaster@foo.co.jp ErrorLog /usr/local/http_proxy/logs/error8443_log SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP SSLCertificateFile /usr/local/http_proxy/conf/server.crt SSLCertificateKeyFile /usr/local/http_proxy/conf/private_key.pem BrowserMatch ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 CustomLog /usr/local/http_proxy/logs/ssl_request8443_log \ "%t %h %{SSL_PROTOCOL}x %{Cookie}i \"%r\" %b" RewriteEngine ON ProxyPreserveHost On ServerName proxy.foo.co.jp:8443 RewriteRule ^(.*) http://serverB.foo.co.jp$1 [P] </VirtualHost>
いくつかポイントを絞って説明します.
SSLPassPhraseDialog exec:/usr/local/http_proxy/conf/pp-filter
秘密鍵にパスフレーズをつけていると,apache起動時に毎回パスフレーズの入力を求められます.セキュリティを確保するためには当然な方法ですが,メンドクサイ.そのため,パスフレーズを自動的に入力しています.pp-filerの中身はこんな感じになります.
#!/bin/sh echo PASSPHRASE
簡単すぎですね.ちなみに,pp-filterはrootを所有者にしてアクセス権を700にしておくことをお勧めします.
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP
SSLCipherSuiteは奥深い話で,とても一言では書けません.ニゲだ.Pound の SSL セキュリティレベルを制限(上げる)方法 - drk7jpがSSLCipherSuiteに詳しく書いているので,そちらを参考にしてください.
CustomLog /usr/local/http_proxy/logs/ssl_request443_log \ "%t %h %{SSL_PROTOCOL}x %{Cookie}i \"%r\" %b"
ログのフォーマットをCLFとはちょっと変更してみました.
Format | 意味 |
---|---|
%t | 受付時間 |
%h | リモートホストIPアドレス |
%{SSL_PROTOCOL}x | mod_sslで使える拡張フォーマット,環境変数を表示 |
%{Cookie}i | リクエストヘッダ中の値 |
%r | リクエスト最初の行 |
%b | httpヘッダを除くレスポンスのバイト数 |
クライアントとの間で使っているSSLのバージョンとクッキーが正しく流れているかどうかを確認するために使っています.
SSLProxyEngine On RewriteEngine On RewriteRule ^(.*) https://serverA.foo.co.jp$1 [P]
ここいら辺がリバースプロキシーの核になります.httpsでサーバにアクセスするためには,SSLProxyEngineをOnにする必要があります.
RewriteEngine ON ProxyPreserveHost On ServerName proxy.foo.co.jp:8443 RewriteRule ^(.*) http://serverB.foo.co.jp$1 [P]
httpでサーバにアクセスする場合にはSSLProxyEngineを使う必要はありません.この例ではProxyPreserveHostとServerNameというディレクティブを設定しています.これはServerBがホストヘッダの値を元に処理を行なっているために設定した項目です.お使いの環境では必要ないかもしれません.バーチャルホストの例 - Apache HTTP サーバ バージョン 2.2に説明が記載されています.