tbortolossi/Panorama-Clean-Unused-Policies

GitHub: tbortolossi/Panorama-Clean-Unused-Policies

基于实际命中数据分析并清理 Palo Alto Panorama 未使用安全与 NAT 规则的 Python 工具,以非破坏性方式生成审核后的配置副本。

Stars: 0 | Forks: 0

# Clean_Unused [![许可证: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Python 3.13](https://img.shields.io/badge/Python-3.13-3776AB.svg?logo=python&logoColor=white)](https://www.python.org/) [![测试](https://img.shields.io/badge/tests-180%20passing-brightgreen.svg)](tests/) [![Docker](https://img.shields.io/badge/Docker-air--gap%20ready-2496ED.svg?logo=docker&logoColor=white)](DOCKER.md) ![Web UI 中的清理运行已完成](https://static.pigsec.cn/wp-content/uploads/repos/cas/a9/a9c63811b4e099b0e7c5b5c743f19b86cc2fd97a8369260f86dd4025b01c71a7.png) ## 描述 **Clean_Unused** 是一个 Python 工具,用于分析、过滤和清理 **Panorama**(Palo Alto Networks)配置中未使用的**安全**(security)和 **NAT** 规则。 它检索配置(通过 API 或 XML 文件),使用实际使用数据(`rule-hit-count`)丰富每条规则,应用可配置的决策树,然后生成: - **删除了规则**的配置副本; - **禁用并打上标签**的规则配置副本(非破坏性替代方案); - 每个类别的详细报告(`.csv` / `.txt`); - 运行的 Markdown 摘要报告; - 已删除规则的 XML 存档(用于回滚)。 ## 决策逻辑 对于每条规则,脚本遵循以下决策树: ``` flowchart TD Start([Rule evaluated]) --> Type{Type?} Type -- NAT --> State Type -- Security --> Action{"Action = Allow?"} Action -- Deny --> Kept[/"Rule kept
not evaluated"/] Action -- Allow --> Log{"Log setting
properly configured?"} Log -- No --> LogFix["Kept + fix set
command generated"] Log -- Yes --> State{"Rule state = used?"} State -- "No (Unused)" --> Grace{"Created less than
the grace period -u ago?"} Grace -- Yes --> Kept Grace -- No --> TagUnused{"Tag Clean_Protected?"} TagUnused -- Yes --> Kept TagUnused -- No --> Deleted[/"Rule deleted"/] State -- "Yes (Used)" --> TagUsed{"Tag Clean_Protected?"} TagUsed -- Yes --> Kept TagUsed -- No --> LastHit{"Last hit older
than -d days?"} LastHit -- No --> Kept LastHit -- Yes --> Deleted classDef kept fill:#9ad06f,stroke:#4a7a2a,color:#000; classDef del fill:#e8584f,stroke:#9c2b24,color:#fff; class Kept,LogFix kept; class Deleted del; ``` **简而言之,只有在满足以下所有条件时,规则才会被删除:** - **未**受到 `Clean_Protected` 标签保护; - 具有可用的使用状态(已设置 `rule-state`); - 对于**安全**规则:操作为 `allow` **且**日志转发配置正确(存在 `log-setting` 且 `log-start` 或 `log-end` 设置为 `yes`); - 在创建后超过 `-u` 宽限期**未被使用**,或者**使用过但在**超过 `-d` 天**没有命中**。 `deny` 规则、无状态规则、在宽限期内的规则以及带有 `Clean_Protected` 标签的规则会被**保留**。日志配置错误的安全规则会被保留,但会生成一个 `set` 命令修复文件。 ## 安装 要求:**Python 3.13**(项目已通过此版本验证)。 ``` git clone https://github.com/tbortolossi/Panorama-Clean-Unused-Policies.git cd Panorama-Clean-Unused-Policies python -m venv .venv # Windows .venv\Scripts\Activate.ps1 # Linux / macOS source .venv/bin/activate pip install -r requirements.txt # 可选 — 仅当你还需要 Web UI 时(见下文) pip install -r requirements-webui.txt ``` ## 测试 测试套件使用 `unittest`(标准库,无额外依赖): ``` python -m unittest discover -s tests # 或者,如果已安装 pytest: pytest ``` 它涵盖了决策树(`filter_rules`)、CLI/配置合并、验证、密码解析(通过 mock)以及 XML 解析/修改——包括针对禁用器中 `find`/`findall` 错误的回归测试。没有任何测试会触及网络。 Web UI 测试需要 `requirements-webui.txt`;如果没有它,测试将被**跳过**而不是失败,因此仅安装 CLI 也能顺利运行测试套件。 ## 配置 ### 配置文件(`config.toml`) 您可以选择将配置集中在一个 **TOML** 文件中(由标准库 `tomllib` 读取,无额外依赖),而不必在每次运行时重复输入相同的选项: ``` cp config.example.toml config.toml # then edit config.toml ``` ``` [panorama] host = "panorama.local" login = "admin" # password = "..." # 可选 — 见下方的 "Password" [cleanup] protected_tags = ["Clean_Protected", "Do_Not_Delete"] days_without_hit = 365 # "used" rule deleted if no hit for X days (-d) grace_days = 30 # "unused" rule kept if created less than X days ago (-u) disabled_tag_prefix = "Clean_Disabled_" ``` 每个值的**优先级**顺序为:**CLI 参数 > `config.toml` > 内置默认值**。 因此,您可以将常用的值保存在文件中,并随时根据需要进行覆盖(`-d 90`)。 脚本会在当前目录中查找 `config.toml`;使用 `-c /path/to/other.toml` 指定其他路径。`config.toml` 被 **gitignored**(它可能包含主机名/登录名/密码);只有 `config.example.toml` 被纳入版本控制。 ### Panorama 密码 密码**绝不硬编码**。它按以下顺序解析: 1. **环境变量** `CLEAN_UNUSED_PASSWORD` —— 非交互模式,非常适合没有 keyring 或终端的无图形界面 Linux 主机(服务器、跳板机、定时任务)。 2. 通过 `keyring` 使用 **OS keyring**(Windows 凭据管理器、macOS Keychain、Linux SecretService)—— 只需输入**一次**,然后加密存储。 3. **配置文件** —— `config.toml` 的 `[panorama].password` 字段(被 gitignored)。很方便,但在磁盘上以明文形式存储;环境变量和 keyring 优先于此方式。 4. **交互式提示**(`getpass`)作为最后的手段;密码验证通过后,如果有可用的后端,则会被存储到 keyring 中。 如果没有可用的 keyring(无图形界面的 Linux),脚本会自动回退到配置文件密码或提示输入——而不会崩溃。 非交互式示例(Linux): ``` read -rs CLEAN_UNUSED_PASSWORD && export CLEAN_UNUSED_PASSWORD python clean_unused.py -a -p panorama.local -l admin -d 365 -u 30 unset CLEAN_UNUSED_PASSWORD ``` ### TLS 验证 Panorama 设备通常使用**自签名**证书,因此默认情况下 TLS 验证是**禁用的**(`verify=False`)。 若要**强制启用**(内部 CA): ``` export CLEAN_UNUSED_VERIFY_TLS=true # 可选,指向你的 CA bundle: export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.pem ``` ## 使用说明 在命令行中,只有**源模式**(`-a` 或 `-i`)是必填的。`panorama`、`login`、`days` 和 `unused` 可以来自于 `config.toml`;CLI 参数会覆盖它们。 ``` # 来自 config.toml 的所有内容 — 仅 CLI 传递的 source 模式 python clean_unused.py -a # 不带 config:CLI 上的所有内容(API) python clean_unused.py -a -p 192.168.1.1 -l admin -d 365 -u 30 # 分析已导出的 XML 文件,默认 config + ad hoc override python clean_unused.py -i panorama_config.xml -d 90 ``` | 参数 | 必填 | 对应配置项 | 描述 | |----------|:--------:|-------------------|-------------| | `-a`, `--api` | ⚠️ | — | 通过 API 下载配置*(与 `-i` 互斥)* | | `-i`, `--input` | ⚠️ | — | 分析本地 XML 文件*(与 `-a` 互斥)* | | `-c`, `--config` | ❌ | — | TOML 文件路径(默认:`config.toml`) | | `-p`, `--panorama` | ◐ | `[panorama].host` | Panorama IP 地址或 FQDN | | `-l`, `--login` | ◐ | `[panorama].login` | Panorama 用户名 | | `-d`, `--days` | ◐ | `[cleanup].days_without_hit` | 删除**已使用**但在这么多天内没有命中的规则 | | `-u`, `--unused` | ◐ | `[cleanup].grace_days` | **未使用**规则创建后的宽限期(天)(`0` = 无宽限期) | ## 输出 每次运行时: - 一个以配置名称命名的**文件夹**,包含所有生成的文件: - 每个规则类别(`rules_to_delete`、`unused_rules`、`old_rules`、`log_problematic_rules` 等)对应一个 `.csv` 和一个 `.txt`; - **`*_report.md`** —— 可读的 Markdown 报告(摘要、前/后对比、已删除的规则及原因、生成的文件)—— 因此您不必依赖日志; - `*_deleted_rules.xml` —— 已删除规则的存档(用于回滚); - `*_set_fix.txt` —— 用于修复问题规则日志记录的 `set` 命令; - `*_cleaned_unused.xml` —— **已删除**规则的配置; - `*_disabled_unused.xml` —— **已禁用 + 打上标签**的规则配置 `Clean_Disabled_<日期>`; - `logfile_<日期>.log` —— 详细的运行日志(写入工作目录)。 ## 保护标签 若要永久将某条规则排除在清理范围之外,请在 Panorama 中为其添加 **`Clean_Protected`** 标签。它会被统计但永远不会被删除或禁用。 ## 项目结构 ``` clean_unused.py # CLI entry point (thin wrapper around lib.pipeline) config.example.toml # Configuration template (copy to config.toml) lib/ pipeline.py # run_pipeline() — the importable pipeline (CLI + Web UI) config.py # TOML loading + CLI > config > default merge utils.py # Args, password (env/keyring/config/getpass), helpers api.py # API key generation, hostname, config export api_rules_requestor.py # rule-hit-count calls (with retry) api_rules_processor.py # Parsing of usage responses devicegroups.py # Device-group detection and hierarchy xml_parser.py # Rule inventory from the XML rule_checker.py # XML enrichment + API usage data filter_rules.py # Decision tree / categorisation write_results.py # Report writing generate_csv.py # CSV export generate_txt.py # TXT export + set commands generate_report.py # Markdown summary report rule_deleter.py # Rule deletion + archiving rule_disabler.py # Rule disabling + tagging webui/ # Optional browser front-end (FastAPI, HTTPS) — see below tests/ # unittest suite docs/screenshots/ # Web UI screenshots used in this README Dockerfile # Offline multi-stage build (CLI + Web UI faces) docker-compose.yml # CLI + Web UI services DOCKER.md # Docker / air-gap build + run guide README.md requirements.txt # CLI dependencies requirements-webui.txt # Additional Web UI dependencies (FastAPI, Uvicorn, …) ``` CLI 和 Web UI 共享**完全相同的 pipeline**(`lib/pipeline.run_pipeline`);无论通过何种方式启动运行,决策树、XML 处理和机密解析都是完全一致的。 ## Web UI 该工具附带了一个可选的**浏览器前端**,它驱动完全相同的 pipeline,因此操作员可以在完全不碰终端的情况下端到端地执行一次清理: - 一个**配置表单**(Panorama 主机/登录名/密码、天数阈值、受保护标签、禁用标签前缀),支持从 `config.toml` 加载和保存; - 一个**“测试连接”**按钮,用于验证针对 Panorama 的连通性**和**凭据,而无需执行清理; - 基于 WebSocket 的**实时进度** —— 一个 11 阶段的跟踪器以及运行日志的流式尾部显示(在漫长的按规则丰富数据步骤中带有 X/总数计数器); - 一个**完成摘要**(统计删除/禁用/保护/出现问题的规则数量、节省的 MB 大小、耗时),外加每个 artifact 的**下载**链接以及 Markdown 报告的内嵌渲染。 | 配置表单 | 实时运行 | |---|---| | [![配置表单](https://static.pigsec.cn/wp-content/uploads/repos/cas/03/035a8b9394604934ef5b4ab82e505498bff7777c2b0a5db3f8eeabf4f70e3f95.png)](docs/screenshots/webui-configuration.png) | [![实时进度](https://static.pigsec.cn/wp-content/uploads/repos/cas/09/09af2be09687f5d6eec272ecf14a28c4d64524f055ac4c7881c37130c23e03fa.png)](docs/screenshots/webui-run-progress.png) | | 支持加载和保存到 `config.toml`;会显示当前生效的密码来源,但绝不会回显机密。 | 11 个阶段,丰富数据期间的 X/总数计数器,以及通过 WebSocket 流式传输的运行日志。 | | 完成摘要 | 内嵌报告 | |---|---| | [![运行完成](https://static.pigsec.cn/wp-content/uploads/repos/cas/a9/a9c63811b4e099b0e7c5b5c743f19b86cc2fd97a8369260f86dd4025b01c71a7.png)](docs/screenshots/webui-run-complete.png) | [![运行报告](https://static.pigsec.cn/wp-content/uploads/repos/cas/02/02ca482df36d50c7e00f19201e28e7a24560eca5690a28b576bab4c5ea2341e3.png)](docs/screenshots/webui-report.png) | | 统计数量、前/后策略总数、节省的大小、持续时间,以及准备好供下载的所有 artifact。 | 在浏览器中渲染生成的 `*_report.md`,所有由 pipeline 生成的文本都被处理为不可执行状态。 | Web UI **始终通过 API 从 Panorama 下载当前运行的配置**(与 CLI 不同,CLI 也接受本地的 `-i` XML 文件)。它**仅提供 HTTPS 服务**(纯 HTTP 会被重定向),并支持带每 IP 暴力破解锁定机制的**可选登录密码**(`config.toml` 中的 `[webui]` —— 见下文)。在没有密码的情况下,它专为**在受信任/隔离网络上的单一操作员**设计。请参阅下方的[安全说明](#web-ui-security)。 ### 使用 Docker 运行(推荐,包括气隙主机) 为 CLI 提供支持的同一个**自包含镜像**也可以用于 Web UI —— 所有的 wheel 包都在构建时打包好了,因此它**在运行时不会下载任何内容**: ``` # 从一次离线 wheel build 构建两个 faces docker build -t clean-unused:latest . docker build -t clean-unused-webui:latest --target webui . # 启动 Web UI(HTTPS 在 8443,HTTP->HTTPS 重定向在 8080) CLEAN_UNUSED_PASSWORD=*** \ docker compose up -d clean-unused-webui # 打开 https://:8443/ (自签名证书 -> 接受警告) ``` 请参阅 **[DOCKER.md](DOCKER.md)** 获取完整的离线构建/导出/运行指南、证书卷以及自签名行为,以及完整的环境变量参考。 ### 不使用 Docker 运行 ``` pip install -r requirements.txt -r requirements-webui.txt CLEAN_UNUSED_DATA_DIR=./data python -m webui # -> https://127.0.0.1:8443/ (8080 上的 HTTP 会重定向到此处) ``` | 环境变量 | 默认值 | 用途 | |----------------------|---------|---------| | `CLEAN_UNUSED_DATA_DIR` | `./data` | 运行输出、日志和证书的存放位置 | | `CLEAN_UNUSED_BIND_HOST` | `127.0.0.1` | 绑定的网络接口(`0.0.0.0` 表示在局域网中暴露 —— 这是刻意为之的) | | `CLEAN_UNUSED_HTTPS_PORT` | `8443` | HTTPS 端口 | | `CLEAN_UNUSED_HTTP_PORT` | `8080` | HTTP→HTTPS 重定向端口 | | `CLEAN_UNUSED_EXTERNAL_ORIGIN` | 请求主机 | 可选的固定 `https://host:port` 重定向目标。默认不需要(重定向会复用请求自身的 Host + HTTPS 端口);如果您发布 HTTPS 的端口与应用监听的端口不同,则需要设置此项 | | `CLEAN_UNUSED_ALLOWED_HOSTS` | — | 逗号分隔的允许的 `Host` 值,或使用 `*` 表示任意主机(请将 `*` 与 WebUI 密码搭配使用) | | `CLEAN_UNUSED_WEBUI_PASSWORD` | — | WebUI 登录密码(覆盖 `config.toml` 中的 `[webui]`) | | `CLEAN_UNUSED_CERT_DIR` | `/certs` | 证书/密钥位置(`cert.pem`/`key.pem`,如果不存在则使用自签名) | `CLEAN_UNUSED_PASSWORD` 和 `CLEAN_UNUSED_VERIFY_TLS` 的行为与 CLI 完全一致。 ### 安全说明 - **可选的应用程序登录。** 在 `config.toml` 中设置密码 —— [webui] password = "change-me" # 或者,更推荐的方式:其哈希值,生成方式为 # password_sha256 = "..." # python -c "import hashlib;print(hashlib.sha256(b'change-me').hexdigest())" max_login_failures = 5 # 每 IP 锁定阈值(默认 5) lockout_minutes = 15 # 锁定持续时间(默认 15) 或通过 `CLEAN_UNUSED_WEBUI_PASSWORD` 设置。会话使用 HttpOnly+Secure cookie;在输错 `max_login_failures` 次密码后,源 IP 将被锁定 `lockout_minutes` 分钟(注意:在 Docker/NAT 端口映射背后,所有远程客户端可能共享同一个源 IP,因此锁定可能会同时影响所有远程操作员)。**在没有密码的情况下**,访问**仅依赖于网络层** —— 请将主机保持在受信任/隔离的网段中。服务器默认绑定在 **loopback**;将其暴露在局域网(`0.0.0.0`)上是出于用户主动选择。 - **仅支持 HTTPS**,因此凭据绝不会以明文形式在网络中传输。首次运行时会生成自签名证书(挂载您自己的 `cert.pem`/`key.pem` 以覆盖它)。 - **跨源加固:** 会验证 `Host` 标头,并拒绝来自外部或缺失 `Origin` 的状态更改请求/WebSocket 握手(防御 CSRF / DNS重绑定攻击)。 - **密码处理。** 默认情况下,密码**仅用于本次运行**,*不会*写入磁盘;它遵循与 CLI 相同的优先级顺序(`CLEAN_UNUSED_PASSWORD` 环境变量 → OS keyring → `config.toml` → 表单字段)。**“将密码持久化到 config.toml”**选项会将机密以**明文**形式写入 `config.toml`(它**不**使用 OS keyring)—— 这是一个需要您主动开启的选项,且不鼓励使用。为了安全存储,请改在 UI 之外设置 OS keyring 或环境变量。 - 源自 pipeline 的字符串(规则/标签/设备组名称)始终作为不可执行的纯文本渲染;生成的 artifact 保持被 gitignored 的状态,并且只能从当前运行自身的文件夹中访问。 ## 免责声明 本项目与 Palo Alto Networks 没有任何隶属关系。请始终在配置的副本上进行操作,并在**任何重新导入之前检查报告**。使用风险由您自行承担。
标签:Docker, Palo Alto, Python, TCP SYN 扫描, Web UI, 安全防御评估, 无后门, 规则清理, 请求拦截, 运维工具, 逆向工具, 防火墙管理