4

开源容器镜像扫描 trivy 懒人重点指南

 1 week ago
source link: https://zhangguanzhang.github.io/2024/04/22/trivy/#/%E5%8F%82%E8%80%83
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

写给那些不爱看文档和自己使用中应该注意的一些技巧

介绍下 trivy 的使用和一些注意的点

介绍和安装

trivy 是一个漏洞安全扫描,可以扫描

  • Container Image
  • Filesystem
  • Git Repository (remote)
  • Virtual Machine Image
  • Kubernetes

因为是 golang 开发的,安装非常简单 release 页面找到最新的 release,点击 Show all xx aseets 后下载 trivy_x.xx.x_Linux-64bit.tar.gz 下来解压即可。

trivy 的 cmd 和 option 是使用 cobra 框架写的,支持子命令和全局选项,可以trivy -htrivy image -h 依次查看对应的命令帮助。

扫描示例:

$ trivy image debian:12
$ trivy image --input debian-12.tar.gz
$ trivy repo https://github.com/knqyf263/trivy-ci-test
$ trivy k8s --report summary cluster

可以自行研究下命令参数和看官方文档,这里不写详细的,很多还是要看官方文档。

trivy 在执行扫描的时候,会下载两个 db文件:

  • ghcr.io/aquasecurity/trivy-db
  • ghcr.io/aquasecurity/trivy-java-db

该文件是 oci(application/vnd.oci.image.manifest.v1) 镜像格式的,同时是存储在 ghcr 的 github 镜像仓库上的,国内可能能拉取到,更大可能是拉取不到。可以使用国内的同步源:

  • m.daocloud.io/ghcr.io/aquasecurity/trivy-db
  • m.daocloud.io/ghcr.io/aquasecurity/trivy-java-db

命令行参数为:

trivy image --db-repository m.daocloud.io/ghcr.io/aquasecurity/trivy-db \
--java-db-repository m.daocloud.io/ghcr.io/aquasecurity/trivy-java-db \
debian:12

cve 准确性

我们内部使用扫描后,客户现场扫描的报告,查看了结果两者不是一样的,属于两者结果有部分交集的结果。查看官方文档 vulnerability 章节说明了前面俩 db 的数据来源,并不是比较全的 cve 列表,同时 trivy-db 是每隔 6 个小时构建更新的

内部 ci 上使用

先得解决机器无法拉取 github 镜像仓库,需要配同步到内网镜像仓库上比较好,另外 oci 格式是不支持 docker pull 的,可以使用 skopeo 的 sync 命令每天定时间隔同步:

skopeo --insecure-policy sync --src docker --dest docker m.daocloud.io/ghcr.io/aquasecurity/trivy-db xxx.com/ci-run/

skopeo --insecure-policy sync --src docker --dest docker m.daocloud.io/ghcr.io/aquasecurity/trivy-java-db xxx.com/ci-run/

根据官方文档 trivy_server 支持 client/server 模式的,server 是一直运行的:

trivy server
trivy image --server http://localhost/remote:4954 alpine

对于我们好多节点还有地域性质的 jenkins 构建场景不适合,同时每个单独运行的话,由于 db 默认是下载后解压到 ~/.cache/trivy 下的文件,默认的 --cache-backend 是 fs,多 jenkins 构建机器的话,会每次运行都下载很浪费容量。

查看了官方文档 cache 支持 redis 作为缓存的,但是从 -h 选项和文档里示例的都是 tls 的 redis 链接方式,对于密码方式就不支持,然后查看源码:

// https://github.com/aquasecurity/trivy/blob/63c9469bdd91ee71ee643862329a3948b42c561d/pkg/commands/operation/operation.go#L43-L69
func NewCache(c flag.CacheOptions) (Cache, error) {
if strings.HasPrefix(c.CacheBackend, "redis://") {
log.Info("Redis cache", log.String("url", c.CacheBackendMasked()))
options, err := redis.ParseURL(c.CacheBackend)
if err != nil {
return Cache{}, err
}

if !lo.IsEmpty(c.RedisOptions) {
caCert, cert, err := GetTLSConfig(c.RedisCACert, c.RedisCert, c.RedisKey)
if err != nil {
return Cache{}, err
}

options.TLSConfig = &tls.Config{
RootCAs: caCert,
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
}
} else if c.RedisTLS {
options.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
}
}

redisCache := cache.NewRedisCache(options, c.CacheTTL)
return Cache{Cache: redisCache}, nil
}

发现 redis 的 client 库是使用的 go-redis,查看它的官方文档,发现可以 DSN 形式传入密码:

opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")

同时,不推荐命令行带参数,不然会泄露密码,参考官方文档configuration 使用配置文件:

db:
repository: m.daocloud.io/ghcr.io/aquasecurity/trivy-db
java-repository: m.daocloud.io/ghcr.io/aquasecurity/trivy-java-db
cache:
backend: "redis://:xxx@redis-server:6379"

一开始报错 noauth,后面发现必须加冒号,没有用户名就是上面这样的格式,同时官方文档说明了,对于每一个长选项,都可以使用环境变量代替,例如:

trivy --config xxx.yml xxx
TRIVY_CONFIG=xxx.yml trivy xxx

这样 ci 里运行也不用带 cmdline 泄露配置文件路径。当然还支持模板和 output format 以及设置 --exit-code 会在 ci 里很实用。避免扫描的时候下载缓存失败导致扫描结果没出来,可以扫描之前,执行下:

until trivy image --download-db-only --download-java-db-only; do
echo "Command failed. Retrying..."
sleep 1
done

jenkins 里,扫描可以使用官方的 html.tpl 模板,最后用 publishHTML 展示。由于 trivy 不支持一次扫描多个镜像,可以把官方的模板文件下载后分割成三部分拼接:

cp "${tpl_dir}/trivy-html-head.tpl" report.html
while read -r line; do
if [ -f "$line" ];then
trivy image --format template --template "@${tpl_dir}/trivy-html-body.tpl" -o report.tmp --input $line
cat report.tmp >> report.html
# break
fi
done < "/dev/stdin"
rm -f report.tmp
cat "${tpl_dir}/trivy-html-end.tpl" >> report.html

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK