1つのインスタンスで240個のSSLサイトをホストしてみた

Instance Types - Amazon Elastic Compute Cloudによれば、m2.4xlargeなどのインスタンスタイプでは 8ENI x 30IPs(/ENI) = 240のIPアドレスを使用する事ができる、とあるので実際に試してみた。

必要な物

  1. EIP上限解除申請
    必要な数のEIPを確保するため、250個のEIP上限申請を行った → http://aws.amazon.com/jp/contact-us/vpc-request/
  2. 7つのENIを作成
  3. m2.4xlargeインスタンス(Amazon Linux 2012.09を使用)
  4. 240個のEIP取得(こちらのスクリプトで取得しました)

構成を決める

VPCを10.1.0.0/16で作成、PublicSubnetを10.1.0.0/24で作成した。インスタンスに振る事のできるPrivateIPアドレスは10.1.0.4-10.1.0.254なので、10.1.0.10-10.1.0.249を使用する事にした。
また、10.1.0.{10.,40,70,100,130,160,190,210}はeth[0-7]に直接振り、それ以外のIPアドレスは追加PrivateIPアドレスとして振る。

インスタンス起動〜ENIの追加

まずeth0に10.1.0.10のIPアドレスを指定してインスタンスを起動した。さらに7個のENIを作成し、インスタンスに紐づけて行く。

$ for x in 40 70 100 130 160 190 210 ; do ec2-create-network-interface --private-ip-address 10.1.0.$x -g sg-xxxxxxxx ; done
$ ec2-attach-network-interface eni-11111111 -i i-xxxxxxxx -d 1
$ ec2-attach-network-interface eni-22222222 -i -xxxxxxxx -d 2
 :
$ ec2-attach-network-interface eni-77777777 -i i-xxxxxxxx -d 7

インスタンスにログインしてifconfig upしておく

$ for x in {1..7} ; do sudo ifconfig eth$x up ; done
$ /sbin/ifconfig | grep ^eth
eth0      Link encap:Ethernet  HWaddr 0A:D7:75:83:32:95  
eth1      Link encap:Ethernet  HWaddr 0A:D7:75:BA:6B:CB  
:
eth7      Link encap:Ethernet  HWaddr 0A:D7:75:92:9A:37  

8本のNICが認識された。

プライベートIPアドレスの付与

$ for x in {11..39} ; do echo ec2-assign-private-ip-addresses -n eni-00000000 --secondary-private-ip-address 10.1.0.$x ; done

これをENIのIDとIPレンジを変えながら実行します。結果、

$ ip addr | grep 10.1.0. | wc -l
240

240個のPrivateIPアドレスが付きました!他のインスタンスから疎通を確かめます。

$ for x in {10..249} ; do ping -c 1 10.1.0.$x ; done

EIPの関連付け

ENIのリストとEIPのAllocationIDのリストからec2-associate-addressコマンドを生成するスクリプトを作りました。pipeでshで受けて1つずつ実行します。

$ ./associate.pl 
ec2-associate-address -aeipalloc-0fa9a064 -n eni-83cec1e8 -p 10.1.0.10
ec2-associate-address -aeipalloc-4a949d21 -n eni-83cec1e8 -p 10.1.0.11
:
ec2-associate-address -aeipalloc-aeaba2c5 -n eni-3ec3cc55 -p 10.1.0.249
$ ./associate.pl | sh

各EIPの疎通を確認します

$ ec2-describe-addresses  | grep vpc | cut -f 2  | xargs -P 1 -L 1 ping

httpd設定

nginxを入れます。またそれぞれのSSLサイト用にdocument rootとindex.htmlを用意します。

# yum install nginx
# cd /usr/share/nginx/
# for x in `seq -w 0 239` ; do mkdir html$x ; echo $x > html$x/index.html ; done

次にSSL証明書を240個用意します。

# openssl genrsa -des3 -out server.key 1024
# cp server.key server.key.org
# openssl rsa -in server.key.org -out server.key
# for x in `seq -w 0 239` ; do openssl req -new -key server.key -out server$x.csr -batch -subj "/CN=ssl$x.example.com/" ; openssl x509 -in server$x.csr -days 365 -req -signkey server.key > server$x.crt ; done
# cp server.key *.crt /etc/nginx

HTTPSサイト用コンフィグをgenerateするスクリプトをサイト数分実行します。

# cd /etc/nginx/conf.d
# for x in `seq 0 239` ; do ./genconf.sh $x ; done
# service nginx reload

これで準備が出来たと思われます。

アクセス確認

本来ならDNSへも登録して動作確認したい所ですが、面倒臭いのでhostsファイルで済ませる事にします。

{EIP000}  ssl000.example.com
{EIP001}   ssl001.example.com
:
{EIP003}  ssl239.example.com

みたいなhostsエントリーを作成し、全てのサイトにアクセスをしてみます。

$ for x in `seq -w 0 239` ; do curl -k https://ssl$x.example.com ; done
000
001
:
239
$ for x in `seq -w 0 239` ; do curl -ksvo /dev/null https://ssl$x.example.com 2>&1 | grep common ; done
*       common name: ssl000.example.com
*       common name: ssl001.example.com
:
*       common name: ssl239.example.com

ちゃんと別のcommon nameが表示されているので、別の証明書を使用しているのが分かります。

何がうれしいか

SSLサイト1つあたりのコストを考えてみます。

1IPあたりのhourly chargeはダントツでt1.microがお得です(2ENIx2IP=4)。しかし、m2.シリーズは非常にたくさんのIPを持てるため、m1.やc1.シリーズよりも、またELBをSSL terminationするよりも安く上がります。
大量のSSLサイトをなるべく安く運用したい場合に、m2.xlarge〜m2.4xlargeを検討してみるとよいかもしれません。

最後に

CDP用という事で、パターン名を無理矢理付けたいと思います。でかい頭(Instance)に8本の足(ENI)、と言えばもうクラーケンしか考えられません。
 (参考イメージ)
Kraken SSL Patternの誕生です!