はじめに
自宅では、Fortinet製のファイアウォール「FortiGate」を使っています。その通信ログを自然言語で調査できるエージェントを、Amazon Bedrock AgentCoreで作りました。
苦戦したのはログ検索ではなく認証でした。CognitoのJWT、Workload Identity、IAMがそれぞれどこで使われるのか分からず、エラーのたびに設定を行き来しました。この記事では、実際に作った構成をもとに認証の流れを整理します。
作った調査エージェント
作成したのは、Webのチャット画面からFortiGateの通信ログを調査できるエージェントです。日本語で質問すると、CloudWatch Logs Insightsでログを検索し、結果を要約して返します。
画像の例では、「直近24時間でブロックされた通信のトップ送信元は?」と質問しています。エージェントは送信元別のブロック件数を集計し、トップの送信元について宛先ポートや過去のログも続けて調査しました。その結果、通信がUDP/6537のブロードキャストに集中していることや、過去と比べてブロック件数が約99%減っていることまで確認できました。

全体アーキテクチャ

▪️ FortiGateログをCloudWatch Logsへ送る
CloudWatch Logsでは、2026年6月23日にマネージドsyslog取り込みが提供されました。AWSの発表では、次のように説明されています。
「ファイアウォール、ルーター、スイッチ、Linuxサーバーから、syslogメッセージをCloudWatch Logsへ直接送信できます」
これにより、EC2などにsyslogの中継サーバーを用意しなくても、ネットワーク機器からVPCエンドポイントへログを送れるようになりました。今回の構成では、FortiGateがUDP/514で送信したログをSite-to-Site VPN経由でsyslog用VPCエンドポイントへ届け、CloudWatch Logsの/syslog/fortigateへ格納します。
▪️ ブラウザからRuntimeを直接呼ぶ
利用者のブラウザはCloudFrontとS3からWeb UIを取得し、Cognitoでログインしてアクセストークンを受け取ります。そのトークンを付けて、AgentCore RuntimeのInvokeAgentRuntimeを直接呼び出します。
ブラウザでAWSの一時認証情報を取得してSigV4署名する必要がないため、RuntimeのInbound AuthにはJWT認証を選びました。
▪️ エージェントがログを調査する
Runtime上のエージェントは、Gateway経由でLambdaを呼び出し、CloudWatch Logs Insightsのクエリを実行します。AgentCore Memoryには会話履歴と調査で注目したIPを保存し、別セッションからも参照できるようにしました。
認証・認可の全体像
この構成の認証は、大きく3段階です。ブラウザからRuntimeへは利用者のJWT、RuntimeからGatewayへはGateway用のM2Mアクセストークン、GatewayからLambdaへはGatewayサービスロールによるSigV4を使います。
Gateway用のM2Mアクセストークンは、AgentCore IdentityのOAuth 2.0 Credential Providerを通じて取得します。Client SecretはSecrets Managerに保存され、取得したOAuthトークンはToken Vaultで管理されます。全体の流れは次のとおりです。

