关于 cloud-audit
cloud-audit 是面向云平台负责人与安全团队的基础设施配置审查技能,覆盖 AWS、GCP、Azure 及多种 PaaS。它检查身份权限、网络、存储、计算、监控和部署配置,并以共享格式记录发现。
主要功能
- 01审查 AWS、GCP 和 Azure 配置
- 02检查多种 PaaS 项目与部署
- 03评估身份权限和网络暴露
- 04检查存储、计算及日志监控
- 05按共享格式记录安全发现
适用场景
- 01审计云账户的权限与公开访问
- 02排查 PaaS 上的陈旧或异常部署
- 03检查仓库安全默认设置与 Supabase 配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ briiirussell/ cybersecurity-skills --skill cloud-audit安装后在 Claude Code 中输入/cloud-audit确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/findings-format.mdfindings.schema.jsonpaas.mdseverity-calibration.mdto-sarif.mjsvalidate-findings.mjsverification.md详细介绍
云审计 — 云基础设施安全审查
审计云基础设施配置中的错误配置、权限过高、公开暴露和合规性缺口。涵盖 AWS、GCP 和 Azure,以及许多小团队用来运行所有服务的 PaaS 部署平台(Vercel、Netlify、Heroku、Render、Railway、Fly)。
交叉参考:iam-audit 用于深入审查 IAM(咨询顾问式,涵盖身份提供商和联合模式的设计、审计与迁移)——本技能包含 IAM 部分,但侧重云安全态势;如需角色设计、JIT 访问、工作负载身份联合和迁移计划,请调用 iam-audit。container-audit 用于审查建立在云之上的 Kubernetes 专属安全态势。secrets-audit 用于检查密钥管理器的卫生状况和轮换。patch-sweep 用于响应一批 PaaS 应用中的 CVE(本技能的 PaaS 部分是其中的安全态势审查部分)。scanner-pipeline 用于定期运行 Supabase 的安全顾问和其他扫描器。
调查结果记录在共享的 findings.json 格式中(参见验证后记录)。处置方式通常由 finding-triage 后续设置:已修复 / 已延期 / 已接受风险 / 已缓解(平台/配置)/ 需要重大迁移。
授权
仅审计用户拥有或获准审查的云账户、项目、订阅和 PaaS 团队,并使用为此提供的凭据。预先批准的命令仅用于读取和描述信息。审计过程中绝不可更改策略、轮换密钥、删除资源或重新部署:提出建议,由所有者执行。如果审计凭据拥有超出只读范围的权限,请将此项本身报告为调查结果。
确定审计范围
确定:
- 云服务提供商和账户
- 使用中的区域
- 是否可用 CLI 工具(
aws、gcloud、az、vercel、heroku、netlify、fly、railway、gh),或是否正在审查 IaC 文件(Terraform、CloudFormation、Pulumi) - 对于 PaaS:范围内的每个团队/账户和 GitHub 所有者/组织,以及其中哪些属于客户或其他维护者
审计类别
身份与访问管理
AWS:
aws iam get-account-summary
aws iam list-users
aws iam generate-credential-report && aws iam get-credential-report --output text --query Content | base64 -d
检查:根账户未启用 MFA、超过 90 天的访问密钥、未使用的凭据、通配符权限("Action": "*")、权限过高的角色。
GCP:
gcloud projects get-iam-policy $PROJECT_ID
gcloud iam service-accounts list
检查:过多主体拥有基本角色(Owner/Editor)、未使用的服务账户、使用服务账户密钥而非工作负载身份。
Azure:
az role assignment list --all
az ad user list
检查:过多的 Owner/Contributor 分配、拥有高权限的访客用户。
IaC 审查: 在 Terraform/CloudFormation 文件中搜索 "Action": "*"、"Resource": "*"、硬编码密钥和范围过宽的信任策略。
网络安全
检查:
- 允许从
0.0.0.0/0入站的安全组或防火墙规则 - 从互联网无限制开放 SSH(端口 22)或 RDP(端口 3389)
- 已禁用 VPC 流日志
- 数据库位于公有子网
- 缺少各层之间的网络隔离
存储
AWS S3:
aws s3api list-buckets
aws s3api get-public-access-block --bucket <name>
aws s3api get-bucket-policy --bucket <name>
aws s3api get-bucket-encryption --bucket <name>
检查:公开存储桶、未启用加密、未启用版本控制、缺少生命周期策略、权限过于宽松的存储桶策略。
GCP/Azure: 对 Cloud Storage 和 Blob Storage 执行同类检查——查找 allUsers/allAuthenticatedUsers 访问权限或匿名 Blob 访问权限。
计算
- 是否强制启用 IMDSv2?(AWS:
HttpTokens = required) - 未加密的 EBS 卷或磁盘
- 不需要公网 IP 的实例却配置了公网 IP
- 过时的 AMI 或镜像(检查补丁时效)
- 特权容器、Kubernetes 中缺少安全上下文
日志与监控
- 是否在所有区域启用 CloudTrail / Cloud Audit Logs / Activity Log
- 日志存储是否已加密、不可变且保留时间充足
- 是否启用 GuardDuty / Security Command Center / Defender for Cloud
- 是否为以下事件配置告警:根账户登录、IAM 变更、安全组变更、大规模数据传输
- 是否启用 VPC 流日志和 DNS 查询日志
密钥管理
- 在源代码、环境变量或 IaC 文件中硬编码密钥
- 使用 Secrets Manager / Key Vault 管理敏感值
- 已配置 KMS 密钥轮换
PaaS(Vercel / Netlify / Heroku / Render / Railway / Fly)
许多小团队根本没有 AWS 账户;他们的生产环境可能是一个 Vercel 团队、几个 Heroku 应用和一个 Render 服务。此类平台上的风险不会出现在 AWS 风格的检查清单中:生产环境不会被任何合并替换、Git 部署已失败数月,以及旧项目仍在平台 URL 上提供未打补丁的代码。以下各项检查均来自 2026 年 10 月的一次真实平台集群巡查。
先盘点:列出每个团队的所有项目 / 应用、用于构建的仓库和分支,以及每个项目提供服务的所有域名(patch-sweep 的步骤 1 中有完整的映射命令)。除非标明,否则以下命令均为只读。Netlify、Railway 和 Fly 的对应做法见 references/paas.md。
1. 过时的手动生产部署。 某客户网站的生产环境运行的是开发者笔记本上执行的 vercel deploy --prod,部署已过去 96 天,仍在提供存在漏洞的 Next.js。仓库的 main 分支里只有一个 README,因此无论怎么合并都不会替换该部署。
vercel ls <project> --prod --scope <team> # latest production deployments, age
vercel inspect <production-url> --scope <team> # target, created, url
vercel api "/v6/deployments?projectId=<id>&target=production&limit=5" --scope <team> \
| jq '.deployments[] | {url, created, source, sha: .meta.githubCommitSha, ref: .meta.githubCommitRef, creator: .creator.username}'
git ls-remote origin refs/heads/<production-branch> # compare with the deployed sha
heroku releases -a <app> -n 20 # who deployed, and how
检查:源代码来自 Git(而非 cli),已部署的提交与生产分支 HEAD 相同(或是其祖先),且部署时间晚于最近一次合并。若不匹配,则属于下文所述的发现类型。
2. Git 部署悄然失效。 有两种情况:一种是忽略构建步骤运行 git diff HEAD^ HEAD,但 .vercelignore 排除了 .git——.vercelignore 同样适用于 Git 构建——因此每次 Git 部署都会报错,生产环境只能通过 CLI 更新;另一种是某个项目仍关联到旧组织的仓库,因此每个 PR 都会显示失败的检查,人们已经习惯忽略它。
vercel ls <project> --status ERROR --scope <team> # recent failures
vercel api /v9/projects/<project> --scope <team> | jq '{link: .link, productionBranch: .link.productionBranch, ignore: .commandForIgnoringBuildStep, rootDirectory}'
grep -n '\.git' .vercelignore 2>/dev/null
gh api repos/<o>/<r>/commits/<branch>/check-runs --jq '.check_runs[] | {name, app: .app.slug, conclusion}' # duplicate/failing Vercel checks
检查:最近 10–20 次由 Git 触发的部署的失败率、忽略命令所需的内容(Git 历史记录、.vercelignore 排除的文件),以及 link.org / link.repo 是否与仓库当前所有者一致。
3. 仍在提供旧代码的旧项目。 域名迁移到新的单体仓库后,旧项目仍通过未打补丁代码提供 *.vercel.app 地址。
vercel project ls --format json --scope <team>
vercel api /v9/projects/<project>/domains --scope <team> | jq -r '.domains[].name'
heroku apps --all --json | jq -r '.[] | "\(.name)\t\(.updated_at)"'; heroku domains -a <app>
检查:域名只有平台默认域名(*.vercel.app、*.herokuapp.com、*.onrender.com、*.netlify.app、*.fly.dev、*.up.railway.app)的项目,以及它们最近一次部署的日期。建议删除;如果所有者希望保留,则启用保护(部署保护 / 维护模式)。
4. 每个仓库对应多个重复项目。 一个仓库会在两个 Vercel 团队中触发构建。虽然只有一个项目提供域名服务,但两个项目都保存了环境变量和密钥。
检查:按 link.org/link.repo 对每个团队的项目分组;除非所有者能说明原因,否则每个仓库 + 根目录对应多个项目都应记录为发现。比较环境变量名称(vercel env ls --scope <team>),查看额外副本保存了哪些变量。
5. 预览和生产环境暴露风险。
vercel project protection <project> --format json --scope <team> # SSO / password / bypass settings
curl -s -o /dev/null -w '%{http_code}\n' https://<project>.vercel.app/ # 200 = generated production URL is public
vercel env ls preview --scope <team> # names only
检查:预览环境是否启用了部署保护;当自定义域名位于 Cloudflare 或其他 WAF 后方时,生成的 *.vercel.app 生产 URL 是否无法访问(该 URL 会绕过 WAF——Vercel 的 Standard Protection 会保护生成的 URL);预览环境变量是否未指向生产数据库。若要比较数据库主机而不暴露密钥,可拉取到临时文件,只打印主机名,然后删除文件:vercel env pull /tmp/p.env --environment=preview && sed -nE 's/^DATABASE_URL="?[^@]*@([^/:]+).*/\1/p' /tmp/p.env; rm /tmp/p.env。
6. 构建队列构成可用性风险。 对于一次只能运行一个构建的团队,紧急补丁曾因无关构建排队而等待 30–60 分钟。
vercel ls --status QUEUED,BUILDING --scope <team>
检查:团队的并发构建数限制。在事件应急手册中记录如何发布紧急补丁:按需提高并发数、取消排队中的非紧急构建,或采用所有者批准的 CLI 部署流程(随后需与 Git 状态核对——见检查 1)。 7. Heroku 特定事项。
heroku stack -a <app> # heroku-22 / heroku-24
heroku run --no-tty "vips --version" -a <app> # libvips on the running dyno
heroku run --no-tty "ruby -v" -a <app> # compare with .ruby-version / Gemfile ruby
heroku pg:backups:schedules -a <app>
heroku pg:backups -a <app> # lists backups AND restores
heroku config -a <app> --json | jq -r 'keys[]' # names only, never values
heroku --version
检查:
- Stack 和 libvips 版本。
VIPS_BLOCK_UNTRUSTED=1(用于缓解 CVE-2026-66066)需要 libvips ≥ 8.13;Heroku-24 随附 8.15.1。 .ruby-version中指定的运行时才是实际运行的版本。- 是否设置了
pg:backups备份计划,以及是否至少执行过一次恢复(从未恢复过的备份未经测试)。 - Heroku CLI 8.x 无法在 Essential 计划上运行
pg:backups;在断定缺少备份之前,请先升级 CLI。 - Review 应用不会继承线上密钥:检查流水线的 Review 应用配置变量,以及
app.jsonenv中的生产环境 Stripe/电子邮件/数据库凭据。
8. 仓库级安全默认设置。 某个账户和组织中的 142 个仓库关闭了 Dependabot 警报。
gh api repos/<o>/<r>/vulnerability-alerts --silent && echo on || echo off # 204 = on, 404 = off
gh api repos/<o>/<r> --jq '.security_and_analysis' # secret scanning, push protection
gh api repos/<o>/<r>/branches/<production-branch>/protection # 404 = no classic protection
gh api repos/<o>/<r>/rules/branches/<production-branch> # rulesets that apply
检查生产分支上的漏洞警报、密钥扫描、推送保护和分支保护(或规则集)——该分支可能不是默认分支。启用警报的命令是 gh api -X PUT repos/<o>/<r>/vulnerability-alerts;这是写操作,因此会提示确认。
后端即服务(Supabase)。 如果应用使用 Supabase,请运行其安全顾问——rls_disabled_in_public 会标记使用 anon 密钥即可读取和写入的公开表。在 2026 年 10 月的扫描中,共发现 10 个此类表,其中包括包含 472k 封入电子邮件正文的表。使用 supabase db advisors 或 Management API GET /v1/projects/{ref}/advisors/security;scanner-pipeline 涵盖了按计划运行该检查,以及用于检测 x.col = x.col 等恒真策略的 semgrep 规则。
发现类型:无法从源代码重现生产环境(手动部署/分支不匹配)
当生产环境中运行的内容无法从生产分支重新构建时,请报告此问题:
- 当前生产部署来自 CLI/手动部署,而非 git;
- 已部署的提交不在生产分支上;
- git 部署失败,导致分支与生产环境不一致;
- 平台的生产分支不是人们合并代码的分支(例如,
main中只有一个 README,而应用位于development)。
重要性:合并到分支的补丁永远不会进入生产环境,无人能确定线上运行的代码是什么,回滚也会回到未知状态。严重程度取决于线上运行的内容:如果手动部署中有易受攻击的框架,严重程度就与该漏洞一样高;如果没有已知易受攻击的内容,则为中等。修复方案由负责人决定——修复构建问题后从 git 重新部署、将已部署的代码纳入分支,或停用项目——绝不能悄悄使用 vercel deploy --prod 覆盖他人的部署。对于一批此类项目,请运行 patch-sweep。
验证并记录
根据 references/findings-format.md 中的定义,为上述类别中的每个候选项给出一个结论,然后写入 findings.json。
1. 先保存证据。 这些发现大多与已部署的资源有关,而非文件。对每项发现,将只读命令的输出脱敏后保存到 <audit dir>/evidence/<name>.json(或 .txt),并进行美化格式化(| jq .),以便行号保持不变。文件名应包含命令和资源名称:evidence/aws-s3api-get-bucket-policy-prod-uploads.json、evidence/vercel-deployments-acme-web.json。让 location、trace[] 和 evidence[] 指向该文件以及包含决定性字段("Principal": "*"、"CidrIp": "0.0.0.0/0"、"source": "cli")的行,路径应像其他位置一样相对于仓库(security-audit/evidence/...)。对于没有仓库的纯账户审计,路径相对于审计目录,并在报告标题中说明这一点。对于纯 IaC 发现,则改为指向 .tf/CloudFormation/Pulumi 文件及其行号。
绝不要保存秘密值。写入文件前,删除环境变量和配置变量的值、令牌、预签名 URL、连接字符串中的密码以及密钥材料。保留查找资源所需的标识符(账户 ID、ARN、存储桶名称、项目 ID);访问密钥 ID 仅保留末尾 4 位(AKIA…7QXZ)。
2. 在确认每个候选项之前,先按照 references/verification.md 运行反证流程。 对于云环境发现项,“路径”是指:谁能访问它(互联网、提供商中的任意已认证主体、另一个租户、CI 作业)→ 允许其访问的规则 → 资源及其所含内容。查找位于它之前的最强控制措施:账户级 Block Public Access、SCP 或组织策略、VPC 端点策略、没有通往互联网网关路由的私有子网、部署保护、IdP 条件。根据证据文件,将路径写成 trace[]:entrypoint = 允许主体进入的规则或设置,propagation = 将其与资源关联的内容(附加到实例 ENI 的组、路由表),sink = 资源及其所含内容。
3. 选择判定结果。
| 判定结果 | 此处的判断依据 |
|---|---|
confirmed | 保存的输出显示了暴露情况以及其后的内容。示例:get-bucket-policy 授予 "Principal": "*" s3:GetObject 权限,get-public-access-block 显示存储桶和账户级别的 RestrictPublicBuckets: false,且存储桶中存有客户上传的文件。安全组允许 0.0.0.0/0 通过 5432 端口访问,并附加到 PubliclyAccessible: true 的 RDS 实例。Vercel 上的生产环境是 96 天前的一次 source: cli 部署,其提交不在生产分支上,且运行的 Next.js 版本存在已知 CVE。 |
needs_validation | 配置支持这一说法,但有一项事实无法读取或未能读取。示例:Terraform 将 22 端口开放给 0.0.0.0/0,但没有状态文件或账户访问权限来证明该配置已应用并附加到资源(阻碍因素:该模块是否已部署;计划:aws ec2 describe-security-groups --group-ids <id> 和 aws ec2 describe-network-interfaces --filters Name=group-id,Values=<id>)。预览环境的 DATABASE_URL 主机看起来像生产环境,但只有所有者才能提取该环境变量(计划:执行检查 5 中仅提取主机名的 vercel env pull 命令)。你描述但未运行的任何检查,若原因是未经授权,都应标记为 needs_validation,并在 validation_plan 中写明确切命令。 |
rejected | 位于明确位置的具名控制措施会阻止所有路径。示例:存储桶策略授予 "Principal": "*" 权限,但账户级公开访问阻止措施(运行 aws s3control get-public-access-block 并将结果保存为证据)中的 RestrictPublicBuckets: true,因此 ruled_out_by.location 应指向该证据文件和行号。宽松开放的安全组未附加到任何资源(describe-network-interfaces 返回 []),且 ruled_out_by 指向该已保存的输出。 |
你收到的 IaC 模块中存在不安全的默认配置(例如,除非传入 block_public = true,否则会创建公开存储桶的模块),应判定为 confirmed,并设置 system_configuration 条件(“未覆盖 block_public 的部署”),置信度为 medium。
没有追踪到影响的缺口属于安全加固建议,而非记录项:关闭了 VPC 流日志、关闭了 KMS 轮换、没有 S3 生命周期策略、存储桶关闭了版本控制但未追踪到任何数据丢失场景、GuardDuty 关闭但没有其他问题。将这些内容放入报告的安全加固部分,不标注严重性。
4. 仅针对 confirmed 记录,按照 references/severity-calibration.md 校准严重性;根据暴露资源所含内容及其允许的操作评级,而非根据基准 ID。 公开的营销图片存储桶属于 Low 或安全加固建议;公开的客户文档存储桶属于 High。overall 不得高于已证实的影响。
置信度:从实时 API 读取的配置是证据,并不代表复现。只有通过经授权的非破坏性请求证明了暴露情况,才设置 "reproduced": true(并允许使用 high 置信度):例如,匿名执行 curl -sI 请求对象并收到 200 响应;或者生成的 *.vercel.app URL 返回 200,而自定义域名位于 WAF 后方。仅有 IaC 的发现项,置信度最高为 medium。
5. 按资源而非行进行指纹标识。 格式:cloud-audit/<class>/<provider>/<account>/<resource>;IaC 使用 cloud-audit/<class>/<IaC file>/<resource address>。ARN 和 host:port 请用斜杠表示;验证器会拒绝 :<digits> 片段。
cloud-audit/public-bucket/aws/123456789012/prod-uploads
cloud-audit/open-ingress/aws/123456789012/sg-0a1b2c3d/5432
cloud-audit/iam-wildcard/aws/123456789012/role/deploy # arn:aws:iam::123456789012:role/deploy
cloud-audit/manual-prod-deploy/vercel/acme-team/acme-web
cloud-audit/iam-wildcard/infra/iam.tf/aws_iam_policy.deploy
使用中的类别:public-bucket、open-ingress、public-database、iam-wildcard、root-no-mfa、stale-access-key、imdsv1、logging-disabled、manual-prod-deploy、git-deploy-broken、legacy-project、duplicate-project、preview-exposure、review-app-live-keys、rls-disabled、repo-security-defaults。如果没有合适的类别,请新增一个。
6. 域字段放在 ext 下:
| 键 | 值 |
|---|---|
provider | aws、gcp、azure、vercel、netlify、heroku、render、railway、fly、supabase、github |
account | 账户 ID、项目 ID、订阅 ID,或 PaaS 团队/组织 slug |
region | us-east-1、europe-west1、global(对于没有区域的 PaaS,省略此项) |
resource | 提供商显示的资源名称(ARN、存储桶名称、sg-…、项目名称、部署 URL) |
7. 编写并验证。 设置 skill: "cloud-audit",按指纹排序,写入 findings.json,并持续修复,直到验证通过:
node references/validate-findings.mjs findings.json
node references/to-sarif.mjs findings.json -o findings.sarif # optional
重新运行时,加载之前的 findings.json 并按指纹匹配。除非记录所指的控制项发生变化,否则 rejected 记录应继续保持拒绝状态(先重新读取相关证据)。
输出格式
先写入 findings.json。报告由该文件生成,不会更改 JSON 中未说明的判定结果、严重程度、阻断项或影响。不要使用“潜在”或“可能”等标签:条目必须是已确认的问题、待验证的问题、被拒绝的记录或加固说明。
# Cloud Security Audit Report
## Provider(s): [AWS / GCP / Azure / Vercel / Heroku / Render / ...]
## Account(s) / team(s): [IDs or slugs] ## Regions: [audited regions] ## Date: [date]
## Scope: [full | partial — what was left out and why] ## Access: [read-only role / CLI identity used]
## findings.json: [path] — validated: [yes] ## Evidence: [audit dir]/evidence/
### Summary
- Confirmed: [N] (Critical [n] | High [n] | Medium [n] | Low [n])
- Needs validation: [N] Rejected: [N] Hardening notes: [N]
### Confirmed findings
#### [SEVERITY] [Category]: [Title] `fingerprint`
**Provider / account / region:** [ext.provider / ext.account / ext.region]
**Resource:** [ext.resource]
**Evidence:** `evidence/<file>:<line>` — [the decisive lines, redacted]
**Confidence:** [medium | high (reproduced)] **Conditions:** [from conditions[]]
**What and why it matters:** [who can reach it → the rule that lets them in → what the resource holds]
**Fix:** [specific command or IaC change; note availability impact]
**Verify the fix:** [the read-only command that shows it's closed]
### Needs validation
| Finding | Blocker | Check for the owner to run |
|---|---|---|
### Hardening notes (not findings)
- [gap] — [why it isn't a finding] — [effort]
### Rejected (do not re-raise)
| Fingerprint | Ruled out by | Location |
|---|---|---|
### Coverage
| Category | Accounts / teams checked | Not checked (and why) |
|---|---|---|
| IAM / Network / Storage / Compute / Logging / Secrets / PaaS / Supabase / Repo defaults | | |
### PaaS deployment inventory
| Team | Project / app | Repo + production branch | Source of live deploy (git / cli) | Deployed sha = branch HEAD? | Domains |
|---|---|---|---|---|---|
### Prioritized remediation plan
1. [Critical — immediate]
2. [High — this week]
3. [Medium — this month]
4. [Low — next quarter]
边界
- 仅审计用户有权访问的账户或项目
- 对于 PaaS:审计期间不要删除项目、覆盖他人的生产部署或禁用保护措施;记录负责人的决定
- 切勿打印环境变量或配置变量的值;仅列出名称
- 不要尝试访问其他账户或租户
- 为每项发现提供修复建议
- 如果修复可能影响可用性,请注明(例如,收紧安全组可能会中断连接)
- 标记审计期间发现的任何活动入侵迹象
- 拒绝利用他人基础设施中发现的错误配置的请求
参考资料
- AWS/GCP/Azure 的 CIS 基准
- AWS Well-Architected 安全支柱
- ScoutSuite(多云审计工具)
- Vercel CLI:
vercel list、vercel inspect、vercel project、vercel api - Heroku CLI 命令;Render API
- GitHub REST — 漏洞警报
- Supabase 数据库顾问
- 共享参考资料(构建时复制到
references/):findings-format.md、findings.schema.json、validate-findings.mjs、to-sarif.mjs、severity-calibration.md、verification.md - 各平台的 PaaS 命令:references/paas.md