これの続きを行います。
RAG環境を作ります。
前提条件
- 源内Web環境が既にデプロイ済みであること
- AWS CLIとCDKがインストール済みであること
- 以下のサービスのクォータ制限を確認済みであること:
- Amazon Bedrock
- OpenSearch Serverless
- Lambda
- 必要な権限:
- AdministratorAccess相当の権限を持つIAMユーザー
公式リポジトリ
参考サイト
環境構築
初期設定
源内Webはデプロイしておきます。
前回の設定で問題ありません。源内WebでデプロイされるNat GatewayのEIPをRAG環境デプロイで使用します。
root@ubuntu-cui:~# cd genai-web/
root@ubuntu-cui:~/genai-web# npm -w packages/cdk run cdk -- deploy --all --require-approval never -c env=-selfHostingDev
AWSアカウントのユーザにRoleを付与します。
カスタム信頼ポリシーでロールを作成します。RoleのJSONは以下となります。cli-userは源内Webをデプロイする際にaws configureで登録したユーザに置き換えてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::535002847634:user/cli-user"
},
"Action": "sts:AssumeRole"
}
]
}
AdministratorAccessポリシーをアタッチします。

Roleの名前はgenai-deploy-roleとしました。

これをIAMユーザに紐づけます。
ユーザの許可タブからインラインポリシーを作成を押下します。

JSON形式に変更して以下のように入力します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::535002847634:role/genai-deploy-role"
}
]
}
cli-user-genai-deploy-policyという名前で保存します。

以下のような設定になるように、ファイルを追記します。
root@ubuntu-cui:~# ls -la .aws/
total 16
drwxr-xr-x 2 root root 4096 May 12 15:31 .
drwx------ 12 root root 4096 May 19 12:08 ..
-rw------- 1 root root 34 May 19 12:15 config
-rw------- 1 root root 116 May 19 12:15 credentials
root@ubuntu-cui:~# cat .aws/credentials
[default]
aws_access_key_id = {アクセスキー}
aws_secret_access_key = {シークレットアクセスキー}
root@ubuntu-cui:~# cat .aws/config
[default]
region = ap-northeast-1
output = json
[profile genai-deploy]
role_arn = arn:aws:iam::535002847634:role/genai-deploy-role
source_profile = default
root@ubuntu-cui:~# aws sts get-caller-identity --profile genai-deploy
{
"UserId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Account": "535002847634",
"Arn": "arn:aws:sts::535002847634:assumed-role/genai-deploy-role/xxxxxxxxxxxxxxxxxxxxxxxx"
}
aws cli,cdkの他にpython3とpip3がインストールされている必要があるので、必要に応じてインストールしておきます。
root@ubuntu-cui:~# python3 -V
Python 3.12.3
root@ubuntu-cui:~# pip3 -V
pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)
リポジトリをクローンします。
その後、リポジトリのルートディレクトリに移動して、npm ciコマンドを実行します。
root@ubuntu-cui:~# git clone https://github.com/digital-go-jp/genai-ai-api
root@ubuntu-cui:~# ls -ltr
total 12
drwxr-xr-x 9 root root 4096 May 12 15:29 genai-web
drwxr-xr-x 7 root root 4096 May 17 10:07 ndlocr-lite-app
drwxr-xr-x 8 root root 4096 May 19 12:08 genai-ai-api
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# npm ci
設定ファイルの更新
更新すべきファイルは4つです
①genai-ai-api/aws/query-expansion-rag/config/apps/qerag.toml
②genai-ai-api/aws/query-expansion-rag/parameter.ts
③genai-ai-api/aws/query-expansion-rag/cdk.json
④genai-ai-api/aws/query-expansion-rag/lib/switch-role-stack.ts
genai-ai-api/aws/query-expansion-rag/config/apps/qerag.toml
root@ubuntu-cui:~# cd genai-ai-api/aws/query-expansion-rag/config/apps/
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/config/apps# ls
qerag.toml
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/config/apps# cp -p qerag.toml qerag.toml.org
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/config/apps# nano qerag.toml
修正箇所は以下。nameは基本なんでも問題ないと思いますが、長いと長いでエラーが出ます。
※Opensearch Serverlessの制限でエラーが出てた気がします。
# アプリケーション基本情報
name = "genai-rag"
# こっちは変えなくてもいいけど検証環境は変えている
# 回答生成の設定(デフォルトから変更する項目のみ)
[answer_generation]
modelId = "jp.amazon.nova-2-lite-v1:0"
diff結果
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/config/apps# diff qerag.toml qerag.toml.org
2c2
< name = "genai-rag"
---
> name = "Query Expansion RAG"
15c15
< modelId = "jp.amazon.nova-2-lite-v1:0"
---
> # modelId = "jp.anthropic.claude-sonnet-4-5-20250929-v1:0"
②genai-ai-api/aws/query-expansion-rag/parameter.ts
①で指定したnameに合わせて修正していきます。
また、源内Webでデプロイした時に作成されたNat GatewayのEIP(プライマリパブリックIPv4)をここで使用します。

