关于 setup-security-agent
为 AWS Security Agent 建立工作区基础资源的技能,供后续扫描和渗透测试流程使用。它配置 AgentSpace、IAM 服务角色和 S3 存储桶,并将工作区设置保存在本地。
主要功能
- 01检查并选择或创建 AgentSpace
- 02创建并配置 IAM 服务角色
- 03创建并保护 S3 存储桶
- 04关联角色与存储桶到 AgentSpace
- 05保存工作区本地配置
适用场景
- 01首次配置 Security Agent 工作区
- 02为安全扫描准备 AWS 资源
- 03为渗透测试流程准备 AgentSpace
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ aws/ agent-toolkit-for-aws --skill setup-security-agent安装后在 Claude Code 中输入/setup-security-agent确认已加载。
详细介绍
AWS Security Agent — 设置
此技能只处理一件事:确保工作区拥有可正常使用的 Agent 空间、IAM 服务角色和相互关联的 S3 存储桶。扫描和渗透测试属于单独的技能,并假设此项设置已完成。
本地状态约定
所有 Security Agent 技能都共享工作区本地状态目录 .security-agent/:
config.json—{ "agent_space_id": "as-...", "region": "us-east-1", "code_reviews": { "<abs_path>": "cr-..." } }。账户 ID、角色 ARN 和存储桶名称按约定推导。code_reviews映射使扫描能够在同一工作区中重复使用同一个 CodeReview。scans.json—{ scan_id, code_review_id, job_id, agent_space_id, scan_type, title, started_at, status, path }数组(保留最近 50 条)pentests.json— 同样的结构,用于渗透测试任务.gitignore— 内容为*,以确保此目录不会被 Git 跟踪findings-{scan_id}.md— 每次扫描完成后由扫描技能写入
此技能负责填充 config.json 并创建 .gitignore。
派生值(按约定而非配置)
其他技能每次运行时都会计算以下值,而不是从 config.json 中读取:
| 值 | 约定 |
|---|---|
ACCOUNT | aws sts get-caller-identity --query Account --output text |
REGION | config.region(默认值为 us-east-1) |
service_role_arn | arn:aws:iam::${ACCOUNT}:role/SecurityAgentScanRole |
s3_bucket | security-agent-scans-${ACCOUNT}-${REGION} |
为何配置保持精简:角色名称和存储桶名称都是确定的,因此保存它们会增加配置漂移风险(用户手动重新创建角色后,可能会在不知情的情况下使用过期路径)。只保存 agent_space_id,因为用户可能有多个 Agent 空间,而且我们不想每次会话都询问要使用哪一个。
工作流
-
检查现有状态: 如果
.security-agent/config.json存在,则读取它。 -
调用方身份 + 区域:
export ACCOUNT=$(aws sts get-caller-identity --query Account --output text) export REGION="${AWS_REGION:-us-east-1}" -
Agent 空间:
-
如果已设置
config.agent_space_id,使用以下命令验证:aws securityagent batch-get-agent-spaces --agent-space-ids <id>如果响应显示该空间不存在,则视为缺失。
-
如果缺失,则列出现有空间:
aws securityagent list-agent-spaces-
如果有任何空间 → 向用户展示这些空间,包含名称和 ID,并询问:“您想重复使用其中一个,还是让我创建一个新的?”等待用户回答。不要自动选择。
-
如果用户选择一个,则使用其
agentSpaceId。 -
如果用户想创建新的,或没有现有空间:
aws securityagent create-agent-space --name security-scans保存返回的
agentSpaceId。
-
-
-
服务角色(
SecurityAgentScanRole,ARN 为arn:aws:iam::$ACCOUNT:role/SecurityAgentScanRole):-
检查:
aws iam get-role --role-name SecurityAgentScanRole -
如果返回
NoSuchEntity,则创建该角色。幂等性说明: 如果角色已存在,create-role会因EntityAlreadyExists而失败。如果发生这种情况,则继续执行update-assume-role-policy,确保信任策略正确。# 信任策略 — 包含 aws:SourceAccount 混淆代理防护 cat > /tmp/sa-trust.json <<EOF {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"securityagent.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"${ACCOUNT}"}}}]} EOF # 权限策略(S3 + CloudWatch Logs) cat > /tmp/sa-perms.json <<EOF {"Version":"2012-10-17","Statement":[ {"Effect":"Allow","Action":["s3:GetObject","s3:GetObjectVersion","s3:ListBucket"],"Resource":["arn:aws:s3:::security-agent-scans-${ACCOUNT}-${REGION}","arn:aws:s3:::security-agent-scans-${ACCOUNT}-${REGION}/*"]}, {"Effect":"Allow","Action":["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],"Resource":"arn:aws:logs:*:${ACCOUNT}:log-group:/aws/securityagent/*"} ]} EOF aws iam create-role --role-name SecurityAgentScanRole --assume-role-policy-document file:///tmp/sa-trust.json # 如果 EntityAlreadyExists: aws iam update-assume-role-policy --role-name SecurityAgentScanRole --policy-document file:///tmp/sa-trust.json # 始终(重新)应用权限: aws iam put-role-policy --role-name SecurityAgentScanRole --policy-name SecurityAgentCodeReviewAccess --policy-document file:///tmp/sa-perms.json
-
-
S3 存储桶(
security-agent-scans-$ACCOUNT-$REGION):存储桶所有权强制校验(必需)。 存储桶名称根据调用方的 AWS 账户 ID 和区域生成——两者都不是机密,且可从 ARN / ECR URI 推导出来——因此任何第三方都可以在自己的账户中预先注册(“抢注”)这个可预测的名称。每次 S3 调用都必须传入
--expected-bucket-owner "$ACCOUNT",以便在存储桶归属他人时安全失败。如果存储桶存在但归属其他账户,出现403 Forbidden就是致命错误——中止设置,绝不要上传。-
探测(校验所有权):
BUCKET="security-agent-scans-${ACCOUNT}-${REGION}" NEED_CREATE=0 if aws s3api head-bucket --bucket "$BUCKET" --expected-bucket-owner "$ACCOUNT" 2>/tmp/sa-head.err; then : # 存储桶存在且归属此账户——可以安全复用 elif grep -q '404' /tmp/sa-head.err; then NEED_CREATE=1 elif grep -Eq '403|Forbidden' /tmp/sa-head.err; then echo "致命错误:存储桶 $BUCKET 已存在,但归属其他账户(403)。可能发生了存储桶抢注——正在中止。未上传任何内容。" >&2 exit 1 else cat /tmp/sa-head.err >&2; exit 1 fi -
如果未找到,则创建存储桶。
BucketAlreadyExists错误表示其他账户已占用该全局名称——应将其视为致命错误,并与BucketAlreadyOwnedByYou(可安全忽略)区分开。创建后、进行任何后续操作前,重新校验所有权:if [ "$NEED_CREATE" = "1" ]; then if [ "$REGION" = "us-east-1" ]; then # us-east-1:不设置 LocationConstraint aws s3api create-bucket --bucket "$BUCKET" 2>/tmp/sa-create.err || true else # 其他区域: aws s3api create-bucket --bucket "$BUCKET" \ --create-bucket-configuration LocationConstraint="$REGION" 2>/tmp/sa-create.err || true fi if grep -q 'BucketAlreadyExists' /tmp/sa-create.err; then echo "致命错误:存储桶名称 $BUCKET 已归属其他账户(BucketAlreadyExists)。可能发生了存储桶抢注——正在中止。" >&2 exit 1 elif [ -s /tmp/sa-create.err ] && ! grep -q 'BucketAlreadyOwnedByYou' /tmp/sa-create.err; then cat /tmp/sa-create.err >&2; exit 1 fi # 使用新创建的存储桶前,确认其所有权。 aws s3api head-bucket --bucket "$BUCKET" --expected-bucket-owner "$ACCOUNT" fi -
始终(重新)应用公共访问阻止设置和 30 天生命周期规则:
aws s3api put-public-access-block --bucket "$BUCKET" \ --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true cat > /tmp/sa-lifecycle.json <<'EOF' {"Rules":[{"ID":"AutoDeleteUploads","Status":"Enabled","Filter":{"Prefix":""},"Expiration":{"Days":30}}]} EOF aws s3api put-bucket-lifecycle-configuration --bucket "$BUCKET" --lifecycle-configuration file:///tmp/sa-lifecycle.json
-
-
在 Agent 空间上注册角色和存储桶(幂等):
-
读取现有资源:
aws securityagent batch-get-agent-spaces --agent-space-ids <id>查看
agentSpaces[0].awsResources.iamRoles和awsResources.s3Buckets。 -
如果角色 ARN 或存储桶名称不在这些列表中,则合并并更新:
aws securityagent update-agent-space --agent-space-id <id> --name <existing-name> \ --aws-resources iamRoles=[<arn1>,<arn2>...],s3Buckets=[<bucket1>,<bucket2>...]
-
-
持久化到
.security-agent/config.json(保持精简——账户/角色/存储桶信息均可推导):{ "agent_space_id": "as-xxxxx", "region": "us-east-1" } -
如果缺少 gitignore 文件,则创建:
mkdir -p .security-agent echo '*' > .security-agent/.gitignore -
向用户确认:"设置完成。现在可以运行安全扫描或渗透测试。"
规则
- 如果存在多个 Agent 空间,绝不自动选择;始终询问用户
- 绝不禁用安全防护(保持 public-access-block 开启)
- 对推导出的存储桶进行的每次 S3 调用都必须传入
--expected-bucket-owner "$ACCOUNT"。存储桶名称根据非机密账户 ID 推导而来,因此第三方可能会抢先注册该名称;如果其他账户拥有该存储桶而导致403/BucketAlreadyExists,则属于致命错误——中止操作,绝不上传。 - 信任策略必须允许
securityagent.amazonaws.com(生产服务主体),并包含aws:SourceAccountconfused-deputy 防护 - 如果用户提供了自己的角色名称或存储桶名称(不同于约定的默认值),请告知他们:此插件使用基于约定的默认值(
SecurityAgentScanRole/security-agent-scans-${ACCOUNT}-${REGION})。请接受这些默认值,或扩展此技能——其他技能会推导这些名称,而不是从配置中读取。 - 如果缺少
config.json,扫描和渗透测试技能可以内联调用此技能——首次使用的用户无需单独运行设置。
故障排除
- 调用
iam:CreateRole时出现AccessDenied→ 用户缺少 IAM 权限。请他们使用自己的角色 ARN 运行设置,或授予iam:CreateRole+iam:PutRolePolicy权限。 - 调用
s3api create-bucket时出现AccessDenied→ 存储桶名称可能已被全局占用,或者用户缺少s3:CreateBucket权限。建议使用他们拥有的现有存储桶,并显式传入该存储桶。 - 推导出的存储桶出现
403 Forbidden/BucketAlreadyExists→ 可预测的名称已被其他账户占用(存储桶抢注)。这是设计上的致命错误——不要上传。让用户选择自己拥有的存储桶名称(或从预期的账户/区域运行),然后重新运行设置。 - 角色已存在,但信任策略有误 → 使用
update-assume-role-policy(第 4 步的备用方案)。如果他们不想更新该角色,请让他们提供其他角色 ARN。 - Agent 空间存在,但位于其他区域 → 告知用户,并建议使用正确的区域,或在当前区域创建新的空间。