2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】Step Functionsをエージェントのツールにしてみた:ピン・IAM・トークンの効き方を検証【AgentCore】

2
Last updated at Posted at 2026-11-01

はじめに

2026年10月29日、AWS Step Functionsのワークフローを、AIエージェントのツールとして使えるようになりました。Amazon Bedrock AgentCore Gatewayの組み込みコネクタを経由します。

エージェントは「何をどの順で行うか」を自分で決めるのが持ち味です。一方で、返金やオンボーディングのように「毎回同じ手順で実行し、何が実行されたかの記録も残したい」業務があります。このコネクタは、その手順をステートマシンに持たせ、エージェントには「いつ起動するか、何を入力にするか」だけを任せる仕組みです。

ただ、エージェントに実行系のAPIを渡すとなると、気になるのは機能紹介よりも「どこまで許すか」です。エージェントが呼べる範囲を絞る仕組み、つまり統制には、ピン留め・IAM・タスクトークンの3つがあります。本記事では公式ドキュメントを一次情報として、コネクタが公開する10個のオペレーションを整理し、この3つの統制をどう使い分けるかを、実機で確かめた結果とあわせて解説します。

検証は8項目です。コネクタに固有の5項目は、tools/list、ピンの拒否、includedData、実行ARNのIAM拒否、waitForTaskTokenによる承認フローです。これに、Standard / Expressの制約、公開していないステートマシンのトークン、CloudTrailでの呼び出し元の見え方の3項目を加えました。結果は「実際に検証した内容と結果」にまとめています。

前提:アップデートで、統制はどこに移ったか

3つの統制のうち、ピンは、ゲートウェイのターゲット設定で、オペレーションのstateMachineArnをあらかじめ固定しておく設定です。ピンしたパラメータはツールの入力スキーマから消え、エージェントは値を変えられません。

公式ドキュメントは、このコネクタの利点を「Lambda関数もMCPサーバーも書かず、ツールも自分で定義しなくてよい」と説明しています(出典:AWS Step Functions as Connector Target)。MCP(Model Context Protocol)は、エージェントがツールを探して呼び出すための共通の取り決めです。裏返すと、アップデート前は、Lambda関数や自作のMCPサーバーを用意して、Step Functionsをツール化していたと読めます(筆者の解釈)。その場合、エージェントに許す範囲を絞る統制は、次のようにコードとロールの側にあったと考えられます。

統制 アップデート前(Lambdaや自作MCPサーバーでツール化)(筆者の解釈) アップデート後(コネクタ)
対象の固定(ピン) コードにステートマシンのARNを書く ターゲット設定のparameterValuesで指定する。ゲートウェイが、違う値を渡す呼び出しを拒否する
IAM Lambdaの実行ロールなど、自分で用意したロールで許可範囲を絞る ゲートウェイのサービスロールで絞る。同一ゲートウェイのターゲット間で共有する
タスクトークン 自分のコードで扱う。検証ロジックなどを挟める SendTask*をそのまま公開する。IAMでは絞れず、トークンだけが制御になる

アップデート後の列も、同じドキュメントの記載にもとづいています。

つまり、コードで書いていた制御が、「ターゲットの設定」と「サービスロール」に置き換わりました。コードを書かなくてよい代わりに、設定どおりに効くか、効かない所はどこかを、自分で把握しておく必要があります。本記事で確かめたいのは、次の3点です。

統制 確かめたいこと 対応する検証(後述の表の番号)
ピン 違うstateMachineArnを渡すと、設定どおり拒否されるか。エージェントには何が見えるか 1、2
IAM 実行ARNで絞ったポリシーで、許可していない実行の参照・停止が拒否されるか。includedDataで何が渡るか 3、4
タスクトークン IAMで絞れない前提で、承認フローがどう動き、トークンが何を制御するか 5

結論

