16
17

More than 5 years have passed since last update.

ELBでProxyProtocolを使ってnginxでTCP接続時のアクセス元IPを取得する

Posted at

ELBへHTTP及びHTTPSでの接続の場合、アクセス元のIPアドレスはHTTPヘッダのhttp_x_forwarded_forより取得できますが、TCPをELBでバランシングした場合、何も設定をしないとアクセス元のIPアドレスの取得がバックエンドのEC2で出来ないようです。

上記についてELBをProxyProtoclを利用することでバックエンドのEC2でもアクセス元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ポートでやってみましたが、同じように他のポートでも実施可能だと思います。

16
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
17