ALBとEC2間をHTTPS通信させてApacheのアクセスログから接続元のクライアントIPを取得する

2021.06.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、岩城です。

ALBとEC2間をHTTPS通信させるかどうかの議論は置いておき、下図のような環境でEC2上のApacheのアクセスログから接続元のクライアントIPを取得する機会がありましたので紹介します。

やってみた

/etc/httpd/conf.d/ssl.confに以下のようなX-Forwarded-Forを含めたLogFormatを追記します。

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

Apacheが停止している場合は起動します。

systemctl start httpd.service

既にApacheが起動している場合は設定ファイルを再読み込みします。

systemctl reload httpd.service

/var/log/httpd/ssl_access_logに記録されたアクセスログを確認します。

sudo tail -f /var/log/httpd/ssl_access_log
- 172.31.47.129 - - [23/Jun/2021:05:47:17 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
- 172.31.40.253 - - [23/Jun/2021:05:47:19 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
- 172.31.22.6 - - [23/Jun/2021:05:47:21 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
219.xxx.xxx.xxx 172.31.40.253 - - [23/Jun/2021:05:47:41 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"

最終行のログを見てください。172.31.xxx.xxxはALBのIPであり、219.xxx.xxx.xxxはクライアントIPです。 クライアントがALBを経由してEC2に到達したことを示すログですが、LogFormatにX-Forwarded-Forを含めることでクライアントIPを記録できたことを示しています。

これだけでは寂しいので検証環境の構築方法を以下に記載します。

検証環境の構築

前提

  • VPC、サブネット、インターネットゲートウェイ、ルートテーブルなど、ネットワークリソースが作成されていること
  • WebサーバーとなるEC2インスタンスがAmazon Linux2で作成されていること

無料ドメインの取得

Freenomで無料ドメインを取得します。サインインが必要なのでユーザー登録してください。本エントリではiwaki.tkドメインを取得できるかチェックし、問題なければ取得手続きを進めます。

Use DNSは後で設定するため、この時点では設定不要です。また、ドメインの有効期限はデフォルトの3ヶ月としています。12ヶ月までは無料なので必要に応じて変更してください。

無料で取得できることを確認した上でドメインを取得します。

取得したドメインはMy Domainsページで確認できます。後でこのページからNameserverを設定します。

取得したドメインをRoute53に委任する

Route53のホストゾーンを作成します。

ドメイン名はFreenomで取得したドメインを指定します。後はデフォルトのままで構いません。

ホストゾーンが作成されるとNSレコードが登録されます。このNSレコードをFreenomに設定するので控えておきます。

先程のFreenomのコンソールに戻り、Manage Domain>Management Tools>Nameseversを選択します。

控えておいたNSレコードをすべてコピペします。

ACMでSSL証明書を発行する

クライアントとALB間の通信をHTTPS化するには、ALBにSSL/TLS証明書をアタッチする必要があり、本エントリではACMで発行したSSL/TLS証明書を利用します。

パブリック証明書のリクエストのまま、証明書をリクエストします

SSL/TLS証明書で保護するドメイン名を指定します。*.iwaki.tkのようにワイルドカード証明書をリクエストします。

証明書リクエストの検証方法を選択します。今回はDNSの検証を選択します。

リクエストすると検証保留中のステータスになるので、コンソールに表示されているままCNAMEレコードをRoute53に作成します。

作成されると検証が済むのでステータスが発行済みとなれば完了です。

EC2のセットアップ

EC2に接続してApacheに関する設定を行います。 mod_sslをインストールすると、Apacheもインストールされ、自己証明書も自動的に作成されます(参照元)。

sudo yum install mod_ssl -y

ALBからのヘルスチェック先となるIndex.htmlを作成します。

sudo vi /var/www/html/index.html
<HTML>
テスト
</HTML>

EC2でSSL終端しても、アクセスログにクライアントIPが記録されるようにssl.confLogFormatを追記します。

sudo vim /etc/httpd/conf.d/ssl.conf
LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""

Apacheに設定ファイルを再読み込みさせるか、停止していれば起動します。

sudo systemctl reload httpd.service
sudo systemctl start httpd.service

ALBを作成する

ALBを作成します。リスナーのプロトコルでHTTPSを選択します。

証明書タイプはACMから証明書を選択する、証明書の名前は先程発行した証明書を選択します。ちなみに、HTTPSリスナーを設定する場合、事前に証明書を用意しておく必要があるので注意してください。

セキュリティグループの設定では、インバウンドルールにHTTPSからの通信を許可するルールを追加します。

ルーティングの設定では、ターゲットグループとヘルスチェックのプロトコルをHTTPSにします。

ターゲットの登録では、EC2を選択して登録済みに追加します。

ALBが作成できましたら、最後にEC2のセキュリティグループを変更します。インバウンドルールにALBにアタッチしたセキュリティグループからのHTTPSを許可するルールを追加しておきます。

ALBのエイリアスレコードをRoute53に追加する

ALBのエイリアスレコードをRoute53に追加し、https://alb.iwaki.tkでアクセスできるようにします。作成したホステッドゾーンからレコードを作成します。

レコード名にalbを指定、エイリアスをクリックし、東京リージョンにあるALBを選択し完了です。

digコマンドでANSWER SECTIONの問合せ結果が返ってくることを確認しておきます。

[ec2-user@ip-172-31-47-123 ~]$ dig alb.iwaki.tk

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.5 <<>> alb.iwaki.tk
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47733
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;alb.iwaki.tk.			IN	A

;; ANSWER SECTION:
alb.iwaki.tk.		42	IN	A	54.64.218.182
alb.iwaki.tk.		42	IN	A	54.199.12.24

;; Query time: 0 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: 水  6月 30 06:38:05 UTC 2021
;; MSG SIZE  rcvd: 73

検証

ブラウザからhttps://alb.iwaki.tkにアクセスして、Index.htmlの内容が表示されることを確認します。

クライアント->ALB->EC2間をすべてHTTPS化させても、ApacheのアクセスログにクライアントIPが記録されることを確認できました。

sudo tail -f /var/log/httpd/ssl_access_log
- 172.31.47.129 - - [23/Jun/2021:05:47:17 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
- 172.31.40.253 - - [23/Jun/2021:05:47:19 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
- 172.31.22.6 - - [23/Jun/2021:05:47:21 +0000] "GET / HTTP/1.1" 200 34 "-" "ELB-HealthChecker/2.0"
219.xxx.xxx.xxx 172.31.40.253 - - [23/Jun/2021:05:47:41 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"

おわりに

これまでALBまでHTTPS化させ、ALB以降はHTTPとする構成しか構築したことがなかったので試してみました。 Apacheのデフォルト設定では設定ファイルやアクセスログが異なることを知りました。 異なる点は以下のとおりです。

  • Apacheの設定はhttpd.confではなくssl.conf
  • アクセスログはaccess_logではなくssl_access_log

本エントリがどなたかのお役に立てれば幸いです。

リファレンス