論点 結論
何が使えるようになったか AgentCore Gatewayの組み込みコネクタ(connectorId: "states")で、既存のStandard / Expressステートマシンを、Lambdaも自作MCPサーバーも書かずにMCPツールとして公開できる
役割分担 エージェントは「いつ・どの入力で実行するか」を決め、ステートマシンが「どのステップをどの順で実行するか」を決める。エージェントはステップを省略・並べ替えできない
統制は3層 ①ステートマシンのピン留め、②ゲートウェイのサービスロールのIAMポリシー、③タスクトークンの秘匿。①と②は補完関係で、③はIAMで絞れない
選ぶ基準 後から実行を参照・停止したい、監査証跡が要る業務はStandard。同期で結果が欲しいだけならExpress(検証した制約から導いた、筆者の解釈)
検証で確認できたこと ピンしたstateMachineArnを渡すと拒否され、実行は作られない。許可していない実行ARNへの参照・停止はIAMで拒否される。includedData: ALL_DATAで入出力が応答に入る。タスクトークンはResource: "*"で動き、使用済みトークンの再送は失敗する。ゲートウェイに公開していないステートマシンの実行も、トークンがあれば完了できる。Standard / Expressの制約エラーは公式の表どおりに発生する

「何が使えるようになったか」「役割分担」「統制は3層」の出典は、前提の節で挙げた公式ドキュメントです。

検証環境

項目 内容
リージョン ap-northeast-1(東京)
ゲートウェイ AWS_IAM認可。主なターゲットはhello、approval。Express検証用にexpress、wrongtypeを追加
ステートマシン Standard 4つ(AgentHelloWorld、AgentOtherWorkflow、ApprovalWorkflow、UnexposedApproval)、Express 1つ(AgentExpressWorkflow)
呼び出し側 awscurl(SigV4署名。AWSのリクエスト署名方式)。エージェントが送るのと同じMCPのJSON-RPCリクエストを直接送った
ツール AWS CLI 2.34.24(検証の途中で2.39.3に更新。後述)、Python 3.12、awscurl 0.44

前提として、IAMロール、Step Functionsの基本、MCPのやり取りに使われるJSON-RPC(ツール一覧を取るtools/listと、ツールを呼ぶtools/call)を理解している読者を想定します。公式チュートリアルと同じ構成をベースにしています。そこに、IAM拒否の確認用に公開しないステートマシン、承認フロー用のSQSとワークフロー、Standard / Expressの違いを確かめるExpressのステートマシンを追加しました。

全体像

公式ドキュメントによると、処理の流れは次のとおりです。

# 内容
1 ゲートウェイにconnectorId: "states"のターゲットを追加し、ツール化するオペレーションを選ぶ。対応するものにはstateMachineArnを固定(ピン)する。ゲートウェイがツールスキーマのスナップショットを取る
2 エージェントがtools/listを呼ぶと、設定したオペレーションごとに1ツールが見える。ピンしたパラメータはスキーマに出ない(例:StartExecutionはinputのみ)
3 エージェントがtools/callを呼ぶと、ゲートウェイがピンしたパラメータと引数をマージし、サービスロールでStep Functionsを呼ぶ
4 Step Functions APIのレスポンスが、JSON文字列としてcontent[].textに入って返る。エラー時はisError: trueで、Step Functionsのエラー名が入る(検証では、本文の先頭にエラー名が付いた形で返った。後述)
5 エージェントがツールを連鎖する。典型例はStartExecution → DescribeExecution → GetExecutionHistory

出典:AWS Step Functions as Connector Target

tools/listを呼ぶと、設定した6オペレーション分のツールが、アルファベット順(設定順ではない)で返りました。ツール名はhello___DescribeExecutionのように、ターゲット名に___(アンダースコア3つ)が付く形です。hello___StartExecutionの入力スキーマはinputのみで、stateMachineArnは見えませんでした。

コネクタが公開する10のオペレーション

公式ドキュメントによると、コネクタ(version 1.0.0)は10のオペレーションを公開します。大きく「ステートマシンにピンできる4つ」と「エージェントが識別子を渡す6つ」に分かれます。

ピンできる4つ

オペレーション 役割 既定でエージェントに見えるフィールド 追加で公開できるフィールド 対応するワークフロー
StartExecution ステートマシンを起動する。返ってくるexecutionArnで、あとから状態を追える input(JSON文字列) name, traceHeader Standard / Express
StartSyncExecution Expressを起動し、完了まで待って、結果を同じ呼び出しで返す input name, traceHeader Expressのみ
ListExecutions ステートマシンの実行の一覧を返す。ステータスで絞れる statusFilter maxResults, nextToken Standardのみ
DescribeStateMachine ステートマシンの定義・ロール・設定を返す includedData なし Standard / Express

エージェントが識別子を渡す6つ(ピン不可)

