目录
目录X
联系信息 首页 /正文内容

Trivy 离线漏洞扫描

AI摘要(BLUF)
> 场景:不能联网的银河麒麟 V10 高级服务器(aarch64 / ARM64) 做系统包漏洞扫描。> 本文命令可直接复制粘贴执行,下载地址、文件大小、输出数据均经实测。1. 这是干嘛的Trivy 是 Aqua Security 开源的漏洞扫描器。它用一个本地漏洞库(trivy-db)去比对机器上装的软件包版本,输出「哪个包、哪个 CVE、当前版本、修复版本」。为什么需要"离线包":Trivy 默认每次运行都会联网更新漏洞库。目标服务器不能联网,所以要把「二进制 + 漏洞库 + 配置」整套打进去,并让它彻底不联网。它扫什么:本方案只做系统包(RPM)的 CVE。配置缺陷、密钥泄露……


> 场景:不能联网的银河麒麟 V10 高级服务器(aarch64 / ARM64) 做系统包漏洞扫描。 > 本文命令可直接复制粘贴执行,下载地址、文件大小、输出数据均经实测。


1. 这是干嘛的


Trivy 是 Aqua Security 开源的漏洞扫描器。它用一个本地漏洞库(trivy-db)去比对机器上装的软件包版本,输出「哪个包、哪个 CVE、当前版本、修复版本」。


为什么需要"离线包":Trivy 默认每次运行都会联网更新漏洞库。目标服务器不能联网,所以要把「二进制 + 漏洞库 + 配置」整套打进去,并让它彻底不联网。


它扫什么:本方案只做系统包(RPM)的 CVE。配置缺陷、密钥泄露、语言依赖(pip/npm/jar)不在范围内。


2. 去哪下载


2.1 主程序 trivy


官方发布页:https://github.com/aquasecurity/trivy/releases


直接下载(在能联网的机器上执行,下载机和目标机架构可以不同):


VER=0.74.0
ARCH=ARM64      # 目标机是 aarch64 用 ARM64;x86_64 改成 AMD64
curl -fL -o trivy.tar.gz \\
  "https://github.com/aquasecurity/trivy/releases/download/v${VER}/trivy_${VER}_Linux-${ARCH}.tar.gz"
tar -xzf trivy.tar.gz trivy


如果这一步卡住或下下来是 0 字节(企业网关拦截 Release CDN 的典型表现:HTTP 200 但内容是空的),换 ghcr.io 的容器镜像通道:ghcr.io/aquasecurity/trivy 的镜像层里就有 /usr/local/bin/trivy,用 oras 或 OCI Distribution API 拉下来再解层取二进制。验证方式见 2.3。


2.2 漏洞库 trivy-db


只有 OCI 通道,没有传统下载链接。以下命令已实测可跑通:


TOKEN=$(curl -s "https://ghcr.io/token?scope=repository:aquasecurity/trivy-db:pull&service=ghcr.io" \\
        | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
  
DIGEST=$(curl -s -H "Authorization: Bearer $TOKEN" \\
         -H 'Accept: application/vnd.oci.image.manifest.v1+json' \\
         https://ghcr.io/v2/aquasecurity/trivy-db/manifests/2 \\
         | python3 -c 'import sys,json;print(json.load(sys.stdin)["layers"][0]["digest"])')
  
curl -L -H "Authorization: Bearer $TOKEN" -o trivy-db.tar.gz \\
     "https://ghcr.io/v2/aquasecurity/trivy-db/blobs/$DIGEST"
  
mkdir -p db && tar -xzf trivy-db.tar.gz -C db
ls -lh db/          # 应看到 trivy.db(解压后约 1.4 GB)和 metadata.json


实测当前层大小约 121 MB(压缩),解压后约 1.4 GB。


2.3 务必校验


# ① 是不是正确的架构(不装 file 也能查)
python3 - <<'PY'
import struct
d = open('trivy','rb').read(20)
mach = struct.unpack_from('<H', d, 18)[0]
print('ELF' if d[:4]==b'\\x7fELF' else '!! 不是 ELF',
      {0xb7:'aarch64', 0x3e:'x86_64'}.get(mach, '未知架构'))
PY
# 期望输出:ELF aarch64
  
# ② 漏洞库完整性
sha256sum trivy-db.tar.gz


3. 怎么部署


3.1 关键一步:修掉漏洞库的时间戳


Trivy 判断「需不需要更新」靠 metadata.json 里的 DownloadedAt。用 OCI 方式拉下来的库这个字段是零值,Trivy 无法区分「首次运行 / OCI 下载 / 文件损坏」,于是每次运行都警告 Trivy DB may be corrupted 并去联网更新——离线机上就是直接失败。必须改掉:


python3 - <<'PY'
import json
p = "db/metadata.json"
m = json.load(open(p))
if str(m.get("DownloadedAt","")).startswith("0001-"):
    m["DownloadedAt"] = m["UpdatedAt"]
    json.dump(m, open(p, "w"), separators=(",", ":"))
print("DownloadedAt =", m.get("DownloadedAt"))
PY
cat db/metadata.json


3.2 打包带到离线机


mkdir -p trivy-offline-pkg && cd trivy-offline-pkg
cp ../trivy . && cp ../trivy-db.tar.gz . && chmod 755 trivy
tar -czf ../trivy-offline-pkg-aarch64.tar.gz -C .. trivy-offline-pkg
sha256sum ../trivy-offline-pkg-aarch64.tar.gz


把 tar.gz 拷到离线机(U 盘 / 内网传输都行),然后:


tar -xzf trivy-offline-pkg-aarch64.tar.gz && cd trivy-offline-pkg


3.3 安装并让 sudo 也生效


sudo mkdir -p /usr/local/lib/trivy /etc/trivy /var/lib/trivy
sudo cp trivy /usr/local/lib/trivy/trivy
sudo chmod 755 /usr/local/lib/trivy/trivy
  
# 铺开漏洞库
sudo mkdir -p /var/lib/trivy/db
sudo tar -xzf trivy-db.tar.gz -C /var/lib/trivy
  
# 写配置文件(注意 key 名和命令行 flag 不一样)
sudo tee /etc/trivy/trivy-offline.yaml >/dev/null <<'YAML'
cache:
  dir: /var/lib/trivy
db:
  skip-update: true
  java-skip-update: true
scan:
  offline: true
pkg:
  types: [os]
YAML
  
# 装一层 wrapper:把配置写进命令行,绕开 sudo 丢环境变量的问题
sudo tee /usr/local/bin/trivy >/dev/null <<'SH'
#!/bin/sh
exec /usr/local/lib/trivy/trivy --config /etc/trivy/trivy-offline.yaml "$@"
SH
sudo chmod 755 /usr/local/bin/trivy
  
# 校验
trivy --version
sudo trivy --version          # sudo 下也必须能跑


为什么必须装 wrapper:sudo 会重置环境变量,/etc/profile.d 里设的 TRIVY_* 传不进被 sudo 执行的命令,Trivy 就会走「检查更新」分支去联网。wrapper 把参数写死在命令行里,任何调用方式都生效。


如果要用 TRIVY_* 环境变量,再补一个 sudoers 放行(写完必须校验,写坏会导致 sudo 整体不可用):


sudo tee /etc/sudoers.d/trivy-offline >/dev/null <<'EOF'
Defaults env_keep += "TRIVY_CACHE_DIR TRIVY_CONFIG TRIVY_DISTRO"
EOF
sudo chmod 0440 /etc/sudoers.d/trivy-offline
sudo visudo -c -f /etc/sudoers.d/trivy-offline


4. 部署完怎么用


# 体检:看版本、配置、漏洞库、发行版识别是否就绪
trivy --version
  
# 扫本机(最小可用命令)
sudo trivy rootfs --scanners vuln --pkg-types os /
  
# 导出成文件
sudo trivy rootfs --scanners vuln --pkg-types os -f json -o /root/cve.json /
sudo trivy rootfs --scanners vuln --pkg-types os -f table -o /root/cve.txt /


国产系统必须补一个参数:麒麟的 /etc/os-release 里 ID=kylin,不在 Trivy 的发行版列表里,不加处理会输出 Unsupported os family="none"、什么都扫不出。麒麟 V10 属 RHEL8/CentOS8 生态,直接映射:


sudo trivy rootfs --scanners vuln --pkg-types os --distro redhat/8 -f table /


结果怎么看


kernel-headers (redhat 8.4)
\================================
Total: 3 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 1)
┌───────────────┬─────────────────┬──────────┬───────────────────┬───────────────┬─────────────────┐
│    Library    │ Vulnerability   │ Severity │ Installed Version │ Fixed Version │      Title      │
├───────────────┼─────────────────┼──────────┼───────────────────┼───────────────┼─────────────────┤
│ openssl-libs  │ CVE-2023-5678   │ HIGH     │ 1.1.1k-7.ky10     │ 1.1.1k-12.el8 │ openssl: ...    │
│ kernel        │ CVE-2026-72319  │ MEDIUM   │ 4.19.90-25.ky10   │               │ kernel: ipvs... │
└───────────────┴─────────────────┴──────────┴───────────────────┴───────────────┴─────────────────┘


  • Fixed Version 是最关键的一列:有值 = 厂商已出修复版本;空白 = 漏洞库里没有修复版本信息。

  • ⚠ Fixed Version 是 RHEL 的版本号,不是你的目标版本。 国产系统的包版本号体系不同(.ky10 后缀、rebase 过的功能版本),不能照抄。要拿 CVE 编号去厂商官方通道查实际修复版本。

  • UNKNOWN 一大堆不是"低风险",是库里没有该 CVE 的 CVSS 评分,要单独人工看。


