
AWS Continuum for penetration testingでタスク時間の上限設定(予算管理)を試してみた
はじめに
クラウド事業統括本部の浅野です。
2026年8月に、AWS Continuum for penetration testingへ2つの機能が追加されました。ひとつはタスク時間の上限設定、もうひとつは検出結果(finding)の個別再検証です。
ペネトレーションテストは消費したタスク時間に対して課金されます($50/タスク時間)。これまでは上限を指定できず、大きなアプリだとどこまで時間がかかるか読みにくいところがありました。今回のアップデートで、タスク時間に上限を設けられるようになり、上限に達するとそれまでの検出結果を保持したままテストが止まります。あわせて、修正後にfinding単位で再検証でき、テスト全体を回し直す必要がなくなりました。
実際にどう動くのか見たかったので、タスク時間の上限を20時間に設定してペネトレーションテストを実行し、上限で止まるところまでを確認しました。上限に届かせるまでに題材選びで少し試行錯誤したので、その過程も残しておきます。本記事ではタスク時間の上限を扱います。もうひとつの新機能である検出結果の再検証は、こちらの記事で扱っています。
構成
今回の構成図です。

検証対象アプリはOWASP Juice Shopです。意図的に脆弱性を埋め込んだECサイト型のWebアプリで、ログイン・カゴ・注文・レビューなど認証後の機能を一通り持っています。公式のコンテナイメージをALB + ECS Fargateにデプロイし、Route 53のサブドメインを割り当ててHTTPで公開しました。リージョンはap-northeast-1です。
本記事の本質はペネトレーションテスト側の新機能なので、インフラ・アプリの詳細は割愛します。
やってみた
上限の20時間に届かせるための工夫
上限で止まる様子を見るには、20時間を超えて走り続けるターゲットが必要です。ところが、これが思ったより難しく、3回試してようやく届きました。
| 題材 | 設定したリソース | 発見・テストしたエンドポイント | 検証タスクの時間 | 実時間 | 消費タスク時間 | 結果 |
|---|---|---|---|---|---|---|
| OWASP Benchmark(脆弱性のテストケース2,740件を同じ形の単機能エンドポイントとして並べたアプリ) | なし | 43 | 3.7h | 3時間48分 | 11.09h | 上限の手前で完了 |
| OWASP Benchmark | OpenAPI仕様書(全2,740エンドポイント) | 125 | 7.5h | 5時間27分 | 19.61h | 上限の手前で完了 |
| OWASP Juice Shop(ログイン・カゴ・注文・レビューなど認証後の機能を持つECサイト型アプリ) | ソースコード(GitHub連携)、認証情報5件(4ロール)、テストデータ | 224 | 10.0h | 5時間20分 | 19.93h | 上限20hに到達して停止 |
表の「検証タスクの時間」は、見つかった脆弱性の候補を1件ずつ実際に再現して確かめるタスク(VALIDATOR TASK)に使ったタスク時間の合計で、消費タスク時間の内訳のひとつです。「実時間」は実行開始から完了までの経過時間です。
最初はOWASP Benchmarkで試しました。テストケースが約2,740個あり、それぞれが独立したエンドポイントになっているので、これだけあれば20時間を超えるだろうと思っていましたが、そのまま実行すると11時間で終わりました。
そこで、API仕様書を渡してエンドポイントを網羅的にテストする機能も使ってみました。全2,740エンドポイントを列挙したOpenAPI仕様書を渡して再実行しましたが、今度も19.61時間と、上限の少し手前で終わってしまいました。
ジョブの概要には、似たようなリクエストを何千回も送るより、代表的なものを確実に検証することを優先したと書かれていました。同じような形のエンドポイントは、いくつか試すと残りも同じ扱いになるようで、単純に数を増やせば、そのぶんタスク時間が伸びるわけではなさそうでした。
その後、AIといろいろ壁打ちして、ログインが必要でユーザーごとにデータや権限が違うアプリなら調べることも増えるだろうと考え、題材をOWASP Juice Shopに変えました。
あわせて、エージェントに渡す情報も増やしました。GitHub連携でソースコードを渡し、管理者・一般顧客2名・deluxe会員・経理の計5ユーザーの認証情報を登録しました。各ユーザーには、カゴ・住所・決済カード・レビューのデータも事前に入れておきました。
この状態で実行すると、発見・テストしたエンドポイントは、Benchmarkの2回目の125から224に増えました。見つかった候補を1件ずつ確かめる検証タスクにも、Benchmarkでは約7.5時間だったところ、今回は約10時間かかりました。全体では19.93時間に達したところで、上限によって止まりました。
今回の結果を見ると、エンドポイントを大量に用意するよりも、ログイン後に調べられる範囲を広げたり、ソースコードから検査の手がかりを増やしたりするほうが、タスク時間は伸びるようでした。
ペネトレーションテストの作成
Juice Shop向けのペネトレーションテストを、ウィザードで作成しました。
- テストの対象範囲: ウェブアプリケーション
- ターゲットURL: デプロイしたJuice ShopのURL
- 認証情報: 5件(admin / customer×2 / deluxe / accounting)
- VPC: なし(公開ALBなので不要)
- リスクタイプ: 除外なし
- 接続されたリソース: GitHub連携したJuice Shopのソースコード
- 最大タスク時間: 20時間
GitHub連携
ソースコードは、エージェントスペースの「統合」からGitHubを連携して渡しました。公式リポジトリをforkし、そのリポジトリだけを選択してGitHub Appをインストールしました。


