SNI 概要
1つの IP 上で複数のサイトを配信するには、「SNI (Server Name Indication)」と呼ばれる技術を使った VirtualHost
の仕組みがあります。
例えば Apache では、以下のような設定ファイルを配置することで、クライアントから送られる SNI によって、サーバーが異なる SSL 証明書を提示することが可能になります。
NameVirtualHost *:443
<VirtualHost *:443>
ServerName www.yoursite.com
DocumentRoot /var/www/site
SSLEngine on
SSLCertificateFile /path/to/www_yoursite_com.crt
SSLCertificateKeyFile /path/to/www_yoursite_com.key
SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>
<VirtualHost *:443>
ServerName www.yoursite2.com
DocumentRoot /var/www/site2
SSLEngine on
SSLCertificateFile /path/to/www_yoursite2_com.crt
SSLCertificateKeyFile /path/to/www_yoursite2_com.key
SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>
その後、受信したクライアントブラウザは、証明書内の SANs を確認し、SNI とマッチングするものがあるかを確かめます。
そして SSL/TLS の処理後にホストヘッダ等を含む HTTP 通信がおこなわれます。
Cloudflare for SaaS とは
Cloudflare SSL for SaaS 設定ガイドを少し具体的に補足 - Qiita が参考になります。
以下の公式ドキュメントも整理されています。
確認結果まとめ
先に図示して載せておきます。
特に SaaS 業者はオリジンの運用において、SNI が重要になる場合がありますが、
Cloudflare for SaaS を経由した場合に独自ドメインで入ってくる Custom Hostname ごとにそうした制御が求められることもあります。
また、Cloudflare for SaaS を採用した際にオリジンで持つべき証明書にも関係します。
オリジン準備
Docker インストール
Docker を使うので、インストールしておきます。
$ cat /etc/redhat-release
CentOS Linux release 8.4.2105
GitHub からファイルダウンロード
SNI を表示するオリジンに使うファイルをダウンロードし、設定を書き換えます。
obezuk/test-sni: Server written in Node.js to debug SNI and Request Headers
sudo yum install git -y
git clone https://github.com/obezuk/test-sni
cd test-sni
export MY_ZONE='saas\.com'
sed -i -e "s/example\.com/$MY_ZONE/g" csr-configuration.txt
# cat csr-configuration.txt
Docker build & run
そのまま Docker ビルドしてラン(かつデタッチ)します。
sudo docker build -t test-sni .
sudo docker run -d -p 80:3080 -p 443:3443 test-sni
確認に必要な設定
オリジンが自己署名証明書を使うため、SSL/TLS encryption mode を Full にしておきます。
SNI を確認する
0. Cloudflare for SaaS なし
通常の SaaS ドメインへのアクセスについて、正しく SNI (servername
) が表示されたことが確認できます。
% curl https://default-fallback.saas.com -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "default-fallback.saas.com",
"servername": "default-fallback.saas.com"
}
% curl https://custom-origin.saas.com -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "custom-origin.saas.com",
"servername": "custom-origin.saas.com"
}
1. Cloudflare for SaaS 経由
Custom Origin を使わない設定だと、デフォルト Fallback Origin に以下の SNI が送られたことが確認できます。
% curl https://customer.shop -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "customer.shop",
"servername": "customer.shop"
}
2. Cloudflare for SaaS 経由 + Custom Origin (Origin server name)
Custom Hostname ごとに Custom Origin を指定して、SNI が Origin server name になったことが確認できます。
% curl https://customer.shop -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "customer.shop",
"servername": "custom-origin.saas.com"
}
3. Cloudflare for SaaS 経由 + Custom Origin (Host header)
Custom Origin であっても、SNI を当初の Host header と一致させられたことが確認できます。
% curl https://customer.shop -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "customer.shop",
"servername": "customer.shop"
}
4. Cloudflare for SaaS 経由 + Custom Origin (Host header) + Host Header Override
以下のような Host Header Override
の Page Rule を加えると、SNI もそれに従って反映されたことが確認できます。
% curl https://customer.shop -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "override.example.com",
"servername": "override.example.com"
}
5. Cloudflare for SaaS 経由 + Custom Origin (Subdomain of zone)
以下のように SNI を saas.com
もしくは subdomain.saas.com
に変更されたことが確認できます。
% curl https://customer.shop -s | jq -r '.|{"host":.headers.host, "servername":.servername}'
{
"host": "customer.shop",
"servername": "subdomain.saas.com"
}
以上。