はじめに:信頼性を技術で担保するということ
NTT西日本 1年目の野村です。私は現在、生成AIを活用したインフラ運用の高度化に取り組んでいます。 生成AIは業務効率化の「有効な手段」として期待される一方、ハルシネーション(情報の誤り)への懸念から、特に信頼性が最優先される分野での導入には高いハードルが存在します。特に、私が携わっているガバメントクラウド(ガバクラ)のような公共性の高いインフラ環境では、「AIが作ったから」という理由は一切通用しません。
前回の記事(前編) では、Amazon Bedrock Agentを用いて、非構造データであるExcel設定シートから「IaCコード(YAML)の自動生成」を行いました。さらに「構成図(Mermaid)の自動レンダリング」までを「司令塔」として実行させる基盤を構築しました。
しかし、技術的にコードが作れることと、それを実環境にデプロイして運用を回せることの間には、大きな隔たりがあります。後編となる本稿では、最後の課題である「人間による承認(Human-in-the-loop)」と「自動デプロイ」を統合し、ガバクラ基準のセキュリティを満たしながら運用を完結させる自律型運用ワークフローの構築について、その全貌を詳説します。
- 前編:ガバクラ運用の司令塔にBedrock Agentを。精度を極めるAPI設計とJSONL正規化で挑むインフラ自律化
- 後編:「AIを疑う」ことで信頼を築く。Step Functionsと視覚的答え合わせによる自律型デプロイの完成(本記事)
※本記事は2025年12月19日時点の情報に基づきます。
対象読者
- 生成AIの「精度・信頼性の壁」を突破したい実務家
- ガバメントクラウドなどの高信頼インフラを運用するエンジニア
- Amazon Bedrock Agentの具体的な活用例を知りたい開発者
1. 背景と直面した課題:自動化の「ラストワンマイル」
1.1 承認プロセスの「心理的・物理的コスト」
1.2 作業の「バトンタッチ」が途切れている
2. アーキテクチャの全貌:Step Functionsによる自律制御
2.1 ワークフローの制御構造(Task Tokenの活用)
3. 技術的実装の深掘り:セキュリティとUXの極致
3.1 CloudFront + OAC + Lambda@Edge による動的認可
3.2 DynamoDBを活用した「短縮URL・トークンマッピング」
3.3 「見てから押す」:視覚的バリデーションの実装
3.4 変更セット(ChangeSet)を活用した安全な自動デプロイ
4. 性能評価と導入効果:数字で見る「AI×自動化」の衝撃
4.1 リードタイムの比較:従来比79%削減の実証
4.2 大規模環境におけるスケールメリット
5. エンジニアとしての内省:試行錯誤と学び
6. まとめと今後の展望:ガバクラ運用の未来へ
6.1 本プロジェクトの成果
6.2 今後のロードマップ
付録:ソースコード全文 / 執筆者紹介
1. 背景と直面した課題:自動化の「ラストワンマイル」
ガバメントクラウド運用において、ASP事業者からのTransit Gateway(TGW)接続要求は急増の一途をたどっています。前編までの取り組みで、複雑なルートテーブル設定を自動化する道筋は見えましたが、実運用への投入を検討した際、効率化の流れを止めてしまう「手作業の連鎖」が浮き彫りになりました。

1.1 承認プロセスの「心理的・物理的コスト」
AIが生成したYAMLコードや構成図を確認するためには、これまではエンジニアが自らS3コンソールへログインし、ファイルをダウンロードして内容を精査する必要がありました。「効率化のためにAIを入れたのに、確認作業のために結局コンソールを操作し続ける」という矛盾が生じていたのです。
1.2 作業の「バトンタッチ」が途切れている
コードの生成と確認が済んだ後、実際にCloudFormationを実行するフェーズでは、再び人間がCLIを実行するか、マネジメントコンソールから「変更セットの実行」をクリックする必要がありました。この「人の手」が介在する瞬間がある限り、リードタイムの劇的な短縮は望めず、また作業の属人化も解消されません。
本プロジェクトの核心は、これら「確認」と「実行」をシームレスにつなぎ、「メール通知から最短2クリックで内容を把握・承認し、そのまま無人でデプロイを完了させる」仕組みを構築することにあります。
2. アーキテクチャの全貌:Step Functionsによる自律制御
ゴールに向け、アーキテクチャを「オーケストレーションの強化」を主軸に再設計しました。中心となるのは AWS Step Functions です。

