CloudArq-net/aws-audit-rules
GitHub: CloudArq-net/aws-audit-rules
一个零依赖的纯函数 AWS CLI 输出审计规则库,通过分析只读命令返回的 JSON 来报告资源配置问题、成本优化机会和信息缺口。
Stars: 1 | Forks: 0
# @cloudarq/aws-audit-rules
用于 AWS CLI 输出的审计规则。纯函数,无依赖,且不会开启 socket。
只需提供来自只读 `aws` 命令的 JSON,它就会报告该 JSON 能够证明的内容——以及无法证明的内容,并附带能解答该问题的相应命令。
```
git clone https://github.com/CloudArq-net/aws-audit-rules
cd aws-audit-rules
npm install
npm test
npm run example # runs the rules over a sample paste and prints the output
```
```
import { analyzeAll } from '@cloudarq/aws-audit-rules';
const result = analyzeAll(pastedJson, new Date());
result.findings; // what's wrong
result.notes; // worth seeing, not wrong
result.gaps; // what this input couldn't answer, and how to answer it
result.examined; // what was actually read
```
上面的导入方式在首次发布到 npm 后即可使用;在此之前,请使用克隆的代码库。
粘贴单个命令或多个命令的输出均可,顺序不限,有无分隔符皆可。它会根据 envelope key 自动识别各自的归属。
## 支持的输入
| 命令 | 规则 |
|---|---|
| `aws ec2 describe-security-groups` | 对全世界开放的 SSH/RDP/敏感端口、所有流量规则、仅 IPv6 的暴露、来自单一主机的所有流量、已被更宽泛规则覆盖的规则 |
| `aws ec2 describe-volumes` | 未加密的卷、未挂载的卷、如果使用 gp3 会更便宜的 gp2 卷 |
| `aws ec2 describe-addresses` | 已分配但未使用的 Elastic IP |
| `aws ec2 describe-snapshots --owner-ids self` | 旧的快照、备份策略保留、源卷已删除的快照 |
| `aws bedrock get-model-invocation-logging-configuration` | 关闭日志记录、开启日志记录但未记录任何内容、日志接收器中的 prompt |
| `aws bedrock list-guardrails` | guardrails 未处于 READY 状态、仅有 DRAFT 版本、存在 guardrails 但无法验证 |
## Severity 是可为空的
引擎只能看到一条粘贴的响应——没有账户上下文,没有第二次 API 调用,也没有指标。对 `0.0.0.0/0` 开放的 SSH 是否重要,取决于该安全组是否已挂载到任何资源上,而这属于此次输入中不包含的另一项 API 调用。
因此,该规则会报告暴露情况,将 `severity` 设为 `null`,并用缺失的内容填充 `unknowable`。`Gap` 的存在也是出于同样的原因:托管前缀列表在我们未获取到的位置声明了其内容,因此它会作为未检查项进行报告,并附带 `aws ec2 get-managed-prefix-list-entries` 命令,而不是盲目猜测其状态。
成本和加密相关的发现确实会带有 severity,因为这种评级不依赖于粘贴内容中所缺失的任何信息。`cost.basis` 会与每个数值一同出现——所有价格均为 us-east-1 的目录价格,未进行区域调整。
有些结果属于备注而非发现:即一些值得查看但并非缺陷的内容。来自单一主机的所有流量并不构成暴露。被更宽泛规则覆盖的规则没有授予任何额外权限。存在 guardrails 并不是一个问题。备注不会增加发现的计数。
## 刻意不予报告的内容
- `0.0.0.0/0` 上的 80 和 443 端口。那是 Web 服务器。
- 没有 Bedrock guardrails 的账户。许多合法的用例并不需要它们。
- 空闲或过度配置的实例——这需要 CloudWatch 指标,而 `describe-*` 响应中并不包含这些指标。
- 备份策略中的单个快照。针对 50 个卷的 35 天保留策略会产生 1,750 个快照,删除其中一个会破坏无法再弥补的保留窗口。因此只会报告一次,并附带完整成本,指向该策略。
十二项冗余的 SSH 规则只会生成一项发现。
## 值得了解的细节
以下大部分内容解释了为什么测试套件会达到目前的规模。
- **ICMP 的 `FromPort`/`ToPort` 代表的是类型和代码,而不是端口。** `-1` 表示“所有类型”。
- **`IpProtocol: "-1"` 会完全省略端口键**——是不存在,而不是零。
- **IPv6 是一个独立的数组** (`Ipv6Ranges[].CidrIpv6`)。
- **协议也会以 IANA 编号的形式传入**:`"6"` 代表 TCP,`"17"` 代表 UDP,`"1"` 代表 ICMP,`"58"` 代表 ICMPv6。
- **JSON 键名是 `State`;而 CLI 筛选器是 `status`。**
- **缺少 `AssociationId` 并不意味着该 Elastic IP 是免费的**——NAT 网关的 ENI 会持有一个,但不会显示关联。
- **无时区的时间戳会被 `new Date` 解析为本地时间**,这会根据读取者的 UTC 偏移量改变快照的时长。
- **AWS 会在字符串中包含大括号**——例如描述、内嵌策略、标签值——因此拆分拼接的文档时必须追踪字符串和转义字符。
- **Bedrock 使用 lowerCamelCase,而 EC2 使用 PascalCase。**
- **当关闭日志记录时,Bedrock 会返回 `{"loggingConfig": null}`**,因此检查应使用 `in` 而非真值判断。
- **日志记录可能处于开启状态,但并不记录任何内容**——AWS 接受带有交付标志但无目标地址的配置。
`RULES.md` 包含了完整列表,包括每一项刻意不为发现的内容。
## 解析错误绝不会包含你的输入
V8 会将出错文本的片段嵌入到 `SyntaxError.message` 中:
```
JSON.parse('{"SecurityGroups": [{"GroupId": sg-0abc}]}')
→ SyntaxError: Unexpected token 's', ..."GroupId": sg-0abc}]}" is not valid JSON
```
任何捕获错误的代码都会因此持有部分被粘贴的内容。`safeParseJson` 会捕获该错误,丢弃其消息,并抛出一个携带位置和基于常量构建的诊断信息的 `ParseError`——并且不会将其作为 `cause` 附加上去,因为报告器会序列化该字段。
这些诊断信息无论如何都比 V8 的更有用:*“在闭括号之前有一个多余的逗号”*,*“JSON 在闭合之前就结束了——看起来被截断了”*。
## 测试
```
npm test
```
共有 247 个测试。`rules/referenceValues.test.ts` 会在去除了标识符并对服务端口重新编号的真实 CLI 输出上运行,而不是使用手动编写的 fixture,因为真实输出包含容易被忽略的数据结构——例如一个缺少端口键的 `IpProtocol: "-1"` 规则会破坏任何假设 `FromPort` 存在的逻辑。
## 项目来源
这些规则为位于 [cloudarq.net/tools/aws-auditor](https://cloudarq.net/tools/aws-auditor) 的免费审计器提供支持,该工具完全在浏览器中运行。将其发布是因为,如果一个页面声称“你粘贴的任何内容都不会离开你的设备”,它就应该让你能够验证这一点。
## 贡献
引擎目前刻意未实现的三件事已作为 issue 开放——解析托管前缀列表、支持区域感知的定价以及 S3 桶策略规则。每一项都是真实的限制,而非占位符。
如果你添加规则:请先编写测试;如果该规则需要输入中无法承载的事实,应将其归入 `Gap` 或 `unknowable`,而不是进行猜测。`RULES.md` 包含了完整的约定。
MIT。
标签:AWS, DPI, GNU通用公共许可证, MITM代理, Node.js, 云安全监控, 无依赖, 暗色界面, 自动化攻击, 静态分析