きっかけ
こちらを参照:
https://zenn.dev/kacchan822/articles/c23c965d0a3312
要はApacheのセキュリティアップデートに起因し、Apache側がHostヘッダーだけではSSL証明書を判断できなくなり421 エラーとして弾くようになった。
ではSNIをつければよいのだが、上位のロードバランサ側では SNI が付けられない状況で、困ってしまった。
対策
インターネット上にも特にSNIをつける以外の対応がないので、SNIの仕組みから調査を開始
※参考サイト(SNIの仕組みについて)
https://www.cloudflare.com/ja-jp/learning/ssl/what-is-sni/
複数のWebサイトが1つのサーバーでホストされ、単一のIPアドレスを共有し各Webサイトに独自のSSL証明書がある場合、
クライアントが安全に接続しようとしてもサーバー側で表示する証明書が特定できないことがあります。
これは、クライアントがHTTPを介して接続先Webサイトを示す前にSSL/TLSハンドシェイクが発生するためです。
SNIはこの問題を解決する仕組みです。
Apache では複数のサイトを同じ IP・ポートで SSL 化すると、どの証明書を出すか SNI で識別します
SNI なしでアクセスすると、default の VirtualHost に飛んでしまう
httpd -S で VirtualHost の配置を確認
VirtualHost configuration:
*:443 is a NameVirtualHost
default server site-a.example.com (/etc/httpd/conf.d/vh-site-b.conf:2)
port 443 namevhost site-b.example.com (/etc/httpd/conf.d/vh-site-b.conf:2)
default vhost が site-a.example.com になっている
site-b.example.com にアクセスすると421エラーとなる(site-a.example.com はアクセス可能)
SNI は「同じ IP・ポートで複数証明書を使うときだけ必要」と理解
なら IP を分ければ SNI なしでも正しいサイトに飛ばせるはず
Apache 設定例:
<VirtualHost 192.168.100.10:443>
ServerName site-a.example.com
DocumentRoot "/var/www/html/sitea"
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.crt
SSLCertificateKeyFile /etc/ssl/private/example.key
</VirtualHost>
httpd -S で VirtualHost の配置を確認、IPが分けられたことを確認
VirtualHost configuration:
192.168.100.10:443 site-a.example.com (/etc/httpd/conf.d/vh-site-a.conf:2)
192.168.100.20:443 is a NameVirtualHost
default server site-b.example.com (/etc/httpd/conf.d/vh-site-b.conf:2)
更にcurlやブラウザアクセスではデフォルトでSNIが付帯されてしまい再現試験ができなかったので、下記からopensslをインストールした。(opensslには SNI無しオプションがあり)
本対応で、上位から各ドメインにアクセスする時にIPを分けてもらうことで、421エラー問題は解消できた。
まとめ
・IP を分ける方法は泥臭いけど、現場ではこういう局所的な対応が求められることもある
・理想は上位 LB で SNI 対応してもらうこと
・個人的にもマイナーな情報の記事に救われたこともあるので、記録として残しておきます