オペレーション 役割 渡す識別子 既定フィールド 追加で公開できるフィールド 対応するワークフロー
DescribeExecution 実行の状態(成功・失敗など)と、開始・終了時刻を返す。ALL_DATAなら入出力も返す executionArn executionArn, includedData なし Standardの実行のみ
StopExecution 実行中の実行を止める executionArn executionArn error, cause Standardの実行のみ
GetExecutionHistory 実行のイベント履歴(各ステップの出来事)を返す executionArn executionArn includeExecutionData, maxResults, reverseOrder, nextToken Standardの実行のみ
SendTaskSuccess 承認待ちのタスクを、成功として再開する taskToken taskToken, output なし Standard / Express
SendTaskFailure 承認待ちのタスクを、失敗として終わらせる taskToken taskToken, error, cause なし Standard / Express
SendTaskHeartbeat 長い作業中であることを伝え、タイムアウトを防ぐ taskToken taskToken なし Standard / Express

追加フィールドを見せたい場合は、そのオペレーションの設定にparameterOverridesでvisible: trueを指定します。stateMachineArnだけはparameterOverridesでは公開できず、ピンでのみ指定できます。

DescribeExecutionとDescribeStateMachineのincludedDataは、既定がMETADATA_ONLYです。ALL_DATAを指定すると、実行の入出力やステートマシンの定義が含まれます。

試してみると、includedDataを省略した応答は、METADATA_ONLYを指定した応答と同一でした。DescribeStateMachineをMETADATA_ONLYで呼ぶと、definitionは"{}"(空)で返り、ALL_DATAで定義の全文が入りました。

Standard / Expressの違い(ハマりどころ)

次のエラーはStep Functions側の制約で、コネクタの不具合ではありません。

オペレーション 使えるタイプ 違うタイプで使うと
StartSyncExecution Expressのみ Standardでは失敗する。StartExecutionとDescribeExecutionのポーリングを使う
ListExecutions Standardのみ ExpressではStateMachineTypeNotSupported
DescribeExecution / GetExecutionHistory / StopExecution Standardの実行のみ Expressの実行ARNではInvalidArn(開始後はARNで扱えないため)
StartExecution / DescribeStateMachine / SendTask* 両方 -
  • 1つのターゲットに両タイプを同居させたい場合は、StartSyncExecutionをExpressに、他のピン可能なオペレーションをStandardに固定します。
  • コールバックパターン(.waitForTaskToken)はStandardのみです。Expressは非対応です。
  • tools/listで返るツール説明文に、これらの制約が書かれているため、エージェントが適切なツールを選べます。

出典:AWS Step Functions as Connector Target

tools/listの説明文を見ると、DescribeExecution・GetExecutionHistory・ListExecutions・StopExecutionの4つに、「Standard workflows only」とありました。ListExecutionsには、ExpressではStateMachineTypeNotSupportedで失敗するとも書かれています。StartExecutionとDescribeStateMachineには制約の記載がなく、両タイプで使えることと対応します。

さらに、Expressのステートマシンを用意して、上の表の動きを実際に発生させました。

操作 結果
StandardのステートマシンにStartSyncExecution StateMachineTypeNotSupported(This operation is not supported by this type of state machine)
ExpressのステートマシンにStartSyncExecution 成功。応答にstatus、output、billingDetailsが入る
ExpressのステートマシンにListExecutions StateMachineTypeNotSupported
ExpressのStartExecutionで得た実行ARNをDescribeExecution・GetExecutionHistory・StopExecutionに渡す 3つともInvalidArn(Resource type not valid in this context: express)
Expressのステートマシンを、.waitForTaskTokenを含む定義で作成 作成時にInvalidDefinition(Express state machine does not support '.waitForTaskToken' service integration)

公式の表と一致しました。公式はStartSyncExecutionをStandardに向けた場合を「失敗する」としか書いていませんが、実際のエラー名はStateMachineTypeNotSupportedでした。また、Expressの実行ARNはexpress:<ステートマシン名>:...という、Standardのexecution:とは別のリソースタイプで返ります。今回はexpress:AgentExpressWorkflow:*もIAMで許可しておき、IAM拒否ではなくStep Functions側のInvalidArnが返ることを確認しました。

Expressを公開すると、エージェントは起動後に状態確認・履歴参照・停止ができません(上の検証のとおり、3つともInvalidArnになります)。「あとから実行を追える」ことが要件なら、Standardを選ぶのが無難です(筆者の解釈)。

統制設計:エージェントに何を許すか

