
AgentCore Observabilityをクロスアカウントで試してみた
はじめに
こんにちは、ドライブ練習中のコンサル部の神野(じんの)です。
久しぶりに高速道路に乗って緊張しました。
さて話は変わって、AgentCore Observabilityをみなさん使っていますか?
AIエージェントの動きが可視化されて便利ですよね。可視化する情報を1つのアカウントに集約したいといったケースはないでしょうか・・・?
そんな中、AgentCore ObservabilityがCloudWatchのクロスアカウントオブザーバビリティに対応していることを公式ドキュメントで見つけました。
モニタリングアカウントを1つ用意すれば、複数のソースアカウントにデプロイされたエージェントのメトリクス・トレース・セッションを一箇所から確認できるとのことです。
公式ドキュメントの手順を参考にして、実際に2つのアカウントを使って試してみました!
仕組みの概要
クロスアカウントオブザーバビリティは、CloudWatchのObservability Access Manager(OAM)という仕組みで実現されます。
| リソース | 作成する場所 | 役割 |
|---|---|---|
| Sink | モニタリングアカウント | ソースアカウントからのテレメトリを受け入れる窓口 |
| Link | ソースアカウント | SinkのARNを指定してテレメトリを共有する接続 |
モニタリングアカウントにSinkを1つ作成し、各ソースアカウントからLinkを張ることで、モニタリングアカウントのAgentCore Observabilityコンソールにソースアカウントのデータが自動的に表示されるようになります。
この仕組みの詳細は川原さんが丁寧に記載されているので、ぜひ必要に応じてご参照ください。
AgentCoreのオブザーバビリティで必要なテレメトリタイプはMetricsとLogsの2つです。トレースやセッションのデータはaws/spansというロググループに格納されるため、Logsの共有に含まれるかたちになります。
今回構築する構成は下記の通りです。

前提
今回の検証環境は下記の通りです。(アカウントIDはダミーです)
| 項目 | 内容 |
|---|---|
| モニタリングアカウント | 111111111111 |
| ソースアカウント | 222222222222 |
| リージョン | us-east-1 |
| エージェント | AgentCore CLIで作成するStrandsエージェント |
ソース側のエージェントはAgentCore CLI(agentcore コマンド)で作成するところから始めます。CLIのインストールがまだの場合は下記でインストールできます。今回使用したバージョンは 1.0.0-preview.16 です。
npm install -g @aws/agentcore
構築
OAMのセットアップはコンソールからもできますが、今回は公式ドキュメントに記載のCloudFormationテンプレートを使ってIaCで構築していきます。手順は下記の4ステップです。
- ソースアカウントにAgentCore CLIでエージェントをデプロイ
- 両アカウントでTransaction Searchを有効化
- モニタリングアカウントにOAM Sinkを作成
- ソースアカウントにOAM Linkを作成
ソースアカウントにエージェントをデプロイ
まずは監視対象となるエージェントを作ります。AgentCore CLIの agentcore create を実行すると、対話形式でプロジェクトを作成できます。今回はStrandsフレームワークのシンプルな構成にしました。
agentcore create --project-name crossacctdemo --name demo_agent \
--framework Strands --model-provider Bedrock --memory none
[done] Create crossacctdemo/ project directory
[done] Prepare agentcore/ directory
[done] Add agent to project
[done] Set up Python environment
Created:
crossacctdemo/
app/demo_agent/ Python agent (Strands)
agentcore/ Config and CDK project
Project created successfully!
エージェント本体(app/demo_agent/main.py)とCDKのデプロイ設定がまとめて生成されます。生成されたmain.pyのエントリーポイント部分を見てみます。あとでクロスアカウントでアプリケーションログを確認したいので、受け取ったプロンプトをログ出力する処理を1行追加しました。
app = BedrockAgentCoreApp()
log = app.logger
# 数値を加算するシンプルなツール
@tool
def add_numbers(a: int, b: int) -> int:
"""Return the sum of two numbers"""
return a+b
@app.entrypoint
async def invoke(payload, context):
log.info("Invoking Agent.....")
agent = get_or_create_agent()
prompt = _extract_prompt(payload)
log.info("Received prompt: %s", prompt) # 追加: アプリケーションログの確認用
async for event in agent.stream_async(prompt):
...
app.loggerで出力したログは、AgentCoreランタイムのロググループにアプリケーションログとして記録されます。あとはソースアカウントのクレデンシャルで agentcore deploy を実行するだけです。
cd crossacctdemo
agentcore deploy -y
✓ Deployed to 'default' (stack: AgentCore-crossacctdemo-default)
Outputs:
...RuntimeArnOutput...: arn:aws:bedrock-agentcore:us-east-1:222222222222:runtime/crossacctdemo_demo_agent-XXXXXXXXXX
...RuntimeIdOutput...: crossacctdemo_demo_agent-XXXXXXXXXX
StackNameOutput: AgentCore-crossacctdemo-default
Note: Transaction search enabled. It takes ~10 minutes for transaction search
to be fully active and for traces from invocations to be indexed.
Next: agentcore invoke | agentcore status
CDKスタックとしてランタイム・IAMロールがまとめてデプロイされました。
Transaction Searchの有効化
AgentCoreのトレースやセッションをコンソールで確認するには、CloudWatchのトランザクション検索(X-Rayトレースの送信先をCloudWatch Logsに変更する設定)が有効になっている必要があります。
スパンの取り込みを許可するには、アカウントごとにトランザクション検索を1回有効にします。CloudWatchコンソールのTransaction Search画面を開き、下記の「Enable Transaction Search」ボタンを押して有効化します。

