1つのCloudFront ALB EC2で複数のホスト(サイト)を扱いたい

実現したい構成例

複数の CloudFront Distribution ー 複数の ALB ー 複数の EC2 で構成する方がシンプルで良いが、費用面などの要因から全てのサービスを単一リソースで作成しなければいけない場合、可能なのか?

#検証
環境
$ ec2-metadata --ami-id
ami-id: ami-090d95e264aea197c
$ cat /etc/system-release
Amazon Linux release 2023.5.20241001 (Amazon Linux)
$ uname -a
example.ap-northeast-1.compute.internal 6.1.109-118.189.amzn2023.aarch64 #1 SMP Tue Sep 10 08:58:40 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux
CloudFront ⇒ ALB ⇒ EC2 間の Security Group 設定は適切に行われている前提
ドメインのレコード設定や、ACMの証明書取得も一部割愛します

今回は一旦 Web サーバーを Apache にする。
以下など参考にインストール
$ httpd -v
Server version: Apache/2.4.62 (Amazon Linux)
Server built: Jul 23 2024 00:00:00

複数ドメインのサイトを扱えるように、httpd に VirtualHost の設定を追記する
<VirtualHost *:80>
ServerName hoge.example.com
ServerAlias example.com *.example.com # CloudFront ⇒ ALB 間で Host ヘッダーを転送する場合は不要
DocumentRoot /var/www/hoge
</VirtualHost>
<VirtualHost *:80>
ServerName huga.example.org
ServerAlias example.org *.example.org # CloudFront ⇒ ALB 間で Host ヘッダーを転送する場合は不要
DocumentRoot /var/www/huga
</VirtualHost>

アクセスログにアクセス元ホスト名が出力されるようデフォルト設定に追記修正
<IfModule log_config_module>
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog "logs/access_log" combined
</IfModule>

バーチャルホストの各ホストにページを作成
# mkdir /var/www/hoge
# mkdir /var/www/huga
# echo "hoge.example.com" > /var/www/hoge/index.html
# echo "huga.example.org" > /var/www/huga/index.html

設定に問題が無い事を確認して再起動(or 停止してたら起動)
# apachectl configtest
Syntax OK
systemctl restart httpd

nginxならこれ参考に設定すれば良さそう

ALB の Host ヘッダー保持設定を設定する
ロードバランサー>属性>パケット処理>ホストヘッダーを保持 を オン に設定

ALB の HTTPS リスナーの証明書リストに複数ドメイン分の ACM 証明書を追加する
ロードバランサー>リスナーとルール>対象のHTTPSリスナー>SNI の SSL 証明書を追加する
対象の証明書を全て選択して「保留中として以下を含める」ボタンをクリック
「保留中の証明書を追加」ボタンをクリック

複数のドメイン名を別の名前として持つ証明書をバージニア北部リージョンの ACM で1つだけ作成する
キーアルゴリズムは CloudFront でも使える RSA 2048 か ECDSA P 256 を指定

CloudFront のディストリビューションに複数ドメイン分の 代替ドメイン名(CNAMEs) と前項で作成した カスタム SSL 証明書 を設定

オリジンドメイン(カスタムドメインで)ALBに繋がるオリジンを作る
オリジングループを作る(用途外だけど)⇒不要だったけど分からなくなるからあった方がいいかも?
ビヘイビアのオリジンリクエストポリシーにALLViewerを設定する(Hostヘッダーを転送するポリシーであれば何でも良い)

無限ループしてしまうため CloudFront に向けている DNS レコードとは別のレコード名で ALB の DNS 名 への DNS レコードを作成する
設定例
レコード名 | タイプ | 値 |
---|---|---|
hoge.example.com | A(Alias)or CNAME | d1abcdefg2hijk.cloudfront.net |
alb.examole.com | A(Alias)or CNAME | example-1234567890.ap-northeast-1.elb.amazonaws.com |
オリジンドメインに、 ALB に繋がるカスタムドメインを指定して、オリジンを作成する
オリジンタイプを Custom origin ではなく Elastic Load Balancing になるように ALB を直接指定してしまうと、HTTP 502 ERROR が返されアクセスが失敗してしまいます。
ALB デフォルトの DNS 名 には証明書が紐づいていないためです。
CloudFront ⇒ ALB 間のリスナープロトコルに HTTP を含む場合は問題無いが、 HTTPS のみの場合に発生します。
参考:CloudFrontとALB間のHTTPS接続がうまくいかなかった件

パスパターンが デフォルト (*) のビヘイビアのオリジンに、前項で作成したオリジンを指定し、オリジンリクエストポリシーに ALLViewer を設定する(恐らく Host ヘッダーを転送するポリシーであれば何でも良い筈)
Host ヘッダーを転送するオリジンリクエストポリシーを指定しない場合、Host ヘッダーがオリジンに指定したドメイン名に置き換えられてリクエストが転送される。
例)hoge.example.com ⇒ alb.examole.com
そのため、バーチャルホストの設定をクライアントのリクエスト時ドメイン名のみで指定している場合、マッチしなくなる。

通信的には必要無いが、構成上オリジンが一つで何故複数ドメインのリクエストが処理できるのか分かり辛いので、もう一つ分までであれば※オリジンを作成して、2つのオリジンを追加したオリジングループを作成し、デフォルトビヘイビアのオリジンをオリジングループに変更することは可能
※オリジングループに追加できるオリジンは2つまでのため
オリジングループの用途はフェイルオーバーのため、用途外利用にはなるが、動作は変わらない

1つの CloudFront ALB EC2 で複数のホスト(サイト)を扱うことができた!
10.0.1.30 - - [25/Nov/2024:08:40:02 +0000] "GET / HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "hoge.example.com"
10.0.0.28 - - [25/Nov/2024:08:40:04 +0000] "GET / HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "huga.example.org"

CloudFront ⇒ ALB を HTTPS にしてるところが難易度を一段階上げてたと思う

参考