連携が追加されました。GitHub連携は、ペネトレーションテストでのソースコード参照のほか、コードレビューでのPRへのコメントや自動修正PRの作成にも使われます。今回はforkしたパブリックリポジトリを連携しましたが、パブリックリポジトリでは脆弱性情報を公開しないよう、PRへのコメントと自動修正PRは作成されません。ペネトレーションテストでソースコードを参照する用途には問題なく使えます。

ウィザード
手順1はテストの詳細です。名前、テストの対象範囲、ターゲットURL、サービスロールを設定しました。

手順3の認証情報に、5ユーザー分を追加しました。

認証情報の入力画面です。ユーザー名とパスワードを直接入力すると、Secrets Managerに保存されます。「Agent Spaceログインプロンプト」にはログイン画面への到達手順と成功判定の方法を書きました。今回は、末尾にそのアカウントのロールと「ロールの異なる他アカウントも渡しているので、ユーザー間・ロール間のアクセス制御も検査してよい」という一文を入れました。

スクリーンショットは管理者(admin)の分だけですが、実際には次の5ユーザーを同じ要領で登録しました。いずれもJuice Shopに最初から入っているデモ用ユーザーで、メールアドレスも公開されているものなので、そのまま載せています。
| 認証情報名 | ユーザー | ロール |
|---|---|---|
| admin | admin@juice-sh.op | 管理者 |
| customer-jim | jim@juice-sh.op | 一般顧客 |
| customer-bender | bender@juice-sh.op | 一般顧客 |
| deluxe-ciso | ciso@juice-sh.op | deluxe会員 |
| accounting | accountant@juice-sh.op | 経理 |
「すべての認証情報をテストする」で、5件ともログインに成功することを確認してから先に進みました。このテストは無料で、5件の実行に全部で20分ほどかかりました。

手順4のネットワーク設定は、ターゲットのみが対象になっていることを確認しました。

手順5の「その他の設定」で、リソースの「既存のリソースから選択」から連携済みのGitHubリポジトリを接続しました。


同じ手順5に、今回の目玉の「最大タスク時間」があります。プルダウンで選べるのは次の4つです。
- 制限なし
- 20時間(最小許容値)
- 30時間(推奨。「ほとんどのペンテストは30時間以内に完了します」と案内されています)
- カスタム(任意の時間数を入力)
カスタムで20時間より小さい値を入れると、「20 時間以上である必要があります」とバリデーションエラーになります。下限は20時間です。

今回は上限で止まる様子を見たいので、最小の20時間を選びました。リソースにGitHubリポジトリが接続され、最大タスク時間が20時間になっています。

作成後の設定画面です。最大タスク時間が20hで設定できていることが分かります。

実行と上限到達
実行を開始しました。

約5時間20分(実時間)走って、タスク時間19時間56分で上限に到達し、テストが止まりました。実行の概要には「タスク時間予算内で完了済み」のバナーが出て、Job aborted: cumulative task-hours (19.9) reached configured maximum (20.0) と理由が表示されます。ステータスはエラーではなくCompletedで、プリフライトから最終処理までの4ステップもすべてCompletedです。検出結果は30件(重要8・高8・中程度14。低信頼度のものは既定で非表示)で、上限で止まってもそれまでの検出結果はそのまま残っています。

