🧑‍💻

ngx_http_realip_module の動作をハンズオンで学ぼう

2024/03/25に公開

この記事は何?

この記事は、Webサーバの前段にロードバランサやリバースプロキシを置いた場合に、Webサーバに記録するアクセスログのリクエストの送信元IPアドレスをクライアントのIPアドレスにする際によく使われるNginxモジュール ngx_http_realip_module についてハンズオン形式で挙動を確かめながら理解を深めようといったことを狙いにした記事です。

この記事が対象としている読者

  • アクセスログに記録されているリクエストの接続元IPアドレスが、ロードバランサやリバースプロキシのIPアドレスになっている状態からクライアントのIPアドレスに変更したいと考えており、そのために
    ngx_http_realip_module を使えばいいことは分かっているが、 ngx_http_realip_module がよく分かっていない方。

結論

  • ngx_http_realip_module とは、クライアントアドレスとオプションのポートを、 指定されたヘッダーフィールドで送られるものに変更するモジュールである。
  • ngx_http_realip_module モジュールは、set_real_ip_from, real_ip_header, real_ip_recursive の3つのディレクティブがある。
  • set_real_ip_from ディレクティブは、実際のクライアントのIPアドレスを指定するために信頼できるソース(通常はプロキシサーバーまたはロードバランサー)のIPアドレス範囲を定義する。
  • real_ip_header ディレクティブは、クライアントの実際のIPアドレスを含むリクエストヘッダーを定義する。
  • real_ip_recursive ディレクティブは、複数のプロキシを通過したリクエストの場合に、どのIPアドレスをクライアントの実際のIPアドレスとみなすかの判断を定義する。

環境構築

ハンズオンではあらかじめ用意したコンテナで構築した環境を使用します。そのため、dockerコマンドが使える環境である必要があります。
もし、dockerコマンドが使えない場合は、以下を参考に設定を行なってください。
https://docs.docker.com/get-docker/

環境は以下のコマンドを実行して、リポジトリをクローンしてください。

git clone https://github.com/TowaYamashita/proxy-nginx-practice.git
cd proxy-nginx-practice

環境の概要は以下のとおりです。

compose.yaml(プロキシサーバが1つ)

  • client: アクセス元
  • proxy-server-1: backendへリクエストを転送するリバースプロキシサーバー
  • backend: 転送先のサーバ

compose-multi-proxy.yaml(プロキシサーバが複数)

  • client: アクセス元
  • proxy-server-1,proxy-server-2: backendへリクエストを転送するリバースプロキシサーバー
  • backend: 転送先のサーバ

ハンズオン1: set_real_ip_from ディレクティブ, real_ip_header ディレクティブ

概要

  • set_real_ip_from

    • 実際のクライアントのIPアドレスを指定するために信頼できるソース(通常はプロキシサーバーまたはロードバランサー)のIPアドレス範囲を定義する。
    • set_real_ip_fromを使用して指定されたIPアドレスからのリクエストの場合のみ、NginxはX-Forwarded-Forヘッダー(またはreal_ip_headerで指定された他のヘッダー)の内容を信頼して、クライアントのIPアドレスを置き換える。
  • real_ip_header

    • クライアントのIPアドレスを置き換えるために使用されるリクエストヘッダーフィールドを定義する。
    • Nginxはこのディレクティブで定義されたヘッダーを使用して、リクエストを行った元のクライアントのIPアドレスを特定する。

動作確認

  1. 以下のコマンドを実行して、環境を立ち上げる。
docker compose up -d
  1. 以下のコマンドを実行して、クライアントからリバースプロキシに対してリクエストを投げる。
docker compose exec client curl http://172.20.0.3:80/index.html
  1. 以下のコマンドを実行して、転送先のサーバのアクセスログを表示する
docker compose logs backend -n 1

以下のように、リクエストの送信元IPアドレスがクライアントのIPアドレスになっていること を確認する。

backend-1  | 172.20.0.2 - - [24/Mar/2024:22:22:39 +0000] "GET /index.html HTTP/1.0" 200 135 "-" "curl/8.6.0" "172.20.0.2"

以下のコマンドを実行して、環境を破棄する。

docker compose down

ハンズオン2: real_ip_recursive ディレクティブ

概要

  • real_ip_recursive
    • off の場合、信頼できるアドレスの1つと一致する元のクライアントアドレスは、real_ip_headerディレクティブで定義されたリクエストヘッダーフィールドに送信された最後のアドレスに置き換えられる。
    • on の場合、信頼できるアドレスの1つと一致する元のクライアントアドレスは、リクエストヘッダーフィールドに送信された最後の信頼できないアドレスに置き換えられる。

動作確認

real_ip_recursive: on の場合

  1. 以下のコマンドを実行して、環境を立ち上げる。
docker compose --file compose-multi-proxy.yaml up -d 
  1. 以下のコマンドを実行して、クライアントからリバースプロキシに対してリクエストを投げる。
docker compose --file compose-multi-proxy.yaml exec client curl http://172.20.0.3:80/index.html
  1. 以下のコマンドを実行して、転送先のサーバのアクセスログを表示する
docker compose --file compose-multi-proxy.yaml logs backend -n 1

以下のように、リクエストの送信元IPアドレスがクライアントのIPアドレスになっていること を確認する。

backend-1  | 172.20.0.2 - - [24/Mar/2024:22:04:47 +0000] "GET /index.html HTTP/1.0" 200 135 "-" "curl/8.6.0" "172.20.0.2, 172.20.0.3"

以下のコマンドを実行して、環境を破棄する。

docker compose --file compose-multi-proxy.yaml down

real_ip_recursive: off の場合

  1. conf/backend/conf.d/proxy.conf の 8行目を以下のように変更する
real_ip_recursive off;
  1. 以下のコマンドを実行して、環境を立ち上げる。
docker compose --file compose-multi-proxy.yaml up -d 
  1. 以下のコマンドを実行して、クライアントからリバースプロキシに対してリクエストを投げる。
docker compose --file compose-multi-proxy.yaml exec client curl http://172.20.0.3:80/index.html
  1. 以下のコマンドを実行して、転送先のサーバのアクセスログを表示する
docker compose --file compose-multi-proxy.yaml logs backend -n 1

以下のように、リクエストの送信元IPアドレスが一段目のリバースプロキシのIPアドレスになっていること を確認する。

backend-1  | 172.20.0.3 - - [24/Mar/2024:22:04:47 +0000] "GET /index.html HTTP/1.0" 200 135 "-" "curl/8.6.0" "172.20.0.2, 172.20.0.3"

以下のコマンドを実行して、環境を破棄する。

docker compose --file compose-multi-proxy.yaml down

関連資料

Discussion