[アップデート] Amazon Bedrock AgentCore Memory のクロスアカウントアクセスを2アカウント構成で試してみた

[アップデート] Amazon Bedrock AgentCore Memory のクロスアカウントアクセスを2アカウント構成で試してみた

Amazon Bedrock AgentCore Memory がクロスアカウントアクセスに対応しました!Strands Agents Session Managerからの連携も確認しました!
2026.07.04

はじめに

こんにちは、ドライブ練習中のコンサル部の神野(じんの)です。

Amazon Bedrock AgentCore Memory にクロスアカウントアクセスのサポートが追加されました(2026年6月23日発表なのでだいぶ遅れたアップデート紹介ですが・・・)。

https://aws.amazon.com/jp/about-aws/whats-new/2026/06/agentcore-memory-cross-account-access/

AgentCore Memory はエージェントに「記憶」を持たせるフルマネージドサービスで、短期記憶(会話履歴)と長期記憶(ユーザーの好み・事実情報・セッション要約など)を管理できます。今回のアップデートにより、リソースベースポリシーを使って別アカウントのプリンシパルからメモリーリソースへのアクセスが可能になりました。

実際に2アカウント構成で試してみたので、設定手順やユースケース、Strands Agents SDK との連携について紹介していきます。

どういうときに嬉しいのか

まずどういう時にクロスアカウントだと嬉しいの・・・・?と思い考えてみます。

チーム間でのエージェントメモリー共有

異なるチームが別々のアカウントでエージェントを開発しているケースでも、共通の顧客長期記憶にアクセスさせることで、同じ顧客に対して一貫した対応が可能になるケースがあるかなと思いました。

他のチームが蓄積した記憶の資産を活用したい場合ですね。

クロスアカウント配信先

メモリーリソースは他のアカウントの S3 バケット、SNS トピック、Kinesis Data Streams へのペイロード配信にも対応しています。会話データの分析基盤が別アカウントにある場合、メモリーイベントを直接配信できるのは嬉しいかもしれません。

なお、配信先の設定は今回試す API アクセスとは別の仕組みで、memory execution role や配信先リソース側のポリシー設定が別途必要です。本記事で試すのは data plane API のクロスアカウントアクセスで、配信先のクロスアカウント設定は扱いません。

私なりに考えてみたのですがあまりイメージが湧きにくいですね・・・とはいえ、できるようになったのは嬉しいことだと思うので早速試してみたいと思います!

今回試す構成

2アカウント構成でメモリーアクセスを試します。アカウント A がメモリー提供側、アカウント B がメモリー利用側です。

CleanShot 2026-07-04 at 19.38.59@2x

全体の流れ

今回実施する流れをフロー図にしました。

前提

今回は下記前提で進めていきます!

  • AWS アカウント2つ(アカウント A:メモリー提供側 / アカウント B:メモリー利用側)
  • AWS CLI 2.34.44
  • Python 3.13
  • uv 0.9.26
  • 使用ライブラリ:boto3 / bedrock-agentcore / strands-agents

パッケージ管理には uv を使います。プロジェクトを作成して依存ライブラリを追加します。

セットアップコマンド
uv init memory-cross-account -p 3.13
cd memory-cross-account
uv add boto3 bedrock-agentcore strands-agents

実装

メモリーリソースの作成(メモリー提供側)

まずはメモリー提供側のアカウント A でメモリーリソースを作成します。
長期記憶の戦略には事実などを記憶する semanticMemoryStrategy とユーザーの好みを記憶する userPreferenceMemoryStrategy を使用します。

setup_memory.py
import boto3

control_client = boto3.client("bedrock-agentcore-control", region_name="us-east-1")