2.1 ワークフローの制御構造
前編で構築した「Agentによる成果物生成」の後に続く、デプロイフェーズの司令塔としてStep Functionsを配置しました。本システムの最大の特徴は、Step Functionsの「Task Token」を用いた待機・再開メカニズムにあります。
- 起動: Bedrock Agentが全ての成果物(YAML, PNG図解)の生成を終えると、Step Functionsをキックします。
- 待機: Step Functionsは承認依頼メールを送信すると同時に、自身のステータスを「承認待ち(Wait for Callback)」に移行させ、トークンを発行します。
- 再開: 人間がWeb画面上で「承認」を行うと、API Gateway経由でトークンが返却され、ワークフローが自動的に動き出します。
この構造により、サーバーレス環境でありながら「人間の意思決定」を非同期に、かつ確実にプロセスへ組み込むことが可能となりました。
3. 技術的実装の深掘り:セキュリティとUXの極致
単なる機能実装に留まらず、ガバメントクラウドという特殊な環境下で求められる「堅牢性」と、現場の「使い勝手」をいかに両立させたか。実装の核心部を4つのポイントで解説します。
3.1 CloudFront + OAC + Lambda@Edge による「ゼロトラスト」資産配信
ガバクラ環境における構成図(PNG)の確認において、最大の障壁は「セキュリティ」でした。S3バケットをパブリック公開することは許容されませんが、一方で承認者がわざわざVPNを張ってAWSコンソールにログインする手間は省きたい。
そこで採用したのが、CloudFrontとOrigin Access Control (OAC)、そして Lambda@Edge を組み合わせた動的認可モデルです。
- 仕組み: 承認リンクをクリックした際、リクエストヘッダーに含まれる署名(トークン)を Lambda@Edge で検証します。
- 価値: S3への直接アクセスを完全に遮断したまま、認可されたユーザーに対してのみ、特定の有効期限内で構成図をストリーミング配信します。

以下は、今回構築した検証ロジックの核心部です。Lambda@Edgeがリクエストをインターセプトし、DynamoDBのTTL(有効期限)を参照してアクセスの可否を判定します。
# Lambda@Edge: cf-viewer-request-approval-validator # 役割: 資産アクセス時の動的バリデーター import urllib.parse import boto3 import time from botocore.exceptions import ClientError from typing import Dict, Any import json # Lambda@Edgeはus-east-1で実行されるが、DynamoDBテーブルは東京(ap-northeast-1)を参照 DYNAMODB_CLIENT = boto3.client('dynamodb', region_name='ap-northeast-1') DYNAMODB_TABLE_NAME = 'ShortenedUrlStore' def get_session_status(short_id: str) -> bool: """DynamoDBでShortIdが存在し、TTL(有効期限)内であることを確認する。""" try: # 予約語'TTL'を扱うため、ExpressionAttributeNamesを使用 response = DYNAMODB_CLIENT.get_item( TableName=DYNAMODB_TABLE_NAME, Key={'ShortId': {'S': short_id}}, ProjectionExpression='#T', ExpressionAttributeNames={'#T': 'TTL'} ) item = response.get('Item') if item is None or 'TTL' not in item: print(f"ShortId {short_id} NOT found or TTL missing.") return False # TTLチェック ttl_epoch = int(item['TTL']['N']) current_time = int(time.time()) is_valid = ttl_epoch > current_time if is_valid: print(f"ShortId {short_id} is VALID. Remaining: {ttl_epoch - current_time}s") else: print(f"ShortId {short_id} expired.") return is_valid except ClientError as e: print(f"DynamoDB ClientError: {e.response.get('Error', {}).get('Message')}") return False def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] querystring = request.get('querystring', '') params = urllib.parse.parse_qs(querystring) short_id = params.get('shortid', [None])[0] # 1. 必須パラメータチェック if not short_id: return {'status': '403', 'body': 'Access Forbidden: Missing ShortId'} # 2. DynamoDBでの実検証 if not get_session_status(short_id): return {'status': '403', 'body': 'Access Forbidden: Link expired or invalid'} # 3. セキュリティ向上: 転送前にクエリから機密トークンを削除 if 'token' in params: remaining_params = [f"shortid={short_id}"] if 'v' in params: # キャッシュ回避パラメータ remaining_params.append(f"v={params['v'][0]}") request['querystring'] = '&'.join(remaining_params) print("Link validated. Proceeding to S3 origin.") return request
3.2 DynamoDBを活用した「短縮URL・トークンマッピング」
Step Functionsが発行するTask Tokenは、URLに含めるには長大すぎて(数キロバイトに及ぶことも)、メールソフトでのリンク切れやセキュリティスキャナーによる誤検知を招きます。私はこの問題を解決するために、DynamoDBをデータストアとして活用した「自前短縮URL機構」を構築しました。
# Lambda (SF-2): トークンをDynamoDBへ保存し短縮キーを発行 import boto3 import uuid import time def lambda_handler(event, context): task_token = event['taskToken'] short_id = str(uuid.uuid4())[:8] # 8文字の短縮ID # DynamoDBへ保存(有効期限TTLを設定し、自動削除されるように設計) table = boto3.resource('dynamodb').Table('TokenStorage') table.put_item(Item={ 'ShortID': short_id, 'FullToken': task_token, 'Status': 'PENDING', 'TTL': int(time.time()) + 86400 # 24時間後に消去 }) # 承認者に送るURLを生成 approval_url = f"https://approval.example.com/confirm?id={short_id}" return {"approvalUrl": approval_url}
この実装により、承認者のメールには非常にクリーンなリンクが届き、リンク切れのリスクを排除しつつ、バックエンドでは確実にセッションを管理できる仕組みを実現しました。
3.3 「見てから押す」:ハルシネーション対策としての二段階承認
AIの出力をそのままデプロイすることのリスクを最小化するため、UX設計にもこだわりました。メールのリンクをクリックして即実行されるのではなく、一旦「確認専用のWebサイト」へ誘導します。
ここで活躍するのが、前編で作成したMermaid図解です。 運用者は、文字ベースのYAMLではなく、視覚化されたネットワーク構成図(「どのVPCが、どのルートテーブルに関連付けられ、どこへ伝播しているか」)を「絵」として確認します。
「視覚的に理解しやすい形式」で情報を提供することで、ハルシネーションを見落とす確率を劇的に下げています。この「視覚的バリデーション」こそが、本システムの信頼性の根幹です。

