BinanIbrahim/Container-Security-Scanner

GitHub: BinanIbrahim/Container-Security-Scanner

一款零依赖的 Go CLI 工具,通过构建 SBOM 并查询 Alpine SecDB 来扫描 Alpine Docker 镜像中的已知 CVE 漏洞。

Stars: 1 | Forks: 0

# Sentinel Scanner Sentinel Scanner 是一个使用 **Go** 编写的**零依赖** **CLI** 工具, 用于扫描基于 **Alpine** 的 **Docker 镜像**以查找已知的安全 **漏洞** — 这一切都在它们发布到生产环境之前完成。 容器镜像打包了数十个 **OS 包**,其中任何一个都可能携带 已公布的 **CVE**。手动跟踪它们是不切实际的:您必须了解 内置到镜像中的每个包和版本,将它们与不断变化的**漏洞数据源** 逐一交叉比对,并理解 **Alpine 的 APK 版本控制**规则, 才能判断已安装的版本是否确实早于修复特定 CVE 的版本。Sentinel 正是将这一流程自动化了。 将其指向一个镜像,它就会作为一个 **pipeline** 运行:它会拉取并保存 镜像,然后从镜像层中**流式传输** **Alpine 包数据库** 以构建轻量级的 **SBOM**(软件物料清单),检测 Alpine OS 版本, 下载匹配的 **Alpine 安全数据库 (SecDB)**,并使用 **支持 APK 的版本比较器** 将每个已安装的包与已知修复进行比较。结果是一份清晰的报告, 包含受影响包的 **CVE ID**、**严重性评分**以及具体的**修复** 指南 — 可以直接打印供人类阅读,或者以 **JSON** 格式输出, 并带有可配置的失败阈值,以便它可以**控制 CI pipeline**。它以单个 **静态二进制文件**的形式发布,并且**不引入任何第三方依赖**。 ## 功能 - 通过命令行扫描 **Docker 镜像** (`--image`)。 - 用于 **CI pipeline** 的机器可读 **JSON 输出** (`--format json`)。 - **基于策略的构建失败**阈值 (`--fail-on`)。 - 从保存的 tar 中**流式传输镜像层**(无需完全解压到磁盘)以构建 **SBOM**。 - 从 `alpine-release` 检测 Alpine 版本(带有安全的镜像标签解析回退机制)。 - 从 `main` 和 `community` 仓库获取并合并 **Alpine SecDB**。 - **支持 APK 的版本比较**,包括预发布/后发布后缀语义(见下文)。 - 按包和 CVE **去重**扫描结果。 - 包级别的**严重性评分**(LOW 到 CRITICAL)以及每个包的**修复**提示。 - 打印**扫描上下文指标**以供置信度评估和调试。 ## 架构 扫描器作为线性 **pipeline** 运行。每个阶段将其输出传递给 下一个阶段,整个过程由 `cmd/scanner/main.go` 统一编排。 ``` --image alpine:3.14 │ ▼ ┌───────────────────┐ │ docker pull │ ensure the image exists locally │ docker save │ export it to image.tar ── internal/extractor └─────────┬─────────┘ │ saved image.tar (manifest.json + layer blobs) ▼ ┌───────────────────┐ │ stream outer tar │ find manifest.json (any order) │ walk each layer │ gzip/plain, in-memory, cap-guarded ── internal/analyzer │ parse apk DB │ lib/apk/db/installed → SBOM └─────────┬─────────┘ │ SBOM: []{name, version} ▼ ┌───────────────────┐ │ detect version │ alpine-release → v3.14 │ fetch SecDB │ main.json + community.json ── internal/matcher │ merge + index │ map[pkg] → secfixes └─────────┬─────────┘ │ vulnerability database ▼ ┌───────────────────┐ │ match versions │ installed < fixed ? (apk-aware) │ score severity │ risk score → LOW…CRITICAL ── cmd/scanner │ render report │ text or JSON, apply --fail-on └─────────┬─────────┘ ▼ report + exit code ``` 单行 Pipeline: ``` docker pull → docker save → stream layers → SBOM → SecDB → match → report ``` ### 项目结构 - `cmd/scanner/main.go` — **CLI 入口点**、匹配循环、评分和报告渲染。 - `internal/extractor/` — 拉取并保存 **Docker 镜像**,并提供受权限保护的流式 tar 遍历器。 - `internal/analyzer/` — 读取清单并流式传输镜像层,以从 Alpine 包数据库构建 **SBOM**。 - `internal/matcher/` — 获取/合并 **SecDB** 并提供**支持 APK 的版本比较**。 ## 为什么需要自定义 APK 版本比较器? 判断一个已安装的包是否存在漏洞,归根结底是一个 问题:*已安装的版本是否早于修复该 CVE 的版本?* 这个比较是整个工具的**正确性核心** — 如果弄错了, 扫描器就会默默地产生**假阴性**(遗漏漏洞)或 **假阳性**。因此我们自己实现了它,位于 [`internal/matcher/version.go`](internal/matcher/version.go),而不是引入 依赖。原因有三: 1. **APK 版本不是 semver。** Alpine 版本包含预发布后缀 (`_alpha`, `_beta`, `_pre`, `_rc`)、后发布后缀 (`_cvs`, `_svn`, `_git`, `_hg`, `_p`) 以及内部版本号 (`-rN`)。其顺序是 `1.2_pre1 < 1.2 < 1.2_p1`。通用的 **semver 库** (`Masterminds/semver`, `hashicorp/go-version`, …) 实现了 semver 规范, 而该规范没有这些后缀的概念 — 它们会将 `1.2.2_pre2` 解析为 垃圾数据,或者将其排名*高于* `1.2.2`, 从而导致在那些极其关键的棘手情况下得出完全相反的结果。 2. **规范的实现是 C 语言。** 权威的排序逻辑存在于 apk-tools 的 **`apk_version.c`** 中。直接移植其**基于 token 的比较** (≈200 行纯 Go 代码,几乎没有内存分配)比封装 **cgo** 或采用庞大的第三方移植要小巧得多,也更容易审计。 3. **掌握代码让我们能够对其进行穷尽测试,且供应链风险为零。** 比较器是**纯逻辑**,因此有**表驱动**测试和一条包含 **17 个元素的规范排序链**作为支撑,对两个方向的所有配对都进行了检查。 对于安全工具而言,保持 `go.mod` 不包含第三方依赖本身就是 一项功能(参见 [CONVENTIONS.md](CONVENTIONS.md)) — 这样就**没有传递依赖** 需要审计、固定版本或信任。 ## 要求 - **Go `1.26.1`**(如 [go.mod](go.mod) 中所定义) - **Docker CLI** + 正在运行的 **Docker daemon** - 可访问 `secdb.alpinelinux.org` 的网络 ## 快速开始 ``` go run cmd/scanner/main.go --image alpine:3.14 ``` CI 风格运行(JSON 输出 + 失败策略): ``` go run cmd/scanner/main.go --image alpine:3.14 --format json --fail-on high ``` 构建独立的二进制文件: ``` go build -o sentinel ./cmd/scanner ./sentinel --image alpine:3.14 ``` ## 示例输出 这是一次对 `alpine:3.14` 的真实扫描。当前镜像已完全修补 — 其五个包拥有 SecDB 通告,但每一个都已经处于或高于修复 版本,因此没有被标记出任何问题: ``` === SENTINEL CONTAINER SCANNER === Target: alpine:3.14 [*] Phase 1: Extracting Image... Pulling image 'alpine:3.14' from registry... Saving image 'alpine:3.14' (using binary: /usr/local/bin/docker)... [*] Phase 2: Analyzing Layers... Found Alpine package database in layer: blobs/sha256/422ed46b1a92... -> Generated SBOM with 14 installed packages. [*] Phase 3: Vulnerability Matching... -> Detected Alpine OS Version: v3.14 -> Loaded 462 packages from Alpine SecDB. === VULNERABILITY REPORT === [✓] No known vulnerabilities found! Your image is clean. === SCAN CONTEXT === - Scanned At (UTC) : 2026-06-19T15:13:58Z - Installed Packages : 14 - SecDB Packages Loaded : 462 - Packages Matched In DB : 5 - Vulnerable Packages : 0 - Unique CVE Findings : 0 - Highest Severity : NONE ``` 扫描一个较旧的、已停止维护的标签会暴露出真实的发现。在这里,`alpine:3.10` 报告了一个存在漏洞的 `apk-tools` 及其 CVE、严重性和修复建议: ``` === SENTINEL CONTAINER SCANNER === Target: alpine:3.10 [*] Phase 1: Extracting Image... Pulling image 'alpine:3.10' from registry... Saving image 'alpine:3.10' (using binary: /usr/local/bin/docker)... [*] Phase 2: Analyzing Layers... Found Alpine package database in layer: blobs/sha256/26d14edc4f17... -> Generated SBOM with 14 installed packages. [*] Phase 3: Vulnerability Matching... -> Detected Alpine OS Version: v3.10 -> Loaded 285 packages from Alpine SecDB. === VULNERABILITY REPORT === [!] VULNERABILITY FOUND: apk-tools - Installed Version : 2.10.6-r0 - Earliest Fix In : 2.10.7-r0 - Severity : LOW (score: 30/100) - CVEs : CVE-2021-36159 - Remediation : Upgrade apk-tools to version 2.10.7-r0 or newer, then rebuild and redeploy the image. [!] Scan complete. 1 unique CVE findings detected. === SCAN CONTEXT === - Scanned At (UTC) : 2026-06-19T15:16:33Z - Installed Packages : 14 - SecDB Packages Loaded : 285 - Packages Matched In DB : 3 - Vulnerable Packages : 1 - Unique CVE Findings : 1 - Highest Severity : LOW ``` ## 输出和策略标志 - `--format text|json` (默认值: `text`) - `--fail-on none|low|medium|high|critical` (默认值: `none`) `--fail-on` 使得当最高发现严重性达到或超过阈值时, 扫描器以非零状态退出 — 可使用它来**控制构建或 pipeline**。 ### 退出代码 | 代码 | 含义 | |------|-------------------------------------------------------------| | `0` | 扫描完成;未达到 `--fail-on` 阈值。 | | `1` | 使用或运行时错误(错误的标志、提取/网络失败)。 | | `2` | 扫描完成但触发了 `--fail-on` 阈值。 | ## 已知的局限性 这些是当前范围内的有意边界,不是意外的疏漏。其中一些 已在 [ROADMAP.md](ROADMAP.md) 中被列为路线图项目。 - **仅支持 Alpine。** 检测和 SecDB 数据源是 Alpine 专用的。Debian/Ubuntu (dpkg) 和 RHEL/UBI (rpm) 已计划在 `DistroAdapter` 接口后实现,但尚未 落地。 - **静态镜像层扫描,而非运行时。** 扫描器读取内置在 镜像层中的 apk 数据库。它**不**检查正在运行的容器、观察进程, 也不会捕获运行时安装的包(例如入口点中的 `apk add`)。 - **仅限 OS 包。** 它与 Alpine 包数据库进行匹配。语言级别的 依赖项(`node_modules`, `go.mod`, `requirements.txt`, …)尚未被扫描。 - **严重性衍生自 CVE 数量,而非 CVSS。** 具有一个严重 RCE 漏洞的包 目前的得分可能低于具有多个低影响问题的包。真实的 CVSS 评分(通过 NVD/OSV)是第二阶段的首要路线图项目。 - **需要 Docker daemon。** 镜像通过 `docker pull`/`docker save` 获取。 无 daemon 的 registry 拉取已在计划中。 - **结果追踪实时的 SecDB 快照。** 随着建议 数据的演变,即使镜像标签固定,发现结果也可能随时间而变化。 ## 运行测试 ``` go test -race ./... ``` ## 贡献 开发约定(包边界、错误处理、测试、 零依赖策略)已在 [CONVENTIONS.md](CONVENTIONS.md) 中记录,计划中的工作在 [ROADMAP.md](ROADMAP.md) 中跟踪。
标签:Docker安全, EVTX分析, Go, LLM防护, Ruby工具, SBOM, 动态分析, 文档结构分析, 日志审计, 硬件无关, 请求拦截