Amazon Bedrock AgentCore PolicyのLOG_ONLYモードでポリシー判定結果を確認する

Amazon Bedrock AgentCore PolicyのLOG_ONLYモードでポリシー判定結果を確認する

2025.12.07

はじめに

こんにちは、スーパーマーケットが大好きなコンサルティング部の神野です。
直近Amazon Bedrock AgentCore Policyがプレビューでリリースされました!

https://dev.classmethod.jp/articles/amazon-bedrock-agentcore-policy-awsreinvent/

そんなAmazon Bedrock AgentCore Policyにはポリシー評価時に2種類のモードが存在します。

  • ENFORCEMENT
    • リクエストがポリシーに適合しているかチェックし、そぐわないリクエストは拒否する
  • LOG_ONLY
    • リクエストがポリシーに適合しているかチェックし、ログに記録する。ログに記録するだけで拒否はしない

コンソール上で上記を選択する際に、下記の注意があります。

モードの選択画面

Enabling enforcement: Consider testing and validating policies in log only mode before enabling enforcement to avoid unintended denials or adversely affecting production traffic.

適用を有効にする前に、ログのみのモードでポリシーを確認してください、とあります。
運用としてはLOG_ONLYで設計通りのログが記載されているか確認して、問題なければENFORCEMENTに切り替える形が考えられます。

ただ、LOG_ONLYのログはどこにどのように出力され、どう確認したらいいのか気になり本記事でまとめてみました。

前提

下記ブログで作成した、Gateway + Policy を使用します。

https://dev.classmethod.jp/articles/amazon-bedrock-agentcore-policy-awsreinvent/

もし未作成の場合は記事と同様に作成いただければ問題ありません。
今回のやり方だと、ログもトレースも自動的に有効化されていますが、有効化手順も説明します。

LOG_ONLYモードの変更する

スクリプトで自動生成するとモードが、ENFORCEMENTになっているのでLOG_ONLYに変更します。
対象のポリシーエンジンの画面を開き、Associate Gateway を選択します。

CleanShot 2025-12-06 at 02.51.43@2x

変更したいGatewayを選択してEmits logs onlyを選択します。

CleanShot 2025-12-06 at 02.52.33@2x

変更後は下記のようにLog onlyとなっていれば問題ありません。

CleanShot 2025-12-06 at 02.57.29@2x

Gatewayのログを有効化してCloudWatchで確認してみる

まずはGatewayのログを有効化します。
ログの配信先はTo Amazon CloudWatch Logsを選択します。

CleanShot 2025-12-06 at 02.19.23@2x

Log typeAPPLICATION_LOGSを選択し、Destination log groupは自動で入力されるのでその値にします。

CleanShot 2025-12-06 at 02.21.49@2x

/aws/vendedlogs/bedrock-agentcore/gateway/APPLICATION_LOGS/gateway名のような形式の値です。

これでログの設定は完了です。この状態でテスト用のスクリプトtest_policy.pyを実行します。

# 実行
python test_policy.py

# 実行結果
(.venv) ~/gatewa-sample-mcp/agentcore-policy-quickstart ❯ python test_policy.py       
============================================================
🧪 Testing Policy Engine
============================================================

Gateway: https://testgateway8ede8d86-xxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp
Refund limit: $1000

🔑 Getting access token...
2025-12-06 08:49:31,604 - bedrock_agentcore.gateway - INFO - Fetching test token from Cognito...
2025-12-06 08:49:31,604 - bedrock_agentcore.gateway - INFO -   Attempting to connect to token endpoint: https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/token
2025-12-06 08:49:32,246 - bedrock_agentcore.gateway - INFO - ✓ Got test token successfully
✅ Token obtained

📝 Test 1: Refund $500 (Expected: ALLOW)
----------------------------------------
Status Code: 200
Response Body: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "{\"status\":\"success\",\"message\":\"Refund of $500 processed successfully\",\"amount\":500}"
      }
    ]
  }
}

📝 Test 2: Refund $2000 (Expected: DENY)
----------------------------------------
Status Code: 200
Response Body: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "{\"status\":\"success\",\"message\":\"Refund of $2000 processed successfully\",\"amount\":2000}"
      }
    ]
  }
}

============================================================
✅ Testing complete!
============================================================

LOG_ONLYモードに切り替えたので、どちらも成功していますね。
CloudWatchのログ上ではどう記載されているのか、成功時のログと失敗時のログをそれぞれ確認してみます。

$500のリクエスト(ポリシー許可)