この操作をモニタリングアカウント・ソースアカウントの両方で実施しておきます。なお、先ほどの agentcore deploy の出力にTransaction search enabledと表示されていた通り、AgentCore CLIでデプロイした場合はソースアカウント側の有効化は自動で行われるため、実質的にはモニタリングアカウント側の対応だけでOKです。
モニタリングアカウントにOAM Sinkを作成
続いてモニタリングアカウント側です。ソースアカウントからのLink作成を受け入れるSinkを作成します。公式ドキュメントのテンプレートをベースに、ソースアカウントIDをパラメータ化したものがこちらです。
AWSTemplateFormatVersion: '2010-09-09'
Description: OAM Sink for cross-account AgentCore Observability (specific accounts)
Parameters:
SourceAccountId:
Type: String
Description: Source account ID to allow linking
Resources:
ObservabilitySink:
Type: AWS::Oam::Sink
Properties:
Name: AgentCoreObservabilitySink
Policy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
- !Ref SourceAccountId
Action:
- 'oam:CreateLink'
- 'oam:UpdateLink'
Resource: '*'
Condition:
ForAllValues:StringEquals:
oam:ResourceTypes:
- 'AWS::Logs::LogGroup'
- 'AWS::CloudWatch::Metric'
Tags:
Purpose: AgentCoreObservability
Outputs:
SinkArn:
Value: !GetAtt ObservabilitySink.Arn
Description: Share this ARN with source accounts to create links
SinkのポリシーでLink作成を許可するアカウントを制御します。Conditionのoam:ResourceTypesでLogsとMetricsのみに共有範囲を絞っているため、意図しないテレメトリタイプが共有される心配はありません。
モニタリングアカウントのクレデンシャルでデプロイします。
aws cloudformation deploy \
--template-file monitoring-sink.yaml \
--stack-name agentcore-observability-sink \
--parameter-overrides SourceAccountId=222222222222 \
--region us-east-1
デプロイが完了したら、OutputsからSinkのARNを控えておきます。
aws cloudformation describe-stacks \
--stack-name agentcore-observability-sink \
--query 'Stacks[0].Outputs[0].OutputValue' \
--output text \
--region us-east-1
arn:aws:oam:us-east-1:111111111111:sink/556e6669-6692-4950-86dc-18276be0c5a3
ソースアカウントにOAM Linkを作成
次はソースアカウント側です。先ほど控えたSinkのARNを指定してLinkを作成します。
AWSTemplateFormatVersion: '2010-09-09'
Description: OAM Link for cross-account AgentCore Observability
Parameters:
SinkArn:
Type: String
Description: Sink ARN from the monitoring account
Resources:
ObservabilityLink:
Type: AWS::Oam::Link
Properties:
LabelTemplate: '$AccountName'
ResourceTypes:
- 'AWS::Logs::LogGroup'
- 'AWS::CloudWatch::Metric'
SinkIdentifier: !Ref SinkArn
Tags:
Purpose: AgentCoreObservability
LabelTemplateは、モニタリングアカウント側でソースアカウントを識別するための表示名です。$AccountNameを指定するとアカウント名がそのままラベルになります。ResourceTypesはSink側のポリシーで許可した範囲と一致させる必要があります。
今回はResourceTypesでLogsとMetricsを共有対象にしています。LinkConfigurationによる絞り込みは設定していないため、ソースアカウント内のロググループとCloudWatchメトリクスが広く共有対象になります。特定のロググループやメトリクス名前空間だけに限定したい場合は、Link側のLinkConfigurationでフィルターできます。
ソースアカウントのクレデンシャルでデプロイします。
aws cloudformation deploy \
--template-file source-link.yaml \
--stack-name agentcore-observability-link \
--parameter-overrides SinkArn=arn:aws:oam:us-east-1:111111111111:sink/556e6669-6692-4950-86dc-18276be0c5a3 \
--region us-east-1
Linkが作成できたか確認してみます。
aws oam list-links --region us-east-1
{
"Items": [
{
"Arn": "arn:aws:oam:us-east-1:222222222222:link/8d09e5f3-0884-44b0-a235-54d7e87837ab",
"Id": "8d09e5f3-0884-44b0-a235-54d7e87837ab",
"Label": "sandbox",
"ResourceTypes": [
"AWS::Logs::LogGroup",
"AWS::CloudWatch::Metric"
],
"SinkIdentifier": "arn:aws:oam:us-east-1:111111111111:sink/556e6669-6692-4950-86dc-18276be0c5a3"
}
]
}
問題なくLinkが作成されていますね!これで構築は完了です。
早速検証してみましょう!
動作確認
テレメトリの生成
まずはデプロイしたエージェントを呼び出して、テレメトリを生成します。agentcore invoke で呼び出します。
agentcore invoke '{"prompt": "123と456を足すといくつですか?ツールを使って計算してください"}'
Session: b96f6616-36fb-46bd-b226-c3c0ea52ea12
--- RESPONSE ---
{
"success": true,
"response": "123と456を足すと、**579**になります。"
}
add_numbersツールを使って計算した応答が返ってきました。この裏でメトリクス・ログ・スパンが生成されている状態になっています。
モニタリングアカウントからCLIで確認
ここからはすべてモニタリングアカウントの権限で操作します。まずSinkに接続されているLinkの一覧を確認します。
aws oam list-attached-links \
--sink-identifier arn:aws:oam:us-east-1:111111111111:sink/556e6669-6692-4950-86dc-18276be0c5a3 \
--region us-east-1
{
"Items": [
{
"Label": "sandbox",
"LinkArn": "arn:aws:oam:us-east-1:222222222222:link/8d09e5f3-0884-44b0-a235-54d7e87837ab",
"ResourceTypes": [
"AWS::Logs::LogGroup",
"AWS::CloudWatch::Metric"
]
}
]
}
ソースアカウントがちゃんとリンクされていますね!次にメトリクスです。--include-linked-accountsオプションを付けると、リンクされたアカウントのメトリクスも一覧できます。
aws cloudwatch list-metrics \
--include-linked-accounts \
--owning-account 222222222222 \
--region us-east-1 \
--query 'Metrics[].[Namespace,MetricName]' \
--output text | sort -u | head
AWS/Bedrock-AgentCore Duration
AWS/Bedrock-AgentCore Invocations
AWS/Bedrock-AgentCore Latency
AWS/Bedrock-AgentCore Sessions
AWS/Bedrock-AgentCore SystemErrors
AWS/Bedrock-AgentCore Throttles
AWS/Bedrock-AgentCore UserErrors
ソースアカウントのAWS/Bedrock-AgentCore名前空間のメトリクスが、モニタリングアカウントから見えていますね!!
メトリクスの実データも取得してみます。クロスアカウントのメトリクス値を取得する場合は、get-metric-dataでAccountIdを指定します。
[
{
"Id": "inv",
"AccountId": "222222222222",
"MetricStat": {
"Metric": {
"Namespace": "AWS/Bedrock-AgentCore",
"MetricName": "Invocations",
"Dimensions": [
{"Name": "Resource", "Value": "arn:aws:bedrock-agentcore:us-east-1:222222222222:runtime/crossacctdemo_demo_agent-XXXXXXXXXX"},
{"Name": "Operation", "Value": "InvokeAgentRuntime"},
{"Name": "Name", "Value": "crossacctdemo_demo_agent::DEFAULT"}
]
},
"Period": 3600,
"Stat": "Sum"
}
}
]
aws cloudwatch get-metric-data \
--metric-data-queries file://metric-query.json \
--start-time 2026-07-11T00:00:00Z \
--end-time 2026-07-11T02:00:00Z \
--region us-east-1
{
"MetricDataResults": [
{
"Id": "inv",
"Label": "Invocations",
"Timestamps": [
"2026-07-11T08:32:00+09:00"
],
"Values": [
1.0
],
"StatusCode": "Complete"
}
],
"Messages": []
}
先ほどのエージェント呼び出しがInvocationsとしてカウントされ、モニタリングアカウントから取得できました!
ログも確認してみます。describe-log-groupsにも同様のオプションがあります。
aws logs describe-log-groups \
--include-linked-accounts \
--account-identifiers 222222222222 \
--region us-east-1 \
--query 'logGroups[?contains(logGroupName, `agentcore`) || contains(logGroupName, `spans`)].logGroupName' \
--output text
/aws/bedrock-agentcore/runtimes/crossacctdemo_demo_agent-XXXXXXXXXX-DEFAULT aws/spans
エージェントのランタイムログに加えて、トレースデータが格納されるaws/spansロググループも見えていますね。
エージェント自身が出力するアプリケーションログもクロスアカウントで読めるのか確認します。main.pyに追加した log.info("Received prompt: ...") の出力を、モニタリングアカウントから探してみます。
aws logs filter-log-events \
--log-group-identifier "arn:aws:logs:us-east-1:222222222222:log-group:/aws/bedrock-agentcore/runtimes/crossacctdemo_demo_agent-XXXXXXXXXX-DEFAULT" \
--filter-pattern 'prompt' \
--max-items 1 \
--region us-east-1 \
--query 'events[].message' \
--output text
{"resource":{"attributes":{"service.name":"crossacctdemo_demo_agent.DEFAULT",
"cloud.platform":"aws_bedrock_agentcore","cloud.region":"us-east-1",...}},
"severityText":"INFO",
"body":"Received prompt: {\"prompt\": \"123と456を足すといくつですか?ツールを使って計算してください\"}",
...}
エージェントのコードで出力したアプリケーションログが、モニタリングアカウントからも確認できましたね!OAMのLogs共有はロググループ単位なので、AgentCoreの標準テレメトリだけでなく、アプリケーション独自のログも一緒に共有されます。
トレースのスパンデータも同様に確認してみます。
aws logs filter-log-events \
--log-group-identifier "arn:aws:logs:us-east-1:222222222222:log-group:aws/spans" \
--filter-pattern 'crossacctdemo' \
--max-items 1 \
--region us-east-1 \
--query 'events[].message' \
--output text
{"resource":{"attributes":{"aws.local.service":"crossacctdemo_demo_agent.DEFAULT",
"cloud.region":"us-east-1","aws.service.type":"gen_ai_agent",
"cloud.platform":"aws_bedrock_agentcore",...}},
"traceId":"...","spanId":"...","kind":"CLIENT",...}
エージェントが生成したOpenTelemetryのスパンデータも読めました!無事メトリクス・アプリケーションログ・トレースのすべてがクロスアカウントで確認できました!
コンソールで確認
CLIでの確認だけだと味気ないので、本命のAgentCore Observabilityコンソールも見てみます。モニタリングアカウントでCloudWatchコンソールを開き、左ペインのGenAI Observabilityを選択します。

