Amazon Web Services ブログ
閉域網で AWS のサーバーレスアーキテクチャ (SPA) を利用する方法
近年、生成 AI アプリケーションの社内利用など、セキュリティ要件が厳しいエンタープライズ企業や公共機関でも、新しいアプリケーションを構築する機会が増えています。
サーバーレスアーキテクチャは、使った分だけの従量課金や高い拡張性から、新規アプリケーション立ち上げに適した選択肢として広く採用されています。
しかし、閉域網 (インターネット非接続環境) で AWS の代表的なサーバーレスアーキテクチャを利用しようとすると、いくつかの制約があります。
本記事では、代表的な構成例をもとに、これらの課題とそのワークアラウンド (回避策) をご紹介します。
代表的なサーバーレス SPA 構成例
以下は、Amazon Cognito を使ったユーザー認証と静的 Web ホスティングを組み合わせた SPA (Single Page Application) の例です。
AWS CDK と React を利用した上記構成の実装例として下記のリポジトリもご参考ください。
https://github.com/aws-samples/aws-react-spa-with-cognito-auth
主な構成要素は以下の通りです。
- ユーザー認証: Amazon Cognito(User Pool / Identity Pool)
- 静的 Web ホスティング: Amazon S3 + Amazon CloudFront (React / Vue などの SPA フレームワークで実装)
- API 実装: Amazon API Gateway + AWS Lambda
フロントエンドのログイン画面やサインアップ画面の実装においても、React や Vue といった代表的な SPA のフレームワークでは Amplify Component が提供されており、ユーザー認証の実装が容易になっています。
閉域網でサーバーレスアーキテクチャ (SPA) を扱うときの課題
本記事で想定する閉域網の要件例は下記の通りです。
- ユーザー端末からインターネットへの直接アクセスが不可
- Amazon VPC にInternet Gateway をアタッチできない
- 例えば、AWS Control Tower で下記のようなコントロールが適用されている場合があります。
- Disallow internet access for an Amazon VPC instance managed by a customer
この要件の場合、代表的な SPA 構成において機能しない箇所を確認しましょう。SPA における通信の流れは以下のようになります。
1. CloudFront へアクセスし、静的コンテンツをダウンロード
2. User Pool Endpoint から IDトークン、アクセストークン等を取得
3. ID Pool Endpoint から IAM の一時的な認証情報 を取得
4. API の認証方法に応じて、いずれかの認証情報 (ID トークン、アクセストークン、IAM の一時的な認証情報※) を利用して API へアクセス
5. フロントエンドから直接利用する AWS サービスの場合、 AWS の一時認証情報を使ってアクセス
この構成を閉域網から利用する場合、1. ではCloudFrontが閉域網からアクセスできず、2.-3. はAmazon Cognito が PrivateLink に対応していないため、ユーザーの端末でアプリケーションが正常に動作しません。
※詳しくは API Gateway で REST API へのアクセスを制御および管理する をご参照ください。
閉域網でサーバーレスアーキテクチャを利用するための回避策
閉域網で同様のサーバーレスアーキテクチャを利用する場合、下記のような構成例が考えられます。
静的 Web ホスティング
静的コンテンツの配信では、2つの方法が考えられます。
a. Application Load Balancer と Amazon S3 を利用する方法
Application Load Balancer に、ターゲットとして Amazon S3 の Interface Endpoint の IP アドレスを指定すると、SPA のコンテンツを表示することができます。
ALB に AWS Certificate Manager で発行した証明書をアタッチすることにより、カスタムドメインを利用しつつ、HTTPS を使ったセキュアな通信を行うことができます。
この方法を利用すると、コンテナ や AWS Lambda 等の Compute リソースを利用せずに SPA のコンテンツを配信できますが、いくつかの制約があります。
- 静的コンテンツが配置してあるパス index.html 以外にアクセスされた際、正しくルーティングできず、404 エラーとなるため、SPAのフレームワークで HashRouter 等を利用する必要があります。URL は
https://example.com/index.html#home
のような表示となります。 - Amazon S3 のバケット名とカスタムドメイン名を同一にする必要があります。Amazon S3 のバケット名はパーティション内のすべての AWS リージョンのすべての AWS アカウント全体で一意である必要があるため、利用したいドメイン名のバケット名が作成されていないか確認が必要です。
- ALB のヘルスチェックの設定に工夫が必要です。ヘルスチェックの成功コードに 200 以外の値を設定する必要があります。
詳しくは VPC エンドポイントを介して Amazon S3 バケットへのプライベートアクセスを設定するや ALB、S3、PrivateLinkによる内部HTTPS静的ウェブサイトのホスティング をご参照ください。
Amazon S3 へのリクエストを中継するという観点で同様の方法として、 Amazon API Gateway と Amazon S3 を利用する方法も考えられます。詳しくは Amazon S3 を使用して、API Gateway をプロキシとして使用する静的ウェブサイトをホストする方法を教えてください。 をご参照ください。
b. Application Load Balancer と Fargate を利用する方法
Amazon ECS と Fargate を組み合わせて静的コンテンツを配信することもできます。
この場合、AWS Fargate で動くプログラムでindex.html
以外にアクセスがあった場合のルーティングを制御できるため、 BrowserRouter を利用できます。例えば、URL は https://example.com/home
のような表示となります。
実装例はこちらをご参照ください。
https://github.com/aws-samples/generative-ai-use-cases/tree/main/packages/cdk/fargate-s3-server
ユーザー認証
a. Amazon Cognito ユーザープールを利用したユーザー認証
Amazon Cognito を利用してユーザー認証を行うためには cognito-idp.ap-northeast-1.amazonaws.com
へのアクセスが必要となります。
閉域網からのアクセスを実現するために、API Gateway での REST API の HTTP 統合を利用します。HTTP 統合を利用すると特定の HTTP エンドポイントへのアクセスを簡単に Proxy することができます。
なお、 Amazon API Gateway から Amazon Cognito の通信は、パブリックエンドポイントへの通信となりますが、通信は AWS グローバルネットワークにとどまります。詳しくはよくある質問 – Amazon VPC | AWS をご参照ください。
Amazon API Gateway での設定例は下記のようになります。
この方法を利用した場合でも、フェデレーションエンドポイントへのアクセスはできないため、サードパーティーの ID プロバイダーによるユーザープールのサインイン は実現できないことに注意が必要です。
b. フロントエンドから AWS リソースへのアクセス
フロントエンドから AWS サービスの API を直接利用したい場合 (Amazon Transcribe を利用したリアルタイム書き起こしなど) 、IAM の一時的な認証情報を利用する必要があります。
Amazon Cognito では、Amazon Cognito アイデンティティプール を利用して IAM の一時的な認証情報を払い出すことができます。
この機能を利用するには cognito-identity.ap-northeast-1.amazonaws.com
へのアクセスが必要です。a. Amazon Cognito ユーザープールを利用したユーザー認証 と同様に、API Gateway の HTTP 統合を利用すれば閉域網からアクセスできる ID Pool のエンドポイントを作成することができます。
AWS CDK での実装例はこちらをご参照ください。
https://github.com/aws-samples/generative-ai-use-cases/blob/main/packages/cdk/lib/construct/closedNetwork/cognito-private-proxy.ts
c. フロントエンド側の設定
API Gateway を使って、Amazon Cognito のための独自エンドポイントを設定できた後、フロントエンドで独自のエンドポイントを利用する設定をします。Amplify JS を利用している場合、下記の設定で独自のエンドポイントを利用する設定を追加できます。
フロントエンド側のコード例
Amplify.configure({
Auth: {
Cognito: {
userPoolId: "USER POOL ID",
userPoolClientId: "CLIENT ID",
identityPoolId: "ID POOL ID",
userPoolEndpoint: "API Gateway Domain for User Pool",
identityPoolEndpoint: "API Gateway Domain for ID Pool",
},
}
});
Amplify JS のバージョンは aws-amplify@6.15.0 以上の必要がある点にご注意ください。
まとめ
閉域網で AWS のサーバーレス SPA を構築する際の課題と解決策を紹介しました。Amazon Cognito が PrivateLink に対応していない点や、閉域網から CloudFront へアクセスできないといった制約に対し、ALB + S3 または ALB + Fargate による静的コンテンツ配信、API Gateway の HTTP 統合を活用した Cognito エンドポイントのプロキシ化、Private API モードの活用などの回避策が有効です。これらの方法を組み合わせることで、セキュリティ要件の厳しい環境でも最新のサーバーレスアプリケーションを使った SPA の開発が可能になります。
著者について