サーバーサイド - TECH PLAY - TECH PLAY

TECH PLAY

サーバーサイド

イベント

マガジン

技術ブログ

はじめに こんにちは! KINTOテクノロジーズのデジタル戦略部DataOpsグループ所属の三浦です。 普段は、社内のデータ分析基盤の開発・保守・運用に加え、Google Analytics 4(以下、GA4)やGoogleタグマネージャー(以下、GTM)を利用した、Webサイトのアクセス解析や計測環境の整備を担当しています。 WebサイトでGA4やGoogle広告を計測する場合、一般的にはGoogleドメインからGoogleタグを読み込み、Googleドメインへ計測リクエストを送信します。 一方、ブラウザのプライバシー保護機能や広告ブロッカーなどの影響により、Googleタグの読み込みや計測リクエストがブロックされ、イベントが欠損することがあります。 今回、この課題への対応として、既存のAmazon CloudFrontを利用し、Googleタグゲートウェイを導入しました。 本記事では、Googleタグゲートウェイを導入した背景や構成、社内での役割分担、検証時に確認したポイント、導入後に確認できた効果について紹介します。 本記事の対象者 本記事は、以下のような方を対象としています。 GTMやGA4を利用したWebサイトの計測を担当している方 Googleタグゲートウェイの導入を検討している方 Amazon CloudFrontをCDNとして利用している方 本記事では、CloudFrontの細かな設定手順ではなく、導入時の考え方や進め方、検証内容を中心に紹介します。 Googleタグゲートウェイ導入の背景と概要 背景 当グループでは、Webサイトの利用状況や広告施策の成果を把握するため、GTMを利用してGA4やGoogle広告などの計測タグを配信しています。 通常の構成では、WebサイトからGoogleドメイン上のGoogleタグを読み込み、計測したイベントをGoogleドメインへ送信します。 通常のGoogleタグ配信の構成 しかし、Googleドメインへの通信は、ブラウザのプライバシー保護機能や広告ブロッカーなどによって、制限されることがあります。 計測タグや計測リクエストがブロックされると、ユーザーが実際にページを閲覧したり、コンバージョンしたりしていても、GA4やGoogle広告へイベントが送信されません。 その結果、以下のような課題が発生する可能性があります。 GA4で確認できるイベント数が、実際の発生件数より少なくなる コンバージョン数が正しく計測されない Webサイトの施策評価に使用するデータが不完全になる 広告経由の成果を正しく評価できない 広告配信の最適化に使用するコンバージョンデータが不足する 特に広告配信では、計測したコンバージョンデータが、自動入札や配信対象の最適化に利用されます。 そのため、イベントの欠損は、レポート上の数値が少なくなるだけでなく、広告配信の学習や最適化にも影響する可能性があります。 実際に対象サイトでは、GA4で計測しているコンバージョンページのイベント数と、バックエンドのデータベースに保存されているコンバージョン件数に差がありました。 もちろん、GA4とバックエンドのデータベースでは、計測の仕組みや集計条件が異なります。 そのため、数値が完全に一致するものではありません。 一方で、差が大きい状態では、実際に発生したコンバージョンの一部をGA4で取得できていない可能性があり、広告施策やサイト改善を評価するうえで課題となっていました。 そこで、Googleタグへの通信を自社ドメイン経由に変更し、タグやイベントがブロックされる影響を軽減することを目的として、Googleタグゲートウェイを導入しました。 概要 対象のWebサイトでは、CDNとしてすでにAmazon CloudFrontを利用していました。 そのため、新たにサーバーを構築するのではなく、既存のCloudFrontを利用してGoogleタグゲートウェイへの通信を中継する構成を採用しました。 導入後の構成は以下のとおりです。 flowchart TB Browser[Webブラウザ] --> Domain[Webサイトと同じ自社ドメイン] Domain --> CF[Amazon CloudFront] CF -->|通常のWebコンテンツ| Origin[既存の配信先] CF -->|Googleタグゲートウェイ用のパス| GTG[Googleタグゲートウェイ] GTG --> GA4[GA4・Google広告など] Webサイト上にGoogleタグゲートウェイ用のパスを用意し、そのパスへの通信をCloudFrontからGoogle側へ転送します。 ブラウザから見ると、Googleタグの読み込み先や対象となる計測リクエストの送信先が、Googleドメインではなく、Webサイトと同じ自社ドメインになります。 Googleタグゲートウェイ導入前後の構成図 要素技術・アーキテクチャの紹介 ここからは、今回の導入で利用したGoogleタグゲートウェイとAmazon CloudFrontについて紹介します。 Googleタグゲートウェイとは? Googleタグゲートウェイ( Google tag gateway for advertisers )は、自社が管理するCDNやロードバランサーなどのインフラを利用して、Googleタグを自社ドメイン経由で配信する仕組みです。 通常はGoogleドメインから読み込まれるGoogleタグを、自社ドメイン上の特定のパスから読み込めるようにします。導入前後の経路の違いは、前述の「 概要 」節の構成図のとおりです。 Googleタグゲートウェイでは、GA4のイベント設計や、GTMコンテナ内のタグの処理内容を大きく変更するのではなく、Googleタグへアクセスする経路を変更します。 そのため、既存のGTMコンテナ内のタグ、トリガー、変数などを維持したまま導入できます。 Amazon CloudFrontとは? Amazon CloudFront は、AWSが提供するCDNサービスです。 Webサイトのコンテンツを利用者に近い拠点から配信することで、表示速度や可用性の向上に利用されます。 CloudFrontでは、アクセスされたURLのパスに応じて、異なる配信先へリクエストを振り分けられます。 今回はこの仕組みを利用し、Googleタグゲートウェイ用のパスへの通信のみを、Google側へ転送するようにしました。 サーバーサイドGTMとの違い Googleタグゲートウェイと混同しやすい仕組みに、サーバーサイドGTMがあります。 サーバーサイドGTMでは、サーバー用のGTMコンテナを構築し、サーバー側で計測リクエストを処理し、送信先を制御します。 一方、Googleタグゲートウェイは、Googleタグの読み込みや対象となる計測リクエストを、自社ドメイン経由に変更する仕組みです。 観点 Googleタグゲートウェイ サーバーサイドGTM 変更するもの Googleタグへの通信経路 計測リクエストの処理・送信先 追加で必要なもの CDN / ロードバランサーの設定 サーバー用GTMコンテナと実行環境 既存のWeb用GTMコンテナ そのまま利用 サーバー用コンテナ向けの設定追加が必要 今回の目的は、既存のGTM構成を維持しながら、Googleタグへの通信経路を変更することでした。 そのため、新たなサーバー用GTMコンテナは構築せず、既存のCloudFrontとWeb用のGTMコンテナを利用する構成を採用しました。 導入の進め方 各担当者の役割分担 今回の導入では、計測担当だけでなく、インフラ担当、プロダクトチームのサイト管理者と連携して進めました。 大きな役割分担は以下のとおりです。 DataOpsグループ・計測担当 Googleタグゲートウェイの導入目的と要件の整理 対象ドメインや対象環境の整理 Googleタグゲートウェイ用パスの検討 ブラウザやGA4を利用した動作確認 既存の計測への影響確認 導入前後のイベント数の比較 インフラ担当 CloudFrontへのGoogleタグゲートウェイ用設定の追加 Googleタグゲートウェイへの転送設定 検証環境と本番環境への設定反映 必要に応じたCloudFrontやWAFの調査 プロダクトチーム・サイト管理者 Webサイトに設置しているGTMコードスニペットの差し替え 検証環境と本番環境へのリリース Googleタグゲートウェイは、GTMやGA4だけで完結する機能ではありません。 CDNなどの配信基盤と、Webサイトへ設置しているGTMコードスニペットの両方に対応が必要です。 そのため、導入前に各担当者の作業範囲と、検証時の確認項目を整理しました。 GTMコンテナ側の設定は変更しない Amazon CloudFrontを利用した今回の構成では、GTMコンテナ側でGoogleタグゲートウェイ用の設定変更は行っていません。 既存の本番用GTMコンテナを、そのまま利用しました。 変更したのは、Webサイトに設置されているGTMコードスニペットの読み込み先です。 変更前 GoogleドメインからGTMコンテナを読み込む 変更後 自社ドメイン上のGoogleタグゲートウェイ用パスから 同じGTMコンテナを読み込む GTMコンテナ内のGA4タグ、Google広告タグ、トリガー、変数などは変更していません。 GTMコードスニペットの差し替えについては、Webサイトを管理しているプロダクトチームへ依頼し、検証環境と本番環境へ反映してもらいました。 通信経路のみを変更する構成だったため、既存の計測設計への変更を抑えて導入を進められました。 検証用GTMコンテナは作成しない 今回の導入では、Googleタグゲートウェイの検証用に、新しいGTMコンテナは作成しませんでした。 実際に本番環境で利用しているGTMコンテナを、検証環境でもそのまま利用しました。 導入の流れは以下のとおりです。 検証環境のCloudFrontへ設定 検証環境のGTMコードスニペットを差し替え 検証環境で動作確認 本番環境のCloudFrontへ設定 本番環境のGTMコードスニペットを差し替え 本番環境で動作確認 先に検証環境のCDNへGoogleタグゲートウェイの設定を追加し、プロダクトチームに検証環境のGTMコードスニペットを差し替えてもらいました。 そこで問題がないことを確認した後、本番環境のCloudFront設定とGTMコードスニペットを変更しました。 本番用のGTMコンテナをそのまま使用したことで、検証用コンテナと本番用コンテナの間に設定差分が発生しません。 実際に本番で使用するタグ構成のまま、通信経路の変更による影響を確認できました。 検証時のポイント Googleタグが自社ドメインから読み込まれているか 最初に、ブラウザの開発者ツールにあるNetworkタブを利用し、GTMコンテナの読み込み先を確認しました。 導入前はGoogleドメインから読み込まれていたGTMコンテナが、導入後は自社ドメイン上のGoogleタグゲートウェイ用パスから読み込まれていることを確認します。 導入前 https://www.googletagmanager.com/... 導入後 https://www.example.com/<Googleタグゲートウェイ用パス>/... 読み込み先だけでなく、HTTPステータスコードが正常であることや、ページ表示時にGTMコンテナが問題なく実行されていることも確認しました。 既存のタグがこれまでどおり発火するか Googleタグの読み込み先を変更しても、GTMコンテナ内のタグやトリガーが、これまでどおり動作する必要があります。 GTMのプレビューモードを利用し、以下を確認しました。 ページ表示時に必要なタグが発火すること クリックなどのイベントタグが発火すること GA4へ必要なイベントが送信されること イベントパラメータの値が導入前と変わっていないこと 同一イベントが重複して送信されていないこと 今回、GTMコンテナ内の設定自体は変更していません。 そのため、通信経路を変更したことで、既存のタグ発火やイベント送信に影響が出ていないかを中心に確認しました。 GA4でイベントを確認できるか ブラウザ上でタグが発火していても、最終的にGA4へイベントが到達していなければ、計測は成立しません。 GA4のDebugViewやリアルタイムレポートを利用し、以下を確認しました。 ページビューが送信されていること 主要なイベントが送信されていること イベントパラメータが欠損していないこと page_location などの値が正しいこと コンバージョンページのイベントが送信されていること 導入前と比較して、想定外の重複や減少がないこと Googleタグゲートウェイを経由した場合でも、GA4上では、これまでと同じイベント名やパラメータとして確認できます。 SPAの画面遷移も確認する 対象サイトには、ページ全体を再読み込みせずに画面を切り替えるSPA形式のページもありました。 SPAでは、初回表示時にGTMコンテナが正常に読み込まれていても、その後の画面遷移でページビューやイベントが正しく送信されるとは限りません。 そのため、以下を分けて確認しました。 ページを最初に表示したときの計測 ページ内で画面遷移したときの計測 画面遷移後の page_location 仮想ページビューの発火 前画面の値が dataLayer に残っていないか 同じイベントが重複して送信されていないか Googleタグゲートウェイ自体は通信経路を変更する仕組みですが、導入を機に、既存のSPA計測が正常に動作していることも合わせて確認しました。 プレビューモードだけで判断しない GTMのプレビューモードでは正常に見えていても、プレビューモードを利用しない通常アクセスでは、想定した通信が発生していない場合があります。 そのため、以下の両方で確認しました。 GTMのプレビューモードを利用した状態 プレビューモードを利用しない通常アクセス 問題が発生した場合は、以下の順番で確認すると、原因を切り分けやすくなります。 Webサイト上でGTMコードスニペットが実行されているか GTMコンテナが読み込まれているか 対象のタグが発火しているか ブラウザから計測リクエストが送信されているか CloudFrontへリクエストが到達しているか Google側へ転送されているか GA4でイベントを確認できるか ブラウザのNetworkタブにリクエスト自体が表示されていない場合は、CloudFrontより前のWebサイトやGTMの処理を確認します。 一方、ブラウザからリクエストが送信されているものの、エラーになっている場合は、インフラ担当と連携して、CloudFrontやWAFなどを確認します。 すべての通信が自社ドメイン経由になるわけではない 検証時には、ブラウザのNetworkタブからGoogle関連の通信を確認しました。 その結果、GA4の計測では自社ドメイン経由になっている通信を確認できましたが、一部の通信は、引き続きGoogleドメインへ送信されていました。 :::message Googleタグゲートウェイを導入したからといって、Googleに関係するすべての通信が自社ドメイン経由になるわけではありません。 ::: そのため、Googleドメインへの通信が完全になくなるかどうかではなく、対象となるGoogleタグや計測リクエストが、想定どおり自社ドメインを経由しているかを確認しました。 導入後の効果 Googleタグゲートウェイの導入後、タグの発火状況と、コンバージョンページのイベント数を確認しました。 タグの発火状況が改善した 導入前は、Googleタグの読み込みや計測リクエストをGoogleドメインへ直接送信していました。 導入後は、対象通信が自社ドメインを経由する構成へと変更されました。 これにより、広告ブロッカー等に起因するタグの未発火が抑制され、GA4へ送信されるイベント数が前月比・前週比で約10〜15%増加しました。 :::message 旧環境との完全な並行稼働による厳密な差分比較はできないため、前後期間の傾向に基づく推定値です。 ::: Googleタグゲートウェイを導入しても、すべてのユーザー環境で必ずタグが発火するようになるわけではありません。 例えば、以下のような要因によって、引き続きイベントが送信されない可能性があります。 JavaScriptが無効化されている ユーザーの同意状況によって計測が制限されている ページ表示が完了する前にユーザーが離脱した ブラウザやネットワークの状態によって通信に失敗した 一方で、Googleドメインへの直接通信がブロックされることによるイベント欠損については、一定の改善効果を確認できました。 GA4とバックエンドデータベースの数値差が縮小した 今回、導入効果を確認するため、GA4で計測したコンバージョンページのイベント数と、バックエンドのデータベースに保存されているコンバージョン件数を比較しました。 導入前は、バックエンドのデータベース上ではコンバージョンが記録されているものの、GA4では対応するイベントを確認できないケースがあり、両者の数値に大きな差がありました。 導入前 バックエンドDBのコンバージョン件数 > GA4のコンバージョンページイベント数 Googleタグゲートウェイの導入後は、GA4で確認できるコンバージョンページのイベント数が増加し、バックエンドのデータベースに記録されている件数へ大きく近づきました。 導入後 バックエンドDBのコンバージョン件数 ≒ GA4のコンバージョンページイベント数 バックエンドのデータベースとGA4では、計測の仕組みや集計条件が異なるため、両者の数値が完全に一致するとは限りません。 例えば、コンバージョン処理がバックエンドで完了していても、ユーザーが完了ページを表示する前に離脱した場合は、GA4のページイベントが発生しない可能性があります。 また、同意設定やブラウザ環境などによって、GA4への送信が制限される場合もあります。 それでも、導入後に両者の数値差が大きく縮小したことから、これまで欠損していた一部のイベントを取得できるようになったと考えています。 広告施策の評価に利用するデータが改善した コンバージョンイベントの取得数が増えたことで、GA4やGoogle広告で確認できるデータが、実際のコンバージョン状況により近づきました。 これにより、広告施策ごとの成果を、導入前より正確に評価できるようになりました。 また、Google広告へ連携されるコンバージョンデータの欠損が減ることで、自動入札や広告配信の最適化に利用できるデータ量の改善も期待できます。 ただし、広告の成果や配信精度は、以下のような複数の要因に左右されます。 広告予算 入札戦略 ターゲティング 広告クリエイティブ ランディングページ 市場環境 コンバージョン設定 そのため、Googleタグゲートウェイの導入だけで広告成果や広告精度が向上したとは断定していません。 今回の主な成果は、広告施策の評価や配信最適化に利用する、コンバージョンデータの欠損を減らせたことだと考えています。 振り返り GTMコンテナ内の変更を抑えて導入できた 今回の構成では、GTMコンテナ内のGA4タグ、Google広告タグ、トリガー、変数などを変更していません。 CloudFront側の通信経路と、Webサイトに設置しているGTMコードスニペットの読み込み先を変更することで導入できました。 既存の計測設計への影響を抑えながら導入できた点は、大きなメリットでした。 検証環境から段階的に導入することが重要 いきなり本番環境へ反映するのではなく、先に検証環境のCloudFront設定とGTMコードスニペットを変更しました。 検証環境では、GTMコンテナの読み込み、GA4イベント、SPA遷移、コンバージョンページなどを確認しました。 問題がないことを確認した後に本番環境へ展開することで、既存計測への影響を抑えながら導入できました。 複数チームの連携が必要 Googleタグゲートウェイは、GTMやGA4だけでなく、CloudFrontなどの配信基盤と、Webサイトに設置されるコードにも関係します。 今回の導入では、DataOpsグループ、インフラ担当、プロダクトチームがそれぞれ以下を担当しました。 DataOpsグループ:要件整理、計測確認、効果検証 インフラ担当:CloudFrontの設定 プロダクトチーム:GTMコードスニペットの差し替え 事前に担当範囲を整理したことで、検証環境から本番環境への展開をスムーズに進められました。 レイヤーごとに切り分けることが重要 Googleタグゲートウェイ導入後の通信には、複数の要素が関係します。 Webサイト ↓ GTMコードスニペット ↓ GTMコンテナ ↓ ブラウザ ↓ Amazon CloudFront ↓ Googleタグゲートウェイ ↓ GA4・Google広告など 問題が発生した場合は、最初からすべてを調査するのではなく、どこまで正常に処理されているかを順番に確認することが重要です。 ブラウザのNetworkタブ、GTMのプレビューモード、GA4のDebugViewなどを組み合わせることで、問題がWebサイト側にあるのか、GTMにあるのか、インフラ側にあるのかを切り分けやすくなりました。 おわりに 今回は、Amazon CloudFrontを利用して、Googleタグゲートウェイを導入した事例を紹介しました。 Googleタグゲートウェイの導入だけで、すべてのイベント欠損を防げるわけではありません。 一方で、Googleドメインへの直接通信がブロックされることによる欠損を軽減し、サイト改善や広告施策の判断に利用するデータを、実態に近づける効果を確認できました。 Amazon CloudFrontを利用してGoogleタグゲートウェイの導入を検討されている方にとって、本記事が少しでも参考になれば幸いです。
財務アナリストが AI アシスタントに「私の担当する顧客請求書のうち、支払期日を過ぎているものはどれですか?」と尋ね、SAP から直接その答えが返ってくる、そんな場面を想像してみてください。企業はまさにこれを求めていますが、AI エージェントを記録システムに接続する際には難しい問いが生じます。エージェントが SAP にアクセスするとき、そのリクエストを行っているのは誰なのか、という問いです。初期の統合の多くは、すべてのリクエストを 1 つの共有 SAP サービスユーザー経由でルーティングします。これでは、すべてのユーザーの操作が単一のテクニカルユーザーにマッピングされてしまうため、SAP は実際の操作者を認可・監査できなくなり、さらにセキュリティおよびコンプライアンスチームがめったに承認しない静的な SAP 認証情報の保存を強いられます。その結果、有望な AI パイロットが本番稼働に至る前に停滞してしまいます。 完全な ID 伝播は、SAP に至るすべての認証区間を通じて各ユーザーの ID を引き継ぐことでこの問題を解決します。リクエストが指名されたユーザーとして到着すると、SAP はそのユーザー自身の権限を適用し、Security Audit Log にそのユーザーの操作として記録し、共有された恒久的な認証情報を一切保存しません。 RFC 8693 のトークン交換で定義されている On-Behalf-Of(OBO)アクセスは、ユーザーの既存トークンを SAP にスコープを絞ったダウンストリームトークンと交換することで、これを可能にします。Microsoft Entra ID や Okta などのエンタープライズ ID プロバイダー(IdP)はこのフローをサポートしているため、ユーザーは 2 度目のログインプロンプトなしで SSO を利用できます。本ブログでは、その体験を構築する方法を解説します。 Amazon Quick を使って SAP の販売オーダー、財務、プラント保全について質問し、さらにアクションを実行しながら、 AWS for SAP MCP Server と Microsoft Entra ID などのエンタープライズ IdP によって、あなたの ID を SAP まで引き継ぎます。 仕組み エンドツーエンドのフローには 4 つの構成要素があります。MCP クライアントとして動作する AI エージェント(Amazon Quick)、AWS for SAP MCP Server をホストする Amazon Bedrock AgentCore Runtime、Entra ID、そして SAP システムです。フローを通過するために、Amazon Bedrock AgentCore 内には 2 つの異なる認証境界が設定されます。 インバウンド : Amazon Quick が、そのユーザーが誰であるかを AgentCore に証明します。AgentCore は Entra ID に対してユーザー ID を検証します。 アウトバウンド : AgentCore が SAP に受け入れられるトークンを取得します。OBO 交換により、SAP リソースにスコープを絞ったこのトークンが生成されます。 図 1. Amazon Quick、AWS for SAP MCP Server、SAP S/4HANA を統合したシングルサインオンのための高レベルアーキテクチャ。 ユーザーは Entra ID ログイン(メールアドレス)またはシングルサインオンを通じて Amazon Quick にサインインします Amazon Quick は OAuth 2.0 を介して Entra ID でこのユーザーを認証し、AWS for SAP MCP Server にアクセスします AgentCore は Entra ID でアクセストークンを検証します AgentCore はすべてのユーザーアクセスを AgentCore Observability に記録します AWS for SAP MCP Server は Entra ID と OBO 交換を実行し、その JSON Web Token(JWT)が SAP への HTTPS API 呼び出しで使用されます Entra ID が提供する JWT は、SAP の OpenID Connect(OIDC)Trust によって検証されます この設計では、以下に説明する 3 つの Entra ID アプリ登録を使用します。 Amazon Quick Client App – Quick がユーザーをサインインさせるために使用する OAuth クライアント。 Inbound / Resource App – インバウンドトークンを検証し、OBO 交換を実行します。AgentCore の認証情報プロバイダーはその client_id を使用し、これは Quick のトークンの aud でもあります。 Outbound App – SAP アクセススコープを表します。SAP は最終トークンをこのアプリに対して検証します。 Microsoft Entra ID ベースのプロバイダー設定と、関連する構成要素について理解するには、 AgentCore Identity のドキュメント を参照してください。 図 2. 3 つの Entra ID アプリ登録にまたがる委任権限のチェーン。 SAP BTP Integration Suite も、OBO(On Behalf Of)トークンチェーンを通じてこのパターンをサポートし、ID フローを次のように拡張します。Amazon Quick → AWS for SAP MCP Server → SAP BTP Integration Suite → SAP S/4HANA。SAP BTP でプリンシパル伝播と呼ばれる ID 伝播は、SAP BTP API Management によって処理されます。SAP ソリューションへの MCP アクセスパターンに関するベストプラクティスについては、SAP の ガイダンス を参照してください。 実装の詳細 本セクションでは、Entra ID アプリ登録から SAP ユーザーマッピングまで、エンドツーエンドの設定を構成する手順を説明します。この設定の前提条件は以下のとおりです。 要件 詳細 Azure CLI Global Administrator または Application Administrator ロールで認証済みの az CLI AWS CLI 対象の AWS アカウントとリージョン向けに構成済み SAP BASIS 7.56 SP1 以降(または SAP Note 3313726 を適用した 7.52) SAP トランザクション SOIDC が利用可能であること CloudFormation テンプレート s3://awsforsap-mcp-server-setup-{region}/cfn-launch-template/latest/ の最新版 Amazon Quick MCP コネクターを作成するアクセス権。コネクターを登録すると Entra ID に Amazon Quick クライアントアプリが作成されます。Step 4 で使用するため、Entra ID ポータル(App registrations)からその QUICK_APP_ID、QUICK_OBJECT_ID、および委任スコープ ID を取得してください。 OIDC サポートの最新情報については、 SAP のドキュメント を参照してください。 Step 1: インバウンド Entra ID アプリ登録を作成する インバウンドアプリは、MCP クライアントが AgentCore Runtime に認証するために使用するトークンを発行します。この手順の 2 つの設定が、フローの後半で重要になります。まず、 requestedAccessTokenVersion を 2 に設定します。これは OBO 交換と SAP 検証のいずれもが v2.0 トークンを期待するためです。次に、 access_as_user 委任スコープを公開します。これは、Quick クライアントアプリがユーザーの代わりにこのアプリを呼び出すために要求する権限です。 TENANT_ID="<your-entra-tenant-id>" INBOUND_APP_NAME="agentcore-mcp-inbound" # Create the inbound app registration az ad app create --display-name "$INBOUND_APP_NAME" --sign-in-audience "AzureADMyOrg" # Capture the Application (client) ID and Object ID INBOUND_APP_ID=$(az ad app list --display-name "$INBOUND_APP_NAME" --query "[0].appId" -o tsv) INBOUND_OBJECT_ID=$(az ad app list --display-name "$INBOUND_APP_NAME" --query "[0].id" -o tsv) # Require v2.0 tokens and set the Application ID URI az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${INBOUND_OBJECT_ID}" \ --body '{"api":{"requestedAccessTokenVersion":2}}' az ad app update --id "$INBOUND_APP_ID" --identifier-uris "api://${INBOUND_APP_ID}" # Expose the access_as_user delegated scope INBOUND_SCOPE_ID=$(uuidgen) az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${INBOUND_OBJECT_ID}" \ --body "{\"api\":{\"requestedAccessTokenVersion\":2,\"oauth2PermissionScopes\":[{\"adminConsentDescription\":\"Access AgentCore MCP Server\",\"adminConsentDisplayName\":\"access_as_user\",\"id\":\"${INBOUND_SCOPE_ID}\",\"isEnabled\":true,\"type\":\"User\",\"userConsentDescription\":\"Access AgentCore MCP Server on your behalf\",\"userConsentDisplayName\":\"Access AgentCore MCP\",\"value\":\"access_as_user\"}]}}" # Create the service principal az ad sp create --id "$INBOUND_APP_ID" Step 2: アウトバウンド Entra ID アプリ登録を作成する アウトバウンドアプリは SAP アクセスを表します。AgentCore Identity はこれを OBO 交換のターゲットとして使用し、SAP は最終トークンをこれに対して検証します。この手順では sap_access スコープを公開し、インバウンドアプリが要求できる対象を用意します。また、インバウンドアプリを既知のクライアントアプリケーションとして事前承認します。これは、ユーザーに同意を求めることなく、Entra ID が 2 つのアプリ間で OBO トークンを発行できるようにする設定です。 OUTBOUND_APP_NAME="agentcore-mcp-obo-sap" az ad app create --display-name "$OUTBOUND_APP_NAME" --sign-in-audience "AzureADMyOrg" OUTBOUND_APP_ID=$(az ad app list --display-name "$OUTBOUND_APP_NAME" --query "[0].appId" -o tsv) OUTBOUND_OBJECT_ID=$(az ad app list --display-name "$OUTBOUND_APP_NAME" --query "[0].id" -o tsv) # v2.0 tokens + Application ID URI az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${OUTBOUND_OBJECT_ID}" \ --body '{"api":{"requestedAccessTokenVersion":2}}' az ad app update --id "$OUTBOUND_APP_ID" --identifier-uris "api://${OUTBOUND_APP_ID}" # Expose the sap_access delegated scope (SAP validates tokens against this) OUTBOUND_SCOPE_ID=$(uuidgen) az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${OUTBOUND_OBJECT_ID}" \ --body "{\"api\":{\"requestedAccessTokenVersion\":2,\"oauth2PermissionScopes\":[{\"adminConsentDescription\":\"Access SAP on behalf of user\",\"adminConsentDisplayName\":\"sap_access\",\"id\":\"${OUTBOUND_SCOPE_ID}\",\"isEnabled\":true,\"type\":\"User\",\"userConsentDescription\":\"Access SAP on your behalf\",\"userConsentDisplayName\":\"SAP Access\",\"value\":\"sap_access\"}]}}" az ad sp create --id "$OUTBOUND_APP_ID" # Pre-authorize the inbound app as a known client application (enables OBO) az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${OUTBOUND_OBJECT_ID}" \ --body "{\"api\":{\"knownClientApplications\":[\"${INBOUND_APP_ID}\"]}}" Step 3: 権限と管理者同意を構成する この手順では、インバウンドアプリにアウトバウンドアプリの sap_access スコープへの委任権限を付与し、それを管理者同意します。この付与が OBO チェーンのインバウンドからアウトバウンドへの部分を有効にします。なぜなら、Entra ID は要求元アプリがターゲットスコープへの同意済み委任権限を保持している場合にのみ OBO トークンを発行するためです。 az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${INBOUND_OBJECT_ID}" \ --body "{\"requiredResourceAccess\":[{\"resourceAppId\":\"${OUTBOUND_APP_ID}\",\"resourceAccess\":[{\"id\":\"${OUTBOUND_SCOPE_ID}\",\"type\":\"Scope\"}]}]}" az ad app permission admin-consent --id "$INBOUND_APP_ID" Step 4: OBO 権限チェーンを構成する この手順は権限チェーンを完成させるもので、不完全な場合 OBO 交換は失敗します。Entra ID は OBO トークンを発行する前に、次の 4 つを一括で検証します。 アサーションの aud が交換を行う client_id と一致すること クライアントアプリがターゲットスコープへの委任権限を保持していること ターゲットアプリの knownClientApplications にクライアントチェーン全体が含まれていること サービスプリンシパルに対する oauth2PermissionGrant が存在すること 重要な設計原則: OBO クライアントはトークンのオーディエンスと一致しなければならない。 Entra ID OBO では、トークン交換を実行する client_id がアサーショントークンの aud クレームと一致する必要があります。Amazon Quick のトークンは aud = Inbound App ID を持つため、AgentCore の認証情報プロバイダーはアウトバウンドアプリではなくインバウンドアプリの認証情報を使用しなければなりません。ここでの不一致は最も一般的な失敗原因であり、 AADSTS500131 (アサーションオーディエンスの不一致)または AADSTS7000114 (OBO が許可されていない)として現れます。 以下のコマンドは、これらの各要件を構成します。Amazon Quick クライアントアプリを作成済み(前提条件を参照)で、その QUICK_APP_ID、QUICK_OBJECT_ID、およびスコープ ID を取得済みであることを前提とします。 # 1. Add Quick + Inbound to the OUTBOUND app's knownClientApplications az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${OUTBOUND_OBJECT_ID}" \ --body "{\"api\":{\"knownClientApplications\":[\"${INBOUND_APP_ID}\",\"${QUICK_APP_ID}\"]}}" # 2. Add Quick to the INBOUND app's knownClientApplications az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${INBOUND_OBJECT_ID}" \ --body "{\"api\":{\"knownClientApplications\":[\"${QUICK_APP_ID}\"]}}" # 3. Grant the Quick client delegated access to both scopes, then admin-consent az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${QUICK_OBJECT_ID}" \ --body "{\"requiredResourceAccess\":[{\"resourceAppId\":\"${INBOUND_APP_ID}\",\"resourceAccess\":[{\"id\":\"${INBOUND_SCOPE_ID}\",\"type\":\"Scope\"}]},{\"resourceAppId\":\"${OUTBOUND_APP_ID}\",\"resourceAccess\":[{\"id\":\"${OUTBOUND_SCOPE_ID}\",\"type\":\"Scope\"}]}]}" az ad app permission admin-consent --id "$QUICK_APP_ID" # 4. Create the oauth2PermissionGrant for the INBOUND service principal INBOUND_SP_ID=$(az ad sp show --id "$INBOUND_APP_ID" --query "id" -o tsv) OUTBOUND_SP_ID=$(az ad sp show --id "$OUTBOUND_APP_ID" --query "id" -o tsv) az rest --method POST \ --uri "https://graph.microsoft.com/v1.0/oauth2PermissionGrants" \ --body "{\"clientId\":\"${INBOUND_SP_ID}\",\"consentType\":\"AllPrincipals\",\"resourceId\":\"${OUTBOUND_SP_ID}\",\"scope\":\"sap_access\"}" # 5. Emit the email claim on the OUTBOUND app — this is the only claim SAP uses for user mapping az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${OUTBOUND_OBJECT_ID}" \ --body '{"optionalClaims":{"accessToken":[{"name":"email","essential":true}]}}' Step 5: インバウンド Entra ID アプリの詳細を AWS Secrets Manager に保存する AgentCore Identity は認証情報プロバイダーを通じて OBO 交換を実行します。この手順における以下の選択は必須であり、Entra ID が OBO リクエストを検証する方法から直接導かれます。 アウトバウンドアプリではなく、インバウンドアプリの認証情報を使用してください。 Entra ID OBO では、交換を行う client_id がアサーショントークンの aud と一致する必要があり、Quick のトークンは aud = Inbound App ID を持ちます。 AWS_REGION="us-east-1" # Client secret for the INBOUND app + store it in AWS Secrets Manager INBOUND_APP_SECRET=[REDACTED_PASSWORD] ad app credential reset --id "$INBOUND_APP_ID" \ --display-name "obo-exchange-secret" --query "password" -o tsv) aws secretsmanager create-secret \ --name "AWSforSAP-MCP-OAuthCredentials-EntraId" \ --secret-string "{\"clientId\":\"${INBOUND_APP_ID}\",\"clientSecret\":\"${INBOUND_APP_SECRET}\"}" \ --region "$AWS_REGION" Step 6: AWS CloudFormation で MCP Server をデプロイする この手順では、AWS CloudFormation を使って AWS for SAP MCP Server をデプロイします。2 つのパラメーターがサーバーによるリクエスト認証の方法を決定し、CloudFormation は両方の認証コンポーネントをプロビジョニングするため、いずれも手作業で構築する必要はありません。InboundAuthProvider を Entra ID に設定すると、インバウンド認証のために AgentCore Runtime に JWT オーソライザーがアタッチされます。これはランタイム組み込みの JWT オーソライザーであり、Entra ID のディスカバリー URL と許可されたオーディエンスから構成されるもので、別個のカスタムオーソライザーではありません。AuthFlow を ON_BEHALF_OF_TOKEN_EXCHANGE に設定すると、アウトバウンドの OBO 交換を実行する MicrosoftOauth2 認証情報プロバイダーが作成されます。次の表のパラメーターは、サーバーを Entra ID テナントと 2 つのアプリ登録に接続します。 パラメーター 値 SapBaseUrl https://<sap-host>/sap/opu/odata/sap/ SapSystemType S4HANA または ECC InboundAuthProvider Entra ID DiscoveryUrl https://login.microsoftonline.com/{TENANT_ID}/v2.0/.well-known/openid-configuration AllowedAudiences {INBOUND_APP_ID} AuthFlow ON_BEHALF_OF_TOKEN_EXCHANGE SapCredentialsSecret AWSforSAP-MCP-OAuthCredentials-EntraId SapTokenUrl https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token OauthScopes api://{OUTBOUND_APP_ID}/sap_access McpServerReadEnabled true McpServerWriteEnabled true McpServerCreateEnabled true McpServerUpdateEnabled true McpServerDeleteEnabled true McpServerFunctionImportEnabled true TEMPLATE_URL="https://awsforsap-mcp-server-setup-${AWS_REGION}.s3.${AWS_REGION}.amazonaws.com/cfn-launch-template/latest/AwsForSapMcpServerStack.template.json" aws cloudformation create-stack \ --stack-name "sapmcp-${UNIQUE_ID}" \ --template-url "$TEMPLATE_URL" \ --parameters \ ParameterKey=UniqueId,ParameterValue="${UNIQUE_ID}" \ ParameterKey=SapBaseUrl,ParameterValue="${SAP_BASE_URL}" \ ParameterKey=SapSystemType,ParameterValue="S4HANA" \ ParameterKey=InboundAuthProvider,ParameterValue="EntraId" \ ParameterKey=DiscoveryUrl,ParameterValue="https://login.microsoftonline.com/${TENANT_ID}/v2.0/.well-known/openid-configuration" \ ParameterKey=AllowedAudiences,ParameterValue="${INBOUND_APP_ID}" \ ParameterKey=AuthFlow,ParameterValue="ON_BEHALF_OF_TOKEN_EXCHANGE" \ ParameterKey=SapCredentialsSecret,ParameterValue="AWSforSAP-MCP-OAuthCredentials-EntraId" \ ParameterKey=SapTokenUrl,ParameterValue="https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \ ParameterKey=OauthScopes,ParameterValue="api://${OUTBOUND_APP_ID}/sap_access" \ ParameterKey=McpServerVpcSecurityGroup,ParameterValue="${VPC_SG}" \ ParameterKey=McpServerNetworkSubnets,ParameterValue="${SUBNET_ID}" \ ParameterKey=McpServerReadEnabled,ParameterValue="true" \ ParameterKey=McpServerWriteEnabled,ParameterValue="true" \ ParameterKey=McpServerCreateEnabled,ParameterValue="true" \ ParameterKey=McpServerUpdateEnabled,ParameterValue="true" \ ParameterKey=McpServerDeleteEnabled,ParameterValue="true" \ ParameterKey=McpServerFunctionImportEnabled,ParameterValue="true" \ --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ --region "$AWS_REGION" aws cloudformation wait stack-create-complete --stack-name "sapmcp-${UNIQUE_ID}" --region "$AWS_REGION" # Verify both auth components were created aws bedrock-agentcore-control get-oauth2-credential-provider \ --name "AWSForSAP-MCP-OAuth2-Provider-${UNIQUE_ID}" --region "$AWS_REGION" \ --query "{vendor:credentialProviderVendor, clientId:oauth2ProviderConfigOutput.microsoftOauth2ProviderConfig.clientId, status:status}" # Register the CFN-created credential provider's callback URL on the inbound app CALLBACK_URL=$(aws bedrock-agentcore-control get-oauth2-credential-provider \ --name "AWSForSAP-MCP-OAuth2-Provider-${UNIQUE_ID}" --region "$AWS_REGION" \ --query "callbackUrl" --output text) az rest --method PATCH \ --uri "https://graph.microsoft.com/v1.0/applications/${INBOUND_OBJECT_ID}" \ --body "{\"web\":{\"redirectUris\":[\"${CALLBACK_URL}\"]}}" デプロイ後の手順: スタックが正常に作成された後、MCP Server のエンドポイント URL を インバウンドアプリの Identifier URI として登録し(Amazon Quick はこれを resource パラメーターとして送信します)、認証情報プロバイダーのコールバック URL をインバウンドアプリのリダイレクト URI として登録します。 次の表は、各認証コンポーネントとその作成元となるパラメーターをまとめたものです。ランタイム構成の型は customJWTAuthorizer という名前ですが、これは Entra ID の発行者とオーディエンスでパラメーター化された AgentCore Runtime の標準 JWT オーソライザーであり、別個のオーソライザーを記述・デプロイする必要はありません。 コンポーネント 型 自動作成元 Inbound Auth Provider ランタイム上の customJWTAuthorizer InboundAuthProvider + DiscoveryUrl + AllowedAudiences Outbound OAuth2 Provider ランタイム上の MicrosoftOauth2 認証情報プロバイダー AuthFlow=ON_BEHALF_OF_TOKEN_EXCHANGE + SapCredentialsSecret(+ SapTokenUrl + OauthScopes) Step 7: SAP OIDC トラストとユーザーマッピングを構成する SAP 側では、トランザクション SOIDC で OIDC トラストを作成し、SAP に Entra ID からのトークンを受け入れるよう指示します。この手順で ID 伝播が実体を持ちます。なぜなら、SAP はトークンをサービスアカウントではなく指名されたユーザーにマッピングするためです。SAP は以下を検証します。 iss : トークン発行者があなたの Entra ID テナントでなければなりません。 aud : Outbound App ID と一致しなければなりません。 署名 : Entra ID が公開する JWKS に対して検証されます。 ユーザーマッピング : SAP はトークン内の email クレームを個々の SAP ユーザーにマッピングします。 図 3. Entra ID 向けの SAP OIDC 構成 マッピングは email に基づくため、各ユーザーの SAP ビジネスパートナーまたはユーザーレコードが、Entra ID が発行するのと同じメールアドレスを保持していることを確認してください。この一致が、認証済みトークンを MULLERF のような特定の SAP ユーザーに解決するものです。 Step 8: OBO フローをエンドツーエンドでテストする フローをテストする前に、AWS for SAP MCP Server を Amazon Quick のコネクターとして追加します。これは Entra ID に Amazon Quick クライアントアプリをプロビジョニングする手順でもあります。コネクターを追加するには、次の手順を実行します。 Amazon Quick でコネクター(MCP サーバー)設定を開き、新しい MCP コネクターの追加を選択します。 Step 6 の CloudFormation スタック出力にある AWS for SAP MCP Server のエンドポイント URL を入力します。 認証(Authenticate)の手順で「User authentication method」を選択し、Auth 構成を「Custom user based OAuth」に設定して、Entra ID テナントの OAuth フィールドを入力します。次を指定します — Client ID として Amazon Quick クライアントアプリの AppID(client)、Public OAuth client はチェックしないまま、Client secret、Authorization URL(https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize)、および Token URL(https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token)。 コネクターを保存し、対話型サインインを一度完了します。Amazon Quick は Entra ID にクライアントアプリケーションを登録します。その QUICK_APP_ID、QUICK_OBJECT_ID、およびスコープ ID を取得し、権限チェーンをまだ完了していない場合は Step 4 を実行します。 コネクターが配置されたら、実際のユーザーとしてサインインし、「私の未処理の販売オーダーを表示して」のような、SAP の読み取りにマッピングされる自然言語の質問をします。テストが成功すると、以下が確認されます。 Quick が SAP パスワードのプロンプトなしで Entra ID に対してあなたを認証します。 MCP Server が SAP データを返します。 SAP では、Security Audit Log(トランザクション SM20 )がリクエストをサービスアカウントではなくあなたのユーザーに帰属させます。この最後の点が、ID がエンドツーエンドで伝播したことの証明です。 トランザクション SOIDC で、OIDC トラストがトークンの email クレームを個々の SAP ユーザーにマッピングしていることを確認し、コネクターと CloudFormation の構成が SAP サービスアカウントの認証情報を一切保持していないことを検証します(保存される唯一のシークレットは AWS Secrets Manager 内の Entra ID インバウンドアプリのクライアントシークレットです)。これは、アクセスが共有 SAP パスワードではなく ID 伝播によって付与されていることを証明します。 トラブルシューティング 以下の注記は、最も一般的な問題に対処します。 AADSTS500131(アサーションオーディエンスの不一致) : 認証情報プロバイダーが誤った client_id を使用しています。Quick のトークンの aud と一致する、インバウンドアプリのものでなければなりません。 AADSTS7000114(OBO が許可されていない) : Step 4 の権限チェーンが不完全です。knownClientApplications、委任権限の付与、管理者同意、および oauth2PermissionGrant を確認してください。 SAP がトークンを拒否する : SOIDC トラストの iss、aud = Outbound App ID を再確認し、email クレームが存在し(Step 4.5)、SAP ユーザーと一致していることを確認してください。 始めましょう AI エージェントに SAP へのアクセスを与えることは、ユーザーごとのセキュリティを諦めることを意味しません。Amazon Bedrock AgentCore を基盤とする AWS for SAP MCP Server を使えば、あなたの ID をバックエンドまで完全に保持しながら、Amazon Quick を通じて SAP と対話できます。 このソリューションは 4 つの成果をもたらします。 監査証跡が個々のユーザーのアクションを記録します。 SAP は、すべての AI 主導のリクエストを、共有サービスアカウントではなく実在の人物として認証、認可、監査します。 SAP パスワードを一切保存しません。 OBO 交換は完全にサーバーサイドで実行され、保存される唯一のシークレットは Entra ID インバウンドアプリの認証情報です。 最小権限と監査を維持します。 SAP は引き続きユーザー自身のロールを適用し、そのアクションをユーザー自身の ID の下で記録します。 スコープを分離した設計。 クライアント、インバウンド、アウトバウンドの各アプリを分離し、OBO 交換ではトークンオーディエンスと一致させるためインバウンドアプリの認証情報を使用します。 始めるには、Microsoft Entra ID と AgentCore Identity の On-Behalf-Of トークン交換を用いて AWS for SAP MCP Server をデプロイしてください。これにより、共有 SAP 認証情報なしで、AI エージェントに SAP へのセキュアなユーザーごとのアクセスを提供できます。 Fortescue、PLDT、Harman などのお客様が、どのように AWS for SAP MCP Server を活用してエージェント型 AI の強化を実現しているかについては、 AWS for SAP Blog をご覧ください。今すぐ構築を始めましょう。始めるには、 AWS for SAP MCP Server のページをご覧ください。AWS が何千もの SAP のお客様にとって選ばれるプラットフォームでありイノベーションの場である理由については、 AWS for SAP のページをご覧ください。 著者について Ferry Mulyadi Ferry は、シンガポールの Amazon Web Services(AWS)における World Wide SAP Tech Alliance Principal Partner Solution Architect であり、25 年以上にわたるエンタープライズアプリケーションとクラウドの経験を活かして、エージェント型 AI の進化をリードしています。彼は、人工知能と SAP エコシステムを橋渡しする自律型ワークフロー、エージェント主導のトランスフォーメーションパターン、エンタープライズ規模の統合フレームワークを設計しました。 Rengarajan Sridharan Renga は、AWS の AI and Strategic Partner Engineering における Senior Technical Program Manager であり、SAP ワークロードに焦点を当てたプログラムを推進しています。エンタープライズリソースプランニング(ERP)ソリューションで 20 年以上の経験を持つ Renga は、お客様やパートナーがエンタープライズシステムをモダナイゼーションし、ビジネス価値を最大化してデジタルトランスフォーメーションの成果を推進できるよう支援することを専門としています。 本ブログの翻訳は Amazon Quick による自動翻訳を行い、パートナー SA 松本がレビューしました。原文は こちら です。
本ブログは 2026 年 9 月 9 日に公開された AWS Blog “ The state of AI for security: Measuring what matters most for building trust ” を翻訳したものです。 セキュリティチームは、脆弱性のトリアージ、ペネトレーションテスト、脅威モデリング、インシデント対応、コードレビューといったセキュリティ業務に AI を積極的に活用し始めています。期待されるのはスピードですが、処理が速くても誤検出 (false alarm) が多すぎるセキュリティツールでは、結果として時間の節約になりません。エンジニアは誤検出の対応に時間を取られ、オンコール対応のノイズが増え、チームは本当に重要な検出結果まで信頼しなくなります。 本日 (2026 年 9 月 9 日)、AWS はこの信頼の問題を直接測定するために設計された初のベンチマーク、Deception Benchmark を公開します。このベンチマークは、実際の脆弱性と、危険に見えても本当は安全なコードをモデルが区別できるかどうかをテストします。収録されているのは、16 のプログラミング言語、70 を超える Common Weakness Enumeration (CWE) カテゴリにわたる 14,822 個のサンプルです。AWS は 5 社のプロバイダーの 12 モデルを評価し、データセットとホワイトペーパーをコミュニティに公開します。これまでに公開されてきた他のベンチマークは、AI が脆弱性を発見または悪用できるかどうかを測定するものです。実際の脆弱性と誤検出を見分けられるかどうかを測定するのは、本ベンチマークが初めてです。標準的なプロンプトでは、実際の脆弱性と誤検出を区別する適合率 (precision) は 50% 台半ばにとどまりました。正確である確率と不正確である確率がほぼ同程度ということです。 攻撃側のタスクでは、エクスプロイトが成功するかしないかという明確な結果が得られることが多くあります。一方、防御側のレビューは攻撃側のタスクよりも検証が難しく、緩和策によって問題が悪用不可能になっていても、モデルは疑わしいパターンだと認識してしまう場合があります。実運用で役に立つシステムには、コード、緩和策、さらに場合によっては周辺の環境まで踏み込んで推論する力が求められます。 測定のギャップ コミュニティはセキュリティ評価の分野で着実に進歩してきました。 CyberGym は 1,500 を超える現実的なタスクでエージェントをテストします。 Meta の CyberSecEval と CyberSecEval 2 はエクスプロイトの生成能力を測定します。 CYBENCH は Capture the Flag (CTF) 課題を評価します。 SEC-Bench と VulnBench は、より実務に近いセキュリティワークフローの再現を目指しています。 最近の研究は、進歩とギャップの両方を裏付けています。 ExploitGym は、AI がクラッシュから実際に動作するエクスプロイトへ発展させられるかを測定します。 Microsoft の Project Perception は、継続的な防御のためにマルチエージェントのレッド/ブルー/グリーンチームをデプロイします。 OpenAI の GPT-Red は、セルフプレイによるレッドチーミングが、フロンティアモデルでも防御できない新種の攻撃を見つけ出すことを示しました。その後、 OpenAI は、同社の GPT-6 Astra モデルがサイバーセキュリティ能力の Critical しきい値を超えたことを公表しました。また OpenAI と Anthropic の双方が、評価中にモデルが本番システムへ不正アクセスしたインシデントを報告しています。攻撃側は急速に進展しています。しかし、これらの研究はいずれも、防御側の適合率を測定していません。つまり、AI システムがコードを脆弱だとフラグ付けしたとき、その判断がどれくらいの頻度で正しいかという問いには答えていません。 Deception Benchmark のご紹介 14,822 個のサンプル、16 言語、70 を超える CWE カテゴリ。安全なサンプルがモデルを欺くように設計されていることから、AWS はこれを Deception Benchmark と名付けました。実際の脆弱性パターン、実際のフレームワーク、実際のイディオムを備えたうえで、エクスプロイトパスを目立たない形で閉じる緩和策が組み込まれています。目標は、ヒントなしでコードを脆弱または安全に分類することです。 ユーザー入力を受け取ってデータベースにクエリを実行する Flask エンドポイントを考えてみましょう。モデルはこのコードに SQL インジェクションのパターンを見いだしますが、クエリはパラメータ化されたステートメントを使用しているため、エクスプロイトパスは閉じられています。シングルターンの分類器はパターンをフラグ付けしてそのまま次へ進み、エクスプロイトが実際に成立するかどうかを確認しません。実運用のツールはこれを補うためにマルチステップのループやエージェント型ワークフローに頼りますが、このようにモデルを外側から支える補助構造 (スキャフォールディング) は、モデル自体がコードを理解しているかどうかを覆い隠してしまいます。本ベンチマークはスキャフォールディングを取り払い、モデルに 1 回の処理で判断を求めます。測定対象となるのは理解力そのものであり、モデルを繰り返し呼び出す仕組み (ハーネス) が何回試行して正解に到達したかではありません。 すべてのサンプルは、生成、フロンティアモデルに対するテスト、強化、反復という敵対的なループを通じて構築しました。モデルが簡単に正解できるサンプルは残りません。その結果として得られたのは、フロンティアの水準に合わせて、それを下回らないように調整されたベンチマークです。この方法での構築にはコストがかかります。サンプルの生成と強化には数百億トークンを消費しました。コミュニティが同じコストを繰り返さずに済むよう、AWS はその成果を公開します。 本ベンチマークは 2 種類の課題で構成されます。コードレベルの課題 (6,988 サンプル) は、わずかな修正だけが異なる脆弱なバリアントと安全なバリアントを提示します。どちらも疑わしく見えますが、悪用可能なのは一方だけです。環境依存型 (environment-gated) の課題 (2,707 サンプル) はさらに踏み込み、同じコードに異なるデプロイのコンテキストを与えます。Kubernetes Network Policy がサーバーサイドリクエストフォージェリ (SSRF) のパスをブロックする、あるいはアイデンティティおよびアクセス管理の境界が権限昇格を防ぐ、といった具合です。パターンはソースコード上で見えていますが、インフラストラクチャによって悪用不可能になっています。モデルは、どちらのシナリオが当てはまるかを見極めなければなりません。 すべてのサンプルは本ベンチマークのために専用に作られており、実世界のパターン、実際のフレームワーク、実際の CWE、実際のインフラストラクチャに基づいています。知的財産上の懸念やトレーニングデータの汚染もありません。 LLM と人間を組み込んだループで作る大規模な高品質データ この規模で信頼できるラベルを生成するのは困難です。人間によるものであれモデルによるものであれ、1 回だけの作業ではスコアをゆがめるエラーが残ります。そこで AWS は、ラベル付けを一度限りの工程ではなく、収束型の監査ループとして扱っています。すべてのラベルは複数の独立したレビュアーが再検証します。レビュアーには、他のレビュアーの判断も、そのラベルを生み出した元の推論も知らされません。意見の不一致は直接裁定へエスカレーションされ、そこで元の推論が、提起された異議と照らし合わせて評価されます。それでも解決しないケースは人間によるレビューへ回します。AWS は、採点対象セットが不一致のしきい値を下回って収束するまでこのループを繰り返します。具体的には、独立レビューで異議が残るサンプルを 3% 未満とし、人間の裁定を経ても異議が残るサンプルは 1% 未満を目標とします。この方式の妥当性を担保しているのは、1 つの選択です。AWS は異議のあるサンプルにラベルを付け直しません。レビュアーの意見が一致しない場合、そのサンプルは修正ラベルを与えられるのではなく非採点プールへ移されます。つまり、誤った異議によってサンプルが除外されることはあっても、採点対象セットに誤ったラベルが持ち込まれることは決してありません。 採点対象サンプルから無作為に抽出した 100 件を人間がレビューした結果、ラベルの誤りは見つかりませんでした。プロセスの全体像は ホワイトペーパー で説明しています。 結果 本ベンチマークはおおむねバランスが取れており、半分が脆弱、半分が安全です。したがってランダムな分類器のスコアは 50% になります。AWS は 2 つのエラー率を個別に報告します。両者は正反対の方向の誤りを表すためです。偽陽性率 (false positive rate、FPR) は、モデルが安全なコードを脆弱だとフラグ付けする頻度です。これがエンジニアの時間を浪費する誤検出です。偽陰性率 (false negative rate、FNR) は、実際の脆弱性を見逃して安全だと判断する頻度です。正解率だけを見ていると、この違いは見えません。すべてを脆弱とラベル付けするモデルは、あらゆるバグを検出できる (FNR は 0%) 一方で、すべての安全なコードをフラグ付けし (FPR は 100%)、それでもスコアは約 50% になります。AWS は、FPR 10% 未満かつ FNR 10% 未満を本番利用の最低基準と考えています。 図 1: 2 つのプロンプト戦略における 12 モデルの FPR と FNR の比較。この緩やかな基準にすら到達したモデルはありません。 モデル プロンプト 正解率 FPR FNR GPT-5.6 Sol Direct 54.9% 92.5% 0.9% GPT-5.6 Sol PoE 58.9% 58.6% 23.1% GPT-5.5 Direct 56.9% 87.8% 1.3% GPT-5.5 PoE 62.9% 63.6% 12.4% GPT-5.4 Direct 60.2% 81.0% 1.5% GPT-5.4 PoE 77.7% 10.1% 33.6% Llama 3.3 70B Direct 58.8% 84.2% 1.1% Llama 3.3 70B PoE 72.2% 10.2% 44.2% Claude Haiku 4.5 Direct 55.6% 92.1% 0.0% Claude Haiku 4.5 PoE 75.6% 22.4% 26.3% Claude Opus 4.6 Direct 55.9% 91.3% 0.1% Claude Opus 4.6 PoE 75.8% 42.7% 7.0% Claude Opus 4.7 Direct 58.3% 85.5% 0.9% Claude Opus 4.7 PoE 75.9% 32.0% 16.8% Claude Opus 4.8 Direct 53.8% 95.7% 0.2% Claude Opus 4.8 PoE 75.8% 32.5% 16.4% Claude Opus 5 Direct 77.3% 41.5% 5.2% Claude Opus 5 PoE 79.3% 24.9% 16.8% Claude Sonnet 5 Direct 62.9% 74.7% 2.2% Claude Sonnet 5 PoE 74.7% 31.8% 19.2% Amazon Nova 2 Lite Direct 56.3% 89.2% 1.2% Amazon Nova 2 Lite PoE 70.1% 45.2% 15.5% Mistral Large Direct 52.2% 99.0% 0.0% Mistral Large PoE 65.5% 49.3% 20.6% テストした汎用フロンティアモデルの中で、本ベンチマークにおいて FPR と FNR の両方を 10% 未満に抑えられた構成はありませんでした。 どのモデルにも同じ失敗パターンが見られます。Direct プロンプトでは、実際の脆弱性を最大 95% 検出する一方で、安全なコードの 41~99% もフラグ付けしてしまいます。適合率は 52~71% の範囲で、多くは 50% 台半ばに集中しており、実質的に正確である確率と不正確である確率が同程度です。モデルは脆弱性パターンを見つけた時点で推論をやめてしまうのです。エクスプロイトの実証を求める Proof-of-exploit (PoE) プロンプトを使うと、偽陽性率は 17~74 ポイント下がりますが、実際の脆弱性の 7~44% を見逃します。環境依存型の課題ではさらに悪化し、モデルはコードをフラグ付けする一方で、その隣にある Kubernetes Network Policy を無視します。テストしたどの構成も、偽陽性率と偽陰性率の両方を 10% 未満に抑えることはできませんでした。 これらの結果は、汎用モデルをシングルターンのプロンプトで評価したものです。特定の目的に合わせて構築され、マルチステップの検証とツール利用を組み込んだシステムは、動作条件が異なり、今回の測定対象には含まれていません。ハーネスがパターン認識と真の理解の間のギャップを埋められるのであれば、本ベンチマークはそれを実証する場になります。ただし、既に埋められていると考える前に、2 つの注意点があります。1 つは、エージェント型の検証が実証されているのは主に攻撃側のタスクであり、そこでは成功を確認できるという点です。エクスプロイトが動作するか、しないかがはっきりします。一方、コードが安全だと判断する場合には、そのように正否を確認できる基準 (オラクル) がありません。もう 1 つは、イテレーションを追加しても、脆弱性がないことを確認できるわけではなく、同じ判断を再サンプリングするだけであり、ハーネスは依然としてベースモデルの理解力を引き継ぐという点です。モデルが 1 回の処理で有効な緩和策と無効な緩和策を区別できないなら、処理の回数を増やしても足りない知識が補われることはありません。本ベンチマークが測定しているのはまさにこの点、つまりコードを理解するモデルの本質的な能力です。それを、スキャフォールディングがギャップを覆い隠せないシングルターンのベースラインでテストしています。 現在 AI ツールを評価しているセキュリティチームの方は、脆弱性を発見できるかどうかだけでなく、この種のタスクでシステムがどの程度の性能を示すのか、どのくらいの頻度で誤るのかをベンダーに確認してください。そして、リスクの高いコードパスでは AI 支援によるレビューを必ず人間による検証と組み合わせ、Deception Benchmark を活用してツールの性能を客観的に検証してください。 提供状況 AWS は、この問題を再現可能な方法で容易に測定できるよう Deception Benchmark を構築しました。公開リリースには、サンプルと評価ワークフローが含まれます。ラベルは公開しません。これにより、ベンチマークが単なる暗記の問題になることなく、提出物を長期にわたって一貫して採点できます。 14,822 個のサンプルのうち 9,695 個が採点対象で、残りの 5,127 個はホールドアウト (非採点) として他のサンプルに混在させています。目的は明快です。システムそのものを改善するよりも、ベンチマークのスコアだけを最適化するほうが難しくなるようにすることです。この設計については、ホワイトペーパーでさらに詳しく説明しています。 Deception Benchmark は GitHub で公開しており、 ホワイトペーパー および検証を伴う採点を受けるための提出手順も併せて提供しています。セキュリティツールを開発している方は、データセットをダウンロードし、ご自身のシステムをベンチマークに対して実行し、採点評価のために予測結果を提出できます。 Anshumali Shrivastava Anshumali は Amazon Scholar であり、ライス大学のコンピュータサイエンス正教授です。動的スパース性、スケッチング、ハッシングに関する研究を通じて、現在では効率的な LLM のトレーニングと推論の中核となっている技術を切り開きました。ThirdAI (ServiceNow が買収) と XMAD.ai (Workato が買収) の 2 社を創業した経験を持ち、コンピュータサイエンスの理論と大規模な実用 AI システムの架け橋となっています。 Neha Rungta Neha は科学者かつビルダーであり、複雑なシステムについて機械が大規模に推論できるようにすることに、キャリアを通じて取り組んできました。その研究は自動推論、形式的検証、セキュリティ、AI にわたり、Cedar、IAM Access Analyzer、Continuum などのシステムを形作ってきました。現在は、LLM、形式手法、エージェント型システムを組み合わせ、次世代の機械推論を築いています。 本ブログは Security Solutions Architect の 中島 章博 が翻訳しました。

動画

書籍