上限で止まったことをCLIで確認する
ジョブの詳細を取ると、errorInformationに停止理由が入っています。
$ aws securityagent batch-get-pentest-jobs \
--region ap-northeast-1 \
--agent-space-id <agent-space-id> \
--pentest-job-ids <pentest-job-id> \
--query 'pentestJobs[0].{status:status,errorInformation:errorInformation}'
{
"status": "COMPLETED",
"errorInformation": {
"code": "STOPPED_BY_USER",
"message": "Job aborted: cumulative task-hours (19.9) reached configured maximum (20.0)"
}
}
コードはSTOPPED_BY_USERで、手動停止と同じコードが使われます。上限による停止かどうかは、messageの文言で見分けることになります。
タスクの状態を集計すると、上限で中断されたタスクがABORTEDとして残っています。166タスクのうち44タスクが中断されました。
$ aws securityagent list-pentest-job-tasks \
--region ap-northeast-1 \
--agent-space-id <agent-space-id> \
--pentest-job-id <pentest-job-id> \
--query 'taskSummaries[].executionStatus' --output text | tr '\t' '\n' | sort | uniq -c
44 ABORTED
122 COMPLETED
消費したタスク時間は、各タスクのtaskHoursを合計すると分かります。コンソールの「19時間56分」と一致します。list-pentest-job-tasksはページングされるので、JSON全体を受け取ってからjqで合計します。
$ aws securityagent list-pentest-job-tasks \
--region ap-northeast-1 \
--agent-space-id <agent-space-id> \
--pentest-job-id <pentest-job-id> \
--output json | jq '{tasks:(.taskSummaries|length), taskHours:([.taskSummaries[].taskHours]|add)}'
{
"tasks": 166,
"taskHours": 19.93386326825888
}
上限で止まると、ログとレポートはどうなるか
上限で止まった事実がどこに残るのかも確認しました。結論から言うと、停止理由が分かるのはコンソールのバナーとAPIのerrorInformationだけで、CloudWatch Logsにも生成レポートにも記載はありません。
CloudWatch Logsには、各タスクのエージェントが実行した内容(ツールの呼び出しと結果、検出内容)が記録されます。上限に達すると、各ログストリームはその時点で途切れて終わります。「上限に達したので停止する」といった通知は出力されません。

生成レポート(PDF)にも停止理由は書かれません。痕跡は「Tasks Executed」の表のStatus列だけで、中断されたタスクがAbortedとして並びます。なぜAbortedになったのかは読み取れないので、レポートを共有する際は上限で途中停止した旨を書き添える必要があります。

無料枠の事後確認
AWS Continuum for penetration testingには、新規利用者向けに2か月の無料トライアル(1か月あたり400タスク時間まで)があり、最初のペネトレーションテストを実行した時点で開始されます。今回のアカウントは一度もペネトレーションテストを実行していなかったので対象のはずでしたが、事前に適用を確認する手段は見当たらなかったので、想定外の課金に備えてAWS Budgetsでメール通知だけ仕掛けて実行しました。
実行後にCost Explorerを見ると、Security Agentの行が$0で計上されていて、トライアルが効いていることが確認できました。確認できるのは実行後のここだけなので、リセール経由のアカウントなど無料枠が適用されないケースに当てはまらないか、事前にしっかり確認しておくことをお勧めします。

最後に
今回の上限設定で、「この予算の範囲で調べられるところまで調べてもらう」という使い方ができるようになりました。継続的なペネトレーションテスト(プレビュー)と組み合わせて定期的に回す運用や、検証環境で規模を意図的に抑えたい場合などに便利なアップデートだと思います。個人的には、最小の20時間はまだ大きいので、10時間くらいから設定できるとさらに使いやすそうです。
ただ、上限に達して止まったことは、CloudWatch Logsにも生成レポートにも残りません。停止コードも手動停止と同じSTOPPED_BY_USERなので、これだけでは区別がつきません。上限で止まったかどうかを確認するには、コンソールのバナーか、APIのerrorInformationを見る必要があります。
また、今回試した範囲では、ソースコードや権限の違う複数ユーザーの認証情報を渡すことで、調べる範囲が広がり、検証にかかる時間も増えました。エンドポイントの数だけではタスク時間を見積もれないので、上限を決めるときは、どこまで情報を渡して調べてもらうかも、あわせて考えたほうがよさそうです。
今回は以上です。