{
  "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-xxx",
  "event_timestamp": 1764957505903,
  "body": {
    "isError": false,
    "log": "Started processing request",
    "requestBody": "{id=1, jsonrpc=2.0, method=tools/call, params={name=RefundTarget___process_refund, arguments={amount=500}}}",
    "id": "1"
  },
  "account_id": "xxxxxxxxxxxx",
  "request_id": "1badab22-4e8a-4c91-8af8-xxxxxxxxxxxx",
  "trace_id": "69331d4130b02df27b1e002a47acd8e5",
  "severityText": "INFO"
}
{
  "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-xxx",
  "event_timestamp": 1764957506495,
  "body": {
    "isError": false,
    "responseBody": "{jsonrpc=2.0, id=1, result={isError=false, content=[{type=text, text={\"status\":\"success\",\"message\":\"Refund of $500 processed successfully\",\"amount\":500}}]}}",
    "log": "Successfully processed request",
    "id": "1"
  },
  "account_id": "xxxxxxxxxxxx",
  "request_id": "1badab22-4e8a-4c91-8af8-xxxxxxxxxxxx",
  "trace_id": "69331d4130b02df27b1e002a47acd8e5",
  "severityText": "INFO"
}

$2000のリクエスト(ポリシー違反だが許可)

{
  "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-xxx",
  "event_timestamp": 1764957506765,
  "body": {
    "isError": false,
    "log": "Started processing request",
    "requestBody": "{id=1, jsonrpc=2.0, method=tools/call, params={name=RefundTarget___process_refund, arguments={amount=2000}}}",
    "id": "1"
  },
  "account_id": "xxxxxxxxxxxx",
  "request_id": "b5f1913c-95c3-4f1b-ad36-xxxxxxxxxxxx",
  "trace_id": "69331d4208d35049567698eb726e7f73",
  "severityText": "INFO"
}
{
  "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-xxx",
  "event_timestamp": 1764957507065,
  "body": {
    "isError": false,
    "responseBody": "{jsonrpc=2.0, id=1, result={isError=false, content=[{type=text, text={\"status\":\"success\",\"message\":\"Refund of $2000 processed successfully\",\"amount\":2000}}]}}",
    "log": "Successfully processed request",
    "id": "1"
  },
  "account_id": "xxxxxxxxxxxx",
  "request_id": "b5f1913c-95c3-4f1b-ad36-xxxxxxxxxxxx",
  "trace_id": "69331d4208d35049567698eb726e7f73",
  "severityText": "INFO"
}

一見、同じように見えます。CloudWatchのログ上でポリシーの許可・拒否の違いがわかりません。

ちなみにENFORCEMENTモードで実際にエラーが起きると下記のようなログが出力されます。isError部分がtrueです。

{
  "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-feklilrkin",
  "event_timestamp": 1764956946241,
  "body": {
    "isError": true,
    "log": "Tool Execution Denied: Tool call not allowed due to policy enforcement [Policy evaluation denied due to no determining policies]",
    "id": "1"
  },
  "account_id": "xxxxxxxxxxxx",
  "request_id": "2fd17c4f-27b2-4180-8e29-xxxxxxxxxxxx",
  "trace_id": "69331b116559f96a6af3cf201493d3d6",
  "severityText": "ERROR"
}

CloudWatch上ではポリシー判断の情報がわからなかったので、トレースで新しい情報がないか確認してみます。

Gatewayのトレースを有効化してGenAI Dashboardで確認してみる

トレースを有効化します。Gatewayのコンソール上画面から有効化可能で、Tracking > Editボタンを選択することで可能です。

CleanShot 2025-12-06 at 02.27.12@2x

Enableにチェックが入った状態とします。

CleanShot 2025-12-06 at 02.27.27@2x

これでトレースの設定は完了です。この状態でテスト用のスクリプトtest_policy.pyを再度実行します。

# 実行
python test_policy.py

# 実行結果
(.venv) ~/gatewa-sample-mcp/agentcore-policy-quickstart ❯ python test_policy.py       
============================================================
🧪 Testing Policy Engine
============================================================

Gateway: https://testgateway8ede8d86-xxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp
Refund limit: $1000

🔑 Getting access token...
・・・(省略)
2025-12-06 08:49:31,604 - bedrock_agentcore.gateway - INFO -   Attempting to connect to token endpoint: https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/token
✅ Token obtained

📝 Test 1: Refund $500 (Expected: ALLOW)
----------------------------------------
Status Code: 200
Response Body: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "{\"status\":\"success\",\"message\":\"Refund of $500 processed successfully\",\"amount\":500}"
      }
    ]
  }
}

📝 Test 2: Refund $2000 (Expected: DENY)
----------------------------------------
Status Code: 200
Response Body: {
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "{\"status\":\"success\",\"message\":\"Refund of $2000 processed successfully\",\"amount\":2000}"
      }
    ]
  }
}

============================================================
✅ Testing complete!
============================================================

トレースの状態を確認してみます。
CloudWatchのGenAI ObservabilityのBedrock AgentCoreをクリックし、対象のGatewayを選択してトレースを確認できます。

CleanShot 2025-12-06 at 08.51.41@2x-4978981

エラー率やレイテンシーなど確認できて便利なダッシュボードです。
ここではログによるエラーを可視化できるビジュアルがあります。

CleanShot 2025-12-06 at 08.51.28@2x

