ELBをNLB(non SSL Termination)からNLB(on SSL Termination)にオンラインで変更したよ


対応にあたる経緯

以前の ELBをCLB(Classic Load Balancer)からNLB(Network Load Balancer)にオンラインで変更した時のメモ - Qiita の対応以後、SSL TerminationがEC2内で行われることから、その負荷に対応するためにインスタンスタイプを上げたり、EC2内でnginxへSSLの設定を加えたり、毎年なり2年おきなりにSSL証明書の更新作業が入って、運用コストがかかっていまして、、、
あー、、、ACMで自動更新できるようにならないかなー ってずっと思ってたんですが、先日、AWSから下記のアップデートが

Network Load Balancer が TLS ターミネーションのサポートを開始

お、これは ということで、軽く検証したところ、SSL証明書をACM化できちゃいました
ということで早速、ちょうどSSL証明書の期限切れアラートがきているシステムがあるので、実際に本番へ反映しちゃいます

対応手順の前に取り急ぎ検証した手順

※今の本番URL(www.XXXXXXX.jp)とは別で(nlb.XXXXXXX.jp)にてアクセスできるようにAWS管理コンソールを色々触りますので注意

1. まずは下記のデモの手順にそって新しいNLBを作成します。

  • AWS Elastic Load Balancer Demos
  • NLB作成時にElastic IPが1つ以上必要なので、作成しました。(ケチって1つだけにしてます
  • NLBへセットするリスナーにて、新しいターゲットグループも作成しました。

2. 作成したNLBへ現在の本番のNLBに接続されているプロキシサーバをぶらさげます。

  • せっかくNLBにて SSL Termination してくれるのであれば、それ以降のバックエンドではHTTPでいいだろってことでポートも 80 にします。
  • ターゲットグループでステータスが healthy にならなくて少しハマりました。。。。
    • 原因は受け側にいるEC2 の SG(セキュリティグループ)にて、80ポートの解放を NLBを配置した subnetのCIDRからアクセスできるように設定する必要があった感じでした

3. また、EC2で動いている nginx でも 80 でアクセスして動作するような設定が必要ということで、取り急ぎ、 /etc/nginx/conf.d/XXXX-http.conf をコピーで作成して設定

/etc/nginx/conf.d/XXXXXXX-http.conf
server {
    listen       80;
    server_name  nlb.XXXXXXX.jp;

<後はコピー元と同じ>

4. んで、nginx再起動でできあがりです

$ sudo service nginx reload

本当にできてるのか?って思ったので、下記の資料の方法を使って、SSL通信でなくて、HTTPでアクセスされるのかをアクセスログを見て、チェックしました。
SSLじゃない場合は -[ハイフン] で出るんですね。勉強になります

ってことで次は本番反映にトライ!

検証はできたので、次はじゃあどうやってオンラインで変更するか ですよね
どうやってやろうかなーってことで、下記の前提条件がありながら、下記の手順を考えました

前提条件と必要条件

  • 今のNLBのグローバルIPは変えたくない
    • 理由は外部からシステムへアクセスする方がVPNをはってアクセスしてくる際に、またルーティングの変更が必要になる。
  • NLBのリスナーは複数作成できそうだったので、試したが同じポートだと作成できない。。。やろうとしたらエラーになっちゃいました・・・
    • 現在:TCP:443
    • 作成トライしたやつ:TLS:443
  • せっかくNLBで Termination してくれるんだからバックエンドはもう http にしたい。
  • バックエンドのnginxはHTTPS、HTTPの両方で動く状態にしておく。具体的には下記。
server {
    listen       80;
    listen       443 ssl;
    server_name  clb.XXXXXXX.jp  www.XXXXXXX.jp;

# ここはコメントアウトしてね
#    ssl                  on;
    ssl_certificate      /etc/pki/tls/certs/XXXXXXX.pem;
    ssl_certificate_key  /etc/pki/tls/certs/XXXXXXX.key;
    ssl_session_timeout  10m;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols  SSLv2 TLSv1.2;

対応手順

  1. まずは新しく、CLB(Classic Load Balancer)を作成。 ※これを選んだのは単純に使い慣れてるのと、コンソール上でわかりやすいからでしたw
  2. 作成できたら今のプロキシEC2をぶらさげて下記を対応
    • CLBへ今回反映しようとしているACMのSSL証明書を設定
    • SG(セキュリティグループ)は取り急ぎ社内LANからのHTTPSを解放
    • ぶらさげたEC2のSGへは社内LANからのHTTPSを解放したSGを送信元としたHTTPを解放するように設定
    • clb.XXXXXXX.jpで、このCLBのエンドポイントが名前解決されるようにRoute53へCNAMEレコード追加(Aレコードでもできた)
    • https://clb.XXXXXXX.jp でアクセスできるかチェック
  3. 今、NLBにぶらさがってるプロキシEC2のSGをCLBへも設定
  4. Route53でwww.XXXXXXX.jp の名前解決先をCLBへ変更
    • これで、アクセスの許可されたユーザが社外からの場合はVPNのルーティングが要変更だが、社内からのアクセスは可能となります
  5. NLBへのアクセスがなくなった時点で、NLBの設定変更に着手
    • リスナーにて、TCP:443からTLS:443へ設定を変更し、新しく作成したACMを設定。
    • ぶら下がってるEC2のSGにて、一時的にHTTPを全解放するように設定
  6. Route53でclb.XXXXXXX.jpにてNLBのエンドポイントに名前解決されるように設定し、アクセス確認
  7. 問題なければ、Route53にて、www.XXXXXXX.jpの名前解決先をNLBへ変更して、アクセスできれば完了!
  8. 一時的に解放したHTTPの全解放をクローズしてアクセス確認
  9. 問題なければ、Route53でclb.XXXXXXX.jpの削除
  10. 最初に作成したCLBの削除などでお片づけして終了

これでちゃんと、Amazon発行の証明書になります!
そして、SSL証明書の年間費用は不要となりましたとさ めでたし、めでたし

参考資料