ここが本記事の中心です。公式ドキュメントは、統制を「ピン」と「IAM」の2層で説明しています。両者は代替ではなく補完関係です(出典:AWS Step Functions as Connector Target)。

図1:エージェントへの権限の絞り方(1:ピン留め、2:サービスロールのIAM、3:タスクトークン)

stepfunctions-agentcore-gateway-governance.png

統制 効く範囲 備考
ピン(stateMachineArnの固定) StartExecution, StartSyncExecution, ListExecutions, DescribeStateMachine エージェントはこの対象を変更できない。ゲートウェイが拒否する
ゲートウェイのサービスロールのIAMポリシー ピンできない6つ DescribeExecution / StopExecution / GetExecutionHistoryは、公開するステートマシンの実行ARNに絞れる
タスクトークンの秘匿 SendTaskSuccess / SendTaskFailure / SendTaskHeartbeat IAMにリソースレベル権限がなく"*"で許可する。有効なトークンを持つエージェントは誰でもそのタスクを完了できる

① ピン留め

ピンしたパラメータはツールスキーマから取り除かれ、すべての呼び出しで強制されます。エージェントがstateMachineArnを渡すと、次のエラーで拒否されます。

Invalid request parameters: cannot set parameter(s): [/stateMachineArn]

別のステートマシン(AgentOtherWorkflow)のARNをstateMachineArnとして渡してみました。isError: trueで次の内容が返り、実行は作られませんでした。公式の記載と同じ文言で、先頭にエラー名が付きます。

IllegalArgumentException - Invalid request parameters: cannot set parameter(s): [/stateMachineArn]

エラー名はIllegalArgumentExceptionで、後述のIAM拒否(DependencyFailedExceptionで包まれたStep Functionsのエラー)とは形式が異なります。ピン違反は、Step Functionsを呼ぶ前にゲートウェイが拒否していると読めます(筆者の解釈)。

公式ドキュメントには、次の注意点が書かれています。

  • ピンはオペレーションごとに1つです。複数のステートマシンを同じオペレーションで公開するなら、ターゲットを分けます。
  • ピンすべきオペレーションでparameterValues.stateMachineArnを設定し忘れても、ターゲット自体は作成できます。ただし、ステートマシンが渡されないため、ツールは毎回失敗します。

② サービスロールのIAMポリシー

ピンできないDescribeExecutionなど3つは、エージェントが渡す実行ARNに対して動きます。ここを絞るのはサービスロールのIAMポリシーです。

実行ARNはステートマシンARNとは別のリソースタイプなので、公式チュートリアルのポリシーは2つのStatementに分かれています(出典:チュートリアル)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "StateMachineOperations",
      "Effect": "Allow",
      "Action": [
        "states:StartExecution",
        "states:ListExecutions",
        "states:DescribeStateMachine"
      ],
      "Resource": "arn:aws:states:<region>:<account-id>:stateMachine:AgentHelloWorld"
    },
    {
      "Sid": "ExecutionOperations",
      "Effect": "Allow",
      "Action": [
        "states:DescribeExecution",
        "states:GetExecutionHistory",
        "states:StopExecution"
      ],
      "Resource": "arn:aws:states:<region>:<account-id>:execution:AgentHelloWorld:*"
    }
  ]
}

信頼ポリシーは、bedrock-agentcore.amazonaws.comを信頼しつつ、aws:SourceAccountとaws:SourceArn(gateway/...)で絞ります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "bedrock-agentcore.amazonaws.com" },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": { "aws:SourceAccount": "<account-id>" },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:bedrock-agentcore:<region>:<account-id>:gateway/step-functions-gateway-*"
        }
      }
    }
  ]
}

上のポリシー(AgentHelloWorldの実行ARNのみ許可)を適用した状態で、許可していないAgentOtherWorkflowの実行ARNを、DescribeExecution・GetExecutionHistory・StopExecutionに渡しました。3つとも拒否されました。許可しているAgentHelloWorldの実行は参照できました。DescribeExecutionの拒否は次のとおりです(アカウントIDなどは伏せています)。

DependencyFailedException - {"errorType":"com.amazon.coral.service#AccessDeniedException","errorMessage":"User: arn:aws:sts::<account-id>:assumed-role/AgentCoreGatewayToStepFunctions/gateway-session-invocation is not authorized to perform: states:DescribeExecution on resource: arn:aws:states:<region>:<account-id>:execution:AgentOtherWorkflow:<execution-id> because no identity-based policy allows the states:DescribeExecution action","statusCode":400,"service":"states","operation":"DescribeExecution"}

