Generative AI Use Cases (GenU) で別 AWS アカウントの Bedrock を使ってみた
いわさです。
AWS には生成 AI のユースケースを手軽に体験できる Generative AI Use Cases (GenU) というソリューションが提供されています。
この GenU は様々なデプロイオプションが用意されており、別アカウントの Amazon Bedrock を使うことが出来ます。
ナレッジベースやエージェント機能を使うかどうかでこのクロスアカウント設定も少し異なってくるのですが、まずはこれらの機能を使わない場合に別のアカウントの Bedrock を使う方法を試してみました。
非常に簡単に設定出来ますので、のっぴきならない事情で Bedrock だけ別アカウントのものを使う必要がある時に使えそうです。
クロスアカウントの設定をする
GenU 公式ドキュメントのデプロイオプションページに「別 AWS アカウントの Bedrock を利用したい場合」について手順など記載されています。このとおり設定するだけです。
クロスアカウントのイメージですが、GenU は色々なリソースがデプロイされるのですがポイントだけ簡略化すると GenU は API Gateway + Lambda 経由で Bedrock のモデルを Invoke しています。

GenU にはクロスアカウント設定のパラメータが用意されており実装されています。
別アカウントにクロスアカウント用の IAM ロールを準備しておき、そのロール ARN を GenU のデプロイオプションに指定することで、Lambda 関数が別アカウントの IAM ロールへスイッチし、そのアカウント上でモデルを使うようになります。

今回試していないのですが、注意点として、「Flow チャットユースケース」「プロンプト最適化ツール」は別 AWS アカウントの利用をサポートしていないため実行時にエラーになる可能性があるとドキュメントに記載されていました。
クロスアカウント設定なしでデプロイ
まずはクロスアカウントの設定なしで通常どおり GenU をデプロイします。
デプロイ手順は割愛しますが、今回はナレッジベースやエージェント機能は有効化していません。そのあたりのクロスアカウント検証は次回行ってみます。
デプロイ後、対象アカウント上でモデルを有効化してから使う必要があるのですが、ここで有効化せずに GenU をまず使ってみましょう。今回は Claude 3.7 Sonnet を対象とします。

一番基本的な機能のチャット機能で Calude 3.7 Sonnet を指定してみると、次のようにモデルが有効になっていないぜと言われました。期待どおりの動作です。

この状態で、対象アカウントのモデルは有効化せずにこのまま別アカウントでモデルを有効化して試してみましょう。なお、特にオプションを指定しなかった場合はバージニア北部のモデルが使用されます。
ちなみにこの時点では Lambda の実行ロールには次のようにbedrock:*アクションが許可されています。このあとのデプロイでこのポリシーも少し変化します。

