AIコーディング 2026.04.24
Claude CodeがAWS本番環境を誤削除するのを防ぐ方法|Hooks設定3ステップ
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"]
}
}
}
]
}