CloudFront経由のリクエストのみに制御する3つの手法
始めに
はじめまして、2024年4月より新卒入社しました、システム基盤チームの安藤と申します。
今回は、業務効率化を目指したAIアシスタント(チャットボット)基盤の構築において、CloudFrontを活用してオリジンへの直接アクセスを禁止する方法についてご紹介します。
弊社では、社内ITサポートを提供するためのSlackチャンネルが存在し、社員がITに関する質問やサポートを求める際に活用されていますが、社員数の増加に伴い、質問に回答する担当者の負担が増加しているという課題がありました。
この問題を解決するために、過去の質問内容や社内ドキュメントをBedrockを活用してナレッジベースとして構築し、それを活用したRAG(Retrieval-Augmented Generation)型のチャットボットを開発しています。このチャットボットは、質問に対して適切な回答を返すことで、担当者の負担軽減と社内の業務効率化を目指しています。
構成
私たちが構築した基盤では以下のアーキテクチャを採用しました。
(わかりやすく説明するために構成図を簡略化しています。)
構成の背景
現在、AIアシスタントは開発環境にデプロイされているため、外部からのアクセスを遮断しセキュリティを強化する必要がありました。この要件を満たすために、CloudFrontにAWS WAFを適用しています。
CloudFrontを前段に置いた理由
セキュリティ管理の一元化
WAFを各オリジンごとに個別設定する手間を省き、一括でポリシーを適用できます。セキュリティの運用効率を向上させることができます。
またLambda@Edgeを利用することもできるため、動的な処理や制御にも対応できます。
エンドポイントに名前をつけて管理できる
CloudFrontはカスタムドメインを使用できるので、AppSyncやAPI Gatewayのデフォルトエンドポイントは使用することなく、https://prod.api.example.com
のようなシンプルでわかりやすいURLを開発者に提供することができます。
WAFによるアクセス制御
WAF(Web Application Firewall)は、次のような役割を果たします。
- 特定のIPアドレスからのアクセス制御
- 悪意のあるリクエストや脆弱性からの防御
今回の環境は社内専用であるため、WAFを利用して社内からのアクセスのみを許可し、外部からのアクセスを防ぐことが求められました。
直接アクセスのリスクと対応策
この構成では、CloudFront経由でのアクセスを管理することで、セキュリティを強化しています。ただし、API GatewayやAppSyncのデフォルトエンドポイントが外部に漏れると、CloudFrontを経由せず直接アクセスされる可能性があります。
これはセキュリティリスクになり得るため、何らかの方法で防ぐ必要があります。
そのため、CloudFront経由以外のアクセスをブロックする仕組みを構築する必要がありました。
次のセクションでは、各オリジンにおいてCloudFront経由のアクセスのみを許可する方法について詳しく説明します。
オリジンへの直接アクセスを禁止する
このセクションでは各オリジン(API Gateway、AppSync、ALB)に対するアクセス制限手法について解説します。
API Gateway
構成図にないAPI Gatewayですが、EKS on Fargateを採用する前に使用していました。コンテナイメージをLambda関数にデプロイして動かしていました。
API Gatewayでは、デフォルトエンドポイントを無効化し、CloudFront経由のアクセスのみを許可する設定が可能です。
設定手順
- AWS マネジメントコンソールからAPI Gatewayコンソールにアクセスします。
- 該当のAPIを選択し、左側のメニューからAPIの設定を開きます。
-
APIの詳細セクションにある
編集
をクリックします。 -
デフォルトのエンドポイントを
非アクティブ
に切り替えます。 -
変更を保存
をクリックして設定を反映します。
デフォルトエンドポイントを無効化することで、リクエストはCloudFrontを経由しないとAPI Gatewayに届かなくなります。
AppSync
AppSyncはパブリックエンドポイントを利用しており、CloudFrontをAppSyncの前段に配置してアクセスを管理する構成を採用しています。
AppSyncにはAPI Gatewayのようにデフォルトエンドポイントを無効化する機能がありません。そのため、CloudFrontのカスタムヘッダーを用いて直接アクセスを防ぐ方法を解説します。この方法では、WAFを活用してカスタムヘッダーをチェックし、不正なリクエストを遮断します。
CloudFront側の設定
まず、CloudFrontにカスタムヘッダーを追加します。
- CloudFrontコンソールにアクセスし、オリジンからAppSyncのオリジンを選択します。
-
編集
をクリックし、ヘッダーを追加
を選択します。
ヘッダー名と値を設定し、変更を保存
をクリックします。
WAF側の設定
AppSyncに適用するためのWAFを設定していきます。
Web ACLの作成
- AppSyncコンソールで、設定 > API 設定に移動します。
-
編集
をクリックし、ウェブアプリケーションファイアウォールを有効化にチェックを入れます。 -
ウェブ ACL を作成
を選択し、以下を設定します。-
Resource type:
Regional resource
(AppSyncが存在するリージョンを指定) - Name: 任意の名前を入力
-
Resource type:
- 下部の
Add AWS resources
をクリックし、該当のAppSync APIを選択後、Add
をクリックしてリソースを追加します。 -
Next
をクリックして進みます。
ルールの作成
-
Rulesセクションで、
Add rules
をクリックし、以下を設定します:-
Rule type:
Rule builder
-
Statement:
-
Inspect:
Single Header
- Header field name: CloudFrontで設定したヘッダー名
- String to match: 設定したヘッダーの値
-
Match type:
Exactly matches string
-
Inspect:
-
Action:
Allow
-
Rule type:
- 設定を保存して戻ります。
デフォルトアクションの設定
Default web ACL action for requests that don't match any rules: Block
を選択し、Next
をクリックします。
その他の設定(Set rule priorityやConfigure metrics)はデフォルトのままで進めます。
最後に設定内容を確認し、Create Web ACL
をクリックして作成完了です。
動作確認
直接アクセスの確認
ターミナルからデフォルトエンドポイントにアクセスすると、リクエストが拒否されることを確認できます。
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"query": "query GetAiAssistants { listAiAssistants { items { id name model description } } }",
"variables": {}
}' \
https://xxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql
出力結果
{
"errors" : [ {
"errorType" : "WAFForbiddenException",
"message" : "403 Forbidden"
} ]
}
CloudFront経由の確認
次に、CloudFrontを経由してアクセスできることを確認します。
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"query": "query GetAiAssistants { listAiAssistants { items { id name model description } } }",
"variables": {}
}' \
https://xxxx.xxxx.xxxx.com/graphql
出力結果
{"data":{"listAiAssistants":{"items":[]}}}
ALB
最後にALBを対象に、Managed Prefix Listとリスナールールを用いて直接アクセスを防ぐ方法をご紹介します。
Managed Prefix List
Managed Prefix Listは、AWSサービス(例えばCloudFront)のIPアドレス範囲をまとめたリストです。このリストを使うことで、特定のサービスからのアクセスだけを簡単に制限できます。
確認方法
- AWSコンソールで、VPC > Prefix Lists に移動します。
-
CloudFront用のプレフィックスリスト(
pl-58a04531
)を確認します。
次にこちらを許可するセキュリティグループを作成します。
セキュリティグループ設定
ALBに割り当てるセキュリティグループを設定し、CloudFrontからのトラフィックのみを許可します。
-
セキュリティグループの作成
- AWSコンソールで EC2 > セキュリティグループ > セキュリティグループを作成 を選択します。
-
インバウンドルール:
- タイプ:
HTTPS
- ポート:
443
- ソース: プレフィックスリスト ID (
pl-58a04531
)
- タイプ:
-
セキュリティグループの適用
- ALBの詳細画面から「セキュリティ」タブに移動。
- 作成したセキュリティグループをアタッチします。
リスナールール設定
Managed Prefix ListはAWS全体で管理されているため、他のAWSアカウントが持つCloudFrontからもアクセス可能です。そのため、リスナールールでホストヘッダーをチェックし、正規のリクエストのみを許可します。
-
リスナールールの追加
- ALBのリスナーとルールタブに移動。
- HTTPSリスナーを選択し、新しいルールを追加します。
-
許可ルール設定
- 条件:
-
ホストヘッダー:
app.example.com
(許可するホスト名を指定)
-
ホストヘッダー:
- アクション:
- 許可された場合: ターゲットグループにリクエストを転送。
- 条件:
-
拒否ルール設定
- 条件:
-
ホストヘッダーが指定した値に一致しない場合(
ホストヘッダーが空白なども含む
)。
-
ホストヘッダーが指定した値に一致しない場合(
- アクション:
- 拒否(404エラーを返す)。
- 条件:
-
ルールの優先順位
- ホストヘッダーの条件を含むルールを優先し、それ以外のリクエストにはデフォルトで拒否ルールが適用されるように設定。
これにより、ALBはCloudFront経由のアクセスのみを許可するようになります。
まとめ、終わりに
本記事では、API Gateway、AppSync、ALBといった各種オリジンに対して直接アクセスを防ぐ手法をご紹介しました。これらの設定を通じて、CloudFrontを経由した正規のリクエストのみを許可するセキュアなアーキテクチャを実現できます。適切なアクセス制御を行うことで、アプリケーションの安全性を高め、セキュリティリスクを軽減できます。今回の内容が、皆さんのシステム設計や運用の参考になれば幸いです。
Discussion