クロスアカウントの設定
クロスアカウントの設定に必要なのは Bedrock を提供するアカウントでクロスアカウント用の IAM ロールを作成することと、GenU 利用側のアカウントでデプロイ時にそのロール ARN を指定することです。
GenU 側のロールから AssumeRole するので、それらを信頼する必要があります。環境ごとに ARN が異なると思うので、それぞれ ARN を調べて設定しましょう。
- GenerativeAiUseCasesStack-APIPredictTitleService
- GenerativeAiUseCasesStack-APIPredictService
- GenerativeAiUseCasesStack-APIPredictStreamService
- GenerativeAiUseCasesStack-APIGenerateImageService
- GenerativeAiUseCasesStack-APIGenerateVideoService
- GenerativeAiUseCasesStack-APIListVideoJobsService
- GenerativeAiUseCasesStack-SpeechToSpeechTaskService
私の環境だと信頼ポリシーは次のようになりました。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Statement1",
			"Effect": "Allow",
			"Principal": {
				"AWS": [
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIPredictTitleServiceRol-HEdaKBfTImh0",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIPredictServiceRole6B8A-23WLX78YYRA6",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIPredictStreamServiceRo-FPSAS2jMWOvb",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIGenerateImageServiceRo-hB2vTT69rPY6",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIGenerateVideoServiceRo-ugWRBTtN9Zmq",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-APIListVideoJobsServiceRo-DFs2Yg1BTMIi",
					"arn:aws:iam::123456789012:role/GenerativeAiUseCasesStack-SpeechToSpeechTaskService-H7tGW59TBwJf"
				]
			},
			"Action": "sts:AssumeRole"
		}
	]
}
ロールのポリシーは次のような感じです。
S3 バケットについては動画生成ユースケースを有効化していない場合は不要だと思います。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBedrockInvokeModel",
      "Effect": "Allow",
      "Action": [
        "bedrock:Invoke*",
        "bedrock:Rerank",
        "bedrock:GetInferenceProfile",
        "bedrock:GetAsyncInvoke",
        "bedrock:ListAsyncInvokes",
        "bedrock:GetAgent*",
        "bedrock:ListAgent*"
      ],
      "Resource": ["*"]
    },
    {
      "Sid": "AllowS3PutObjectToVideoTempBucket",
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": ["arn:aws:s3:::videotmpbucketstackus-east-1-bucket83908e77-vnbnt0xexg3k/*"]
    }
  ]
}
IAM ロールが作成出来たら ARN を取得し、GenU デプロイ側のアカウントでcrossAccountBedrockRoleArnというパラメータを指定出来るので設定します。
GenU ではparameter.tsあるいはpackages/cdk/cdk.jsonを変更することで設定の変更が可能です。どちらも使えるのですが複数環境の設定が可能なので公式ではparameter.tsの使用が推奨されています。
私は環境を分けてまだ作成していなかったのでcdk.jsonに設定しました。
{
  "app": "npx ts-node --prefer-ts-exts bin/generative-ai-use-cases.ts",
  "watch": {
    "include": ["**"],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "env": "",
    "ragEnabled": false,
:
    "anonymousUsageTracking": true,
    "guardrailEnabled": false,
    "crossAccountBedrockRoleArn": "arn:aws:iam::987654321098:role/hoge0525crossaccount",
    "useCaseBuilderEnabled": true,
:
  }
}
設定後、npm run cdk:deployしなおします。
Bedcork 利用側アカウントでモデルを有効化して使ってみましょう。Claude 3.7 Sonnet を有効化しています。

今度はモデルが無効化されていると言われなくなりました。レスポンスが取得出来ましたね。

どういう仕組みでクロスアカウントに切り替わっているのでしょうか。
先ほどのデプロイでどのような変更が発生したのか中身を少しだけ確認してみます。
各 Lambda 関数から使用する Bedrock クライアントの生成箇所で AssumeRole するような仕組みが実装されています。
:
export const initBedrockRuntimeClient = async (
  config: BedrockRuntimeClientConfig & { region: string }
) => {
  // Use cross-account role
  if (process.env.CROSS_ACCOUNT_BEDROCK_ROLE_ARN) {
    return new BedrockRuntimeClient({
      ...(await getCrossAccountCredentials(
        process.env.CROSS_ACCOUNT_BEDROCK_ROLE_ARN
      )),
      ...config,
    });
  }
  // Use Lambda execution role
  if (!(config.region in bedrockRuntimeClient)) {
    bedrockRuntimeClient[config.region] = new BedrockRuntimeClient(config);
  }
  return bedrockRuntimeClient[config.region];
};
:
そして先程のデプロイで、実行ロールからbedrock:*アクションの許可が削除され、sts:AssumeRoleの許可が追加されています。

さいごに
本日は Generative AI Use Cases (GenU) で別 AWS アカウントの Bedrock を使ってみました。
ナレッジベースやエージェントを使わない場合は別アカウントで IAM ロールを作成してモデルを有効化するだけで使えますね。非常に簡単でした。
次回はナレッジベースやエージェント機能を有効化した場合のクロスアカウント設定も試してみます。