3.4 変更セット(ChangeSet)を活用した安全な自動デプロイ
承認後のデプロイ処理(Lambda SF-7)では、既存スタックにいきなり反映させるのではなく、CloudFormationの「変更セット(ChangeSet)」を中間生成する設計にしました。
# Lambda (SF-7): 承認後の自動デプロイ def execute_deployment(event, context): cfn = boto3.client('cloudformation') # 前段のステップで生成しておいたChangeSetを「実行」するだけ cfn.execute_change_set( ChangeSetName=event['changeSetName'], StackName=event['stackName'] ) # 実行後のステータスを監視し、SNSで完了通知を送る後続タスクへ return {"status": "SUCCESS", "message": "Deployment initiated."}
万が一デプロイ中に予期せぬエラーが発生しても、CloudFormationの標準機能により自動ロールバックが行われるため、環境の整合性が保たれます。
4. 性能評価と導入効果:数字で見る「AI×自動化」の衝撃
本システムの導入効果を検証するため、2つのASP-VPCをTGWに新規接続するシナリオで性能評価を行いました。比較の指標には、「人間のアクション開始からデプロイ完了(疎通可能状態)まで」の総経過時間である「合計リードタイム」を採用しています。
4.1 リードタイムの比較
計測の結果、大幅な短縮効果が実証されました。
※表内の短縮率は従来法に対する本システム(全自律型)の実行時間の比較を整数で数値化しています。
| 工程 | 従来法(手動・GUI) | 本システム(半自律型) | 本システム(全自律型) | 短縮率 |
|---|---|---|---|---|
| パラメータシート作成 | 12分(手動で抽出) | 2.5分(Agentが一連実行) | 2.5分(Agentが一連実行) | 80%削減 |
| 承認プロセス(確認〜ボタン) | - | 1.5分(S3で自ら確認) | 1.5分(リンククリック) | - |
| デプロイ実行 | 11分(マネジメントコンソール) | 3分(CloudFormation手動デプロイ) | 1分(承認後CloudFormation自動デプロイ) | 93%削減 |
| 合計リードタイム | 23分 | 7分 | 5分 | 79%削減 |
| 合計操作回数 | 40回 | 12回 | 6回 | 85%削減 |
4.2 大規模環境におけるスケールメリット
前編でも触れましたが、Bedrock Agentの特性として、処理対象が増えても推論時間は指数関数的には増えません。 下図は、VPCアタッチ数(設定の複雑さ)に対する従来のGUI操作による実行とAgentによる実行の時間比較を示したものです。

