项目文件夹

文件
2026-07-13 12:32:19 +08:00

94 行
3.1 KiB
Python

#!/usr/bin/env python3
"""PreToolUse hook: block direct secret fetching from AWS Secrets Manager.
Reads JSON from stdin, checks tool_name and tool_input, and returns
a deny decision if the call would fetch secret values directly.
Use {{resolve:secretsmanager:secret-id:SecretString:key}} with asm-exec instead.
"""
import json
import re
import sys
DENY_MSG = (
"Direct secret fetching is blocked. "
"Use {{resolve:secretsmanager:secret-id:SecretString:key}} with asm-exec instead. "
"Run /aws-secrets-manager for details."
)
SMA_PATTERN = re.compile(
r'(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]|::1):2773/secretsmanager/get'
)
# Match the operation regardless of casing/separators:
# GetSecretValue, get_secret_value, get-secret-value, BatchGetSecretValue, ...
GSV_PATTERN = re.compile(r'(batch[-_]?)?get[-_]?secret[-_]?value', re.I)
# Structured operation names normalized to lowercase, no separators.
GSV_OPERATIONS = ("getsecretvalue", "batchgetsecretvalue")
def _normalize_op(operation):
"""Collapse casing and -/_ separators so GetSecretValue == get-secret-value."""
return operation.lower().replace("-", "").replace("_", "")
def deny():
json.dump({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": DENY_MSG
}
}, sys.stdout)
sys.exit(0)
def allow():
sys.exit(0)
def main():
data = json.load(sys.stdin)
tool_name = data.get("tool_name", "")
tool_input = data.get("tool_input", {})
# Check structured AWS tool calls (use_aws or MCP AWS tools)
if tool_name == "use_aws" or tool_name.startswith("mcp__"):
service = (tool_input.get("service_name") or tool_input.get("service") or tool_input.get("serviceName") or "").lower()
operation = tool_input.get("operation_name") or tool_input.get("operation") or tool_input.get("operationName") or ""
if service == "secretsmanager" and _normalize_op(operation) in GSV_OPERATIONS:
deny()
# Fallback: search all string values for secret-fetching patterns
if GSV_PATTERN.search(json.dumps(tool_input)):
if "secretsmanager" in json.dumps(tool_input).lower():
deny()
# Check run_script tools for secret fetching in code
if "run_script" in tool_name:
for key, val in tool_input.items():
if isinstance(val, str) and GSV_PATTERN.search(val):
deny()
if GSV_PATTERN.search(json.dumps(tool_input)):
deny()
allow()
# Check Bash commands
if tool_name == "Bash":
command = tool_input.get("command", "")
# AWS CLI secret fetching
if re.search(r'aws\s+secretsmanager\s+(get-secret-value|batch-get-secret-value)', command, re.I):
deny()
# Direct SMA access
if SMA_PATTERN.search(command):
deny()
# boto3/SDK secret fetching in scripts
if GSV_PATTERN.search(command):
deny()
allow()
if __name__ == "__main__":
main()