LLM推論、Memory、Secrets Manager、SSEは省略しています。②〜④の内訳は次の表で整理します。
| ポイント | 処理 | 使用するID・資格情報 | 確認内容 |
|---|---|---|---|
| ① | ブラウザからRuntime | Cognito発行のアクセストークン | WebクライアントIDとFortiGateOperatorsグループが一致するか |
| ② | RuntimeからAgentCore Identity | Workload Access TokenとRuntime実行ロール | 利用者・Workload Identityを識別し、IAMのGetResourceOauth2Token権限を確認 |
| ③ | AgentCore IdentityによるClient Secretの参照 | Credential Providerにひも付くSecret | Runtime実行ロールがsecretsmanager:GetSecretValueを持つか |
| ④ | AgentCore IdentityからCognito | client_id、client_secret、scope |
クライアント資格情報と要求スコープを検証 |
| ⑤ | RuntimeからGateway | Cognito発行のM2Mアクセストークン | M2MクライアントIDとagentcore-fortigate-gw/invokeスコープが一致するか |
| ⑥ | GatewayからLambda | Gatewayサービスロール(SigV4) | IAMのlambda:InvokeFunction |
①と⑤はどちらも受信側がJWTを検証します。①はRuntimeのInbound Auth、⑤はRuntimeから見ればOutbound Auth、Gatewayから見ればInbound Authです。⑥はGatewayのIAMロールで認可されます。
RuntimeとGatewayのInbound Auth(①・⑤)
▪️ JWT authorizerの設定
RuntimeとGatewayの設定はほぼ同じです。
# ① ブラウザ → Runtime
custom_jwt_authorizer {
discovery_url = local.cognito_discovery_url
allowed_clients = [aws_cognito_user_pool_client.web.id]
custom_claim {
inbound_token_claim_name = "cognito:groups"
inbound_token_claim_value_type = "STRING_ARRAY"
authorizing_claim_match_value {
claim_match_operator = "CONTAINS"
claim_match_value {
match_value_string = "FortiGateOperators"
}
}
}
}
# ⑤ Runtime → Gateway
custom_jwt_authorizer {
discovery_url = local.cognito_discovery_url
allowed_clients = [aws_cognito_user_pool_client.m2m.id]
allowed_scopes = ["agentcore-fortigate-gw/invoke"]
}RuntimeとGatewayは、受け取ったアクセストークンの署名と発行元を検証し、client_idがallowed_clientsに含まれるかを確認します。さらにRuntimeではcognito:groupsにFortiGateOperatorsが含まれること、Gatewayではscopeにagentcore-fortigate-gw/invokeが含まれることも確認します。
▪️ allowed_clientsだけでは利用者を制限できない
allowed_clientsは、アクセストークンのclient_idが許可したCognitoアプリクライアントIDと一致するかを確認します。この値が表すのは利用者ではなくWebアプリであるため、同じWebアプリからログインした利用者には同じclient_idが入ります。そのため、allowed_clientsだけでは利用者を区別できません。
そこでRuntimeでは、cognito:groupsにFortiGateOperatorsが含まれることも認可条件にしました。
"cognito:groups": ["FortiGateOperators"]Gatewayでは、M2MクライアントIDに加えてagentcore-fortigate-gw/invokeスコープも検証します。これはCognitoのResource Serverに定義した「Gatewayを呼び出す権限」となります。
なお、RuntimeのInbound AuthではJWT認証とIAM SigV4を併用できません。JWT認証を設定したRuntimeは、CognitoのアクセストークンをBearer Tokenとして呼び出します。
RuntimeからGatewayへのOutbound Auth(②〜④)
ブラウザからRuntimeへ送る利用者のJWTは、RuntimeのInbound Authで認証・認可するためのものです。Gatewayの呼び出しには使いません。
エージェントがGatewayを呼ぶときは、AgentCore IdentityからGateway用のM2Mアクセストークンを別に取得します。Gatewayは、そのトークンのクライアントIDとスコープをInbound Authで検証します。
このように、エージェントが外部サービスを呼ぶためのOAuthトークンやAPIキーを取得する仕組みがOutbound Authです。今回の流れは次のようになります。
【Workload Access Tokenの発行】
利用者JWTのiss・sub
+
RuntimeのWorkload Identity
↓
Workload Access Token
【Gateway用トークンの取得】
Workload Access Token
+
Runtime実行ロール
↓ GetResourceOauth2Token
AgentCore Identity
↓ WATを検証し、IAM権限を確認
Credential Providerの資格情報を使用
↓ client_credentials
Gateway用M2Mアクセストークン
↓
GatewayWorkload Access Tokenは、利用者とRuntimeをひも付け、AgentCore Identityから外部サービス用の資格情報を取得する際に使う内部トークンです。Gateway用M2Mアクセストークンとは別物であり、Gatewayへは送りません。
▪️ Workload Identityで要求元を識別する
AgentCore Identityが資格情報を渡すには、どのエージェントからの要求なのかを識別する必要があります。そのために使われるのがWorkload Identityです。
“Workload identities represent the digital identity of your agents within the AWS environment.”
「Workload Identityは、AWS環境内におけるエージェントのデジタルIDを表します」
今回の構成では、Runtimeに対応するWorkload Identityが要求元のエージェントを表します。
Runtimeは、ブラウザから受け取ったJWTをWorkload Access Tokenへ交換します。このトークンには、利用者とエージェントの情報が含まれます。
“Tokens contain both user identity and agent identity information for secure credential access.”
「トークンには、安全に資格情報へアクセスするため、利用者とエージェント双方のID情報が含まれます」
AgentCore Identityは、このトークンから「どの利用者が、どのRuntimeを通じて要求しているか」を識別します。Workload Access TokenはAgentCore内部で使うもので、Gatewayへは送りません。
今回はM2Mのため、最終的にGatewayへ送るアクセストークンが表すのはCognitoのM2Mクライアントです。ブラウザの利用者情報がGateway用トークンへ引き継がれるわけではありません。
▪️ Credential Providerにトークンの取得方法を登録する
Workload Access Tokenによって要求元は識別できますが、それだけではGateway用トークンを取得できません。どの認証サーバーから、どの資格情報を使って取得するのかをOAuth 2.0 Credential Providerへ登録します。
今回はCognitoにGateway呼び出し用のM2Mクライアントを作成し、Credential Providerへ次の情報を登録しました。
- Cognitoのトークンエンドポイント
- M2MクライアントのClient IDとClient Secret
agentcore-fortigate-gw/invokeスコープclient_credentialsgrant
AgentCore Identityはこの設定を使い、CognitoからGateway用アクセストークンを取得します。Client SecretはAgentCoreによってSecrets Managerへ保存されるため、エージェントコードへ直接渡す必要はありません。
agentcore-fortigate-gw/invokeは、CognitoのResource Serverに定義したカスタムスコープです。Cognitoはこのスコープを含むトークンを発行し、Gatewayは同じスコープが含まれていることを確認します。
▪️ requires_access_tokenでトークン取得を開始する
要求元を表すWorkload Access Tokenと、取得方法を定義したCredential Providerをつなぐのがrequires_access_tokenデコレータです。
@requires_access_token(
provider_name="fortigate-gateway-m2m",
scopes=["agentcore-fortigate-gw/invoke"],
auth_flow="M2M",
into="token",
)
async def _get_gateway_token(*, token: str) -> str:
return tokenデコレータを実行すると、Workload Access Tokenを使ってAgentCore Identityへトークン取得を要求します。AgentCore Identityは、fortigate-gateway-m2mに登録した資格情報を使い、CognitoからM2Mアクセストークンを取得します。
取得されたアクセストークンはtoken引数へ渡されます。エージェントはこのトークンをBearer TokenとしてGatewayへ送り、GatewayはクライアントIDとagentcore-fortigate-gw/invokeスコープを検証します。
▪️ IAMでCredential Providerへのアクセスを制限する
Workload Access Tokenは要求元を識別しますが、Credential ProviderやSecretへのアクセスを許可するかどうかはIAMが決めます。
ここを理解できておらず、Gateway用トークンを取得できない原因をCognito側の設定だと思い込んでいました。実際には、Runtime周辺のIAM権限が不足していました。
| 処理 | 必要な権限 | 権限を持つロール |
|---|---|---|
| JWTをWorkload Access Tokenへ交換 | bedrock-agentcore:GetWorkloadAccessTokenForJWT |
Identityサービスリンクロール |
| Gateway用トークンを取得 | bedrock-agentcore:GetResourceOauth2Token |
Runtime実行ロール |
| Client Secretを読み取る | secretsmanager:GetSecretValue |
Runtime実行ロール |
2025年10月13日以降に作成または更新したRuntimeでは、JWTからWorkload Access Tokenへの交換をIdentityサービスリンクロールが担当します。
Runtime実行ロールには、GetResourceOauth2TokenとGetSecretValueを追加しました。権限の対象は、今回使用するWorkload Identity、Credential Provider、Token Vault、SecretのARNに限定しています。
GatewayからLambdaへのIAM認証(⑥)
GatewayはM2Mアクセストークンを検証した後、自身のサービスロールを使ってLambdaを呼び出します。この区間はJWTではなくIAM認証で、サービスロールにlambda:InvokeFunctionを許可しています。呼び出されたLambdaがCloudWatch Logs Insightsを実行します。
まとめ
FortiGate調査エージェントを作り、認証・認可を通信ごとに追いました。ブラウザからRuntimeへは利用者のCognito JWT、RuntimeからGatewayへはAgentCore Identityで取得したGateway用のM2Mアクセストークン、GatewayからLambdaへはサービスロールを使います。Inbound Authは受信時の検証、Outbound Authは送信に使う資格情報の取得と考えると、役割を分けて理解できました。
次に試したいこと
今回のエージェントは読み取り専用です。次は、LLMが生成するLogs Insightsクエリの検索期間や件数を制限し、ログ経由のプロンプトインジェクションも検証します。その先で、FortiGate設定との照合、人間の承認を伴う期限付きブロック、誤検知時の自動解除まで試す予定です。
参考リンク
- Amazon Bedrock AgentCore公式ドキュメント
- Authenticate and authorize with Inbound Auth and Outbound Auth
- Set up outbound authorization for your gateway
- Amazon CloudWatch Logs supports managed syslog ingestion
- CloudWatch Logsのマネージドsyslogインジェスト
- Strands Agents
- Amazon Bedrock AgentCore 実践入門 Strands Agentsで構築するAIエージェント[AWS深掘りガイド](御田稔、森田和明、熊田寛 著/SBクリエイティブ)
書籍はアイデンティティとゲートウェイが章立てで解説されており、コンポーネント同士の関係を整理するのに何度も助けられました。