手作業であれば接続数が倍になれば工数も倍(あるいはそれ以上)になりますが、本システムでは「大規模になればなるほど、1接続あたりのコストが極小化される」という、高い拡張性(Scalability)を証明しました。
5. エンジニアとしての内省:試行錯誤と学び
本プロジェクトを完遂するまで、私は「1年目の壁」に何度もぶつかりました。特に、Bedrock AgentとLambdaの連携におけるOpenAPIスキーマの微調整や、Step FunctionsのTask Tokenの受け渡し不良など、デバッグに数日を要したこともあります。
しかし、その過程で得た最大の学びは、「生成AIを信じるためのインフラを、AWSのマネージドサービスでいかに強固に組み上げるか」という視点です。 AIが優秀であればあるほど、人間はその「出力」を鵜呑みにしがちです。そこを敢えて「疑う」ための仕組み(Mermaid図解や二段階承認)を、Step Functionsのような堅牢なオーケストレーターで実装することの重要性を痛感しました。
これは、プロフェッショナルなクラウドエンジニアを目指し・歩み続ける上で、私の血肉となる貴重な経験となりました。
6. まとめと今後の展望:ガバクラ運用の未来へ
2回にわたってお届けした本プロジェクトを通じて、ガバメントクラウドという最も厳格な環境においても、「Agentによる創造」と「Step Functionsによる統制」を組み合わせることで、人間が確信を持って運用できる自律型システムが構築可能であることを示しました。
6.1 本プロジェクトの成果
- 工数削減: TGW設定業務のリードタイムを約80%削減し、現場の負担を大幅に軽減。
- 品質向上: ヒューマンエラーを排除し、構成図の自動生成により運用の可視性を確保。
- セキュリティ: ガバクラ基準を一切妥協せず、セキュアな外部承認フローを確立。
6.2 今後のロードマップ
今後の展望として、このシステムを以下の領域へ拡張させていく予定です。
- 接続パターンの網羅: VPCアタッチメントだけでなく、AWS PrivateLinkやTGWピアリングなど、全てのネットワーク(NW)要求を単一のAgentインターフェースで受容可能にします。
- LLMによる異常検知: CloudWatch Logsと連携し、デプロイ後の通信状況をAgentが監視。「正常に疎通できているか」までを自然言語で報告する機能の実装を目指します。

「複雑なインフラを、より確実で、誰もが迷わないプロセスへ」
生成AIとAWSのマネージドサービスを組み合わせることで、効率化だけでなく、運用そのものの「安心感」を底上げできる可能性を実感しました。1年目のエンジニアとして、これからも現場の課題に真摯に向き合い、技術を通じた実効性のある貢献を積み重ねていきたいと思います。
執筆者

野村 稜武
NTT西日本 サービス開発担当。新卒入社1年目。
クラウドインフラの高度/自動化と生成AIの実用化に情熱を注いでいます。
現在は現場への技術還元を加速させるべく、AWSの「Kiro」や「MCP」の学習、そして最新技術のキャッチアップとアウトプットに日々尽力しています。
プロジェクトメンバー
- 西山 七海 プロジェクトリーダー。生成AIを活用したサービス開発の全体統括を担当。
- 梅木 大助 テクニカルアドバイザー。長年の経験に基づき、アーキテクチャの精査や技術的助言を担当。
付録:ソースコード全文
本プロジェクトで実装したLambdaのロジックや、Bedrock Agentのアクショングループを定義するOpenAPIスキーマの全文は、以下のGitHubリポジトリにて公開しています。 実運用における具体的な実装の詳細や、エラーハンドリングの記述など、興味のある方はぜひご参照ください。
GitHub Repository: https://github.com/nomu-ryo/bedrock-agents-project
参考資料・商標
[1]Wait for a Callback with the Task Token
[2]Amazon CloudFront オリジンアクセスコントロール (OAC) の導入
[3]変更セットを使用したスタックの更新
※「AWS」「Amazon Bedrock」「AWS Step Functions」「AWS Lambda」「Amazon CloudFront」「Amazon DynamoDB」「Amazon S3」「AWS CloudFormation」「Amazon API Gateway」「Amazon SNS」「Amazon CloudWatch」は、Amazon.com, Inc. またはその関連会社の商標です。
免責事項
本記事で紹介した内容やコードは、筆者個人の見解であり、所属組織の公式見解を示すものではありません。実際の導入にあたっては、各環境のセキュリティポリシーやAWSの最新仕様を必ずご確認ください。また、本記事の利用により生じた直接的・間接的な損害について、筆者は一切の責任を負いかねます。