1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】デジタル庁の生成AI基盤「源内(GenAI)」でRAG環境を構築してみた

1
Posted at

これの続きを行います。
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で入ります。
チーム管理から作成を実行します。

適当な名前でチームを作成します。

AIアプリの作成ボタンを押下します。

APIリクエストのデータ形式(JSON)は以下のように設定します。
またエンドポイントとキーはCFnの出力から得た内容を記載します。

{"question": {"type": "textarea", "title": "質問", "desc": "これは、源内RAGです。ドキュメントに関する質問を入力してください", "required": true}}

AIアプリを作成できました。

動作確認

実際にRAGを試してみます。S3にファイルを格納します。
Bedrockからナレッジベースを開きます。今回はsharedのを使っているのでそちらを開きます。

ソースリンクを押下します。

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

今回は育児休業等給付の内容と支給申請手続<厚生労働省>を使用します。

アップロードしました。

Bedrockのナレッジベースから同期を実行します。

源内WebからRAGを試してみます。
回答が返ってくればOKです。

削除手順

RAG環境は以下のコマンドを実行します。RAG環境だけではなく、Web側も削除しましょう。
このコマンド一発できれいさっぱり消えます。

root@ubuntu-cui:~/genai-ai-api/aws/query-expansion-rag# npx cdk destroy --all -c env=-dev --force
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?