ALBで複数のSSL/TLS証明書を設定できるSNIに対応しました
ウィスキー、シガー、パイプをこよなく愛する大栗です。
Application Load Balancerで同じポートに複数のSSL/TLS証明書を設定できるSNI(Server Name Indication)に対応しました。
SNI(Server Name Indication)とは
SNI(Server Name Indication)とはRFC 6066に記述されている仕様です。「Server Name Indication」つまりサーバ名表示のことです。SNI以前の仕様ではIPアドレス/ポートに対して一つのSSL/TLS証明書しか設定が行なえませんでした。SNIによりサーバ名ごとにSSL/TLS証明書を設定できるようになり、リクエストから証明書を適用するサーバ名が判断して適用するようになります。
HTTPSリクエストのホストヘッダーを見れば判断できるだろうと思われるかもしれませんが、HTTPSで暗号化されるため証明書を適用する前にはホスト名を判断できません。そこで、SSL/TLSハンドシェイクのプロセス中でホスト名を送信することで解決しています。クライアントからサーバへ初回アクセスする時のClient Helloの中にserver_name
と言う型のExtensionsを含めてアクセス先のホスト名(host_name)を通知します。サーバ側ではClient Hello(とクライアントへ返すServer Hello)の内容を元にSSL/TLSで通信するための暗号形式などを決定するので、SSL/TLSで暗号化する前にアクセス先のホスト名が判断でき適切な証明書を適用します。
2003年6月にRFC 3546でTLSに加わった仕様であるため、古いUserAgentではSNIに対応していない場合がありました。例えばWindows XP上のIEやAndroid 2系ではSNIを使用できません。幸いなことにWindows XPは延長サポートフェーズが終了していますし、Android 2系最期のバージョンである2.3.7のリリースから6年を経過しているので、一般的な環境でSNIを使用できないということは無いでしょう(と思いたい)。
試してみる
下図のような環境を考えてみます。
ALBにtarget-1.example.com
とtarget-2.example.com
の2個のドメインを設定します。同様にACMで各々の証明書をALBに設定します。EC2側でもバーチャルホストで2個のサーバ名を受け付けます。
証明書の取得
ここでは証明書はACMで取得します。以下のエントリを参考に2つのドメインの証明書を発行してください。
EC2の設定
ここでは以下を前提とします。
- リージョン:東京リージョン
- OS:Amazon Linux AMI 2017.09.0(ami-2a69be4c)
- インスタンスタイプ:t2.small
- Webサーバ:Apache HTTP Server 2.4.27
EC2を起動してhttpdをインストールしておきます。
httpd.confはこんな感じに適当に2つのホスト名でリスエストを受けるようにしておきます。
ServerRoot "/etc/httpd" Listen 80 Include conf.modules.d/*.conf User apache Group apache <VirtualHost *:80> DocumentRoot "/var/www/target1/html" ServerName target-1.example.com </VirtualHost> <VirtualHost *:80> DocumentRoot "/var/www/target2/html" ServerName target-2.example.com </VirtualHost> <IfModule mime_module> TypesConfig /etc/mime.types </IfModule>
アクセス確認用のファイルを作成します。
$ sudo mkdir -p /var/www/target1/html /var/www/target2/html $ echo target-1 `curl -s http://169.254.169.254/latest/meta-data/instance-id` | sudo tee /var/www/target1/html/index.html target-1 i-0a1b2c3d4e5f6g7h8 $ echo target-2 `curl -s http://169.254.169.254/latest/meta-data/instance-id` | sudo tee /var/www/target2/html/index.html target-2 i-0a1b2c3d4e5f6g7h8
httpdを開始します。
$ sudo service httpd start Starting httpd: [ OK ]
index.html
にアクセスできることを確認しましょう。デフォルトのtarget-1の内容が表示されます。
$ curl http://127.0.0.1/index.html target-1 i-0a1b2c3d4e5f6g7h8
上記EC2の設定をもう一台別AZで実施します。
ターゲットグループの作成
以下の内容でターゲットグループを作成します。
項目名 | 値 | 備考 |
---|---|---|
ターゲットグループ名 | sni-target | |
プロトコル | HTTP | |
ポート | 80 | |
ターゲットの種類 | instance | |
VPC | <EC2を設置したVPC> | |
ヘルスチェックの設定 プロトコル | HTTP | |
ヘルスチェックの設定 パス | /index.html |
作成したターゲットグループのターゲットとして2台のEC2を設定します。
ALBの作成
ALB(Application Load Balancer)を作成します。
1. ロードバランサーの設定
項目名 | 値 | 備考 |
---|---|---|
名前 | sni-alb | |
スキーマ | インターネット向け | |
IP アドレスタイプ | ipv4 | |
ロードバランサーのプロトコル | HTTPS(セキュア HTTP) | |
ロードバランサーのポート | 443 | |
アベイラビリティゾーン | <対象VPCのパブリックなサブネット> |
2. セキュリティ設定の構成
項目名 | 値 | 備考 |
---|---|---|
証明書タイプ | ACM から証明書を選択する | |
証明書の名前 | target-1.example.com | デフォルトの証明書です |
セキュリティポリシー | ELBSecurityPolicy-TLS-1-2-2017-01 | 安全なプロトコルのみを許可します |
3. セキュリティグループの設定
クライアントのHTTPSリクエストを受けられて、EC2へHTTPリクエストができるセキュリティグループを設定します。
4. ルーティングの設定
項目名 | 値 | 備考 |
---|---|---|
ターゲットグループ | 既存のターゲットグループ | |
名前 | sni-target | |
プロトコル | HTTP | |
ポート | 80 | |
ターゲットの種類 | instance | |
ヘルスチェック プロトコル | HTTP | |
ヘルスチェック パス | /index.html |
5. ターゲットの登録
先程設定したEC2が設定されていることを確認して作成します。
SNIの設定
作成したALBのリスナーでView/edit certificates
をクリックします。
target-2.example.com
の証明書を選択して追加
をクリックします。
DNSの設定
ここではRoute 53で登録します。
このような形で、Alias Targetをtarget-1.example.com
とtarget-2.example.com
で登録します。Alias Targetで登録する名前はdualstack.<ALBのDNS名>
となります。
アクセスしてみる
まずはhttps://target-1.example.com/index.html
にアクセスしてみます。するとtarget-1の内容が表示されます。
証明書も確認してみるとtarget-1.example.com
の証明書でアクセスしています。target-1の内容が表示されます。
次にhttps://target-2.example.com/index.html
にアクセスしてみます。target-2の内容が表示されます。
証明書も確認してみるとtarget-2.example.com
の証明書でアクセスしています。
このようにホスト名によって別の証明書でアクセスしていることが確認できました。
特殊なパターンとしてIPアドレスでアクセスする場合を試してみます。https://203.0.113.139/index.html
のようにIPアドレスでアクセスしてみるとtarget-1の内容が表示されます。これはhttpd.confでtarget-1.example.com
を最初に書いているためデフォルトの設定となっているためです。
証明書も確認してみるとtarget-1.example.com
の証明書でアクセスしています。
デフォルトの証明書をtarget-2で、追加の証明書をtarget-1に変更してみると、IPアドレスでアクセスした時の証明書もtarget-2となります。
このようにホスト名によって別の証明書でアクセスしていることが確認できました。
さいごに
今回ALBがSNIに対応することによって複数の証明書を設定可能となりました。実は、以前から同じように複数ドメインのHTTPSアクセスを1つのALBでホストすることは可能でした。マルチドメイン証明書を使用することです。しかしマルチドメイン証明書を使用すると、ドメインを追加する場合に全ドメインの証明書の再発行が必要となり運用上の手間が増えます。SNIではドメインごとに別の証明書を運用できるため個別に追加削除が行えるという利点があります。また1つの証明書にできないドメインでも使用可能となります。1つの環境で複数のドメインをホストする場合にはALBのSNIサポートが有力な選択肢となると思います、
追伸
AWS田舎クラウドデザインパターン(AWS Inaka Cloud Design Pattern, 略してICDPと呼ぶ)というネタに100EZUD(100ドメイン EC2に 全部入り 運用次第で どんどん安く!)というパターンがありましたが、ALBとACMがあればhttpsでも大丈夫ですね!(ネタが古すぎて覚えている人がいなそう。。。)