ELB経由のForward Proxyでアクセス元のIPアドレスを記録する
ELBを使用して(Reverseでない)Forward Proxyサーバを負荷分散させる場合に、アクセス元のIPアドレスを正しく記録したいというのはよく聞くのですが、残念ながらsquidやmod_proxyはProxy Protocolに対応していません。
このページによれば、Foward ProxyでProxy Protocolに対応しているのは、ExaProxyだけのようなので、ExaProxyを試してみる事にします。
ExaProxyをEC2(Amazon Linux)上で動かす
Python 2.7で開発されているらしいので、まずPython 2.7をインストールする(Python 2.6だとエラーが出て動かない)
$ sudo yum install python27 : インストール: python27.x86_64 0:2.7.5-11.32.amzn1 依存性関連をインストールしました: python27-libs.x86_64 0:2.7.5-11.32.amzn1 完了しました!
ドキュメント通りにtar ballを落として実行してみる。
$ wget http://exaproxy.googlecode.com/files/exaproxy-1.1.2.tgz $ tar zxvf exaproxy-1.1.2.tgz $ cd exaproxy-1.1.2 $ ./sbin/exaproxy ExaProxy 15282 supervisor Starting exaproxy version 1.1.2 ExaProxy 15282 supervisor python version 2.7.5 (default, Feb 24 2014, 15:33:10) [GCC 4.6.3 20120306 (Red Hat 4.6.3-2)] ExaProxy 15282 daemon could not increase file descriptor limit to 65826, limit is still 4096 ExaProxy 15282 daemon please increase your system maximum limit, alternatively you can reduce ExaProxy 15282 daemon exaproxy.http.connections, exaproxy.web.connections and/or configuration.redirector.maximum
ファイルディスクリプタを沢山使うみたいです。とりあえずテストなので1024コネクションもあれば大丈夫でしょう。大規模に使用するのであれば、kernel paramterやlimits.confで上限を上げてください。
ついでに0.0.0.0でListenするようにして、アクセスログも出力するようにしてみます。
$ vi etc/exaproxy/exaproxy.conf : $ diff etc/exaproxy/exaproxy.conf.default etc/exaproxy/exaproxy.conf 22c22 < connections = 32768 --- > connections = 1024 66c66 < host = '127.0.0.1' --- > host = '0.0.0.0' 83c83 < enable = false --- > enable = true $ ./sbin/exaproxy ExaProxy 15389 supervisor Starting exaproxy version 1.1.2 ExaProxy 15389 supervisor python version 2.7.5 (default, Feb 24 2014, 15:33:10) [GCC 4.6.3 20120306 (Red Hat 4.6.3-2)]
とりあえず起動したようです。curlで動作確認。
$ http_proxy=http://172.30.0.202:3128 curl -v http://checkip.amazonaws.com * About to connect() to proxy 172.30.0.202 port 3128 (#0) * Trying 172.30.0.202... connected * Connected to 172.30.0.202 (172.30.0.202) port 3128 (#0) > GET http://checkip.amazonaws.com HTTP/1.1 > User-Agent: curl/7.21.4 (x86_64-apple-darwin12.0.0) libcurl/7.21.4 OpenSSL/0.9.8y zlib/1.2.5 libidn/1.20 > Host: checkip.amazonaws.com > Accept: */* > Proxy-Connection: Keep-Alive > < HTTP/1.1 200 OK < Date: Fri, 28 Feb 2014 19:26:21 GMT < Server: lighttpd/1.4.29 < Content-Length: 14 < Connection: keep-alive < 192.168.1.154 * Connection #0 to host 172.30.0.202 left intact * Closing connection #0
ちゃんと中継してくれたようです。コンソールにもちゃんとログが出ています。
$ ./sbin/exaproxy ExaProxy 15908 supervisor Starting exaproxy version 1.1.2 ExaProxy 15908 supervisor python version 2.7.5 (default, Feb 24 2014, 15:33:10) [GCC 4.6.3 20120306 (Red Hat 4.6.3-2)] ExaProxy 15908 usage 2014-02-28 19:28:52 1393615732.43 1 192.168.1.154 GET checkip.amazonaws.com/ PERMIT/checkip.amazonaws.com
ELBから使う
次にInternal ELBを作成し、TCP listenerをインスタンスの3128ポートに向け、インスタンスを追加します。
$ http_proxy=http://internal-proxy-284387118.us-west-2.elb.amazonaws.com:3128 curl -v http://checkip.amazonaws.com * About to connect() to proxy internal-proxy-284387118.us-west-2.elb.amazonaws.com port 3128 (#0) * Trying 172.30.0.235... connected * Connected to internal-proxy-284387118.us-west-2.elb.amazonaws.com (172.30.0.235) port 3128 (#0) > GET http://checkip.amazonaws.com HTTP/1.1 > User-Agent: curl/7.21.4 (x86_64-apple-darwin12.0.0) libcurl/7.21.4 OpenSSL/0.9.8y zlib/1.2.5 libidn/1.20 > Host: checkip.amazonaws.com > Accept: */* > Proxy-Connection: Keep-Alive > < HTTP/1.1 200 OK < Date: Sat, 01 Mar 2014 03:42:23 GMT < Server: lighttpd/1.4.29 < Content-Length: 13 < Connection: keep-alive < 172.30.0.235 * Connection #0 to host internal-proxy-284387118.us-west-2.elb.amazonaws.com left intact * Closing connection #0 --- ExaProxy 946 usage 2014-03-01 03:42:23 1393645343.26 5 172.30.0.235 GET checkip.amazonaws.com/ PERMIT/checkip.amazonaws.com
アクセス元がELBのIPアドレスとして判定されてしまいました。これでは、誰が利用したのか分からなくなってしまいます。
ProxyProtocolを有効にする
というわけで、ProxyProtocolを有効にします。手順はこちらのページにある通りです。
$ elb-create-lb-policy proxy --policy-name EnableProxyProtocol --policy-type ProxyProtocolPolicyType --attribute "name=ProxyProtocol, value=true" OK-Creating LoadBalancer Policy $ elb-set-lb-policies-for-backend-server proxy --instance-port 3128 --policy-names EnableProxyProtocol OK-Setting Policies
これでアクセスしてみましょう。
$ http_proxy=http://internal-proxy-284387118.us-west-2.elb.amazonaws.com:3128 curl http://checkip.amazonaws.com 172.30.0.235 --- ExaProxy 946 usage 2014-03-01 03:49:45 1393645785.84 7 172.30.0.235 GET checkip.amazonaws.com/ PERMIT/checkip.amazonaws.com
IPがELBのままです。ExaProxy側でProxyProtocolを使用する設定を行う必要がありました。
$ vi etc/exaproxy/exaproxy.conf : $ diff etc/exaproxy/exaproxy.conf* 27c27 < proxied = false --- > proxied = true
これでexaproxyを再起動して試してみます。
$ http_proxy=http://internal-proxy-284387118.us-west-2.elb.amazonaws.com:3128 curl http://checkip.amazonaws.com 192.168.1.154 --- ExaProxy 3337 usage 2014-03-01 03:53:24 1393646004.53 3 192.168.1.154 GET checkip.amazonaws.com/ PERMIT/checkip.amazonaws.com
正しくクライアント側のIPアドレスが記録されました!