読み取れる点は次の2つです。

  • 拒否はStep FunctionsのIAM評価で起きている("service":"states")。エラー名はDependencyFailedExceptionで包まれるため、エージェント側は中のJSONを読む必要がある
  • 呼び出し主体は、サービスロールのassumed-role/.../gateway-session-invocation。セッション名は固定で、どのエージェントや利用者の呼び出しかは、このメッセージからは分からない

次の2枚の画面は、検証5で承認ワークフロー(ApprovalWorkflow)を追加したあとのものです。そのため、ResourceにはAgentHelloWorldとApprovalWorkflowの2つが入っています。

図2:サービスロールのインラインポリシー(StateMachineOperations:ステートマシンARNで許可)

13_許可ポリシー.png

図3:サービスロールのインラインポリシー(ExecutionOperations:実行ARNで許可)
12_許可ポリシー.png

同一ゲートウェイのターゲットは、サービスロールを共有します。ワークフローごとにIAM境界を変えたい場合は、ゲートウェイを分けます。

③ タスクトークン

SendTaskSuccess・SendTaskFailure・SendTaskHeartbeatの3つは、IAMで特定の実行に絞れません(出典:AWS Step Functions as Connector Target)。そのため、タスクトークンそのものが唯一の制御になります。トークンは秘密情報として扱い、処理すべきエージェントにだけ届けます。

サービスロールにstates:SendTaskSuccessなど3つをResource: "*"で許可すると(下のスクリーンショット)、ゲートウェイ経由のSendTaskSuccessは成功しました。一度完了したタスクのトークンを再送すると、TaskTimedOut(Provided task does not exist anymore)で失敗しました。

図4:サービスロールのインラインポリシー(TaskTokenOperations:SendTask*をResource: "*"で許可)

11_許可ポリシー.png

また、ゲートウェイのどのターゲットにも公開していないステートマシン(UnexposedApproval)で、実行をCLIから直接起動しました。そのトークンをゲートウェイ経由のSendTaskSuccessに渡すと、実行はSUCCEEDEDになりました。でたらめなトークンはInvalidTokenで拒否されました。ピンでもIAMでも絞れないため、トークンを持っていれば、ゲートウェイに公開していないステートマシンの実行でも完了できます。

図5:ゲートウェイに公開していないステートマシン(UnexposedApproval)のグラフビュー(ゲートウェイ経由のSendTaskSuccessの後。全ステップが成功)

15_StepFunctions.png

図6:同じ実行のイベント履歴(TaskSucceededからExecutionSucceededまで)

16_StepFunctions.png

統制設計のまとめ

要件 使う統制
起動できるワークフローを限定したい ピン留め
参照・停止できる実行の範囲を限定したい サービスロールのIAMポリシー(実行ARNでスコープ)
人手承認など、後から再開するタスクを渡したい タスクトークンの配送先を限定(IAMでは絞れない)
ワークフローごとに権限境界を分けたい ゲートウェイを分ける(サービスロールが共有のため)

運用上の観点

観点 内容
呼び出し元の記録 ゲートウェイ経由の実行は、CloudTrail上でゲートウェイのサービスロールが呼び出し元になる(出典:チュートリアル)。実際のイベントでも、StartExecutionイベントのuserIdentityがAssumedRole(assumed-role/AgentCoreGatewayToStepFunctions/gateway-session-invocation)で、invokedByはbedrock-agentcore.amazonaws.comだった
誰が起動したかの識別 呼び出し元がゲートウェイのロールなので、「どのエージェント/利用者が起動したか」はCloudTrailだけでは区別できない。確認した範囲では、セッション名はgateway-session-invocationで固定で、ゲートウェイIDや、呼び出したエージェント・利用者を示すフィールドは見当たらなかった。また、requestParameters.inputはHIDDEN_DUE_TO_SECURITY_REASONSに置き換えられ、入力の中身はCloudTrailに残らない。そのため、実行のinputに利用者IDを入れても、CloudTrailからは追えない。一方、responseElements.executionArnは記録されるので、CloudTrailのイベントから実行を特定し、Step Functionsの実行履歴で入力を確認する形になる
入出力の露出 includedData: ALL_DATAを許すと、実行の入出力がエージェント(LLMのコンテキスト)に渡る。個人情報を含むワークフローでは扱いに注意。試した範囲では、入力約400文字の実行で、応答が674文字(省略時・METADATA_ONLY)から1410文字(ALL_DATA)になり、入力のJSON(顧客ID・住所を含めた模擬データ)と出力がそのまま入った

