AWS ELBのProxy Protocolを触ってみた
Amazon Web Serviceブログに7/31付で発表がありましたが、ELBでProxy Protocolがサポートされました。
これにより、TCP接続の負荷分散でも、接続元IPアドレスの取得が可能になったようです。
Proxy Protocol?
ELBでは、(2013/08/04現在)以下のプロトコルをサポートしています。
HTTPとHTTPSに関してはX-Forwarded-Forを見ることで接続元クライアントのIPアドレスを知ることができましたが、TCPの負荷分散ではヘッダが付与されないため、取得することができませんでした。
しかし、先日追加されたELB Proxy Protocolで、この機能を有効化した場合、TCPデータ内に接続元IPアドレス情報が付加されるようになりました。
というわけで、ELBの設定方法と接続元IPアドレスの取得方法について調べてみました。
検証
以下の手順で検証しました。(かなり簡易的な検証となっています)
- EC2上にインスタンスを2台作成し、各サーバにMySQLをインストール
- ELBを作成し、作成したインスタンスを関連づける
- 作成したELBに対し、Proxy Protocolを有効にする
- telnetを叩き、通信をEC2インスタンス上でtcpdumpして取得する
MySQLインストール
特筆することはないです。いつも通りさくっと。
$ sudo yum -y install mysql-server $ sudo service mysqld start
ELB作成
ELB自体の作成は、Management Consoleからさくっとやってしまいます。 EC2に作成したインスタンスのMySQLポートに分散するように設定しましょう。
最初の画面で設定したBalancer Nameは次の手順で利用します。
Proxy Protocolを有効にする
ここが本番です。
Proxy Protocolの有効化、Management Consoleからは行うことができません。 現状はAPI経由でのみ行うことができるようです。
ELBのDocumentationでは、旧来の(?)CLIが使われているので、私はPython版CLIで検証してみました。
まず、Policyの情報を取得します。
$ aws elb describe-load-balancer-policy-types | jq '.PolicyTypeDescriptions[] | select(.PolicyTypeName=="ProxyProtocolPolicyType")' { "PolicyAttributeTypeDescriptions": [ { "Cardinality": "ONE", "AttributeName": "ProxyProtocol", "AttributeType": "Boolean" } ], "PolicyTypeName": "ProxyProtocolPolicyType", "Description": "Policy that controls whether to include the IP address and port of the originating request for TCP messages. This policy operates on TCP/SSL listeners only" }
ProxyProtocolPolicyTypeの設定値をTrueにしてあげればいいようです。 ので、次のコマンドを実行。
オプションの--load-balancer-name の部分は、さっき作成したELBにつけた名前を設定して下さい。
--policy-nameはこのpolicyの名前になるものです。今回は[proxy-protocol-policy]としています。
$ aws elb create-load-balancer-policy \ --policy-name proxy-protocol-policy \ --load-balancer-name proxy-protocol \ --policy-type-name ProxyProtocolPolicyType \ --policy-attributes '[{"attribute_name":"ProxyProtocol","attribute_value":"True"}]' { "ResponseMetadata": { "RequestId": "eadec4c1-fcc9-11e2-9925-39cfc649e8ce" } }
今作成したPolicyを、既存のELB配下のインスタンス群の3306番ポートに対して適用します。
$ aws elb set-load-balancer-policies-for-backend-server \ --load-balancer-name proxy-protocol \ --policy-name proxy-protocol-policy \ --instance-port 3306 { "ResponseMetadata": { "RequestId": "2dd9fbcf-fcca-11e2-9925-39cfc649e8ce" } } $ aws elb describe-load-balancers (...前略) "Policies": { "LBCookieStickinessPolicies": [], "AppCookieStickinessPolicies": [], "OtherPolicies": [ "proxy-protocol-policy" ] }, "Scheme": "internet-facing", "VPCId": "vpc-62cb0a0a", "CanonicalHostedZoneNameID": "Z2YN17T5R711GT", "BackendServerDescriptions": [ { "PolicyNames": [ "proxy-protocol-policy" ], "InstancePort": 3306 } ], (...後略)
これで、Proxy Protocolが有効になりました。
telnet & tcpdump
皆さん大好きtcpdumpで、接続元のIPアドレスがとれているかどうか確認してみます。
$ sudo tcpdump -w packet.dump tcp port 3306
ローカルのマシンから、telnetで接続を確認します。
$ telnet proxy-protocol-1621762185.ap-northeast-1.elb.amazonaws.com 3306
で、キャプチャしたものをWiresharkで見てみます。
モザイクで編集してしまいましたが、IPアドレスと、ポート番号(のようなもの)が2つずつあります。
モザイクの黒っぽい部分に、接続元のIPアドレスが書いてあります。白っぽいモザイクの方には、プライベート帯のIPアドレスがありました。ELBの内部アドレスでしょうか。
疑問点
ここまでやって本日は時間切れ。
残った疑問点としては、
- 2つめのIPアドレスとポート番号の正体
- 自前アプリケーションからの取得方法
ここらへんはまた近いうちに。