ガバメント AI 源内(genai-web)を閉域ネットワークでも動作するように、源内のフロントエンドを CloudFront から ALB + ECS Fargate に変更し、Lambda を VPC 内へ配置するようにした上で AWS サービスにはインターフェース VPC エンドポイントで到達できるよう変更したフォーク(閉域モード版源内)を作りました。
このフォークは、VPC エンドポイントを含めて必要な AWS リソースを全て CDK で作成できるようになっています。
しかし、いざガバメントクラウドのような閉域ネットワークに閉域モード版源内をデプロイしようとした時に、いくつか注意点が分かりました。
閉域モード版源内を閉域ネットワークにデプロイする時の注意点とは
オンプレミスまでのルートの確保
閉域モード版源内でデプロイされるのは単独の VPC(以下「源内 VPC」)であるため、オンプレミスとのネットワーク接続を別途作る必要があります。
ガバメントクラウドの閉域ネットワークでは、Direct Connect でオンプレミスと AWS が接続されています。また、複数の VPC が接続されることから、Direct Connect Gateway (DXGW) と Transit Gateway (TGW) を使うことが多いです。そして、DXGW と TGW は、ネットワークアカウントという共有リソース用のアカウントに集約することが一般的です。
そのため、閉域モード版源内をデプロイした後、CDK Deploy とは別の手順で、源内 VPC に作成されたプライベートサブネットと TGW をアタッチメントで接続し、同様に源内 VPC に作成された VPC ルートテーブルへオンプレミスへのルートを登録することにします。
インターフェース VPC エンドポイントの名前解決
閉域モード版源内では、CDK で必要な VPC エンドポイントをデプロイするようになっています。
しかし、ガバメントクラウドの閉域ネットワークでは、ネットワークアカウントに VPC(以下「共有リソース VPC」)を作成し、Route 53 インバウンドエンドポイントやその他インターフェース型 VPC エンドポイントを集約させる構成が多く見られます。
また、共有リソース VPC の Route 53 インバウンドエンドポイントは、AWS 環境の名前解決に必要なオンプレミスの DNS リゾルバーからの条件付きフォワード先に設定されているケースが多いです。
そのため、閉域モード版源内で必要な VPC エンドポイントをオンプレミスからも名前解決させるには、主に以下のパターンが考えられます。
- 源内 VPC に作成したインターフェース型 VPC エンドポイントのうち、オンプレミスのクライアントから直接アクセスさせる必要があるもののみ、エンドポイントと同名の Route 53 Private Hosted Zone (PHZ) を作成し、共有リソース VPC へ関連付けを行う
- CDK でインターフェース型 VPC エンドポイントを作成するのをやめて、全て共有リソース VPC へ作成するようにし、エンドポイントと同名の Route 53 PHZ を作成し、源内 VPC へ関連付けを行う
コスト効率を考えると後者の方がよいですが、この場合 CDK を修正しなければならないので、今回は前者のパターンで閉域モード版源内をデプロイしてみます。
構成図は以下のとおりです。
閉域モード版源内のデプロイ手順
事前準備
ランタイム等のインストール
Node.js, AWS CLI, jq, Docker をインストールします。手順は割愛します。
依存関係のインストール
閉域モード版源内のルートディレクトリで依存ライブラリをインストールします。
$ npm ci
CDK Bootstrap
初めて CDK を使う AWS アカウントやリージョンの場合、CDK Bootstrap を実行します。
$ npm -w packages/cdk run cdk -- bootstrap
Docker サービスの起動
ECS の Docker イメージをビルドするのに Docker が必要なので、Docker サービスを起動しておきます。
AWS Certificate Manager で Application Load Balancer 用の TLS 証明書を作成
事前に AWS Certificate Manager (ACM) で Application Load Balancer (ALB) 用の TLS 証明書を作成しておきます。手順は割愛します。
Elastic Container Registry のレジストリポリシーを修正
Elastic Container Registry (ECR) のプライベートレジストリにレジストリポリシーで制限をかけている場合、CDK からの操作を許可しておかないとデプロイできません。
具体的には以下の IAM ロールからの操作をレジストリポリシーの許可ルールへ追加する必要があります。
| IAM ロール | ロール名のパターン | ECR を使う場面 |
|---|---|---|
| CDK のイメージ発行ロール | cdk-hnb659fds-image-publishing-role-* |
デプロイ元マシンからのフロントエンド配信コンテナの push |
| Fargate タスク実行ロール | GenerativeAiUseCasesStack-* |
タスク起動時のイメージ pull |
Bedrock から Claude を初めて使う場合はユースケースの送信
源内では Bedrock から Claude のモデルを使うことがあるので、デプロイする AWS アカウントで初めて Bedrock から Claude のモデルを使う場合は、事前に Bedrock のマネジメントコンソールから任意の Claude のモデルのプレイグラウンドを開き、画面の指示に従ってユースケースを送信してください。
CDK のパラメーター等設定
テンプレートファイルの作成
以下のとおり、テンプレートファイルからデプロイする環境用のファイルを作成します。ここでは self-hosting-prod.ts というファイルを作成することにしました。
$ cd packages/cdk/env-parameters
$ cp self-hosting-template.ts self-hosting-prod.ts
self-hosting-prod.ts ファイルの閉域ネットワークに関する設定を抜粋します。設定内容はコメントのとおりです。
ここで、closedNetworkCertificateArn の値は、事前に ACM で発行していた証明書の ARN を指定します。
export const selfHostingProdParams: Partial<StackInput> = {
// ============================================================================
// Closed Network 設定(必須)
// ============================================================================
/**
* 新規 VPC の CIDR
* オプション
* デフォルト: '10.1.0.0/16'
*/
closedNetworkVpcCidr: '10.129.0.0/16',
/**
* Private Hosted Zone のドメイン名
* 必須: Yes
* ALB + ACM + Route53 で HTTPS を提供するために使用します
* 例: 'genai.example.internal'
*/
closedNetworkDomainName: 'genai.intra.morori.jp',
/**
* ACM 証明書 ARN
* 必須: Yes
* 注意: アプリのリージョン(modelRegion と同じ)で発行された証明書を指定してください。
* us-east-1 ではありません(CloudFront を使わないため)。
*/
closedNetworkCertificateArn:
'arn:aws:acm:ap-northeast-1:xxxxxxxxxxxx:certificate/xxxxxxxx',
/**
* 既存の Private Hosted Zone ID(任意)
* オプション
* 指定した場合は既存の Hosted Zone を利用し、ALB の A レコードはユーザーが
* 別途作成してください。指定しなければスタックが新規 PrivateHostedZone を作成します。
*/
// closedNetworkPrivateHostedZoneId: 'Z1234567890ABC',
/**
* 利用者端末(オンプレミス)側の CIDR リスト
* 必須: 専用線/VPN 越しのオンプレミス端末から利用する場合は Yes
* VPC エンドポイント共通 SG と ALB の SG の許可対象に追加されます。
* ブラウザは Cognito・API Gateway・Lambda・S3(署名付き URL)を VPC エンドポイント
* 経由で直接呼び出すため、未設定だとオンプレミス端末からはサインインもできません。
* 例: ['172.16.0.0/12', '192.168.10.0/24']
*/
closedNetworkAllowedClientCidrs: ['10.1.0.0/16','10.128.0.0/16'],
parameter.ts の修正
packages/cdk/parameter.ts の deploy_envs オブジェクトに、作成した設定ファイルをインポートして追加します。
ここではデプロイ先の環境を selfHostingProd としました。
import { selfHostingProdParams } from "./env-parameters/self-hosting-prod";
const deploy_envs: Record<string, Partial<StackInput>> = {
// 他の環境も追加可能
"-selfHostingProd": selfHostingProdParams,
};
デプロイ先リージョンの設定
packages/cdk/cdk.context.json の AWS アカウント ID の箇所を実際にデプロイするアカウントのものに修正します。
また、デプロイ先のリージョンとなっていることを確認してください。
{
"availability-zones:account=123456789012:region=ap-northeast-1": [
"ap-northeast-1a",
"ap-northeast-1c"
]
}
ローカルから CDK をデプロイ
事前に aws login コマンドなどでクレデンシャルを取得します。
$ aws login
CDK Deploy を実行します。env には先に設定した -selfHostingProd を指定します。
$ npm -w packages/cdk run cdk -- deploy --all --require-approval never -c env=-selfHostingProd
デプロイに成功すると、コンソールに以下のような出力があります。
源内 Web へサインインするためのユーザーの作成
デプロイが完了したら、Cognito のユーザープールに源内 Web へサインインするためのユーザーを追加します。
閉域モード版源内はセルフサインアップ機能を使用できないので、Cognito のユーザープールに直接マネジメントコンソールからユーザーを追加する必要があります。
セルフサインアップ機能を使わない場合の Cognito でのユーザー追加手順は以下のとおりです。
- デプロイ完了後に作成された Cognito User Pool の管理画面にアクセスし、以下の設定でユーザーを手動で登録してください
- 招待メッセージ: E メールで招待を送信を選択
- E メールアドレスを検証済みとしてマーク: チェックを入れる
- 仮パスワード: パスワードの生成を選択
- ユーザーを登録後、UserGroup グループにユーザーを追加してください
- 初回ログイン用のパスワードが記載されたメールを確認しパスワードを控えてください
digital-go-jp/genai-web / docs / アカウント登録 から引用
TGW アタッチメントの作成及び VPC ルートテーブルの追加
閉域モード版源内では VPC に 2 つのプライベートサブネットを作成します。
ここからは手動で、閉域モード版源内からオンプレミスと接続できるよう、オンプレミスまでのルートがある TGW にアタッチメント接続を作ります。
その後、2 つのプライベートサブネットに関連付けられている 2 つの VPC ルートテーブルに、オンプレミスと共有リソース VPC へのルートとして、ネクストホップを TGW としたルートを追加します。
参考に、CDK Deploy で出力された源内 VPC のサブネット ID とルートテーブル ID などをセットして CloudFormation で上記の作業を行う時の参考スクリプトは以下のとおりです。
AWSTemplateFormatVersion: 2010-09-09
Description: This template deploys a TGW Attachments for genai-web VPC.
Parameters:
VPC2Id:
Description: Please select the genai VPC ID
Type: AWS::EC2::VPC::Id
PrivateSubnet1Id:
Description: Please select the private subnet in the first Availability Zone
Type: AWS::EC2::Subnet::Id
PrivateSubnet2Id:
Description: Please select the private subnet in the second Availability Zone
Type: AWS::EC2::Subnet::Id
PrivateSubnet1RouteTableId:
Description: Please enter the genai route table 1 ID
Type: String
PrivateSubnet2RouteTableId:
Description: Please enter the genai route table 2 ID
Type: String
OnpremisesCidr:
Description: Please enter the Onpremises CIDR
Type: String
Default: 10.0.0.0/8
TGWId:
Description: Please enter the TGW ID
Type: String
VPC1Cidr:
Description: Please enter the Shared Resource VPC CIDR
Type: String
Default: 10.128.0.0/16
Resources:
# オンプレミス宛てのルートテーブルはネクストホップを TGW とする
PrivateSubnet1RouteTableRoute1:
Type: AWS::EC2::Route
DependsOn: TGWAttachment2
Properties:
DestinationCidrBlock: !Ref OnpremisesCidr
RouteTableId: !Ref PrivateSubnet1RouteTableId
TransitGatewayId: !Ref TGWId
# VPC1(共有リソース VPC)宛てのルートテーブルはネクストホップを TGW とする
PrivateSubnet1RouteTableRoute2:
Type: AWS::EC2::Route
DependsOn: TGWAttachment2
Properties:
DestinationCidrBlock: !Ref VPC1Cidr
RouteTableId: !Ref PrivateSubnet1RouteTableId
TransitGatewayId: !Ref TGWId
# オンプレミス宛てのルートテーブルはネクストホップを TGW とする
PrivateSubnet2RouteTableRoute1:
Type: AWS::EC2::Route
DependsOn: TGWAttachment2
Properties:
DestinationCidrBlock: !Ref OnpremisesCidr
RouteTableId: !Ref PrivateSubnet2RouteTableId
TransitGatewayId: !Ref TGWId
# VPC1(共有リソース VPC)宛てのルートテーブルはネクストホップを TGW とする
PrivateSubnet2RouteTableRoute2:
Type: AWS::EC2::Route
DependsOn: TGWAttachment2
Properties:
DestinationCidrBlock: !Ref VPC1Cidr
RouteTableId: !Ref PrivateSubnet2RouteTableId
TransitGatewayId: !Ref TGWId
#
# TGW アタッチメントを作成
#
TGWAttachment2:
Type: AWS::EC2::TransitGatewayAttachment
Properties:
Options:
DnsSupport: enable
SecurityGroupReferencingSupport: enable
SubnetIds:
- !Ref PrivateSubnet1Id
- !Ref PrivateSubnet2Id
Tags:
- Key: Name
Value: genai-tgw-attach-vpc-tokyo
TransitGatewayId: !Ref TGWId
VpcId: !Ref VPC2Id
Outputs:
TGWAttachment2:
Value: !Ref TGWAttachment2
Export:
Name: TGWAttachment2Id
源内 VPC 側のルートテーブル等が変更できたら、共有リソース VPC 側や TGW のルートテーブルに源内 VPC 向けのルートを追加してください。手順は割愛します。
なお、これらの変更は CDK でデプロイされたものへの変更になるため、CDK Destroy で削除する時は必ず先に上記のルートテーブル等を元に戻してから削除するようにしてください。
オンプレミスのクライアントから必要なエンドポイントを名前解決させる
閉域モード版源内へのクライアントからの接続について、フロントの ALB だけではなく、いくつかのインターフェース型 VPC エンドポイントへ直接アクセスする必要があります。
| # | 解決すべき DNS 名 | 解決先 | 用途 |
|---|---|---|---|
| 1 | cognito-idp.<リージョン>.amazonaws.com |
Cognito IDP エンドポイント | サインイン・トークン取得 |
| 2 | cognito-identity.<リージョン>.amazonaws.com |
Cognito Identity エンドポイント | 一時クレデンシャル取得 |
| 3 | *.execute-api.<リージョン>.amazonaws.com |
API Gateway エンドポイント | REST API(メイン + チーム管理) |
| 4 | lambda.<リージョン>.amazonaws.com |
Lambda エンドポイント | チャットストリーミング応答の直接 Invoke |
| 5 |
s3.<リージョン>.amazonaws.com と *.s3.<リージョン>.amazonaws.com
|
S3 Interface エンドポイント | 署名付き URL でのファイル送受信(バケット名付きの仮想ホスト形式で解決されるためワイルドカードが必要) |
| 6 |
closedNetworkDomainName に設定したドメイン |
内部 ALB | アプリ本体の画面 |
そこで、以下の手順でこれらのエンドポイントと同名の Route 53 PHZ を作成し、Route 53 インバウンドエンドポイントのある共有リソース VPC に関連付けることで、オンプレミスのクライアントからも上記エンドポイントを名前解決できるようになります。
- CDK デプロイ後、源内 VPC の VPC エンドポイントの DNS エントリを確認
- サービス名と同名の Route 53 PHZ を、共有リソース VPC に関連付けて作成
- 作成した Route 53 PHZ へ VPC エンドポイントへの Alias レコードを追加
ただし、既に共有リソース VPC に上記のインターフェース型 VPC エンドポイントがある場合はこの作業をしないでください。この作業をしてしまうと、既存の共有リソース VPC と連携しているオンプレミスや他の VPC の名前解決に影響があります。
Route 53 PHZ の作成が必要なものは以下のとおりです。
| ゾーン名 | 作成するレコード名 |
|---|---|
cognito-idp.ap-northeast-1.amazonaws.com |
ゾーン頂点(ゾーン名と同じ) |
cognito-identity.ap-northeast-1.amazonaws.com |
ゾーン頂点 |
execute-api.ap-northeast-1.amazonaws.com |
*.execute-api.ap-northeast-1.amazonaws.com(ワイルドカード) |
lambda.ap-northeast-1.amazonaws.com |
ゾーン頂点 |
s3.ap-northeast-1.amazonaws.com |
ゾーン頂点 と *.s3.ap-northeast-1.amazonaws.com の 2 レコード |
VPC エンドポイントの DNS エントリを確認
作成した VPC エンドポイントの DNS 名を確認します。
サービス名と同名の Route 53 PHZ を作成
サービス名と同名の Route 53 PHZ を、共有リソース VPC に関連付けて作成します。
作成した Route 53 PHZ へ VPC エンドポイントへの Alias レコードを追加
作成した Route 53 PHZ へ、先ほど確認した VPC エンドポイントの DNS 名への Alias レコードを追加します。
以下同様の手順となります。一部アスタリスクで設定するものがあることに注意してください。
以上の作業が終わったら、オンプレミスから閉域モード版源内へ接続できるはずです。
オンプレミスから閉域モード版源内への接続確認
以下のように源内のログイン画面が表示されればネットワーク接続は成功です。
Cognito でユーザープールに追加したユーザーでログインできれば、無事閉域モード版源内を使うことができます。
まとめ
閉域モード版源内をガバメントクラウドのような閉域ネットワークにデプロイする際は、主にネットワーク関係で追加の作業が生じます。
特に名前解決については、環境によりベストな方法が異なると思うので、事前にしっかり設計してからデプロイするようにしましょう。





