3
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?

ガバメント AI「源内」(genai-ai-api)を閉域の AWS 環境へデプロイしてみた

3
Posted at

デジタル庁が政府機関で実装を進めている生成 AI 利用環境であるガバメント AI「源内」について、その一部が先日オープンソースとして公開されました。

地方自治体側としても、将来的に源内をガバメントクラウドで使うことがあるのではないかと気になっているところです。

そこで早速、地方自治体のガバメントクラウドにある基幹システムで源内を使うようなケースを想定し、源内を閉域ネットワーク環境でデプロイできないか、Claude Code に相談しながら試してみました。

genai-ai-api の閉域 AWS 環境へのデプロイ検証の構成図

genai-ai-api.drawio.png

閉域ネットワーク環境へ genai-ai-api をデプロイするために、元の CDK から以下のとおり変更しています。

  • Lambda を VPC 内にデプロイする
  • Lambda 関数から Bedrock と KMS へ VPC エンドポイント経由でアクセスさせる
  • Lambda と統合した API Gateway を Private REST API に変更し、execute-api VPC エンドポイント経由で他の VPC やオンプレミスからアクセスさせるようにする
  • WAF が閉域ネットワークで使えないため削除(IP アドレス制限は VPC エンドポイントのセキュリティグループで代用する)

また、genai-ai-api は Bedrock Knowledge Base のベクトルストアに OpenSearch Serverless を使いますが、コスト削減のため、これを S3 Vectors へ変更しました。

アクセスの検証は、別アカウントのプライベートサブネットにある EC2 から Transit Gateway 経由で REST API のエンドポイントにアクセスして行います。

実運用の際は、この Transit Gateway にオンプレミスが繋がっており、オンプレミスからもアクセスがある想定です。

CDK の変更箇所(抜粋)

genai-ai-api の CDK に変更を加えた主な箇所を抜粋します。

VPC, Security Group, VPC エンドポイントの追加

Lambda 統合 API Gateway を Private REST API として VPC へデプロイするのに必要となる、VPC, Security Group, VPC エンドポイントを作成するコードを、NetworkStack クラスとして追加し、他のモジュール等から呼び出せるようにします。

具体的には設定した CIDR で VPC とプライベートサブネットを作成し、セキュリティグループも作成します。

また、プライベートサブネットから以下の VPC エンドポイントを作成します。

  • Bedrock
  • KMS
  • CloudWatch Logs
  • API Gateway (execute-api)
  • S3 (Gateway Endpoint)