ゲートウェイ経由のStartExecutionイベントは次のとおりです(アカウントIDなどは伏せています)。

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROA****************:gateway-session-invocation",
        "arn": "arn:aws:sts::<account-id>:assumed-role/AgentCoreGatewayToStepFunctions/gateway-session-invocation",
        "accountId": "<account-id>",
        "accessKeyId": "ASIA****************",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROA****************",
                "arn": "arn:aws:iam::<account-id>:role/AgentCoreGatewayToStepFunctions",
                "accountId": "<account-id>",
                "userName": "AgentCoreGatewayToStepFunctions"
            },
            "attributes": {
                "creationDate": "2026-11-01T11:28:30Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "bedrock-agentcore.amazonaws.com"
    },
    "eventTime": "2026-11-01T11:28:30Z",
    "eventSource": "states.amazonaws.com",
    "eventName": "StartExecution",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "bedrock-agentcore.amazonaws.com",
    "userAgent": "bedrock-agentcore.amazonaws.com",
    "requestParameters": {
        "stateMachineArn": "arn:aws:states:ap-northeast-1:<account-id>:stateMachine:AgentHelloWorld",
        "input": "HIDDEN_DUE_TO_SECURITY_REASONS"
    },
    "responseElements": {
        "executionArn": "arn:aws:states:ap-northeast-1:<account-id>:execution:AgentHelloWorld:<execution-id>",
        "startDate": "2026-11-01T11:28:30Z"
    },
    "requestID": "<request-id>",
    "eventID": "<event-id>",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "<account-id>",
    "eventCategory": "Management"
}

userIdentityのセッション名はgateway-session-invocationで固定され、invokedByがbedrock-agentcore.amazonaws.comです。どのエージェントや利用者の呼び出しかを示すフィールドは、このイベントにはありません。

エージェントとワークフローの2つの連携パターン

公式ドキュメントによると、エージェントとワークフローの協働は2通りです(出典:AWS Step Functions as Connector Target)。

パターンA:エージェントがワークフローを起動・監視する

StartExecution → DescribeExecution(ポーリング)→ GetExecutionHistory →(必要なら)StopExecution。同期でよければ、ExpressにStartSyncExecutionを使います。

パターンB:ワークフローがエージェントの作業を待つ(Human-in-the-loop)

# 内容
1 Standardのタスクを.waitForTaskTokenで一時停止し、Step Functionsがタスクトークンを発行する
2 ワークフロー側で、トークンとタスク詳細をエージェントのアプリへ届ける(例:SQSキュー、アプリがポーリングするActivity)
3 エージェントが作業し、SendTaskSuccess(結果)またはSendTaskFailureで再開させる。長い作業はSendTaskHeartbeatで生存を伝える

トークンの配送はワークフロー側の責任です。ゲートウェイは配送を行いません。

図7:人手承認(コールバック)パターンの流れ(ステートマシンがSQSにトークンを送って停止し、エージェントがSendTask*で再開する)

stepfunctions-agentcore-gateway-human-approval.png

.waitForTaskTokenでSQSにトークンを送って待つStandardワークフロー(ApprovalWorkflow)で、次の流れを確認しました。

# 操作 結果
1 approval___StartExecutionで起動(入力は{"requestId":"refund-1001","amount":3000}) 実行はRUNNINGで停止。TaskSubmitted(sqs:sendMessage)まで進んでいる
2 SQSからメッセージを受信 BodyはRequest(実行の入力)とTaskToken(656文字)の2キー
3 approval___SendTaskSuccessにtaskTokenとoutput(JSON文字列)を渡す 成功(応答は{})。引数は2つとも必須
4 approval___DescribeExecution(ALL_DATA)で確認 SUCCEEDED。outputは送った{"approved":true,"approver":"agent"}

ワークフローがSQSにトークンを送り、アプリ側がそれを読んでエージェントに渡す部分は、ゲートウェイが関与しません。今回は、筆者がSQSからトークンを取り出してエージェント役の呼び出しに渡しました。

図8:ApprovalWorkflowのイベント履歴(待機中。sqs:sendMessageのTaskSubmittedで停止)

3_TaskScheduled.png