root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/config/apps# cd ../..
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# ls
assets cdk.json jest.config.ts package-lock.json README.md tsconfig.json
bin config lib parameter.ts test
cdk.context.json custom-resources package.json README.en.md tools
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# cp -p parameter.ts parameter.ts.org
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# nano parameter.ts
修正箇所は以下です。ここのappNameの設定を①に合わせます。
"-dev": {
"qeRagAppNames": [
{"appName": "genai-rag", "appParamFile": "qerag.toml"}
],
// genai-webをデプロイした時に自動生成されるNATゲートウェイのパブリックIP(EIP)を指定
// 許可する送信元 IPv4 アドレス範囲を指定してください
allowedIpV4AddressRanges: [
"54.248.151.38/32", // TODO: Replace with your actual source IP address ranges
"52.68.33.49/32"
],
diff結果
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# diff parameter.ts parameter.ts.org
19,21c19,21
< "qeRagAppNames": [
< {"appName": "genai-rag", "appParamFile": "qerag.toml"}
< ],
---
> // "qeRagAppNames": [
> // {"appName": "qerag", "appParamFile": "qerag.toml"}
> // ],
28,29c28
< "54.248.151.38/32", // TODO: Replace with your actual source IP address ranges
< "52.68.33.498/32"
---
> "0.0.0.0/0", // TODO: Replace with your actual source IP address ranges
③genai-ai-api/aws/query-expansion-rag/cdk.json
switchRoleがDummyなので、デプロイに使用しているユーザを指定します。
apiについてはデフォルトがquota制限解除しないと達成できない値180秒となっているためquota制限内のものに修正します。今回は29秒に設定しています。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# ls
assets cdk.json jest.config.ts package-lock.json README.en.md tools
bin config lib parameter.ts README.md tsconfig.json
cdk.context.json custom-resources package.json parameter.ts.org test
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# cp -p cdk.json cdk.json.org
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# nano cdk.json
以下のように修正します。
"switchRoleName": "arn:aws:iam::535002847634:user/cli-user",
"apiLambdaIntegrationTimeout": 29,
diff結果は以下です。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# diff cdk.json cdk.json.org
34,35c34,35
< "switchRoleName": "arn:aws:iam::535002847634:user/cli-user",
< "apiLambdaIntegrationTimeout": 29,
---
> "switchRoleName": "DummyRole",
> "apiLambdaIntegrationTimeout": 180,
④genai-ai-api/aws/query-expansion-rag/lib/switch-role-stack.ts
デフォルトの設定だとSSO環境前提らしく?その設定を解除してSSO環境じゃなくてもデプロイできるようにします。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# cd lib/
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/lib# ls
api-waf-stack.ts rag-knowledge-base-stack.test.ts rag-s3vectors-kb-stack.ts switch-role-stack.ts
config-types.ts rag-knowledge-base-stack.ts shared-cmek-stack.ts utils
constructs rag-lambda-api-stack.ts stack-input.ts
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/lib# cp -p switch-role-stack.ts switch-role-stack.ts.org
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/lib# nano switch-role-stack.ts
switch-role-stack.tsの中身を以下とします。
import { CfnOutput, Stack, StackProps } from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
/**
* Properties for SwitchRoleForBedrockFlowsDeveloperStack
*/
interface SwitchRoleForBedrockFlowsDeveloperStackProps extends StackProps {
/** IAM Identity Center user names allowed to assume this role */
readonly idcUserNames: string[];
/** SSO role name or IAM ARN that can assume this role */
readonly switchRoleName: string;
/** Application name identifier */
readonly appName: string;
}
/**
* Stack for creating a switch role with minimal permissions for
* Bedrock Flow development, data source uploads, and Knowledge Base sync.
*
* 修正内容:
* - switchRoleName が "arn:aws:iam" で始まる場合は SSO パスを組み立てず
* ARN をそのまま Principal に使用する
* - SSO 未使用環境では withConditions(aws:userid)も付与しない
*/
export class SwitchRoleForBedrockFlowsDeveloperStack extends Stack {
/** The created IAM role for switching */
public readonly switchRole: iam.Role;
constructor(
scope: Construct,
id: string,
props: SwitchRoleForBedrockFlowsDeveloperStackProps
) {
super(scope, id, props);
const awsAccount = Stack.of(this).account;
const awsRegion = Stack.of(this).region;
// ✅ 修正:ARN判定の分岐
// switchRoleName が "arn:aws:iam" で始まる場合はそのまま使用
// それ以外は SSO ロールパスを組み立てる
const isDirectArn = props.switchRoleName.startsWith('arn:aws:iam');
const principalArn = isDirectArn
? props.switchRoleName
: `arn:aws:iam::${awsAccount}:role/aws-reserved/sso.amazonaws.com/${awsRegion}/${props.switchRoleName}`;
// ✅ 修正:SSO未使用時は withConditions を付与しない
// IAMユーザーARNを直接指定する場合、aws:userid 条件は不要
const assumeRolePrincipal = isDirectArn
? new iam.ArnPrincipal(principalArn)
: new iam.ArnPrincipal(principalArn).withConditions({
StringLike: {
'aws:userid': props.idcUserNames.map((user) => `*:${user}`),
},
});
// Define Bedrock permissions policy
const bedrockPolicy = this.createBedrockPolicy(awsRegion);
// Create the switch role
const developerRole = new iam.Role(this, 'SwitchRoleForBedrockFlowsDeveloper', {
assumedBy: assumeRolePrincipal,
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLogsReadOnlyAccess'),
],
inlinePolicies: {
BedrockBasePolicy: bedrockPolicy,
},
});
this.switchRole = developerRole;
// Output role name
new CfnOutput(this, 'SwitchRoleName', {
value: developerRole.roleName,
});
// Apply CDK-NAG suppressions
this.applyNagSuppressions(developerRole);
}
/**
* Create Bedrock policy with foundation model and listing permissions
*/
private createBedrockPolicy(region: string): iam.PolicyDocument {
return new iam.PolicyDocument({
statements: [
// Foundation model invocation
new iam.PolicyStatement({
actions: [
'bedrock:GetFoundationModel',
'bedrock:GetFoundationModelAvailability',
'bedrock:InvokeModel',
'bedrock:InvokeModelWithResponseStream',
],
resources: [`arn:aws:bedrock:${region}::foundation-model/*`],
}),
// Listing operations (require * resource)
new iam.PolicyStatement({
actions: [
'bedrock:ListFoundationModels',
'bedrock:ListIngestionJobs',
'bedrock:ListInferenceProfiles',
'bedrock:ListMarketplaceModelEndpoints',
'bedrock:ListProvisionedModelThroughputs',
],
resources: ['*'],
}),
// SageMaker hub access
new iam.PolicyStatement({
actions: ['sagemaker:ListHubContents'],
resources: [`arn:aws:sagemaker:${region}:aws:hub/SageMakerPublicHub`],
}),
],
});
}
/**
* Apply CDK-NAG suppressions for required permissions
*/
private applyNagSuppressions(role: iam.Role): void {
NagSuppressions.addResourceSuppressions(
role,
[
{
id: 'AwsSolutions-IAM4',
reason: 'CloudWatchLogsReadOnlyAccess managed policy is required for log viewing',
},
{
id: 'AwsSolutions-IAM5',
reason: 'Wildcard required for Bedrock List* operations, foundation model access, and KMS operations',
appliesTo: [
'Resource::*',
'Resource::arn:aws:bedrock:<AWS::Region>::foundation-model/*',
{ regex: '/^Resource::arn:aws:bedrock:.+::foundation-model\\/\\*$/g' },
'Action::kms:GenerateDataKey*',
'Action::kms:ReEncrypt*',
],
},
],
true
);
}
}
diffの結果です。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag/lib# diff switch-role-stack.ts switch-role-stack.ts.org
12c12
< /** SSO role name or IAM ARN that can assume this role */
---
> /** SSO role name that can assume this role */
21,25d20
< *
< * 修正内容:
< * - switchRoleName が "arn:aws:iam" で始まる場合は SSO パスを組み立てず
< * ARN をそのまま Principal に使用する
< * - SSO 未使用環境では withConditions(aws:userid)も付与しない
41,58c36,43
< // ✅ 修正:ARN判定の分岐
< // switchRoleName が "arn:aws:iam" で始まる場合はそのまま使用
< // それ以外は SSO ロールパスを組み立てる
< const isDirectArn = props.switchRoleName.startsWith('arn:aws:iam');
<
< const principalArn = isDirectArn
< ? props.switchRoleName
< : `arn:aws:iam::${awsAccount}:role/aws-reserved/sso.amazonaws.com/${awsRegion}/${props.switchRoleName}`;
<
< // ✅ 修正:SSO未使用時は withConditions を付与しない
< // IAMユーザーARNを直接指定する場合、aws:userid 条件は不要
< const assumeRolePrincipal = isDirectArn
< ? new iam.ArnPrincipal(principalArn)
< : new iam.ArnPrincipal(principalArn).withConditions({
< StringLike: {
< 'aws:userid': props.idcUserNames.map((user) => `*:${user}`),
< },
< });
---
> // Build assume role principal with SSO conditions
> const assumeRolePrincipal = new iam.ArnPrincipal(
> `arn:aws:iam::${awsAccount}:role/aws-reserved/sso.amazonaws.com/${awsRegion}/${props.switchRoleName}`
> ).withConditions({
> StringLike: {
> 'aws:userid': props.idcUserNames.map((user) => `*:${user}`),
> },
> });
124a110,111
> // Suppress for the role resource and all child resources
> // Includes KMS wildcard actions that may be added by other stacks
137a125
> // Also match resolved region values for foundation model resources
デプロイ
以下のコマンドを実行します。デプロイに20分~30分位かかるかなと思います。
スタックが作成されます。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# pwd
/root/genai-ai-api/aws/query-expansion-rag
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# npx cdk deploy --all -c env=-dev --require-approval never
✅ ApiWafStack
✨ Deployment time: 17.07s
✅ genai-rag-SwitchRoleStack
✨ Deployment time: 32.13s
✅ SharedCmekStack-dev
✨ Deployment time: 32.12s
✅ qerag-shared-1-SwitchRoleStack
✨ Deployment time: 47.47s
✅ genai-rag-qeRagKB
✨ Deployment time: 502.55s
✅ qerag-shared-1-qeRagKB
✨ Deployment time: 252.16s
✅ genai-rag-qeRagApi
✨ Deployment time: 93.59s
✅ qerag-shared-1-qeRagApi
✨ Deployment time: 93.55s
Outputs:
qerag-shared-1-qeRagApi.ApiEndpoint = https://sa4r5zwi2f.execute-api.ap-northeast-1.amazonaws.com/prod/invoke
qerag-shared-1-qeRagApi.ApiKeyId = 3m7oeotah8
qerag-shared-1-qeRagApi.SwitchRole = qerag-shared-1-SwitchRole-SwitchRoleForBedrockFlows-4Jtvb4yd9gBt
qerag-shared-1-qeRagApi.qeragshared1RagApiEndpoint371B1A7E = https://sa4r5zwi2f.execute-api.ap-northeast-1.amazonaws.com/prod/
CFnのスタックが作成されています。
今回はqerag-shared-1-qeRagApiというスタックを使用します。