import { CfnOutput, Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';

/**
 * Properties for NetworkStack
 */
export interface NetworkStackProps extends StackProps {
  /** CIDR block for the VPC (e.g. "10.130.0.0/20") */
  readonly vpcCidr: string;
}

/**
 * Stack that provisions the private network used by all RAG APIs.
 *
 * - VPC with private (isolated) subnets only across 2 AZs
 * - Security groups for Lambda and VPC interface endpoints
 * - Interface endpoints for Bedrock, KMS, CloudWatch Logs, and execute-api
 * - Gateway endpoint for S3
 *
 * No NAT gateway and no public subnets — all egress goes through VPC endpoints.
 */
export class NetworkStack extends Stack {
  public readonly vpc: ec2.Vpc;
  public readonly lambdaSecurityGroup: ec2.SecurityGroup;
  public readonly executeApiVpcEndpoint: ec2.InterfaceVpcEndpoint;

  // Hard-code AZs to avoid an AWS context lookup during synth.
  // Deploy region is fixed to ap-northeast-1 in bin/qe-rag-apis.ts.
  get availabilityZones(): string[] {
    return ['ap-northeast-1a', 'ap-northeast-1c'];
  }

  constructor(scope: Construct, id: string, props: NetworkStackProps) {
    super(scope, id, props);

    // VPC: private isolated subnets only, across 2 AZs
    this.vpc = new ec2.Vpc(this, 'Vpc', {
      ipAddresses: ec2.IpAddresses.cidr(props.vpcCidr),
      maxAzs: 2,
      natGateways: 0,
      subnetConfiguration: [
        {
          name: 'private',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
          cidrMask: 22,
        },
      ],
      // VPC flow logs to CloudWatch
      flowLogs: {
        toCloudWatch: {
          trafficType: ec2.FlowLogTrafficType.ALL,
          destination: ec2.FlowLogDestination.toCloudWatchLogs(),
        },
      },
    });

    // Security group attached to the Lambda functions.
    // Egress 443 only — outbound traffic targets VPC endpoints.
    this.lambdaSecurityGroup = new ec2.SecurityGroup(this, 'LambdaSg', {
      vpc: this.vpc,
      description: 'Security group for RAG Lambda functions',
      allowAllOutbound: false,
    });
    this.lambdaSecurityGroup.addEgressRule(
      ec2.Peer.ipv4(props.vpcCidr),
      ec2.Port.tcp(443),
      'HTTPS to VPC endpoints'
    );
    this.lambdaSecurityGroup.addEgressRule(
      ec2.Peer.ipv4('10.0.0.0/8'),
      ec2.Port.tcp(443),
      'HTTPS to on-premises networks via VPN/Direct Connect'
    );

    // Security group for VPC interface endpoints.
    // Inbound 443 from the Lambda security group only.
    const endpointSg = new ec2.SecurityGroup(this, 'EndpointSg', {
      vpc: this.vpc,
      description: 'Security group for VPC interface endpoints',
      allowAllOutbound: false,
    });
    endpointSg.addIngressRule(
      this.lambdaSecurityGroup,
      ec2.Port.tcp(443),
      'HTTPS from Lambda SG'
    );

    // Gateway endpoint for S3 (free, attached via route tables)
    this.vpc.addGatewayEndpoint('S3Endpoint', {
      service: ec2.GatewayVpcEndpointAwsService.S3,
    });

    const interfaceEndpointDefaults = {
      subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      securityGroups: [endpointSg],
      privateDnsEnabled: true,
    };

    // Bedrock runtime — Converse API
    this.vpc.addInterfaceEndpoint('BedrockRuntimeEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.BEDROCK_RUNTIME,
      ...interfaceEndpointDefaults,
    });

    // Bedrock agent runtime — Knowledge Base Retrieve / RetrieveAndGenerate
    this.vpc.addInterfaceEndpoint('BedrockAgentRuntimeEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.BEDROCK_AGENT_RUNTIME,
      ...interfaceEndpointDefaults,
    });

    // KMS — encryption operations against CMEK
    this.vpc.addInterfaceEndpoint('KmsEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.KMS,
      ...interfaceEndpointDefaults,
    });

    // CloudWatch Logs — Lambda log delivery
    this.vpc.addInterfaceEndpoint('LogsEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
      ...interfaceEndpointDefaults,
    });

    // execute-api — Private API Gateway invocation entry point
    this.executeApiVpcEndpoint = this.vpc.addInterfaceEndpoint(
      'ExecuteApiEndpoint',
      {
        service: ec2.InterfaceVpcEndpointAwsService.APIGATEWAY,
        ...interfaceEndpointDefaults,
      }
    );

    new CfnOutput(this, 'VpcId', {
      value: this.vpc.vpcId,
      description: 'VPC ID hosting the private RAG network',
    });

    new CfnOutput(this, 'ExecuteApiVpcEndpointId', {
      value: this.executeApiVpcEndpoint.vpcEndpointId,
      description: 'VPC endpoint ID used to invoke the private API Gateway',
    });

    NagSuppressions.addResourceSuppressions(
      this.vpc,
      [
        {
          id: 'AwsSolutions-VPC7',
          reason: 'VPC flow logs are enabled via the flowLogs option',
        },
      ],
      true
    );

    // EndpointSg only accepts ingress from the Lambda SG, but cdk-nag cannot
    // resolve the source SG ID at synth time and emits a false-positive warning.
    NagSuppressions.addResourceSuppressions(endpointSg, [
      {
        id: 'CdkNagValidationFailure',
        reason:
          'Ingress is restricted to the Lambda security group via SG reference; cdk-nag cannot resolve the SG token at synth time',
      },
    ]);
  }
}

Lambda 統合 API Gateway REST API を VPC にデプロイするように変更

RagLambdaApiStack クラスのオブジェクトで API Gateway の Lambda 統合 REST API を作成しているので、これに設定したい VPC, Security Group, VPC エンドポイントをプロパティとして扱えるようにします。

また、併せて閉域ネットワークでは WAF が使えないため、WAF を設定する箇所も削除します。

./aws/query-expansion-rag/lib/constructs/rag-lambda/index.ts
 // 前略
 import * as crypto from 'crypto';
 import * as toml from 'toml';
 import { spawnSync } from 'child_process';
 import { AssetHashType, Duration, RemovalPolicy, Stack } from "aws-cdk-lib";
