CloudFront+ALB 構成のオリジンアクセスをカスタムヘッダーで制限する
概要
本記事のゴール
- CloudFront + Application Load Balancer(ALB) 構成のオリジンであるALB へのアクセスを制限する方法を紹介します。
- CloudFront + ALB 構成は、ALB が提供するウェブアプリケーションに関して、CloudFront がオブジェクトをキャッシュしてクライアントへ提供することでALB の負荷の低減や、他にもレイテンシーのレイテンシーの改善、DDoS 攻撃の緩和が可能です。しかし、クライアントが直接オリジンである ALB にアクセスした場合、これらのメリットが得られません。
- 今回、CloudFront+ALB 構成のオリジンアクセスを以下の方法で、堅牢に実現します。
- 先ず、Application Load Balancer に設定するセキュリティグループのインバウンドルールに、CloudFront のグローバル IPアドレスのみ許可します。ALBは、CloudFront 以外のアクセスを受け付けません。
- 次に、CloudFront からオリジンにリクエストを転送する際にカスタムヘッダーを付与します。ALB では、リスナールールを設定し、特定のカスタムヘッダーのみを処理するルールを登録します。
- この方法で、CloudFront+ALB 構成のオリジンアクセスを堅牢にします。
システム構成概要
- 今回の記事に記載するシステム構成は以下の通りです。
- ALB のリスナールールにおいて正しいリクエストであった場合に、固定レスポンスの 200 を返します。一般的には、正しい転送先であるターゲットグループを設定します。
- ALB のリスナールールでALB に不正なリクエスト(特定のカスタムヘッダーが設定されていないリクエスト)があった場合に、403 を返します。
CloudFront+ALB 構成のオリジンアクセスを堅牢にする手順
CloudFront、ALB を準備する
- オリジンアクセスを制限する前に、基本的な構成であるCloudFront+ALB 構成を準備します。CloudFront およびALB の作成については、こちらの記事では省略します。
- 今回は、オリジンにアクセスする際のプロトコルを「HTTPのみ」に設定しています。オリジンアクセスにHTTPS プロトコルを使用する場合は、ビヘイビアのキャッシュポリシーの設定が必要、かつ後述のセキュリティグループに使用するポート番号を443 とします。
ALB セキュリティグループでCloudFront のGlobal IP のみを許可する
- ALB に設定するセキュリティグループを編集し、インバウンドルールにCloudFront のGlobal IP アドレスが登録されているマネージドプレフィックスリストを指定します。
- セキュリティグループの「インバウンドのルールを編集」を選択し、「ルールを追加」を選択、タイプに「HTTP」を選択(オリジンアクセスがHTTPS の場合はHTTPS を選択)、ソースに「カスタム」を選択、最後にソースの値に「プレフィックスリスト (ap-northeast-1は pl-58a04531) 」を選択します。
- これは、AWS マネージドプレフィクスリストで、CloudFront のグローバルに分散されたオリジン向けサーバーの IP アドレス範囲が含まれています。
- 基本的には、このマネージドプレフィックスリスト以外は選択しませんが、必要に応じて疎通テスト用のIPアドレスを指定します。
CloudFrontにカスタムヘッダーを付与する
- 次に、CloudFront の設定を変更します。CloudFront のディストリビューションを選択し、オリジンを選択、「編集」を押します。
- 「カスタムヘッダーを追加 – オプション」のヘッダー名、値 にカスタムヘッダーをセットします。今回は、AWSドキュメントのサンプルに記載されている値を使用し、ヘッダー名を “X-Custom-Header" としました。
- 「変更を保存」を選択します。
- セキュリティを高める際には、カスタムヘッダーの値を定期的に変更します。
ALB にリスナールールを設定し、カスタムヘッダーで制限する
- ロードバランサーにて対象のALB リソースを選択し、「リスナーとルール」を選択、対象のリスナーを選択します。
- リスナールールにて、「ルールを追加する」を選択します。
- ルール条件の定義に進み、「条件の追加」を選択します。
- 条件の選択に「HTTPヘッダー」を選択し、HTTP ヘッダー名、HTTP ヘッダー値を指定します。
- 次に進み、ルールアクションの定義を行います。今回は、「固定レスポンスを返す」を選択していますが、本来は正しい転送先であるターゲットグループの設定が一般的かと思います。
- ルールの優先度を設定します。今回は “1" を指定しています。複数のルールがある場合は適切に設定ください。
- 次に進み、以下の画面で「作成」を選択します。
- 続いて、"デフォルト" のルールを選択し、「アクション」→「ルールの編集」を選択します。
- こちらは不正なリクエストを想定しているため、デフォルトアクションとして、「固定レスポンスを返す」、「レスポンスコード」に403を選択します。「変更内容の保存」を選択します。
- 最終的に、今回は以下のリスナールールを設定しました。
CloudFront+ALB 構成のオリジンアクセス制限をテストする
- それでは、CloudFront+ALB 構成のオリジンアクセスが制限されたかを疎通テストします。
CloudFront へ疎通テストする(正常ケース)
- CloudFront のドメイン名にアクセスします。
ブラウザのアクセス
- ブラウザからアクセスし、200 (レスポンスにセットした “Hello.") が表示されました。
curl コマンドのアクセス
- curlコマンドからアクセスし、200 が返却されました。
niikawa@niikawa1:~$ curl https://d21x31w46quoly.cloudfront.net -vv
* Rebuilt URL to: https://d21x31w46quoly.cloudfront.net/
* Trying 99.xx.xx.xx...
* TCP_NODELAY set
* Connected to d21x31w46quoly.cloudfront.net (99.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=*.cloudfront.net
* start date: Oct 10 00:00:00 2023 GMT
* expire date: Sep 19 23:59:59 2024 GMT
* subjectAltName: host "d21x31w46quoly.cloudfront.net" matched cert's "*.cloudfront.net"
* issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x558cf443c620)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET / HTTP/2
> Host: d21x31w46quoly.cloudfront.net
> User-Agent: curl/7.58.0
> Accept: */*
>
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
< HTTP/2 200
< content-type: text/plain; charset=utf-8
< content-length: 7
< server: awselb/2.0
< date: Sat, 02 Dec 2023 01:17:54 GMT
< x-cache: Miss from cloudfront
< via: 1.1 33a8c80e33219ff09d001534e1f845c4.cloudfront.net (CloudFront)
< x-amz-cf-pop: NRT20-C3
< x-amz-cf-id: XHzOulVfPGV71wCxOFWjHTksn-687ZU3-ObgJjhhdtsGJgHO9c6rRQ==
<
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection #0 to host d21x31w46quoly.cloudfront.net left intact
Hello.
ALB へ疎通テストする(異常ケース1)
- ALB のドメイン名にアクセスします。
ブラウザのアクセス
- ブラウザからアクセスしましたが、クライアントのIPアドレスは、ALB のセキュリティグループで許可されていないため、応答がありません。
curl コマンドのアクセス
- curlコマンドからアクセスしても応答が返りません。
niikawa@niikawa1:~$ curl niikawa-test-alb-559810170.ap-northeast-1.elb.amazonaws.com
curl: (7) Failed to connect to niikawa-test-alb-559810170.ap-northeast-1.elb.amazonaws.com port 80: Connection timed out
ALB へ疎通テストする(異常ケース2)
- テストの目的で、ALB のセキュリティグループにクライアントのIP を追加します。
ブラウザのアクセス
- ブラウザからアクセスし、403 が表示されました。
curl コマンドのアクセス
- curlコマンドからアクセスし、403 が返却されました。
niikawa@niikawa1:~$ curl http://niikawa-test-alb-706076898.ap-northeast-1.elb.amazonaws.com -vv
* Rebuilt URL to: http://niikawa-test-alb-706076898.ap-northeast-1.elb.amazonaws.com/
* Trying 52.xx.xx.xx...
* TCP_NODELAY set
* Connected to niikawa-test-alb-706076898.ap-northeast-1.elb.amazonaws.com (52.xx.xx.xx) port 80 (#0)
> GET / HTTP/1.1
> Host: niikawa-test-alb-706076898.ap-northeast-1.elb.amazonaws.com
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: awselb/2.0
< Date: Sat, 02 Dec 2023 01:40:53 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 0
< Connection: keep-alive
<
* Connection #0 to host niikawa-test-alb-706076898.ap-northeast-1.elb.amazonaws.com left intact
- これで、CloudFront+ALB 構成のオリジンアクセスを堅牢に変更することが出来ました。
- さらにセキュリティを高めたい場合は、オリジンアクセスを HTTPS に変更すること、CloudFront が付与するカスタムヘッダーの値を定期的に変更こととなります。他に、リスナールールにパス等のルールを追加しても良いでしょう。