Webシステムへの接続元を制限したい場合、クライアント証明書による認証を行うことがあります。しかし、それにより可用性やセキュリティなどその他の要件を実現することが難しくなる側面があります。
今回はAWSにおいて、ロードバランサ構成のWebシステムにおけるクライアント認証の実装方式について考察してみます。
実案件でのシステム要件
今回の考察するきっかけは実案件です。
そのシステムの現状の構成は以下の通りです。
この構成におけるポイントは大きく5つ。
- ALB(Application Load Balancer)でWeb通信をバランシング。併せてSSL暗号の終端を担う。
- ALBのスティッキーセッションを使ったWebサーバでのセッション管理。
- X-Forwarded-Forヘッダーを使って接続元のIPアドレスをログ出力。
- Route53のフェールオーバールーティングにより、障害時はCloudFront経由でS3のソーリーページに転送。
- ALBにAWS WAFをアタッチ。
このシステムに対するセキュリティ向上策として、クライアント証明書認証を実装するというのが今回の要件でした。
クライアント認証を実現するシステム構成
システム全体図
クライアント認証を実装するための変更後のシステム構成が下記です。
変更前の構成ポイントそれぞれに対する変更内容に触れていきます。
1.ロードバランサ方式
クライアント証明書認証はその仕様上、SSL終端が認証処理を行います。
(参考)この辺りの仕様は下記サイトが分かり易いと思いました。「パターン2」で記載されている方式です。
ということは中継するロードバランサでSSL終端を担えないということです。
将来的にALBでクライアント証明書認証を行う機能が搭載されることを期待しますが、現時点では不可能なため、WebサーバがSSL終端となり、クライアントとのEnd-to-End暗号化が必要です。
そのためロードバランサはALBではなくNLBを採用する必要があります。
2.セッション保持方式
変更前の構成ではスティッキーセッションを使っていましたが、NLBでもスティッキーセッションが使えます(2020年2月にEU圏のリージョンからスタート。東京リージョンも使えるようになったのは比較的最近です)。
ただし、セッション保持の方式がALBと異なることに注意する必要があります。
ALBではCookieベースで振り分け先のサーバを管理していました。
一方でNLBは接続元IPアドレスベースで管理します。接続元がプロキシサーバ等を経由していて大勢が単一IPアドレスになるようなケースの場合、全員が同じWebサーバに割り振られて、サーバ毎の負荷が均一にならないケースが発生しえます。
3.接続元IPアドレス判定方法
ALBではX-Forwarded-Forヘッダーを使って接続元のIPアドレスを判定していましたが、これはALBがリクエスト元IPを自身(ALB)のIPアドレスに書き換えてしまうために実装した処理でした。
NLBではクライアントのIPアドレスがリクエストIPとして保持されるため、X-Forwarded-Forヘッダを見る必要がなくなりました。
4.ソーリーページ切替方式
構成前はRoute53のフェールオーバールーティングを使って、Webサーバ障害時はS3に配置した静的HTMLであるソーリーページに通信させるようにしていました。
S3は独自ドメインに対するSSL暗号化ができないので、CloudFrontを経由してSSL証明書をCloudFrontにアタッチすることでそれを実現しています。
NLBに構成変更してもこの構成自体は踏襲で大丈夫でした(Route53における正常時の転送先はALBからNLBのエンドポイントに変更が必要)。
5.WAFによるセキュリティ実装
最後のこの要件が最も難しく、結果としてクライアント証明書認証とWAFの共存はできないと判断しました。
まず、AWS WAFがアタッチできるのはCloudFrontかALBに限定されています。
また「HTTPヘッダーや本文などに基づいてWebトラフィックをフィルタリングする」というWAFの特性上、HTTPSを使用する場合はSSL終端にWAFをアタッチする必要があります。SSL暗号化された状態だとHTTPの本文が確認できないためです。
前述の「1.ロードバランサ方式」でNLBを採用しているため、ALBは選択から除外。CloudFrontにWAFをアタッチするとすれば、CloudFrontをSSL終端にしないといけないのですが、やはり「1.ロードバランサ方式」で触れたようにSSL終端がクライアント証明書認証を担わなければならず、CloudFrontではその機能がありません。
ということで、クライアント証明書認証とWAFは共存できないという結論に達しました。
元々セキュリティレベルを高めるために検討し始めたのが、トレードオフとして別の側面ではセキュリティレベルを落とさざるを得ないという残念な結果なのですが、SQLインジェクションやXSS(クロスサイトスクリプティング)、CSRF(クロスサイトリクエストフォージェリ)などの攻撃に対する脆弱性は別途アプリケーション診断を受診し撲滅させていることや、クライアント証明書認証によりアクセスできる環境が関係者のみに限定可能であることから当該システムにおいてはWAF廃止による影響は軽微と判断し、クライアント証明書認証を導入するのが良いと考えました。
構成変更時のステップ
実はまだ運用環境には適用していないのですが、もし構成変更する場合は次のステップになるはずです。
万が一の場合は、3.のALIASレコードを元に戻せば旧戻し可能です。
構成変更そのものよりもクライアント証明書を漏れなく事前に配布し、全ユーザにインストールしていただくほうが移行のネックになりそう。。
まとめ
NLBを実運用で使ったことが無かったので、ALBとの違いを調べる良い機会になりました。
クライアント証明書+ロードバランサの構成にWAFを使いたいという要件は、そこまでレアケースではないように思うのですが、「こういう実装方法があるよ!」という方がいたら教えてください・・・
※参考サイト
ロードバランサー配下の Web サーバーへのクライアント認証
[アップデート] NLB でスティッキーセッションが使えるようになりました! | DevelopersIO
【AWS】S3+CloudFront+Route53+ACMでSSL化(https)した静的Webサイトを公開する