出力タブを見ると、色々あると思います。ApiEndpointとApiKeyIdを控えます。

ApiKeyIdの値に対して以下のコマンドを実行します。
出力のvalueが必要になるので控えます。
aws apigateway get-api-key --api-key <KEY_ID> --include-value
例:
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# aws apigateway get-api-key --api-key 3m7oeotah8 --include-value
{
"id": "3m7oeotah8",
"value": "YCRqMDrmbN84UZurEOv273H2sPV24c8967pAVBBT",
"name": "qerag--qerag-4N1fZEhLbB0H",
"enabled": true,
"createdDate": "2026-05-19T13:33:49+00:00",
"lastUpdatedDate": "2026-05-19T13:33:49+00:00",
"stageKeys": [
"sa4r5zwi2f/prod"
],
"tags": {
"aws:cloudformation:logical-id": "qeragshared1RagApiqeragshared1RagApiKey6F2F1C28",
"aws:cloudformation:stack-id": "arn:aws:cloudformation:ap-northeast-1:535002847634:stack/qerag-shared-1-qeRagApi/358f2520-5387-11f1-ab18-0e011a4f37a5",
"aws:cloudformation:stack-name": "qerag-shared-1-qeRagApi"
}
}
源内Webにログインします。この時のユーザはSystemAdminGroupで入ります。
チーム管理から作成を実行します。

APIリクエストのデータ形式(JSON)は以下のように設定します。
またエンドポイントとキーはCFnの出力から得た内容を記載します。
{"question": {"type": "textarea", "title": "質問", "desc": "これは、源内RAGです。ドキュメントに関する質問を入力してください", "required": true}}
動作確認
実際にRAGを試してみます。S3にファイルを格納します。
Bedrockからナレッジベースを開きます。今回はsharedのを使っているのでそちらを開きます。

S3のバケットのdocsフォルダが開きます。ここにRAG用のファイルをアップロードします。

今回は育児休業等給付の内容と支給申請手続<厚生労働省>を使用します。
源内WebからRAGを試してみます。
回答が返ってくればOKです。

削除手順
RAG環境は以下のコマンドを実行します。RAG環境だけではなく、Web側も削除しましょう。
このコマンド一発できれいさっぱり消えます。
root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# npx cdk destroy --all -c env=-dev --force










