kingkyylian/linwarden
GitHub: kingkyylian/linwarden
Linwarden 是一款无 root 权限的 Linux 安全加固扫描工具,专为 CI 流水线和资产快速分诊而设计,能在零依赖下检测常见的风险配置。
Stars: 2 | Forks: 1
# Linwarden
[](https://github.com/kingkyylian/linwarden/actions/workflows/ci.yml)
[](https://pypi.org/project/linwarden/)
[](pyproject.toml)
[](LICENSE)
Linwarden 是一款无 root 权限的 Linux 强化扫描工具,专为 CI 和资产分诊设计。它读取普通系统文件(如 `/etc/os-release`、`/etc/ssh/sshd_config` 以及选定的 `/proc/sys` 值),随后生成 Markdown、JSON 或 SARIF 产物,全程无需安装任何 agent、daemon、特权辅助程序、数据库或网络服务。
本项目的目标非常务实:为维护者提供一款小巧且可审计的工具,用于揭示存在风险的 Linux 默认配置,且无需依赖 agent、daemon、特权服务、外部数据库或网络访问。
## 为什么选择 Linwarden
当您需要快速了解安全态势信号,而不是一个笨重的合规平台时,请使用 Linwarden。
| 需求 | Linwarden 方案 |
| --- | --- |
| 对 CI 友好的输出 | 提供用于 GitHub 代码扫描的 JSON、Markdown 和 SARIF 格式。 |
| 低运营风险 | 以只读方式从普通 Linux 文件中收集信息。 |
| 离线分析 | 可扫描已挂载的根目录、解压的镜像、容器以及测试固件。 |
| 可解释的发现结果 | 每条规则均包含证据、影响、修复建议及参考来源。 |
| 极简供应链 | 除 Python 3.9+ 外,零运行时依赖。 |
Linwarden 并非要替代 CIS 或 STIG。它是一款轻量级的“第一道防线”工具,可在运维人员动用更重型的扫描器之前,告知他们哪些问题值得关注。
## 30 秒信号展示
Linwarden 旨在让审查者在阅读冗长报告之前,就能直观地发现存在风险的 Linux 默认配置。针对合成的测试固件根目录运行的结果如下:
```
$ linwarden scan --root tests/fixtures/linux-root --format markdown --fail-on off
# Linwarden 报告
- Host: `fixture-box`
- Score: `0/100`
- Findings: `17`
| Severity | Rule | Title | Evidence |
| --- | --- | --- | --- |
| HIGH | LNX-SSH-001 | SSH root login is permitted | PermitRootLogin yes |
| MEDIUM | LNX-SSH-002 | SSH password authentication is enabled | PasswordAuthentication yes |
| HIGH | LNX-KRN-001 | Address space layout randomization is disabled | kernel.randomize_va_space=0 |
| MEDIUM | LNX-FW-001 | Host firewall is disabled | ufw firewall disabled |
```
如需了解 SARIF/代码扫描工作流,请查看完整的[合成终端演示](docs/assets/terminal-demo.md)以及 [GitHub Actions 示例](docs/github-actions.md)。
## 发布来源
当前版本的发布产物发布在 [GitHub 发布页面](https://github.com/kingkyylian/linwarden/releases/tag/v0.15.0),该包也可从 [PyPI](https://pypi.org/project/linwarden/) 获取。
每个标签版本的发布都包含 `SHA256SUMS` 校验和文件,以及针对构建的源码和 wheel 文件的 GitHub 产物证明(artifact attestations)。验证指南详见 [docs/release.md#artifact-attestations](docs/release.md#artifact-attestations),其中包括 `gh attestation verify` 命令的使用方法。
## 功能
- 以无 root 权限方式从 `/etc`、`/proc` 以及 procfs sysctl 路径中收集信息。
- 为 CI 流水线和定时主机扫描提供确定性的 JSON 输出。
- 提供 Markdown 格式输出,适合用于 GitHub 作业摘要(job summaries)和 Issue 附件。
- 提供 SARIF 格式输出,适合 GitHub 原生安全检测结果接入。
- 支持 JSON 配置文件,可用于配置 profiles、禁用规则以及合理的抑制项。
- 可选的有效 OpenSSH 配置收集功能(通过 `sshd -T` 实现),包含 Match 上下文。
- 在无 root 权限文件可见的情况下,提供包更新和主机防火墙的安全态势信号。
- 针对常见的包管理器缓存标记,进行包元数据的新鲜度检查。
- 基于 procfs sysctls 进行反向路径过滤(reverse-path filtering)和源路由(source-route)安全态势检查。
- 针对容器主机,进行网桥接口及网桥防火墙钩子的安全态势检查。
- 针对暴露的 Docker 或 Podman API 以及 Docker 用户组成员资格,进行静态容器运行时安全态势检查。
- 支持通过本地 JSON 数据源提供可选的包漏洞扫描结果。
- 提供发布校验和清单,并支持可选的分离式 GPG 签名。
- 提供基于严重程度的评分机制,分为 `critical`(严重)、`high`(高)、`medium`(中)和 `low`(低)等级别。
- 通过 `--fail-on` 参数提供对 CI 友好的退出阈值控制。
- 提供复合式 GitHub Action 封装,可通过 `uses: kingkyylian/linwarden@v0.15.0` 使用。
- 支持针对固件根目录(fixture-root)进行扫描,适用于测试、容器、取证副本以及离线分析场景。
- 除 Python 3.9+ 外,零运行时依赖。
## 快速开始
从 PyPI 安装:
```
python3 -m pip install linwarden
linwarden --version
linwarden scan --format markdown
```
进行隔离的 CLI 安装:
```
pipx install linwarden
```
从开发检出版本运行:
```
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .
linwarden scan --format markdown
```
针对内置的固件运行扫描:
```
PYTHONPATH=src python3 -m linwarden scan \
--root tests/fixtures/linux-root \
--format json \
--fail-on high
```
退出码 `2` 表示至少有一条发现结果达到了选定的阈值。
请查看[合成终端演示](docs/assets/terminal-demo.md),了解基于该固件根目录生成的 Markdown 扫描记录。
## 常见工作流
| 工作流 | 命令或文档 |
| --- | --- |
| 文档索引 | [docs/index.md](docs/index.md) |
| 本地分诊 | `linwarden scan --format markdown` |
| CI 失败阈值 | `linwarden scan --format json --fail-on high` |
| GitHub 代码扫描 | `uses: kingkyylian/linwarden@v0.15.0` |
| Actions 故障排查 | [docs/github-actions.md#troubleshooting](docs/github-actions.md#troubleshooting) |
| JSON 报告结构 | [docs/assets/json-report-example.json](docs/assets/json-report-example.json) |
| 报告产物处理 | [docs/report-artifacts.md](docs/report-artifacts.md) |
| 挂载镜像扫描 | [docs/mounted-root-scans.md](docs/mounted-root-scans.md) |
| 有效 SSH 扫描 | `linwarden scan --sshd-mode effective --sshd-match user=deploy` |
| 工具定位 | [docs/comparison.md](docs/comparison.md) |
## CLI
```
linwarden profiles [--format markdown|json]
linwarden scan [--root PATH] [--proc-root PATH] [--etc-root PATH] [--sys-root PATH]
[--config PATH] [--format markdown|json|sarif]
[--vulnerability-feed PATH] [--vulnerability-feed-format linwarden|trivy|grype|osv]
[--sshd-mode static|effective|auto] [--sshd-binary PATH]
[--sshd-match KEY=VALUE]
[--output PATH]
[--fail-on off|low|medium|high|critical]
```
常见示例:
```
linwarden profiles
linwarden scan --format markdown --output linwarden-report.md
linwarden scan --format json --fail-on high
linwarden scan --config linwarden.json --format sarif --output linwarden.sarif
linwarden scan --sshd-mode effective --format json
linwarden scan --sshd-mode effective --sshd-match user=deploy --sshd-match addr=203.0.113.10
linwarden scan --root /mnt/server-image --format json
linwarden scan --proc-root /host/proc --etc-root /host/etc --sys-root /host/sys --format markdown
linwarden scan --vulnerability-feed ./linwarden-vulnerabilities.json --format sarif
linwarden scan --vulnerability-feed ./trivy-report.json --vulnerability-feed-format trivy --format sarif
linwarden scan --vulnerability-feed ./grype-report.json --vulnerability-feed-format grype --format sarif
linwarden scan --vulnerability-feed ./osv-scanner-report.json --vulnerability-feed-format osv --format sarif
```
## 配置
Linwarden 接受无额外依赖的 JSON 配置文件:
```
{
"profile": "router",
"disabled_rules": ["LNX-NET-002"],
"suppressions": [
{
"rule_id": "LNX-SSH-002",
"reason": "Temporary migration host; password auth removed after cutover."
}
]
}
```
Profiles:
| Profile | 行为 |
| --- | --- |
| `server` | 适用于常规 Linux 服务器的默认选项。无 profile 抑制规则。 |
| `workstation` | 适用于交互式台式机或笔记本电脑的安全态势。无 profile 抑制规则;SSH、防火墙、软件包以及内核相关的发现结果均会显示。 |
| `router` | 适用于有意进行流量路由的主机。抑制有关 IPv4、IPv6 以及网桥转发的发现结果。 |
| `container` | 适用于容器或镜像根目录扫描,此时可能会继承主机内核的 sysctl 值。抑制有关内核和文件系统 sysctl 的发现结果。 |
被抑制的发现结果在 JSON 和 Markdown 报告中依然可见。SARIF 输出仅包含处于活动状态的发现结果。
## 退出码
| 代码 | 含义 |
| --- | --- |
| `0` | 扫描完成,且未触发选定的阈值。 |
| `1` | 参数解析导致的 CLI 使用错误。 |
| `2` | 扫描完成,且达到了 `--fail-on` 设定的阈值。 |
## 当前规则
| 规则 | 严重程度 | 领域 | 概要 |
| --- | --- | --- | --- |
| `LNX-SSH-001` | high | SSH | 启用了 `PermitRootLogin yes`。 |
| `LNX-SSH-002` | medium | SSH | 启用了 `PasswordAuthentication yes`。 |
| `LNX-SSH-003` | high | SSH | 启用了 `PermitEmptyPasswords yes`。 |
| `LNX-SSH-004` | medium | SSH | `MaxAuthTries` 大于 `4`。 |
| `LNX-SSH-005` | medium | SSH | 启用了 `AllowTcpForwarding yes` 或设为 `all`。 |
| `LNX-KRN-001` | high | Kernel | `kernel.randomize_va_space=0` 禁用了 ASLR。 |
| `LNX-KRN-002` | high | Kernel | `vm.mmap_min_addr` 小于 `65536`。 |
| `LNX-KRN-003` | medium | Kernel | `kernel.kptr_restrict=0` 暴露了内核指针。 |
| `LNX-FS-001` | high | Filesystem | `fs.protected_hardlinks=0` 禁用了硬链接保护。 |
| `LNX-FS-002` | high | Filesystem | `fs.protected_symlinks=0` 禁用了符号链接保护。 |
| `LNX-NET-001` | medium | Network | 启用了 `net.ipv4.ip_forward=1`。 |
| `LNX-NET-002` | low | Network | 启用了 `net.ipv4.conf.all.accept_redirects=1`。 |
| `LNX-NET-003` | medium | Network | 启用了 `net.ipv6.conf.all.forwarding=1`。 |
| `LNX-NET-004` | low | Network | 启用了 `net.ipv6.conf.all.accept_redirects=1`。 |
| `LNX-NET-005` | medium | Network | 存在网桥接口时,网桥 IPv4 防火墙钩子被禁用。 |
| `LNX-NET-006` | medium | Network | 存在网桥接口时,网桥 IPv6 防火墙钩子被禁用。 |
| `LNX-NET-007` | medium | Network | 某个网桥接口启用了转发功能。 |
| `LNX-NET-008` | medium | Network | `net.ipv4.conf.all.rp_filter=0` 禁用了 IPv4 反向路径过滤。 |
| `LNX-NET-009` | medium | Network | `net.ipv4.conf.all.accept_source_route=1` 允许接收 IPv4 源路由数据包。 |
| `LNX-NET-010` | medium | Network | `net.ipv6.conf.all.accept_source_route` 允许接收 IPv6 源路由数据包。 |
| `LNX-PKG-001` | medium | Packages | 存在可用的软件包更新。 |
| `LNX-PKG-002` | high | Packages | 存在可用的安全软件包更新。 |
| `LNX-PKG-003` | medium | Packages | 软件包元数据已过期。 |
| `LNX-PKG-004` | feed severity | Packages | 本地漏洞数据源报告了受影响的软件包。 |
| `LNX-FW-001` | medium | Firewall | 已知的常用主机防火墙被禁用。 |
| `LNX-SVC-001` | medium | Services | 已启用的 systemd unit 显示存在外部绑定。 |
| `LNX-CTR-001` | high | Containers | 容器运行时 API 绑定到了非本地回环(non-loopback)的 TCP 端口。 |
| `LNX-CTR-002` | high | Containers | Docker 用户组为非 root 用户授予了 daemon 级别的访问权限。 |
| `LNX-CTR-003` | medium | Containers | Docker 用户命名空间重映射(user namespace remapping)被显式禁用。 |
详细的规则说明请参阅 [docs/rules.md](docs/rules.md)。
## 报告评分
Linwarden 每份报告的初始分数为 `100`,并根据发现的问题扣除固定的惩罚分数:
| 严重程度 | 扣分 |
| --- | --- |
| critical | 35 |
| high | 20 |
| medium | 10 |
| low | 3 |
该评分机制特意设计得很简单。它是一个用于分诊的参考信号,而不是合规性评级。
## 项目结构
```
src/linwarden/
cli.py command line entry point
config.py profiles, disabled rules, and suppressions
collectors.py host snapshot collection
parsers.py small parsers for Linux files
rules.py built-in hardening checks
reporters.py JSON, Markdown, and SARIF rendering
models.py report data structures
tests/
fixtures/ deterministic Linux fixture root
docs/
architecture.md implementation overview
configuration.md profile and suppression config
comparison.md positioning against adjacent Linux security tools
contributor-ideas.md scoped contribution backlog
github-actions.md CI and SARIF workflow examples
launch.md copy and checklist for public announcements
positioning.md maintainer messaging guide
release.md release artifact and publishing workflow
rules.md rule catalog
report-schema.md JSON report contract
schemas/
report.schema.json machine-readable JSON report schema
```
## 开发
```
make test
make compile
make lint
make typecheck
make smoke
make smoke-sarif
make check
```
如果通过项目的虚拟环境运行,请使用 `make check PYTHON=.venv/bin/python`。
测试套件不需要网络服务或特权权限。
## 安全模型
Linwarden 默认是只读的。它不会修改主机状态、加载内核模块、调用包管理器或发送遥测数据。由于报告中可能包含主机配置的详细信息,因此请将生成的产物视为敏感运营数据。
请通过 [SECURITY.md](SECURITY.md) 报告漏洞;请勿针对敏感报告提交公开的 Issue。
## 已知限制
- 静态 SSH 模式会读取 `sshd_config` 以及简单的 `Include` 指令;其 `Match` 行为可能与实际有效的 OpenSSH 配置有所不同。
- 有效 SSH 模式会执行 `sshd -T`;请仅在有意扫描实时主机时此模式。
- 软件包元数据的新鲜度依赖于本地缓存标记的 mtime,并不会调用包管理器命令。
- 软件包漏洞扫描需要显式提供本地 JSON 数据源,且绝不获取远程 CVE 数据。
- 网桥安全态势检查依赖于被扫描根目录内的 procfs 和 sysfs 文件;如果缺少网桥数据,将被视为未知状态。
- 当存在 systemd 启用标记时,会从中推断 Firewalld 和 nftables 的服务状态;如果仅能进行基于配置的检测,其启用状态将被视为未知。
- 已启用的 systemd 服务暴露检测是静态的,仅标记服务 unit 的 `ExecStart` 行中常见的通配符绑定选项。
- 容器运行时安全态势检查仅报告来自配置、用户组或已启用的 unit 文件中明确的静态证据;如果缺少运行时文件,状态为未知,而非安全。
- 缺失的文件被视为数据不存在,从而确保扫描可以在容器和固件根目录中正常运行。
- Linwarden 是一款用于安全强化的分诊工具,不是完整的 CIS 或 DISA STIG 合规扫描器。
## 路线图
- 基于测试固件,扩大对软件包元数据和防火墙安全态势的发行版覆盖范围。
- 仅在证据可靠且无需 root 权限时,增加静态容器运行时信号。
- 完善发布检查,确保 GitHub 产物、证明(attestations)以及 PyPI 安装过程均可验证。
如需提出首发反馈和无 root 权限规则的建议,请访问[首发讨论区](https://github.com/kingkyylian/linwarden/discussions/57)。适合贡献者参与的想法已发布在 [docs/contributor-ideas.md](docs/contributor-ideas.md) 中,您可以从 [Ubuntu 测试固件 Issue](https://github.com/kingkyylian/linwarden/issues/56) 开始了解。
请查阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解以 Issue 为导向的工作流、规则质量标准以及本地验证检查清单。
## 许可证
MIT。详见 [LICENSE](LICENSE)。
标签:GitHub Advanced Security, Python, SARIF, 关系图谱, 基线检查, 子域名枚举, 安全加固, 无后门, 系统安全