初めまして、RevCommインフラチーム所属の平島と申します。
インフラチームは、主に当社で用いられる全マイクロサービスの共通基盤の設計・構築・運用を担当していますが、それに加えてSite Reliability Engineering (SRE) 業務も担っています。その SRE 業務の一環として、サービスのセキュリティ強化に順次取り組んでいます。
セキュリティ対策の一つひとつは、技術的には地味なことも多いです。しかし、どこかに対策漏れがあれば、情報漏洩などの重大インシデントを引き起こしかねません。ひとたびそのような事態が引き起こされれば、多額の損害賠償や信用失墜による顧客離れなどのネガティブインパクトが非常に大きいため、セキュリティ向上はビジネスでは非常に重要なタスクです。
今回は以前に取り組んだ AWS 上のセキュリティ対策である、CloudFront を経由しないApplication Load Balancer (ALB) へのアクセスを制限する方法についてご紹介します。
- 前提
- セキュリティ上の課題
- 方法 1:カスタムヘッダーを利用したリクエストの検証
- 方法 2:AWS Managed Prefix Listを利用した Security Group によるアクセス制限
- まとめ
前提
今回想定するのは、以下のような CloudFront-ALB-Elastic Container Service (ECS) で構成されたアーキテクチャです。ユーザからのリクエストはすべて CloudFront が受け付け、CloudFront-ALB 間は HTTPS で接続するものとします。
また、CloudFront にはWeb Application Firewall (WAF) を設定しており、リクエストの中身を検査します。
セキュリティ上の課題
ALB は世界各所に設置された CloudFront のサーバーからアクセスを受け付けるために、インターネットに向けて設置する必要があります。逆に言えば、ALB の DNS 名が外部に漏れてしまった場合、CloudFront を経由せずとも、直接 ALB の DNS 名を指定してアクセスすることが可能です。
これは CloudFront で設定した WAF によるリクエストの検査をすり抜けることと同義であり、セキュリティリスクとなりえます。したがって、CloudFront 以外からの ALB へのアクセスを何かしらの方法で防ぐ必要があります。
方法 1:カスタムヘッダーを利用したリクエストの検証
AWSによって公式に紹介されている方法で、当初はこちらを採用していました。
大まかな方針は以下の通りです。
- CloudFront において、到来したリクエストに対してカスタムヘッダーを付与する。カスタムヘッダーの値には、秘密の値を設定する。
- ALB のリスナールールを設定して、カスタムヘッダーの値が秘密の値と一致するか検証する。一致した場合はアプリケーションの Target Group にリクエストを転送し、一致しない場合は 403 エラーをクライアントに返す。
それでは、AWS Console 上で具体的な設定方法を見ていきます。
まず、CloudFront の設定を行います。オリジンである ALB にリクエストを転送する際に付与するカスタムヘッダーは、オリジンの新規作成/編集画面で設定することが可能です。
ここでは仮に、ヘッダー名を "x-cf-secret"、値を "test1234" としておきます。
次に、ALB Listener の設定を行います。CloudFront でオリジンとして設定した ALB のListener Rule を編集します。今回は、HTTPS (443) のリスナーを編集します。
まず、Target Group へ転送する既存ルールについて、それぞれ条件を設定します。「条件の追加」から「HTTP ヘッダー」を選択し、CloudFront で設定したカスタムヘッダー名と値をそれぞれ入力します。
さらに、一番最後のルール(デフォルトルール)では、常に 403 エラーを返すよう設定します。
以上で設定は完了です。実際にオリジンに直接リクエストを飛ばすと、403 が返ってくることが確認できます。
方法 1 のデメリット
カスタムヘッダーの情報が漏洩した場合、ヘッダーさえ付与していれば、CloudFront 以外からでもオリジンにアクセスできてしまいます。つまり、カスタムヘッダーは秘匿情報にあたりますが、方法 1 ではその秘匿情報が平文の状態で CloudFront、ALB Listener それぞれの設定に保存されることになります。そのため、開発者・運用担当者が容易に秘匿情報にアクセスできてしまいます。
秘匿情報へのアクセスを厳格に管理するなら、前記 2 つのリソースに対して、IAM Role などによる閲覧制限を行う必要があります。ただし、権限の設定が煩雑になる上、カスタムヘッダー以外の設定作業においても作業者が限定されてしまうなど、日常の開発・運用に支障をきたすおそれがあります。
方法 2:AWS Managed Prefix Listを利用した Security Group によるアクセス制限
2022年2月に CloudFront の Managed Prefix List が公開されたことで、方法 1 よりも簡単に目的を達成できることが判明しました。そのため、弊社では現在こちらの方法を採用しています。
AWS Managed Prefix List とは
AWS Managed Prefix List(以下、Prefix List)は複数の CIDR Block を一括して登録・管理することができる機能です。Security Group の Rule を作成する際に、ソースとしてこの Prefix LIst の ID を指定することができます。こうすることで、Prefix List に登録されたすべての CIDR Block に対してRule が適用されます。
また、いくつかの Prefix List がデフォルトとして用意されています。CloudFront の Prefix List はその 1 つで、CloudFront から ALB へリクエストが転送される際は、この Prefix List に登録された CIDR の範囲に含まれる IPアドレスからリクエストが送られることになります。
ここでは、CloudFront の Prefix List をソースとした Security Group を作成し ALB にアタッチすることで、CloudFront 以外からのアクセスを防ぎます。
設定
まず、VPC > マネージドプレフィックスリストより、CloudFront の Prefix List を確認します。Prefix List 名 "com.amazonaws.global.cloudfront.origin-facing" が、今回使用する Prefix List です。
次に Security Group を作成します。Inboud Rule では HTTPS のソースに先ほど確認した Prefix List の ID を指定します。
最後に、作成した Security Group を ALB にアタッチすれば完了です。
実際に curl を使ってオリジンにアクセスしようとすると、応答がないままタイムアウトします。方法 1 と挙動は異なりますが、接続を阻止できていることに変わりありません。
まとめ
今回は、CloudFront 以外からの ALB へのアクセスを防ぐ方法を 2 つ紹介しました。 方法1(カスタムヘッダーを用いるやり方)と比べて、方法 2 (Prefix List を用いるやり方) は、
- 秘匿情報の管理が不要
- 作業が少ない(Security Group を作成してアタッチするだけ)
という点でメリットが大きいです。結論として、何か特殊な事情がない限りは Prefix Listを用いる方法 2 をお勧めします。