この記事はHTアドベントカレンダー12日目の記事です。
はじめに
こんにちは、博報堂テクノロジーズの森田です。
AWS Application Load Balancer (ALB) をよく使うのですが、同じ指摘をすることが多かったので文章に残しておこうと思います。
尚、この記事はGemini:人 = 1:9くらいで書いています。
よく指摘するレビュー観点
レビューでよく指摘する観点は次の通りです。あくまで私が関わるプロジェクト中心の話で、網羅的なものではないのでご留意ください。
- パブリックサブネットに配置する必要性はあるか?
- ALBに紐づけているセキュリティグループのIPアドレス、ポートは最小限にできているか?
- 適切なSSL/TLS証明書を設定できているか?
- 特定のHostヘッダのみ許可しているか?
- スティッキーセッションは意図した設定か?
- ALBおよびその前段、後段のKeep Alive Timeoutを適切に設定できているか?
- WAF設定が重複していないか?
指摘項目
それぞれの指摘内容と修正方法を下記に並べて行きます。
パブリックサブネットに配置する必要性はあるか?
サービスエンドポイントを作成する上で、外部からの接点を最小化することはセキュリティ上重要です。
主な修正方法
前段にCloudFrontを配置したり、API Gateway + NLB(もはやALBではないのですが)※という構成に切り替えることによってELBをパブリックサブネットに置かずともインターネットからサービスにアクセスさせることが可能です。
考慮の上でCloudFrontやAPI Gatewayが要件上ノックアウトであるから意図的に除外しているのであれば問題無しです。
※最近API GatewayからプライベートALBに接続できるようになったみたいです。参考記事
ALBに紐づけているセキュリティグループのIPアドレス、ポートは最小限にできているか?
理由は同上です。特に80ポートを開けたままにしたりするケースをよく見ます。
主な修正方法
前段にCloudFrontがある場合はCloudFrontのマネージドプレフィックスリストからHTTPSのみインバウンドを許可します。VPC Originsを使う場合は CloudFront-VPCOrigins-Service-SG からのみ通信を許可するようにします。
セキュリティグループ以外の制限も複合して行いたい場合はポートのみ制限してIPアドレスはANYでオープンし、WAF側で制御する方法もあります。こちらはIPアドレスまたは特定のヘッダーが含まれている場合に通信を許可するといった柔軟な設定が可能です。
適切なSSL/TLS証明書を設定できているか?
CloudFrontをALBの前段に配置する構成の時によく指摘する項目となりますが、通信の時に用いられるHostヘッダに対して適切なコモンネームのSSL/TLS証明書をALBに設定する必要があります。これが適切に設定されていないとSSL/TLSハンドシェイクに失敗し通信が成立しません。(502 Bad Gatewayエラーとなります。)
CloudFront側でALBにHostヘッダを転送する設定漏れもよく指摘する項目です。
主な修正方法
CloudFront側のビヘイビアでHostヘッダを転送対象とし、そのHostヘッダに対応するコモンネームの証明書をALB側にも設定します。CloudFront用に設定したバージニア北部のACMと同じ内容のACMをALBと同じリージョンにも設定してALBに設定します。
特定のHostヘッダのみ許可しているか?
ALBを一般向けに公開(セキュリティグループで0.0.0.0/0を許可)している場合の指摘項目です。
AWSのIPアドレスレンジは一般に公開されており、攻撃者は常にこのIPアドレスレンジに対して攻撃ができそうなものが無いかを探しています。ELBを公開してアクセスログを眺めてみるとわかるのですが、IPアドレス直打ちの通信やELB自体のドメイン(name-id.region.elb.amazonaws.com形式のもの)への通信がよく見受けられます。これらの通信は受け付けないようにしてしまいましょう。
主な修正方法
ALBのリスナールールでHostヘッダを条件にターゲットグループへルーティングするルールを作成し、デフォルトルールは404 Not Foundの固定レスポンスで応答するようにします。ALBのルールに手を入れたくない場合は、WAFでチェックする方法でも良いです。
スティッキーセッションは意図した設定か?
主にALBの背後のアプリケーションがステートフルな作りになっている時に使うスティッキーセッションですが、ステートレスな作りにしているにも関わらずスティッキーセッションを有効化してしまっているケースをたまに見ます。なにか意図があれば別ですが、特になければ適切にバランシングされずに負荷の偏りが出てしまう可能性があるのでアリーデヴェルチしてしまいましょう。
主な修正方法
ターゲットグループの維持設定をオフにします。
ALBおよびその前段、後段のリクエストTimeout、Keep Alive Timeoutを適切に設定できているか?
TCP通信を終端するポイントが多い時は特にTimeoutおよびKeep Alive Timeoutに注意する必要があります。Timeoutは一般的に後段に行くほど小さい数値に設定すべきですが、Keep Alive Timeoutは一般的に前段の設定よりも大きい数値にする必要があります。CloudFront - ALB - Webサーバ - APサーバ - DB という構成の場合、タイムアウトはCloudFront > ALB > Webサーバ > APサーバ > DBになります。下流が応答を返す前に上流が待機を止めてしまうと下流リソースの浪費になる為このような設計が一般的です。一方でKeep Alive Timeoutは ALB < Webサーバというように前段よりも後段の値を大きくする必要があります。後段のKeep Alive Timeoutが前段より短いと、後段がコネクションを切断した直後に前段がそのコネクションを再利用しようとして「502 Bad Gateway」が発生してしまいます。Keep Aliveについては細かくは説明しませんが、簡単に言うと一度張ったTCP接続を複数リクエストで再利用する仕組みです。これが正しく設定されないとリクエストとしては問題ないはずだけど時々通信が切れてエラーが出るということが起こります(常に発生するわけではないのが厄介なところです)。この部分は意識していないと後々のトラブルシュートが難航しがちです。
また、当然ですがリクエストタイムアウトよりも先にTCP接続が切れてしまうのはまずいのでTimeout < Keep Alive Timeoutとなるような考慮も必要です。
主な修正方法
各通過点のTimeout、Keep Alive Timeout値を全体で見直して修正しましょう。Keep Alive Timeoutは特にクライアントとのKeep AliveとサーバとのKeep Aliveが別れているものとそうでないものもあるので、注意が必要です。
別れていないものの場合、設定を連鎖的に考慮する必要がでてきます。例えばALB < Webサーバ < APサーバ < DBとなるように考慮するという形です。
WAF設定が重複していないか?
CloudFrontとALBを直列で組み合わせて使う時、両方に同じルールを登録してしまっているケースを見ます。余分なコストがかかるだけなので注意しましょう。
主な修正方法
それぞれのルールどこに設定すべきかを見直したうえで適切に配置しなおしましょう。
さいごに
最後までお読みいただきありがとうございました。
本記事が、皆様の業務の一助となれば幸いです。