+import * as ec2 from "aws-cdk-lib/aws-ec2";
 import * as lambda  from "aws-cdk-lib/aws-lambda";
 import * as iam from "aws-cdk-lib/aws-iam";
 import * as kms from "aws-cdk-lib/aws-kms";
 // 中略
 export interface RagLambdaProps {
   encryptionKey: kms.IKey;
   /** Bedrock regions allowed for model invocation (defaults to deploy region if not specified) */
   bedrockRegions?: string[];
+  // RagLambda クラスに VPC と Security Group を扱うインターフェースを追加
+  /** VPC to attach the Lambda function to */
+  vpc: ec2.IVpc;
+  /** Security group attached to the Lambda function */
+  securityGroup: ec2.ISecurityGroup;
 }

 export class RagLambda extends Construct {
       description: 'RAG Lambda function with query expansion and KB retrieval',
       memorySize: 512,
       timeout: Duration.seconds(900),
+      // RagLambda クラスに VPC と Security Group を扱うプロパティを追加
+      vpc: props.vpc,
+      vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
+      securityGroups: [props.securityGroup],
       environment: {
         KNOWLEDGE_BASE_ID: props.knowledgeBaseId,
         KB_NUM_RESULTS: '20',
 // 後略
./aws/query-expansion-rag/lib/rag-lambda-api-stack.ts
 // 前略
 import { CfnOutput, Duration, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
 import * as apigateway from 'aws-cdk-lib/aws-apigateway';
+import * as ec2 from 'aws-cdk-lib/aws-ec2';
 import * as iam from 'aws-cdk-lib/aws-iam';
 import * as kms from 'aws-cdk-lib/aws-kms';
 import * as logs from 'aws-cdk-lib/aws-logs';
-import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
 import { NagSuppressions } from 'cdk-nag';
 import { Construct } from 'constructs';
 import { RagLambda } from './constructs/rag-lambda';
 // 中略
 const API_QUOTA_CONFIG = {
 interface RagLambdaApiStackProps extends StackProps {
   /** Application name identifier */
   readonly appName: string;
-  /** ARN of WAF WebACL to associate with API Gateway */
-  readonly webAclArn: string;
   /** Bedrock Knowledge Base ID */
   readonly knowledgeBaseId: string;
   /** IAM role for switch role access */
 // 中略
 interface RagLambdaApiStackProps extends StackProps {
   readonly apiLambdaIntegrationTimeout: number;
   /** Bedrock regions allowed for model invocation (defaults to deploy region if not specified) */
   readonly bedrockRegions?: string[];
+  // RagLambdaApiStack クラスのオブジェクトに VPC, Security Group, VPC エンドポイントを扱うインターフェースを追加
+  /** VPC for the Lambda function */
+  readonly vpc: ec2.IVpc;
+  /** Security group for the Lambda function */
+  readonly lambdaSecurityGroup: ec2.ISecurityGroup;
+  /** VPC endpoint for execute-api — used to restrict the Private API */
+  readonly executeApiVpcEndpoint: ec2.IInterfaceVpcEndpoint;
 }
 // 中略
  export class RagLambdaApiStack extends Stack {
       appParamFile: props.appParamFile,
       encryptionKey: props.encryptionKey,
       bedrockRegions: props.bedrockRegions,
+  // RagLambdaApiStack クラスのオブジェクトに VPC, Security Group を扱うプロパティを追加
+      vpc: props.vpc,
+      securityGroup: props.lambdaSecurityGroup,
     });

     // Create API Gateway REST API
-    const restApi = this.createRestApi(props.appName, props.encryptionKey);
+    // Private REST API を作成するようにプロパティを設定
+    const restApi = this.createRestApi(
+      props.appName,
+      props.encryptionKey,
+      props.executeApiVpcEndpoint
+    );
 // 中略
 export class RagLambdaApiStack extends Stack {
     // Add gateway responses for CORS
     this.addGatewayResponses(restApi);

-    // Associate WAF WebACL
-    this.associateWaf(restApi, props.webAclArn);
-
     // Create POST /invoke endpoint
     const invokeEndpoint = this.createInvokeEndpoint(
       restApi,
 // 中略
 export class RagLambdaApiStack extends Stack {
   }

   /**
    * Create REST API with logging and CORS
    */
   private createRestApi(
     appName: string,
     encryptionKey: kms.IKey
+    executeApiVpcEndpoint: ec2.IInterfaceVpcEndpoint
   ): apigateway.RestApi {
     const accessLogGroup = new logs.LogGroup(this, `${appName}-ApiGatewayLogGroup`, {
       encryptionKey: encryptionKey,
 // 中略
 export class RagLambdaApiStack extends Stack {
       retention: logs.RetentionDays.ONE_WEEK,
     });

+    // REST API を VPC エンドポイント以外からアクセスできないように設定
+    // Resource policy: deny everything not coming through the designated VPC endpoint.
+    const resourcePolicy = new iam.PolicyDocument({
+      statements: [
+        new iam.PolicyStatement({
+          effect: iam.Effect.ALLOW,
+          principals: [new iam.AnyPrincipal()],
+          actions: ['execute-api:Invoke'],
+          resources: ['execute-api:/*'],
+        }),
+        new iam.PolicyStatement({
+          effect: iam.Effect.DENY,
+          principals: [new iam.AnyPrincipal()],
+          actions: ['execute-api:Invoke'],
+          resources: ['execute-api:/*'],
+          conditions: {
+            StringNotEquals: {
+              'aws:SourceVpce': executeApiVpcEndpoint.vpcEndpointId,
+            },
+          },
+        }),
+      ],
+    });
+
     return new apigateway.RestApi(this, `${appName}-RagApi`, {
-      endpointTypes: [apigateway.EndpointType.REGIONAL],
+      // REST API をプライベートに変更する
+      endpointConfiguration: {
+        types: [apigateway.EndpointType.PRIVATE],
+        vpcEndpoints: [executeApiVpcEndpoint],
+      },
+      policy: resourcePolicy,
       deployOptions: {
         dataTraceEnabled: true,
         metricsEnabled: true,
 // 中略
 export class RagLambdaApiStack extends Stack {
     });
   }

-  /**
-   * Associate WAF WebACL with API Gateway
-   */
-  private associateWaf(api: apigateway.RestApi, webAclArn: string): void {
-    new wafv2.CfnWebACLAssociation(this, 'ApiWafAssociation', {
-      resourceArn: api.deploymentStage.stageArn,
-      webAclArn: webAclArn,
-    });
-  }
-
 // 中略
 export class RagLambdaApiStack extends Stack {
     api: apigateway.RestApi,
     invokeResource: apigateway.Resource
   ): void {
-    NagSuppressions.addResourceSuppressions(api, [
-      {
-        id: 'AwsSolutions-APIG2',
-        reason:
-          'Request validation is implemented in the Lambda function with comprehensive input validation and error handling',
-      },
-    ]);
+    NagSuppressions.addResourceSuppressions(
+      api,
+      [
+        {
+          id: 'AwsSolutions-APIG2',
+          reason:
+            'Request validation is implemented in the Lambda function with comprehensive input validation and error handling',
+        },
+        {
+          id: 'AwsSolutions-APIG3',
+          reason:
+            'Private API Gateway accessed only via execute-api VPC endpoint; access is restricted by resource policy on aws:SourceVpce instead of WAFv2 (WAFv2 is not supported on Private REST APIs)',
+        },
+      ],
+      true
+    );
 // 後略
./aws/query-expansion-rag/bin/qe-rag-apis.ts
 // 前略
 import * as cdk from 'aws-cdk-lib';
 import { AwsSolutionsChecks } from 'cdk-nag'
 import { getParams, validateAppNames } from '../parameter';
 import { RagLambdaApiStack } from '../lib/rag-lambda-api-stack';
-import { ApiWafStack } from '../lib/api-waf-stack';
 // NetworkStack クラスのインポートを追加
+import { NetworkStack } from '../lib/network-stack';
 import { RagKnowledgeBaseStack } from '../lib/rag-knowledge-base-stack';
 import { RagS3VectorsKbStack } from '../lib/rag-s3vectors-kb-stack';
 import { SwitchRoleForBedrockFlowsDeveloperStack } from '../lib/switch-role-stack';
 // 中略
 const env = {
 // CDK-NAGの有効化
 cdk.Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));

-const waf = new ApiWafStack(app, `ApiWafStack`, {
+// 各 RagLambdaApiStack オブジェクトを作るときにプロパティに設定したい VPC と VPC エンドポイントを作成
+// Shared private network for all RAG APIs (VPC + endpoints)
+const network = new NetworkStack(app, `NetworkStack${params.env}`, {
   env: env,
-  allowedIpV4AddressRanges: params.allowedIpV4AddressRanges,
-  allowedIpV6AddressRanges: params.allowedIpV6AddressRanges,
-  allowedCountryCodes: params.allowedCountryCodes
+  vpcCidr: params.vpcCidr,
 });

 // ragAppNamesに定義されたAppName(プレフィックス)ごとにRole、KnowledgeBase、RAG APIを作成(個別CMEK)
 // 中略
 for (const appCfg of params.qeRagAppNames) {
   new RagLambdaApiStack(app, `${mergedParams.appName}-qeRagApi`, {
     env: env,
     appName: mergedParams.appName,
-    webAclArn: waf.webAclArn,
     knowledgeBaseId: kb.knowledgeBaseId,
     switchRole: swtichRoleStack.switchRole,
     logLevel: params.logLevel,
 // 中略
 for (const appCfg of params.qeRagAppNames) {
     encryptionKey: kb.encryptionKey,
     apiLambdaIntegrationTimeout: params.apiLambdaIntegrationTimeout,
     bedrockRegions: params.bedrockRegions,
     // VPC, Security Group, VPC エンドポイントを追加
+    vpc: network.vpc,
+    lambdaSecurityGroup: network.lambdaSecurityGroup,
+    executeApiVpcEndpoint: network.executeApiVpcEndpoint,
   });
 }
 // 中略
  if (params.qeRagAppNamesWithSharedCmek.length > 0) {
     new RagLambdaApiStack(app, `${mergedParams.appName}-qeRagApi`, {
       env: env,
       appName: mergedParams.appName,
-      webAclArn: waf.webAclArn,
       knowledgeBaseId: kb.knowledgeBaseId,
       switchRole: switchRole,
       logLevel: params.logLevel,
 if (params.qeRagAppNamesWithSharedCmek.length > 0) {
       encryptionKey: kb.encryptionKey,
       apiLambdaIntegrationTimeout: params.apiLambdaIntegrationTimeout,
       bedrockRegions: params.bedrockRegions,
       // VPC, Security Group, VPC エンドポイントを追加
+      vpc: network.vpc,
+      lambdaSecurityGroup: network.lambdaSecurityGroup,
+      executeApiVpcEndpoint: network.executeApiVpcEndpoint,
     });
   }
 }
 for (const appCfg of params.qeRagAppNamesWithS3Vectors) {
   new RagLambdaApiStack(app, `${mergedParams.appName}-qeRagApi`, {
     env: env,
     appName: mergedParams.appName,
-    webAclArn: waf.webAclArn,
     knowledgeBaseId: kb.knowledgeBaseId,
     switchRole: swtichRoleStack.switchRole,
     logLevel: params.logLevel,
 for (const appCfg of params.qeRagAppNamesWithS3Vectors) {
     encryptionKey: kb.encryptionKey,
     apiLambdaIntegrationTimeout: params.apiLambdaIntegrationTimeout,
     bedrockRegions: params.bedrockRegions,
     // VPC, Security Group, VPC エンドポイントを追加
+    vpc: network.vpc,
+    lambdaSecurityGroup: network.lambdaSecurityGroup,
+    executeApiVpcEndpoint: network.executeApiVpcEndpoint,
   });
 }
 // 後略

その他の設定

API Gateway の REST API のタイムアウトのデフォルトの上限値が 29 秒なのでこれに合わせて変更しました。RAG のような API の場合はタイムアウトを長くした方がよいので、AWS へ事前に上限緩和申請をして 180 秒しておくと良いかと思います。

また、CDK でデプロイされる IAM Role の中に、どの IAM Role からのスイッチロールを許可するか設定する箇所があり、そのため実際にデプロイ先のアカウントに存在している IAM Role を定義しておかないとデプロイに失敗します。

そのほか、VPC の CIDR をここで設定しています。

./aws/query-expansion-rag/cdk.json
     // 前略
     ],
     "qeRagAppNamesWithSharedCmek": [],
     "bedrockRegions": ["ap-northeast-1", "ap-northeast-3"],
-    "allowedIpV4AddressRanges": null,
-    "allowedIpV6AddressRanges": null,
-    "allowedCountryCodes": null,
     "idcUserNames": ["dummy-user"],
-    "switchRoleName": "DummyRole",
-    "apiLambdaIntegrationTimeout": 180,
+    // 実際に存在する IAM Role 名を設定する
+    "switchRoleName": "AWSReservedSSO_SwitchOnlyRole_xxxxxxxxxxxx",
+    /*
+    API Gateway  Private REST API のタイムアウト上限値に合わせて変更
+    AWS に事前に上限緩和申請をして 180 秒のままにするのが望ましい(検証環境のためそのままにした)
+    */
+    "apiLambdaIntegrationTimeout": 29,
+    // VPC  CIDR を定義
+    "vpcCidr": "10.130.0.0/20",
     "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
     "@aws-cdk/core:checkSecretUsage": true,
     "@aws-cdk/core:target-partitions": [
     // 中略
     "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
     "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true
   }
   // 後略

今回作成したコードは Github へアップしています。

genai-ai-api のデプロイ

デプロイ手順は開発元の手順と変わりません。プロジェクトルートにて以下のとおり実行します。

事前に aws login コマンドでクレデンシャルをセットしておきます。

$ aws login

依存関係のインストール

$ npm ci

CDK ブートストラップ

初めて CDK をデプロイする AWS環境(アカウント/リージョン)の場合のみ、一度だけ実行します。

$ cdk bootstrap

デプロイの実行

以下のコマンドでデプロイします。

$ cdk deploy --all -c env=-dev     # 開発環境
$ cdk deploy --all -c env=-stg     # ステージング環境
$ cdk deploy --all -c env=-prd     # 本番環境

デプロイが完了すると、REST API のエンドポイント URL や ApiKeyId が出力されます。

スクリーンショット 2026-04-29 16.56.57.png

ApiKeyId は REST API の認証に必要な API キーの取得に必要となるので、この画面からメモしておきます。

genai-ai-api の実行

CloudFormation のステータスを見てデプロイに成功していたら、早速 genai-ai-api のインターフェースにアクセスしてみます。

API キーの取得

genai-ai-api は HTTP の x-api-key ヘッダーに API キーをセットすることで認証する仕組みになっています。

API キーを取得するには、AWS CLI から以下のコマンドを実行します。CDK のデプロイ後に出力された ApiKeyId をセットしてください。

$ aws apigateway get-api-key --api-key <ApiKeyId> --include-value --query value --output text

リクエストの実行

コマンドに成功すると API キーの文字列が返ってくるので、これをセットして REST API へのリクエストを組み立てます。

ここで重要なのは、VPC の外から REST API にアクセスするためには、エンドポイント URL にそのままアクセスするのではなく、次のとおりリクエストを組み立てる必要があることです。

  • POST する URL はホスト部分を VPC エンドポイント(execute-api)の DNS 名に置換する
  • HOST ヘッダーに本来の REST API のエンドポイント URL のホスト部分をセットする

つまり、execute-api の VPC エンドポイントを名前解決できて、かつ返ってきた IP アドレスに到達できる環境からでなければデプロイした REST API にアクセスができないことになります。

今回は検証していませんが、オンプレミスや別の VPC から REST API へアクセスさせるために、Route 53 インバウンドエンドポイントと Route 53 Private Hosted Zone を使って管理しやすい名前でアクセスできるようにした方がよいと思われます。

ここでは検証用途のため、curl でリクエストを実行します。

$ curl -X POST "ホスト部分を execute-api の VPC エンドポイントの DNS 名に置換した REST API のエンドポイント URL" \
  -H "HOST: '本来の REST API エンドポイント URL のホスト部分'" \
  -H "Content-Type: application/json" \
  -H "x-api-key: '取得した API キー'" \
  -d '{
    "inputs": {
      "question": "フレックスタイム制について教えて",
      "n_queries": 3,
      "output_in_detail": false
    }
  }'

成功するとレスポンスが返ってきます。RAG を設定していないので回答はできていませんが、応答が返るところまでは確認できました。

スクリーンショット 2026-04-27 0.17.28.png

まとめ

源内を閉域 AWS 環境にデプロイできることが確認できました。

地方自治体の基幹業務システムの環境にデプロイできるので、セキュリティ的な制限のあるマイナンバー利用事務系のクライアントから生成 AI を利用することができると思います。これは地方自治体にとってメリットが大きいのではないでしょうか。

運用をどうするかは考えなければなりませんが、非効率な地方自治体の業務効率の向上に役立てられるようにしていきたいですね。

3
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
3
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?