ELBへHTTP及びHTTPSでの接続の場合、アクセス元のIPアドレスはHTTPヘッダのhttp_x_forwarded_for
より取得できますが、TCPをELBでバランシングした場合、何も設定をしないとアクセス元のIPアドレスの取得がバックエンドのEC2で出来ないようです。
上記についてELBをProxyProtoclを利用することでバックエンドのEC2でもアクセス元IPアドレスが取得できるのでメモ。
参考
- 【AWS】ELBがProxy Protocolをサポート 〜 RubyでEchoサーバ作って確かめてみた
- 【AWS発表】 Elastic Load BalancingがProxy Protocolをサポート
- ロードバランサーの Proxy Protocol のサポートを設定する
- ELB(Elastic Load Balancer)の後ろをTCPにしてHTTP2をサポートしつつ、リクエスト元IPも記録
デフォルトの状態で試す
AWSでは以下を設定します。
- EC2->sshできるもの、ELBから80ポートを受け付けるSecurityGroupの設定
- ELB->上記EC2にTCPの80ポートのトラフィックを転送するように設定
次にEC2にsshログインしてnginxのインストールと設定確認をしてみます。
# インストール
$sudo yum install nginx -y
# 起動
$sudo service nginx start
# /etc/nginx/nginx.confのログの確認(抜粋)
$cat
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
では実際にローカルのPCからEC2及びELB経由でアクセスし、nginxのアクセスログ(/var/log/nginx/access.log)を確認します。
# 直接EC2のPublicIPを指定.先頭のIPがアクセス元のIP
101.111.248.34 - - [20/Jan/2016:03:04:42 +0000] "GET /nginx-logo.png HTTP/1.1" 304 0 "http://52.192.82.149/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" "-"
# ELB経由.先頭のアクセス元のIPがELBのIP。末尾のhttp_x_forwarded_forもなし
172.31.5.107 - - [20/Jan/2016:03:06:40 +0000] "GET /nginx-logo.png HTTP/1.1" 304 0 "http://testprojectelb-320584224.ap-northeast-1.elb.amazonaws.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" "-"
なお、HTTPによるトラフィックの転送の場合、以下のように末尾のhttp_x_forwarded_for
でアクセス元IPが判定できているのが分かります。
# ELB経由
172.31.5.107 - - [20/Jan/2016:03:08:09 +0000] "GET /poweredby.png HTTP/1.1" 304 0 "http://testprojectelb-320584224.ap-northeast-1.elb.amazonaws.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" "101.111.248.34"
ELBにProxyProtocolを指定する
以下を参考にELBにProxyProtoclを設定してみます。
ロードバランサーの Proxy Protocol のサポートを設定する
マネージメントコンソールでは設定できないのでAWS CLIから実施します。
最初にELBでサポートされているポリシーの中から、ProxyProtocolの設定を確認します。
# 出力結果は一部省略
$aws elb describe-load-balancer-policy-types
{
"PolicyTypeDescriptions": [
{
"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"
},
次にProxyProtocolを有効にするポリシーを設定します。事前にELBの名称を確認して--load-balancer-name
で指定します。
$aws elb create-load-balancer-policy --load-balancer-name my-loadbalancer --policy-name my-ProxyProtocol-policy --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=true
次に先ほど作成したポリシーで特定のポート(今回は80)を有効にします。
$aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-loadbalancer --instance-port 80 --policy-names my-ProxyProtocol-policy
最後にELBにポリシーが設定されているか確認します。
# 出力結果は一部省略
$aws elb describe-load-balancers --load-balancer-name my-loadbalancer
"BackendServerDescriptions": [
{
"InstancePort": 80,
"PolicyNames": [
"my-ProxyProtocol-policy"
]
}
],
nginxの設定を変更する
CONFIGURING NGINX TO ACCEPT THE PROXY PROTOCOL
次にnginxの設定を変更します。
diffを以下に記載します。
$git diff
diff --git a/nginx.conf b/nginx.conf
index 5d1233b..367c5e0 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -44,9 +44,11 @@ http {
index index.html index.htm;
server {
- listen 80;
+ listen 80 proxy_protocol;
server_name localhost;
root /usr/share/nginx/html;
+ set_real_ip_from 172.31.0.0/16;
+ real_ip_header proxy_protocol;
#charset koi8-r;
- listenディレクティブ->ProxyProtocolの接続を許可
- set_real_ip_from->RealIPの変換を適応するCIDR。ELBのあるVPCのCIDRを設定
- real_ip_header->Porxyプロトコルにのっとり、接続元IPを設定する
公式だとlogformatを$remote_addr
から$proxy_protocol_addr
に変えてますが、上記設定を行えば、どちらでも取得できる値は同じです。
設定を反映させます。
$sudo service nginx reload
次にELBのヘルスチェックをHTTPからTCPの80に変更します。
これで準備ができたのでELBのCNAMEでアクセスしてみます。
# 先頭のremote_addがアクセス元のIPアドレスになっている
101.111.248.34 - - [20/Jan/2016:04:09:06 +0000] "GET /poweredby.png HTTP/1.1" 304 0 "http://testprojectelb-320584224.ap-northeast-1.elb.amazonaws.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" "-"
無事にTCPのバランシングでもアクセス元IPアドレスが取得できました!
今回は80ポートでやってみましたが、同じように他のポートでも実施可能だと思います。