Policy decisions over timeで確認可能です。ここで青色が拒否された回数、赤色が許可された回数を表します。test_policy.pyはそれぞれ許可・拒否が発生するリクエストなので予定通りです。ざっくりとした傾向はここで確認できます。

ビジュアルだけではなく、個々のトレースからも拒否が発生したリクエストを確認したい場合は、OverviewからTracesにタブを切り替えて見れます。

CleanShot 2025-12-06 at 09.06.20@2x

Policy DecisionDENYALLOWが記載されて一覧で確認可能です。もしPolicy Decisionが表示カラムとして存在しない場合は、歯車マークから表示カラムの追加が可能です。

CleanShot 2025-12-06 at 09.10.10@2x

個々のトレースレベルで挙動を確認したい場合は、Trace IDをクリックすることで確認可能です。
例えばDENYのトレースを追ってみます。

CleanShot 2025-12-06 at 09.12.24@2x

開いたらトレース全体のイベントが表示されます。
ここから個々のスパン詳細を確認することが可能ですが、今回はログでの拒否がどう記録されているか確認します。実際にログで拒否されている場合は、どのようなリクエストを送っているかを確認する形になると思います。

AgentCore.Policy.AuthorizeActionを選択します。

CleanShot 2025-12-06 at 09.14.58@2x

Metadataを開くと、aws.agentcore.policy.authorization_decisionALLOWDENYか記載があります。またaws.agentcore.policy.authorization_reasonに拒否された理由があります。

CleanShot 2025-12-07 at 08.52.33@2x

{
  "traceId": "69336f8e796bb6e73c15bf3a1d38a970",
  "spanId": "e1f25f8221d211b3",
  "flags": 0,
  "name": "AgentCore.Policy.AuthorizeAction",
  "kind": "CLIENT",
  "startTimeUnixNano": 1764978574459000000,
  "endTimeUnixNano": 1764978574459000000,
  "durationNano": 0,
  "attributes": {
    "aws.local.service": "testgateway8ede8d86-xxx",
    "telemetry.extended": true,
    "rpc.service": "RefundPolicyEngine-mi3ro9_bj0",
    "aws.request.id": "06fc5baf-600e-42c8-8bfa-12815b59f292",
    "rpc.system": "aws-api",
    "aws.remote.service": "AWS::RefundPolicyEngine-mi3ro9_bj0",
    "aws.resource.type": "AWS::BedrockAgentCore::Gateway",
    "aws.agentcore.gateway.policy.mode": "LOG_ONLY",
    "aws.local.environment": "generic:default",
    "aws.remote.operation": "AuthorizeAction",
    "http.status_code": 200,
    "aws.local.operation": "UnmappedOperation",
    "aws.agentcore.policy.authorization_decision": "DENY",
    "aws.span.kind": "CLIENT",
    "aws.agentcore.policy.authorization_reason": "Policy evaluation denied due to no determining policies",
    "rpc.method": "AuthorizeAction",
    "aws.xray.origin": "AWS::BedrockAgentCore::Gateway",
    "aws.resource.arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-feklilrkin",
    "aws.agentcore.gateway.policy.arn": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:policy-engine/RefundPolicyEngine-mi3ro9_bj0",
    "aws.agentcore.policy.target_resource.id": "testgateway8ede8d86-feklilrkin",
    "aws.agentcore.policy.determining_policies": [],
    "aws.agentcore.policy.mismatched_policies": [],
    "PlatformType": "Generic",
    "http.response.status_code": 200
  },
  "status": {
    "code": "OK"
  },
  "resource": {
    "attributes": {
      "cloud.resource_id": "arn:aws:bedrock-agentcore:us-west-2:xxxxxxxxxxxx:gateway/testgateway8ede8d86-feklilrkin",
      "cloud.provider": "aws",
      "service.name": "testgateway8ede8d86-feklilrkin",
      "cloud.platform": "aws_bedrock_agentcore"
    }
  },
  "parentSpanId": "7c04545014a52945"
}

この結果を踏まえて、全体概要などを見つつリクエストが設計通り許可・拒否されているか、意図せぬ結果になっていないかを確認する形になると思います。

まとめ

本記事を3行でまとめると下記となります。

  • LOG_ONLYモードでは、ポリシーに違反するリクエストも拒否されずに処理される
  • ポリシー判定結果はCloudWatchログではなく、トレース(GenAI Observability)で確認する
  • ダッシュボードの「Policy decisions over time」で傾向を把握し、個別トレースで詳細を確認できる

今後はアップデートなどで便利になっていくかもしれませんが。現状はこんな流れかと思います!(もしもっとログの便利な見方があれば教えてください・・・!!)

おわりに

本記事ではLOG_ONLYモードの挙動やログの確認を行いました!
いきなりポリシーを本番運用する前に、LOG_ONLYモードを活用して挙動を確認して、意図通りの設計になっているか確認したいですね。

ただ現状、ポリシーの許可・拒否のログを確認するのはCloudWatchではなく、トレース側で確認する必要があるのは少し注意が必要です。

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

この記事をシェアする

FacebookHatena blogX

関連記事