図9:ApprovalWorkflowのグラフビュー(SendTaskSuccessの後。全ステップが成功)

4_タスク完了.png

図10:ApprovalWorkflowのイベント履歴(完了後。TaskSucceededからExecutionSucceededまで)

5_タスク完了詳細.png

設定の最小構成

公式チュートリアルの流れを要約します。詳細はチュートリアルを参照してください。

# ゲートウェイ作成(AWS_IAM認可)
aws bedrock-agentcore-control create-gateway \
  --name "step-functions-gateway" \
  --protocol-type MCP \
  --authorizer-type AWS_IAM \
  --role-arn "arn:aws:iam::<account-id>:role/AgentCoreGatewayToStepFunctions" \
  --region <region>
# ターゲット追加(READYになってから)
aws bedrock-agentcore-control create-gateway-target \
  --gateway-identifier "<GATEWAY_ID>" \
  --name "hello" \
  --target-configuration '{
    "mcp": {
      "connector": {
        "source": { "connectorId": "states" },
        "configurations": [
          { "name": "StartExecution",
            "parameterValues": { "stateMachineArn": "arn:aws:states:<region>:<account-id>:stateMachine:AgentHelloWorld" } },
          { "name": "ListExecutions",
            "parameterValues": { "stateMachineArn": "arn:aws:states:<region>:<account-id>:stateMachine:AgentHelloWorld" } },
          { "name": "DescribeStateMachine",
            "parameterValues": { "stateMachineArn": "arn:aws:states:<region>:<account-id>:stateMachine:AgentHelloWorld" } },
          { "name": "DescribeExecution" },
          { "name": "GetExecutionHistory" },
          { "name": "StopExecution" }
        ]
      }
    }
  }' \
  --credential-provider-configurations '[{"credentialProviderType": "GATEWAY_IAM_ROLE"}]' \
  --region <region>

本記事の検証環境(AWS CLI 2.34.24)では、上のターゲット追加コマンドが次のエラーで失敗しました。connector型のtargetConfigurationを、CLIが認識していません。

Unknown parameter in targetConfiguration.mcp: "connector", must be one of: openApiSchema, smithyModel, lambda, mcpServer, apiGateway

AWS CLIを2.39.3に更新して、同じコマンドをもう一度実行すると、connector型のターゲットが作成できました。get-gateway-targetの出力にも、connectorId: "states"とversion: "1.0.0"が表示されました。2.34.24のget-gateway-targetは、connectorをSDK_UNKNOWN_MEMBERとしか表示しませんでした。コネクタを使う場合は、AWS CLIを更新しておくのが安全です(boto3 1.43.91でも、同じAPIが通りました)。

コンソールでは、このターゲットは「ターゲットタイプ: Step Functions」と表示され、ステータスはReadyでした。一方、ピンしたstateMachineArnなどのコネクタの設定は、コンソールには表示されません(「追加設定」を展開しても認証付与タイプのみ)。ピンの設定は、CLIのget-gateway-target(2.39.3)で確認できます。

図11:ゲートウェイのターゲット一覧(helloとapproval。ターゲットタイプは「Step Functions」、インバウンド認証は「IAM 許可」)
7_AgentCoreGateway(target).png

図12:ゲートウェイの詳細(名前・ID・URL・ステータス「Ready」)

8_AgentCoreGateway(gaiyou).png

  • ゲートウェイとステートマシンは、同一リージョンに作ります。ゲートウェイは自リージョンのStep Functionsを呼びます。
  • AWS_IAM認可では、呼び出し側のIDにbedrock-agentcore:InvokeGateway権限とSigV4署名が必要です。
  • ツール名には、ターゲット名がプレフィックスで付きます。チュートリアルの例はhello___StartExecution(アンダースコア3つ)です。

実際に検証した内容と結果

公式ドキュメントから読み取れない点、または自分で確かめたい点のうち、8項目を検証しました。1〜5はStep Functionsコネクタに固有の確認、6〜8は追加の確認です。リクエストは、awscurlでゲートウェイにJSON-RPCを直接送っています(エージェントのフレームワークは使っていません)。

