AIコーディング 2026.04.24

Claude CodeがAWS本番環境を誤削除するのを防ぐ方法|Hooks設定3ステップ

タグ:ClaudeCode / AWS / セキュリティ / 生成AI / 開発ツール

Step 1: .claude/settings.jsonにフックを設定する

// .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(aws * --profile prod*)",
      "Bash(aws * --profile production*)",
      "Bash(terraform * -var-file=prod*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "python3 .claude/hooks/aws_prod_guard.py"
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "python3 .claude/hooks/post_tool_log.py"
        }]
      }
    ]
  }
}

Step 2: AWS本番ガードスクリプト

# .claude/hooks/aws_prod_guard.py
# Claude Codeが本番AWSプロファイルにアクセスしようとしたら阻止する

import sys
import json
import os
import subprocess
from datetime import datetime
from pathlib import Path

# 本番として扱うAWSプロファイル名
PRODUCTION_PROFILES = {"prod", "production", "prd", "main"}

# ログファイル
LOG_FILE = Path(".claude/hooks/blocked_operations.log")
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)

def get_current_aws_profile() -> str:
    """現在のAWSプロファイルを取得する"""
    env_profile = os.environ.get("AWS_PROFILE", "")
    if env_profile:
        return env_profile
    
    try:
        result = subprocess.run(
            ["aws", "configure", "get", "profile"],
            capture_output=True, text=True, timeout=3
        )
        return result.stdout.strip()
    except Exception:
        return ""

def check_command_for_prod(command: str) -> bool:
    """コマンドが本番プロファイルへのアクセスを含むか検査する"""
    for profile in PRODUCTION_PROFILES:
        patterns = [
            f"--profile {profile}",
            f"--profile={profile}",
            f"AWS_PROFILE={profile}",
            f"-profile {profile}",
        ]
        if any(p in command for p in patterns):
            return True
    return False

if __name__ == "__main__":
    hook_data = json.loads(sys.stdin.read())
    tool_name = hook_data.get("tool_name", "")
    tool_input = hook_data.get("tool_input", {})
    command = tool_input.get("command", "")
    
    # AWSコマンドの本番プロファイルチェック
    if tool_name == "Bash" and "aws" in command:
        if check_command_for_prod(command):
            blocked_msg = f"[{datetime.now().isoformat()}] BLOCKED: {command[:200]}"
            LOG_FILE.write_text(blocked_msg + "\n", mode="a")
            
            print(f"🚫 本番AWSプロファイルへの操作をブロックしました。")
            print(f"   コマンド: {command[:100]}")
            print(f"   開発プロファイル(--profile dev)を使用してください。")
            
            # Slack通知(任意)
            # notify_slack(command)
            
            sys.exit(1)  # ← exit 1でClaude Codeは実行を停止
    
    # 環境変数経由の本番プロファイルチェック
    current_profile = get_current_aws_profile()
    if current_profile in PRODUCTION_PROFILES and "aws" in command.lower():
        if any(word in command for word in ["delete", "destroy", "remove", "drop"]):
            print(f"🚫 本番環境での削除操作をブロックしました(現在のプロファイル: {current_profile})")
            sys.exit(1)
    
    sys.exit(0)  # ← exit 0で実行を許可

Step 3: PostToolUseでSlack通知

#!/bin/bash
# .claude/hooks/notify_slack.sh
# 本番に関連する操作をSlackに通知する(PostToolUse用)

COMMAND="$1"
SLACK_WEBHOOK="${SLACK_WEBHOOK_URL:-}"

# 本番キーワードを含む操作だけを通知
if echo "$COMMAND" | grep -qE "(prod|production|prd)" && [ -n "$SLACK_WEBHOOK" ]; then
    payload="{\"text\": \"⚠️ Claude Code: 本番環境コマンド実行\n\`\`\`${COMMAND:0:200}\`\`\`\"}"
    curl -s -X POST -H 'Content-type: application/json' \
         --data "$payload" "$SLACK_WEBHOOK" > /dev/null
fi

IAMポリシーによる二重防護

// 開発者IAMポリシー(DenyProductionDelete)
// フックを回避されても、この権限でブロック
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyProductionDeleteAndModify",
      "Effect": "Deny",
      "Action": [
        "ec2:TerminateInstances",
        "rds:DeleteDBInstance",
        "s3:DeleteBucket",
        "lambda:DeleteFunction"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:ResourceTag/Environment": ["prod", "production"]
        }
      }
    }
  ]
}

あわせて読みたい

参考ソース