response = control_client.create_memory(
    name="CrossAccountDemoMemory",
    description="クロスアカウントアクセスのデモ用メモリ",
    eventExpiryDuration=30,
    memoryStrategies=[
        {
            "semanticMemoryStrategy": {
                "name": "UserFacts",
                "description": "ユーザーに関する事実情報を抽出",
            }
        },
        {
            "userPreferenceMemoryStrategy": {
                "name": "UserPreferences",
                "description": "ユーザーの好みを学習",
            }
        },
    ],
)

memory_id = response["memory"]["id"]
memory_arn = response["memory"]["arn"]

print(f"Memory ID: {memory_id}")
print(f"Memory ARN: {memory_arn}")
実行コマンド
uv run setup_memory.py
実行結果
Memory ID: CrossAccountDemoMemory-NCd6eP6wJq
Memory ARN: arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq

メモリーリソースが作成されると、ID と ARN が返却されます。クロスアカウントアクセスでは、この ARN を使ってメモリーを参照することになります。

リソースベースポリシーの設定(メモリー提供側)

メモリー利用側であるアカウント B のロールからメモリーリソースにアクセスできるよう、リソースベースポリシーをアタッチします。

memory-cross-account-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCrossAccountMemoryAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:role/ConsumerRole"
            },
            "Action": [
                "bedrock-agentcore:CreateEvent",
                "bedrock-agentcore:GetEvent",
                "bedrock-agentcore:ListEvents",
                "bedrock-agentcore:ListActors",
                "bedrock-agentcore:ListSessions",
                "bedrock-agentcore:GetMemoryRecord",
                "bedrock-agentcore:ListMemoryRecords",
                "bedrock-agentcore:RetrieveMemoryRecords"
            ],
            "Resource": "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"
        }
    ]
}

Principal にはアカウント B で使用する IAM ロール ARN を指定しています。Action にはメモリー利用側で必要な操作を列挙しました。イベントの作成(短期記憶への書き込み)と、メモリーレコードの取得・検索(長期記憶の参照)を許可しています。Resource には先ほど作成したメモリーの ARN を指定します。

なお、アクセスが許可されるにはリソースベースポリシーだけでなく、呼び出し元プリンシパル側の identity-based ポリシーでも bedrock-agentcore の操作が許可されている必要があります。今回アカウント B 側では管理者権限相当のロールを使用しているため、以降の手順ではリソースベースポリシーの設定のみで動作します。

CLI でポリシーをアタッチします。

ポリシーのアタッチ
aws bedrock-agentcore-control put-resource-policy \
    --resource-arn arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq \
    --policy file://memory-cross-account-policy.json \
    --region us-east-1

メモリー利用側からイベントを書き込む

メモリー利用側のアカウント B から、アカウント A のメモリーにイベントを書き込んでみます。ポイントは memoryId に短い ID ではなく ARN を指定するところです。

write_cross_account.py
import boto3
from datetime import datetime, timezone

client = boto3.client("bedrock-agentcore", region_name="us-east-1")

MEMORY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"

response = client.create_event(
    memoryId=MEMORY_ARN,
    actorId="user-001",
    sessionId="cross-account-session-001",
    eventTimestamp=datetime.now(timezone.utc),
    payload=[
        {
            "conversational": {
                "content": {"text": "こんにちは!旅行の計画を手伝ってほしいです。"},
                "role": "USER",
            }
        },
        {
            "conversational": {
                "content": {"text": "もちろんです!どちらへの旅行をお考えですか?"},
                "role": "ASSISTANT",
            }
        },
        {
            "conversational": {
                "content": {
                    "text": "来月、京都に3泊4日で行きたいです。寺社仏閣より、和菓子巡りやカフェを中心にしたいです。あと抹茶スイーツが大好きです。"
                },
                "role": "USER",
            }
        },
        {
            "conversational": {
                "content": {
                    "text": "京都で和菓子巡りとカフェ中心の旅行ですね!抹茶スイーツがお好きとのこと、おすすめのプランを考えてみますね。"
                },
                "role": "ASSISTANT",
            }
        },
    ],
)

print(f"Event created: {response['event']['eventId']}")
実行コマンド
uv run write_cross_account.py
実行結果
Event created: 0000001783165130534#3f3e979a

同一アカウント内で使う場合と比べて、アプリケーションコード上の主な変更点は memoryId に ARN を渡す点です。別途、呼び出し元ロール側にも bedrock-agentcore の操作を許可する identity-based ポリシーが必要な点はご注意ください。

イベントが正しく書き込まれたか、ListEvents で確認できます。

list_events.py
import boto3

client = boto3.client("bedrock-agentcore", region_name="us-east-1")

MEMORY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"

response = client.list_events(
    memoryId=MEMORY_ARN,
    actorId="user-001",
    sessionId="cross-account-session-001",
)

for event in response["events"]:
    print(f"Event ID: {event['eventId']}")
実行コマンド
uv run list_events.py
実行結果
Event ID: 0000001783165130534#3f3e979a

問題なく書き込まれていることを確認できました!

長期記憶の確認

イベント書き込み後、組み込みストラテジーが自動的に会話内容を分析し、事実情報やユーザーの好みを長期記憶として抽出してくれます。

メモリー提供側(アカウント A)から確認してみます。

check_long_term_memory.py
import boto3

client = boto3.client("bedrock-agentcore", region_name="us-east-1")

MEMORY_ID = "CrossAccountDemoMemory-NCd6eP6wJq"

response = client.list_memory_records(
    memoryId=MEMORY_ID,
    namespacePath="/",
)

for record in response["memoryRecordSummaries"]:
    text = record["content"]["text"]
    strategy = record["memoryStrategyId"]
    print(f"[{strategy}] {text}")
実行コマンド
uv run check_long_term_memory.py
実行結果
[UserFacts-Vu0glFBLrC] ユーザーは抹茶スイーツが大好きである。
[UserPreferences-nnBhOa5Pbm] {"context":"ユーザーは抹茶スイーツが大好きと明示的に述べた。","preference":"抹茶スイーツが大好き","categories":["グルメ","スイーツ","食べ物"]}
[UserPreferences-nnBhOa5Pbm] {"context":"ユーザーは京都旅行の計画について、寺社仏閣よりも和菓子巡りやカフェを中心にしたいと明示的に述べた。","preference":"旅行では寺社仏閣よりも和菓子巡りやカフェを中心にしたい","categories":["旅行","グルメ","スイーツ","カフェ"]}
[UserFacts-Vu0glFBLrC] ユーザーは2026年8月に京都へ3泊4日の旅行を計画している。

会話の中からユーザーの事実情報(Facts)と好み(Preferences)が自動抽出されていますね!

メモリー利用側(アカウント B)からも同じ長期記憶にセマンティック検索でアクセスできます。

search_from_consumer.py
import boto3

client = boto3.client("bedrock-agentcore", region_name="us-east-1")

MEMORY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"

response = client.retrieve_memory_records(
    memoryId=MEMORY_ARN,
    namespacePath="/",
    searchCriteria={
        "searchQuery": "このユーザーの食の好みは?",
        "topK": 5,
    },
)

for record in response["memoryRecordSummaries"]:
    text = record["content"]["text"]
    score = record.get("score", "N/A")
    print(f"Score={score}: {text}")
実行コマンド
uv run search_from_consumer.py
実行結果
Score=0.4189935: {"context":"ユーザーは抹茶スイーツが大好きと明示的に述べた。","preference":"抹茶スイーツが大好き","categories":["グルメ","スイーツ","食べ物"]}
Score=0.41755167: ユーザーは抹茶スイーツが大好きである。
Score=0.4072743: ユーザーは京都旅行で寺社仏閣よりも和菓子巡りやカフェを中心にしたいと考えている。
Score=0.40258944: {"context":"ユーザーは京都旅行の計画について、寺社仏閣よりも和菓子巡りやカフェを中心にしたいと明示的に述べた。","preference":"旅行では寺社仏閣よりも和菓子巡りやカフェを中心にしたい","categories":["旅行","グルメ","スイーツ","カフェ"]}
Score=0.3739571: ユーザーは2026年8月に京都へ3泊4日の旅行を計画している。

別アカウントからでも、セマンティック検索で関連度スコア付きの長期記憶を取得できました!

許可していないロールからは拒否されることを確認

逆に、リソースベースポリシーの Principal に含まれていないロールからアクセスするとどうなるかも確認してみます。アカウント B に検証用ロール CrossAccountDenyTestRole を作成し、identity-based ポリシーでは bedrock-agentcore の操作を全許可した状態で、このロールに Assume して ListEvents を呼び出してみます。

実行コマンド(検証用ロールに Assume した状態)
aws bedrock-agentcore list-events \
    --region us-east-1 \
    --memory-id arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq \
    --actor-id user-001 \
    --session-id cross-account-session-001
実行結果
An error occurred (AccessDeniedException) when calling the ListEvents operation: User: arn:aws:sts::222222222222:assumed-role/CrossAccountDenyTestRole/deny-test is not authorized to perform: bedrock-agentcore:ListEvents on resource: arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq because no resource-based policy allows the bedrock-agentcore:ListEvents action

呼び出し元の identity-based ポリシーで全許可していても、リソースベースポリシーの Principal に含まれていないロールは拒否されました。エラーメッセージに no resource-based policy allows the bedrock-agentcore:ListEvents action と拒否理由が明示されるのは分かりやすくて嬉しいですね!

Strands AgentCoreMemorySessionManager でのクロスアカウント利用

ここからは Strands Agents SDK の AgentCoreMemorySessionManager を使ったクロスアカウント利用について見ていきます。

AgentCoreMemorySessionManager とは

Strands Agents SDK には AgentCoreMemorySessionManager というセッションマネージャーが用意されています。Agent の引数に渡すだけで会話履歴の保存・参照を自動でやってくれる便利なやつです。

https://strandsagents.com/docs/community/session-managers/agentcore-memory/

よく使うため、AgentCoreMemorySessionManagerでもクロスアカウントでアクセスできるかは気になりますよね。

クロスアカウントでも使えるか

早速結論ですが、AgentCoreMemoryConfig の memory_id に ARN を指定すれば動作します。試してみます。

strands_cross_account.py
from strands import Agent
from bedrock_agentcore.memory.integrations.strands.config import (
    AgentCoreMemoryConfig,
    RetrievalConfig,
)
from bedrock_agentcore.memory.integrations.strands.session_manager import (
    AgentCoreMemorySessionManager,
)

MEMORY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"

config = AgentCoreMemoryConfig(
    memory_id=MEMORY_ARN,
    session_id="strands-cross-account-session-001",
    actor_id="user-001",
    retrieval_config={
        "/strategies/UserFacts-Vu0glFBLrC/actors/user-001/": RetrievalConfig(
            top_k=5,
            relevance_score=0.3,
        ),
    },
)

with AgentCoreMemorySessionManager(
    agentcore_memory_config=config,
    region_name="us-east-1",
) as session_manager:
    agent = Agent(
        model="us.anthropic.claude-haiku-4-5-20251001-v1:0",
        system_prompt="あなたは旅行プランナーです。ユーザーの好みに合わせた旅行プランを提案してください。",
        session_manager=session_manager,
    )

    response = agent("京都でおすすめの場所を教えて!")
    print(response)
実行コマンド
uv run strands_cross_account.py
実行結果(抜粋)
# 京都 和菓子&カフェ巡り 3泊4日プラン 🍵

抹茶スイーツ好きのあなたにぴったりの京都旅行プランをご提案します!

## 📅 1日目:宇治エリアで本場の抹茶を堪能

### 午前
- **中村藤吉本店**(宇治)
  - 生茶ゼリィや抹茶パフェが絶品
  - 江戸時代創業の老舗