# 確認したいこと 確認方法 結果
1 tools/listで見えるツールの説明文・スキーマの実物 awscurlでtools/listを呼ぶ 6ツール。stateMachineArnは非公開。4ツールの説明文に「Standard workflows only」の記載
2 ピンしたパラメータを渡したときの拒否 tools/callで別のステートマシンのARNをstateMachineArnに指定 IllegalArgumentException - ... cannot set parameter(s): [/stateMachineArn]で拒否。実行は作られない
3 includedData: ALL_DATAで、エージェントに渡る情報量が変わるか DescribeExecutionを省略・METADATA_ONLY・ALL_DATAで呼ぶ 省略とMETADATA_ONLYは同一(674文字)。ALL_DATAで入出力が加わり1410文字
4 実行ARNを絞ったIAMポリシーで、別ステートマシンの実行が拒否されるか 許可していない実行ARNでDescribeExecution・GetExecutionHistory・StopExecutionを呼ぶ 3つともAccessDeniedException(DependencyFailedExceptionで包まれる)で拒否
5 .waitForTaskTokenとSQSを組み合わせた承認フロー Standardでコールバックを組み、SendTaskSuccessで再開 RUNNINGで停止 → SQSからトークン取得 → SendTaskSuccessでSUCCEEDED。使用済みトークンの再送はTaskTimedOut
6 Standard / Expressの制約エラー Expressのステートマシンと、型違いのターゲットを用意して呼ぶ StateMachineTypeNotSupported、InvalidArn、Expressの.waitForTaskTokenは作成時にInvalidDefinition。公式の表どおり
7 別の実行(ゲートウェイに公開していないステートマシン)のトークンでも通るか 公開していないステートマシンの実行をCLIで起動し、そのトークンをSendTaskSuccessに渡す SUCCEEDED。でたらめなトークンはInvalidToken
8 CloudTrailでの呼び出し元の見え方 lookup-eventsでStartExecutionイベントを確認 AssumedRole、セッション名gateway-session-invocationで固定。エージェントや利用者を区別するフィールドは見当たらない。inputはHIDDEN_DUE_TO_SECURITY_REASONSに置き換わり記録されない。executionArnは記録される

検証後は、チュートリアルのStep 6の手順(ターゲット → ゲートウェイ → ステートマシン → IAMロールの順に削除)でクリーンアップしてください。本記事の検証では、SQSキューと承認用の実行ロールも作ったので、あわせて削除しました。

料金

公式ドキュメントに専用の追加料金の記載はなく、Step Functions(ステート遷移)とAgentCore Gateway(ツール呼び出し)の標準料金が適用されます。単価は本記事では割愛します。最新の単価は各料金ページで確認してください。

さいごに

今回のコネクタは、「手順は固定し、起動の判断だけをエージェントに任せる」という切り分けを、追加コードなしで実現するものでした。一方で、ツール化した瞬間に、サービスロールという1つの権限の入口にエージェントの操作が集まります。ピン・IAM・タスクトークンのどこで何を絞れて、どこは絞れないのかを把握したうえで、公開するオペレーションを最小限に選ぶことが、この機能を実務で使う鍵になりそうです。

ここまでの検証では、公式の記載どおりに動きました。ピンは、違うstateMachineArnを渡すとゲートウェイ側で拒否され、実行は作られません。サービスロールのIAMは、許可していない実行ARNへの参照・停止をStep Functions側のAccessDeniedで拒否します。一方、タスクトークンはResource: "*"で許可する必要があり、IAMでは絞れません。実際、ゲートウェイに公開していないステートマシンの実行でも、トークンがあれば完了できました。ただし、拒否の仕方はピンとIAMで異なります(IllegalArgumentExceptionと、DependencyFailedExceptionで包まれたAccessDenied)。呼び出し主体もgateway-session-invocationで固定されます。この2点は、エージェント側のエラー処理や監査の設計で意識しておく必要があります。

これから使う場合は、次の順で進めるのが安全そうです(筆者の解釈)。

  • まず、起動と参照のオペレーション(StartExecution、DescribeExecutionなど)だけを公開し、ステートマシンはピンで固定する
  • SendTask*はResource: "*"が必要になるため、人手承認のように必要なワークフローだけを、別のゲートウェイに分けて公開する(同一ゲートウェイのターゲットはサービスロールを共有するため)
  • 入出力に個人情報を含むワークフローは、includedData: ALL_DATAでエージェントに渡る内容を確認してから公開する

参考文献

発表

ドキュメント

関連(ワークフローからエージェントを呼ぶ逆方向の連携)

英語版

[AWS] Using Step Functions as an agent tool: Testing how PINs, IAM, and tokens work [AgentCore]

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?