NLB ＋ Nginx ＋α でのアクセスログ

#### 初めに
すでに色々と情報はあるNginx ですが、AWSのNetwork Load Balancer（以降NLB）をTargetにてIP指定＋nginx を連携させた際のアクセスログが、かゆい所に手が届いてなかったのでその際の情報をまとめてみました。

#### 困った事
* NLBとNginxを連携したところ、Nginxのアクセスログに出力していた送信元のクライアントIPが変わってしまった。
* Nginx のアクセルログに`X-Forwarded-For`の値を出力させたいが、その値が入る `$http_x_forwarded_for` 変数にも-(ハイフン)となり取れていないので、後続（下図におけるApache）へ渡せるようにしたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311053/fe81e6b9-d45b-0f68-7e5d-d87675bf3211.png)		


#### 原因
* 困った事の原因としては、NLB(target group)の設定で、ターゲットをインスタンス指定でなくIP指定としていた為、 出力していたクライアントのIPがNLBのIPになっていた。これはAWS仕様。
* NLBは`X-Forwarded-For`を付与しない為、個別に設定する必要があった。  
(NLBでは送信元IPアドレスと送信元ポートの書き換えを行わないため、パケットからの情報でアクセス元が判断する)

#### 対応前
##### `nginx.conf`
+ log_format  
余談ですが、log_formatにて変数を””（ダブルクォーテーション）で囲っているものは値に空白を含む可能性のある場合に設定しておくと位置特定に便利です。	

```
    log_format  main  '$remote_addr $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent"';
```
##### Nginx 
+ `access.log`

`remote_addr` にはNLBのIPアドレスが入るためクライアントIPは出力されてない。

`172.26.22.241 - [09/Dec/2020:18:07:46 +0900] "GET / HTTP/2.0" 403 2135 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36" `

- - -

#### 対応 
* NLB target group  
 Proxy Protocol ヘッダーから送信元のIP アドレスを取得するため、NLBのターゲットグループにてProxy Protocol V2 機能を利用する。

有効化にチェックをつけて保存する。（反映に数分かかります。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311053/3a8c4e1e-bacd-32d5-28db-4e8fd05daba5.png)
	
* Nginx  
 Nginx でのproxy_protocolの設定。

| ディレクティブ| 説明 | 
| :--- | :--- | 
| listen  | ディレクティブにproxy_protocolを追加することで有効になる。 |
| real_ip_header | 今回X-Forwarded-Forはとれていないので、remote_addrをクライアントIPで上書きしたいのであれば「real_ip_header proxy_protocol」とする必要がある。remote_addrをクライアントIPで上書きしたくないので今回は不要。 |
| set_real_ip_form | NLBのIPアドレスを指定。 |
| real_ip_recursive | real_ip_header X-Forwarded-Forの場合に意味のある設定のため今回は不要。 |

  
```
server {
    listen 443 ssl proxy_protocol;
    set_real_ip_from XXX.XXX.XXX.XXX;
}
```

`nginx.conf` のlog_formatに変数を追加。

- $proxy_protocol_addr ：クライアントのIPアドレスが格納される。
- $proxy_protocol_port ：クライアントのポートが格納される。

```
log_format  main  '$proxy_protocol_addr:$proxy_protocol_port  $remote_addr:$remote_port $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" "$http_user_agent" $server_port';                    
```

Nginx access_log
クライアントのIPアドレスとポートが出力されるようになりました。

`192.178.185.120:51714  172.26.22.241:6919 - [09/Dec/2020:18:43:34 +0900] "GET / HTTP/2.0" 403 2135 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36" 443 `

- - -

#### 対応 + α
欲しい情報は無事取得できましたが、アクセスログの最後に出力しようとしている `http_x_forwarded_for`は変わらず-（ハイフン）のままなので、後続のサーバでも取得できません。

後続へ転送設定時に取得した`proxy_protocol_addr`変数の値を渡す必要があります。

Nginxの後ろにあるApacheのアクセスログに出力されているか確認します。

```
location / {
    proxy_pass  http://XXX.XXX.XXX.XX2/;
    proxy_set_header Host XXX.XXX.XXX.XX2;
    proxy_set_header X-Forwarded-for $proxy_protocol_addr; 
    proxy_pass_request_headers on;
}
```

* Apache  
Nginxで設定した `X-Forwarded-For` の値を Apache のアクセスログで出力されているか確認する為にApache側のLogFormatを以下のように変更します。

`httpd.conf`

```
 LogFormat  "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
```

`access.log`(Apache)

`192.178.185.120 172.26.22.183 - - [09/Dec/2020:18:43:31 +0900] "GET /noindex/css/fonts/Light/OpenSans-Light.ttf HTTP/1.0" 404 240 "https://XXX-nlb-dev-XXXXXXXXXXXXX.elb.ap-northeast-1.amazonaws.com/noindex/css/open-sans.css" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"`

- - -
#### NLBとNginxのアクセスログ出力項目 
障害調査や監査等でNLBのアクセスログとNginxのアクセスログを突合せたいケースがあると思います。
その際に、どの項目で突合せできるかまとめてみました。
NLBのアクセスログをベースにNginxのアクセスログへ出力できる変数を表にしてみました。

- NLBの項目と突合せできそうなものを表にします。（一部マスキングしています）
- 意外と対応する項目がない。  
★箇所がクライアントIP、portではなくNLBの値になってしまう。

| フィールド（NLB）| NLB出力結果 | Nginx変数 | Nginx出力結果 | 
| :--- | :--- |  :--- |  :--- | 
| type | tls | ― | |
| バージョン | 2.0 | ― | |
| time | 2020-12-10T08:22:43 | \$time_iso8601、$time_local | 2020-12-10T17:22:44+09:00、10/Dec/2020:17:44:09 +0900 |
| elb | net/xxx-NLB-DEV/XXXXXXXXXXXXX |― | |
| listener | XXXXXXXXXXXXX| ― | |
| client:port | 192.178.185.120:57569 | ★ ~~\$remote_addr:$remote_port~~ \$proxy_protocol_add:\$proxy_protocol_port |~~172.26.22.241:58000~~ 192.178.185.120:57831 |
| destination:port | 172.26.22.241:443 | ― | |
| connection_time | 102628 | ― | |
| tls_handshake_time | 4 | ―  | |
| received_bytes | 1008 | ― | |
| sent_bytes | 28259 | \$bytes_sent | 28259 |
| incoming_tls_alert | - |  ― | |
| chosen_cert_arn | arn:aws:iam::XXXXXXXXXXXXX:server-certificate/dx-xxx-test2 | ― | |
| chosen_cert_serial | - | ― | |
| tls_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ― | |
| tls_protocol_version | tlsv12 | ― | |
| tls_named_group | - | ― | |
| domain_name | xxx-nlb-dev-XXXXXXXXXXXXX.elb.ap-northeast-1.amazonaws.com | $host | xxx-nlb-dev-XXXXXXXXXXXXX.elb.ap-northeast-1.amazonaws.com |
| alpn_fe_protocol | h2 | ― | |
| alpn_be_protocol | h2 |― | |
| alpn_client_preference_list | "h2","http/1.1"|  ― | |


NLBのアクセスログの詳細については以下の公式を参考にしてください。
[Network Load Balancer のアクセスログ](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/load-balancer-access-logs.html)

[Nginx 日本語ドキュメント](http://mogile.web.fc2.com/nginx/)
[NLB](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/load-balancer-target-groups.html)