abhisheksoppanna/probepath

GitHub: abhisheksoppanna/probepath

probepath 在 Terraform apply 之前基于可达性图分析,验证互联网到数据库等敏感资源的真实攻击路径并抑制误报。

Stars: 1 | Forks: 0

# probepath **在你执行 `apply` 之前,证明你的 Terraform 中是否真的存在从互联网到数据库的攻击路径。** [![ci](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/2b2926b18d202446.svg)](https://github.com/abhisheksoppanna/probepath/actions/workflows/ci.yml) ![python](https://img.shields.io/badge/python-3.11%2B-3776ab) ![license](https://img.shields.io/badge/license-MIT-blue) ![deps](https://img.shields.io/badge/runtime%20deps-4-success) 针对单一资源的扫描工具(Checkov、tfsec、Trivy)会孤立地标记每一个开放的安全组和每一个 `publicly_accessible` 标志。这些发现中大部分都是噪音:资源可能位于私有子网中,或者面向互联网的设备实际上根本无法访问到它。probepath 会为你的 Terraform plan 构建一个 **可达性图**,并回答那个唯一重要的问题 —— *数据包真的能从互联网到达这个数据库吗?* —— 然后它会抑制那些被证明不可达的发现,并渲染出那些可达的路径。 它建模的网络准入层与 **AWS VPC Reachability Analyzer** 完全相同,但它是 **在执行 apply 之前,直接在 plan 上** 完全离线运行的 —— 不需要账户,不需要 API 密钥,也不需要已部署的资源。 ``` $ probepath scan plan.tfplan.json Scanned 29 resources · 6 sensitive sinks ● 3 reachable ◐ 0 potentially reachable ✓ 3 suppressed (provably unreachable) ● REACHABLE RDS aws_db_instance.orders internet └→ aws_instance.web SG web allows 0.0.0.0/0 on 443; public subnet (0.0.0.0/0 → igw); public IP └→ aws_db_instance.orders SG orders_db allows SG web on 5432 ● REACHABLE RDS aws_db_instance.legacy internet └→ aws_instance.web SG web allows 0.0.0.0/0 on 443; public subnet (0.0.0.0/0 → igw); public IP └→ aws_db_instance.legacy SG legacy_db allows 10.0.1.0/24 on 5432 ← "private subnet" is not a control ● REACHABLE S3 aws_s3_bucket.exports [policy/ACL exposure] internet └→ aws_s3_bucket.exports bucket policy allows Principal:* with no source scoping Suppressed — provably unreachable (shown with the gate that closes them): ✓ aws_s3_bucket.secrets — Block Public Access fully enabled ✓ aws_redshift_cluster.warehouse — no internet-reachable network path ✓ aws_elasticache_cluster.sessions — sink subnet is private (no 0.0.0.0/0 → igw route) $ echo $? # with --fail-on reachable 1 ``` 这个退出代码才是核心。将 `probepath` 接入 CI 后,任何试图打通从互联网到数据库路径的变更都会**停止发布** —— 全自动完成,并将具体路径打印在日志中。 ## 攻击路径可视化 `probepath explain --format mermaid` 会渲染出该路径。上面的演示技术栈如下: ``` flowchart LR internet(["🌐 internet — 0.0.0.0/0"]):::net web["aws_instance.web
public subnet · public IP"] orders[("aws_db_instance.orders")]:::bad legacy[("aws_db_instance.legacy")]:::bad exports[("aws_s3_bucket.exports")]:::bad internet -->|"443 · SG 0.0.0.0/0"| web web -->|"5432 · SG ref"| orders web -->|"5432 · SG 0.0.0.0/0"| legacy internet -->|"bucket policy Principal:*"| exports subgraph suppressed [" provably unreachable — never connected to the internet "] secrets[("aws_s3_bucket.secrets
BPA fully on")]:::ok warehouse[("aws_redshift_cluster.warehouse
internal-only")]:::ok sessions[("aws_elasticache_cluster.sessions
private subnet")]:::ok end classDef net fill:#1f2937,stroke:#60a5fa,color:#fff; classDef bad fill:#7f1d1d,stroke:#ef4444,color:#fff; classDef ok fill:#14532d,stroke:#22c55e,color:#fff; style suppressed fill:#0b1f12,stroke:#14532d,color:#9ca3af; ``` 注意 `aws_db_instance.legacy`:它位于一个“私有”子网中,但其安全组对 `0.0.0.0/0` 开放,因此被攻破的公网主机会直接通过它进行内网穿透(横向移动)。**“它在一个私有子网里”并不是一种网络访问控制** —— 而单一资源扫描器是看不到这一点的,因为这个发现横跨了三个不同的资源。 ## 为什么用图论,以及为什么有三种判定 信任模型就是这个产品的核心。probepath 会对每个接收端发出 **三种** 判定之一,且其中只有一种会隐藏信息: | 判定 | 含义 | 是否抑制该发现? | |---|---|---| | **`REACHABLE`** | 存在从互联网出发的具体路径,每一跳都被证明是开放的。 | 否 —— 显示为红色,展示每一跳。 | | **`POTENTIALLY_REACHABLE`** | 无法证明其不可达;路径上的某些输入是未知的。 | **否** —— 显示为黄色。 | | **`UNREACHABLE`** | 在所有相关输入已知的情况下,*所有* 路径都被证明是阻断的。 | **是** —— 唯一会执行抑制的判定。 | 基本准则是:**只有当模型拥有完整且已知的信息来证明路径已阻断时,才会发出 `UNREACHABLE`。** 如果路径上的某个输入是 `known after apply`、未解析的变量、我们无法查看的托管前缀列表,或者是我们尚未建模的功能(Transit Gateway、第三方防火墙),判定就会降级为 `POTENTIALLY_REACHABLE`,并且该发现将**保持可见**。被错误抑制的真实路径是我们视为致命失败的情况 —— [基于属性的测试](tests/test_properties.py) 的存在就是为了揪出它(单调性:使配置*更加*宽松,绝不会导致判定在格中向*下*移动)。 这就是为什么它基于引用而非基于值。在 plan 阶段,安全组的 `id` 是 `known after apply`,因此 `vpc_security_group_ids` 的值为 `[null]`。仅基于值的工具会看到 `[null]` 并(致命地)得出“没有路径”的结论。probepath 会从 plan 的符号化 `configuration.references` 中解析拓扑结构,因此 `web → db` 的边(edge)在 id 未知的情况下依然能够保留。 ## 安装 ``` pipx install "git+https://github.com/abhisheksoppanna/probepath@v0.1.0" # (PyPI 发布 — `pipx install probepath` — 即将推出) ``` 运行时依赖:四个纯 Python 库(`networkx`、`typer`、`rich`、`python-hcl2`)。 不需要 `boto3`,也没有网络出站流量 —— 一款安全工具绝不应该偷偷向外发送数据。 ## 使用方法 ``` # 1. 生成 plan JSON(最高保真度的输入) terraform plan -out plan.out terraform show -json plan.out > plan.tfplan.json # 2. 扫描 probepath scan plan.tfplan.json # human report probepath scan plan.tfplan.json -f sarif -o probepath.sarif # GitHub code scanning probepath scan plan.tfplan.json --fail-on reachable # exit 1 if a path exists # 完整解释一个 sink(包括为什么它是安全的,如果它确实安全的话) probepath explain aws_db_instance.orders plan.tfplan.json ``` probepath 还可以读取 `.tfstate` 和原始的 `.tf` 文件(对 HCL 的支持是尽力而为的 —— 因为 `count`/`for_each`/变量等未被实际求值,为了防止漏报,它宁可多报)。Plan JSON 是主要的数据源。 ## CI 门禁 (GitHub Action) ``` - run: | terraform plan -out plan.out terraform show -json plan.out > plan.tfplan.json - uses: abhisheksoppanna/probepath@v0.1.0 with: plan: plan.tfplan.json fail-on: reachable # freeze the deploy on any internet→sink path baseline: base.json # optional: gate only on NEWLY-introduced paths ``` 引入 `baseline` 后,只有当 PR **引入** 了新路径时检查才会失败 —— 原本已存在的路径会被展示出来,但不会阻塞合并,因此它可以从第一天起就无缝应用在混乱的代码库中。SARIF 结果会显示在 PR 的 code-scanning 标签页中,并将逐跳路径作为代码流展示。 ## 建模范围 具体包括:路由表和 `is_public` 推导(基于路由,绝不基于名称)、安全组(有状态、CIDR + SG 到 SG 的引用 + `self`、全协议 `-1`)、NACL(无状态、有序、瞬时返回路径)、IGW / NAT / egress-only IGW、ALB + NLB(包括无 SG 的 NLB)、RDS / Aurora / ElastiCache / Redshift / OpenSearch、S3(Block Public Access + bucket policy + ACL)、IPv4 **以及** IPv6,以及多跳的传递性内网穿透。完整的支持矩阵请参见 [DESIGN.md](DESIGN.md)。 ## 客观的局限性 probepath 是一款**可达性推理工具,而不是安全神谕。** 它判断的是在 AWS 记录在案的 VPC 语义下,从不可信源到敏感接收端的*网络路径*是否可能存在。它**不会**发送数据包或分析数据平面,也**不会**对以下内容进行建模:应用层身份验证(数据库密码、IAM DB 身份验证、S3 *authorization* 策略、TLS);主机防火墙、服务健康状况、监听进程;DNS;AWS Network Firewall / GWLB 或第三方设备(→ 这些会将路径降级为 `POTENTIALLY_REACHABLE`,绝对不会将其抑制);完整的 Transit Gateway 路由表传播;以及在 apply 之后在 Terraform 之外进行的任何更改。 已知盲点:账户级的 S3 Block Public Access 通常不在 Terraform 的管理范围内,因此我们永远不会假设它是存在的。 我们**不公布任何准确率百分比** —— 因为目前没有带标签的真实数据集能够为其提供诚实的支撑。我们所能承诺的都是可验证的:每一个 `UNREACHABLE` 都会指出阻断该路径的具体网关;每一个 `REACHABLE` 都会渲染出完整的路径;并且引擎在设计上就是保守的 (我们提供了 `probepath verify-against-aws` 但我们自己不运行它,方便想要在自己的 AWS 账户中对照 AWS Reachability Analyzer 交叉验证判定的用户使用)。 ## 构建方式 ``` ingest/ terraform plan JSON / tfstate / HCL → normalized records (reference-based resolution) model/ pure data model: port & CIDR algebra, graph, the three-verdict enum aws/ AWS semantics, isolated & auditable: security groups, NACLs, routing, ELB, S3 engine/ graph build + constrained reachability search (networkx) report/ human (rich) · JSON · SARIF 2.1.0 · Mermaid ``` 审查者只需阅读 `aws/` 和 `engine/reachability.py` 即可验证其正确性。 约 2 千行强类型 Python 代码(`mypy --strict`),经过属性测试,并包含由 [`scripts/regen_fixtures.sh`](scripts/regen_fixtures.sh) 重新生成的真实 Terraform 固件。 ## 许可证 MIT —— 详见 [LICENSE](LICENSE)。
标签:AWS, DPI, ECS, IaC扫描, Terraform, 攻击路径分析, 特权检测, 网络可达性分析, 逆向工具