三个必踩的坑


报错原因解决
Trivy DB may be corrupted and will be re-downloadedmetadata.json 的 DownloadedAt 是零值 + sudo 丢了环境变量见 3.1 + 3.3
'--skip-java-db-update' cannot be specified on the first run传了跳过 java-db 但 java-db 元数据不存在。只在 jar 分析器被调用时才检查加 --pkg-types os(禁用全部语言分析器)
Unsupported os family="none"发行版不在 Trivy 列表里加 --distro redhat/8


5. 实测例子:麒麟 V10 上的「假的 0 漏洞」


环境:银河麒麟 V10 高级服务器,aarch64,rpm -qa 共 1454 个包。Trivy v0.74.0,漏洞库更新于 2026-09-28。


第一次扫描的结果:


$ sudo trivy rootfs --scanners vuln --pkg-types os --distro redhat/8 -f table /
INFO  Detected OS  family="redhat" version="8"
INFO  [redhat] Overriding detected OS with provided distro  detected="none" provided="redhat/8"
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)


退出码 0、不报错、1 秒结束、0 漏洞。看起来系统很干净。


真相:加上 --debug 才看到


DEBU [redhat] Skipping third-party packages  packages=[...几乎全部包名...]


根因(读源码确认):Trivy 的 RPM 分析器默认把所有包标记为 third-party,只有厂商名命中一份硬编码白名单才改判为 official。这份白名单只有十来家上游厂商(Red Hat、CentOS、Fedora、AlmaLinux、Rocky、Oracle、SUSE、Amazon、VMware、Microsoft 等),一个国产发行版都没有。于是本地包全被判 third-party,被 DropThirdPartyPackages 整批丢弃,0 个包进入 CVE 匹配,自然 0 漏洞。


本机的厂商分布正好说明问题:


%{VENDOR}包数命中白名单
KylinSoft1117否
KylinOS311否
(空)19否
kylin4否
Xiph.org / OCI / JingJiaMicro3真第三方,本就该丢


教训:0 漏洞 不等于安全,它可能意味着「扫描器根本没看见你的包」。交付前必须做阳性对照——先确认扫描器认出了你的资产。修法见《给 Trivy 打国产系统适配补丁》一篇。


【打印正文】 发布时间:2026-10-12 09:53:11 浏览次数: 次 作者: 来源:本站原创