(中略)

## 🎁 おすすめお土産リスト

1. マールブランシュ「茶の菓」
2. 中村藤吉「生茶ゼリィ」
3. 伊藤久右衛門「抹茶チョコレート」
4. 然花抄院「花ラスク」
5. 老松「夏柑糖」(日持ち注意)

このプランはいかがでしょうか?ご希望に応じてカスタマイズも可能です!特に行きたいエリアや、避けたい場所などあればお知らせください 😊

事前に書き込んでいた、抹茶スイーツが大好き・寺社仏閣より和菓子巡りやカフェ中心という長期記憶が反映された回答になっていますね!

内部的には AgentCoreMemorySessionManager が API を呼んでいるため、memory_id に ARN を渡せばそのまま別アカウントのメモリーにアクセスしてくれます。リソースベースポリシーが正しく設定されていれば、同一アカウントの場合と同じコードで動きます。

短期記憶も確認してみる

長期記憶だけでなく、短期記憶(会話履歴)もクロスアカウントで機能するか確認してみます。先ほどとまったく同じ設定・同じ session_id で、質問だけ変えたスクリプトを別プロセスとして実行し、「さっきの会話覚えている?」と聞いてみます。

strands_short_term.py
from strands import Agent
from bedrock_agentcore.memory.integrations.strands.config import (
    AgentCoreMemoryConfig,
    RetrievalConfig,
)
from bedrock_agentcore.memory.integrations.strands.session_manager import (
    AgentCoreMemorySessionManager,
)

MEMORY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111111111111:memory/CrossAccountDemoMemory-NCd6eP6wJq"

config = AgentCoreMemoryConfig(
    memory_id=MEMORY_ARN,
    session_id="strands-cross-account-session-001",
    actor_id="user-001",
    retrieval_config={
        "/strategies/UserFacts-Vu0glFBLrC/actors/user-001/": RetrievalConfig(
            top_k=5,
            relevance_score=0.3,
        ),
    },
)

with AgentCoreMemorySessionManager(
    agentcore_memory_config=config,
    region_name="us-east-1",
) as session_manager:
    agent = Agent(
        model="us.anthropic.claude-haiku-4-5-20251001-v1:0",
        system_prompt="あなたは旅行プランナーです。ユーザーの好みに合わせた旅行プランを提案してください。",
        session_manager=session_manager,
    )

    response = agent("さっきの会話覚えている?")
    print(response)
実行コマンド
uv run strands_short_term.py
実行結果
はい、もちろん覚えています!

先ほどご提案した**京都 和菓子&カフェ巡り 3泊4日プラン**についてですね。

- 2026年8月の3泊4日
- 寺社仏閣よりも和菓子やカフェ中心
- 抹茶スイーツがお好き

という条件で、宇治・祇園・嵐山などを巡る抹茶スイーツ中心のプランをお作りしました。

何か変更したい点や、追加で知りたいことはありますか?例えば:

- 特定のお店の詳細情報
- 移動手段や所要時間
- 予算の目安
- もっと穴場のカフェ情報

など、お気軽にお聞きください!😊

別プロセスからでも、前回の会話内容を踏まえた回答が返ってきました!AgentCoreMemorySessionManager が同じセッションの会話履歴をアカウント A のメモリーから読み込んで復元してくれるため、短期記憶もクロスアカウントで問題なく機能していますね!

おわりに

Strands の AgentCoreMemorySessionManager でも memory_id に ARN を渡すだけで動くので、既存のコードをほぼ変更せずにクロスアカウント構成も採用できそうです!

ユースケースが自分自身ピンときていないところもありますが、実際にやった事例などあればまたブログに書きたいと思います!あるアカウントに長期記憶を集約して活用したいなどはありそうですね。

本記事が少しでも参考になりましたら幸いです。最後までご覧いただきありがとうございました!

この記事をシェアする

関連記事