mcpField
S
setup-security-agent

setup-security-agent

github.com/aws安全3.3k1.5k 次安装1 天前更新
代码仓库

关于 setup-security-agent

为 AWS Security Agent 建立工作区基础资源的技能,供后续扫描和渗透测试流程使用。它配置 AgentSpace、IAM 服务角色和 S3 存储桶,并将工作区设置保存在本地。

主要功能

  1. 01检查并选择或创建 AgentSpace
  2. 02创建并配置 IAM 服务角色
  3. 03创建并保护 S3 存储桶
  4. 04关联角色与存储桶到 AgentSpace
  5. 05保存工作区本地配置

适用场景

  1. 01首次配置 Security Agent 工作区
  2. 02为安全扫描准备 AWS 资源
  3. 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 中读取:

值约定
ACCOUNTaws sts get-caller-identity --query Account --output text
REGIONconfig.region(默认值为 us-east-1)
service_role_arnarn:aws:iam::${ACCOUNT}:role/SecurityAgentScanRole
s3_bucketsecurity-agent-scans-${ACCOUNT}-${REGION}

为何配置保持精简:角色名称和存储桶名称都是确定的,因此保存它们会增加配置漂移风险(用户手动重新创建角色后,可能会在不知情的情况下使用过期路径)。只保存 agent_space_id,因为用户可能有多个 Agent 空间,而且我们不想每次会话都询问要使用哪一个。


工作流

  1. 检查现有状态: 如果 .security-agent/config.json 存在,则读取它。

  2. 调用方身份 + 区域:

    export ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
    export REGION="${AWS_REGION:-us-east-1}"
    
  3. 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。

  4. 服务角色(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
      
  5. 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
      
  6. 在 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>...]
      
  7. 持久化到 .security-agent/config.json(保持精简——账户/角色/存储桶信息均可推导):

    {
      "agent_space_id": "as-xxxxx",
      "region": "us-east-1"
    }
    
  8. 如果缺少 gitignore 文件,则创建:

    mkdir -p .security-agent
    echo '*' > .security-agent/.gitignore
    
  9. 向用户确认:"设置完成。现在可以运行安全扫描或渗透测试。"


规则

  • 如果存在多个 Agent 空间,绝不自动选择;始终询问用户
  • 绝不禁用安全防护(保持 public-access-block 开启)
  • 对推导出的存储桶进行的每次 S3 调用都必须传入 --expected-bucket-owner "$ACCOUNT"。存储桶名称根据非机密账户 ID 推导而来,因此第三方可能会抢先注册该名称;如果其他账户拥有该存储桶而导致 403/BucketAlreadyExists,则属于致命错误——中止操作,绝不上传。
  • 信任策略必须允许 securityagent.amazonaws.com(生产服务主体),并包含 aws:SourceAccount confused-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 空间存在,但位于其他区域 → 告知用户,并建议使用正确的区域,或在当前区域创建新的空间。

评论

支持 Markdown