CloudFront+ALB 構成のオリジンアクセスをカスタムヘッダーで制限する

12月 1, 2023AWS,CloudFront,ELB

概要

本記事のゴール

  • 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 が付与するカスタムヘッダーの値を定期的に変更こととなります。他に、リスナールールにパス等のルールを追加しても良いでしょう。

 

関連資料