ソースアカウントのエージェントが、モニタリングアカウントのコンソールに自動的に表示されていますね!クロスアカウント設定後は一覧にAccount / Account IDの列が追加され、どのアカウントのエージェントかが一目でわかるようになっています。
トレースの詳細画面も開いてみます。

トレース詳細にはAccount ID: Source Accountとして、ソースアカウントのデータであることが明示されています。add_numbersツールの呼び出しやLLM呼び出しのスパンツリー、Trajectory、入出力の中身まで、モニタリングアカウントからそのまま確認できましたね!
制約事項
公式ドキュメントに記載の制約をまとめておきます。
| 制約 | 内容 |
|---|---|
| リージョン | 単一リージョン内でのみ動作。モニタリングとソースは同一リージョン必須 |
| Linkの維持 | OAM Linkを削除するとクロスアカウントデータは見えなくなる |
| テレメトリタイプ | MetricsとLogsの両方の共有が必要。片方だけだとデータが欠落する |
| リソース操作 | Bedrockコンソールへの遷移など一部の操作はクロスアカウントでは不可。ソースアカウントへのサインインが必要 |
またベースとなるCloudWatchクロスアカウントオブザーバビリティ(OAM)自体の制限・仕様も押さえておくとよいです。
| 項目 | 内容 |
|---|---|
| Sink数 | 1アカウント・1リージョンあたり1つまで |
| リンク数 | モニタリングアカウントは最大10万ソースアカウントとリンク可能。ソースアカウント側は最大5つのモニタリングアカウントまで |
| テレメトリタイプの整合 | ソース側がモニタリング側より多くのテレメトリタイプを選択しているとLink作成自体が失敗する |
| メトリクス表示 | Link作成後に新しいデータポイントが発行されるまで、メトリクス名はモニタリングアカウントに表示されない |
| 削除の順序 | Sinkを削除するには、先にすべてのLinkを削除する必要がある |
| 料金 | クロスアカウント共有自体に追加料金はなし。ただしTransaction Searchのスパン取り込みなど元機能側の料金は別途発生 |
おわりに
マルチアカウントでエージェントを運用するケースで、運用チームのアカウントをモニタリングアカウントにして可視化する場合に今回紹介した機能は便利そうですね!今後はアラームやダッシュボードと組み合わせた運用設計なども考えらればと思いました。
本記事が少しでも参考になりましたら幸いです。最後までご覧いただきありがとうございました!
補足: 検証環境のクリーンアップ
検証が終わったら、下記の順で削除すればもとに戻せます。
- ソースアカウントでLinkのスタックを削除(
aws cloudformation delete-stack --stack-name agentcore-observability-link) - モニタリングアカウントでSinkのスタックを削除(
aws cloudformation delete-stack --stack-name agentcore-observability-sink) - ソースアカウントでエージェントを削除。AgentCore CLIでプロジェクト設定からエージェントを外し、再デプロイすることでCDK経由でランタイムが削除されます
agentcore remove agent --name demo_agent -y
agentcore deploy -y
CDKスタック自体も含めて完全に削除する場合は、aws cloudformation delete-stack --stack-name AgentCore-crossacctdemo-default を実行します。





