Trivy离线扫描:容器安全实践指南

一、Trivy简介

1.1 Trivy 概述

Trivy 是一款全面多功能的安全扫描器。Trivy具有寻找安全问题和目标的扫描器。现已经被 Github Action、Harbor 等主流工具集成,Trivy支持大多数流行的编程语言、操作系统和平台的扫描,应该是该领域目前目前采用最广的开源工具之一了。

1.2 Trivy可扫描的内容

  • 容器镜像
  • 文件系统
  • Git存储库(远程)
  • 虚拟机镜像
  • Kubernetes
  • AWS

Trivy支持大多数流行的编程语言、操作系统和平台。有关完整列表,请参阅扫描范围页面

  • 正在使用的操作系统包和软件依赖关系(SBOM)
  • 已知漏洞(CVE)
  • IaC问题和配置错误
  • 敏感信息和秘密
  • 软件许可证

目前支持的操作系统

1.3 Trivy 的工作原理

Trivy 自身只是一个扫描工具,实际上支撑这个工具的还有一个工具链,多种工具/库的协同,完成了从 CVE 到扫描识别的各个环节

其中包括:

  • vuln-list-update: 负责更新各个来源的威胁数据,转换成 JSON 数据,保存在 vuln-list 项目之中。
  • trivy-db: 既是工具,也是库,用于操作 Trivy 的数据库。
  • fanal: 从 vuln-list 获取数据,并构建成 bbolt 格式的数据库文件,可以用 upload 命令上传到 Github Release。
  • Trivy: 获取 trivy-db 的 Release 数据,进行漏洞扫描工作。

综上所述,Trivy 的总体工作流程:

  1. 从操作系统厂商等 CVE 源获取数据,使用 vuln-list-update 脚本进行汇总,转换为一致的 JSON 数据,保存到 vuln-list 项目。
  2. trivy-dbvuln-list 下载数据,转换为 bbolt 格式,发布到 trivy-db 的 Release。
  3. Trivy 下载 trivy-db 数据,作为本地检测的数据源。

二、Trivy安装&配置离线库

2.1 二进制部署Trivy

  • Trivy 支持多种部署方式,常见的有rpm包,deb包, 通用二进制源码部署,当然也支持docker部署, 详细的安装手册

方便快速部署升级,我采用了二进制的部署方式,下载地址: https://github.com/aquasecurity/trivy/releases/tag/v0.49.1

bash 复制代码
#下载加速地址:
[root@openeuler ~]# wget https://github.com/aquasecurity/trivy/releases/download/v0.49.1/trivy_0.49.1_Linux-64bit.tar.gz

[root@openeuler ~]# tar -xf trivy_0.49.1_Linux-64bit.tar.gz

[root@openeuler ~]# mv ./trivy /usr/local/bin/

[root@openeuler ~]# chmod +x /usr/local/bin/trivy

[root@openeuler ~]# which trivy
/usr/local/bin/trivy

2.2 配置离线漏洞库

2.2.1 了解官方漏洞库的生成过程

Trivy 漏洞库是以符合 OCI 制品的方式发布。OCI,Open Container Initialtive,是目前通用的镜像格式规范,以 Docker 镜像规范 v2 为基础制定的,是围绕容器格式和运行时开放的行业标准。它定义了镜像的主要格式及内容,主要用于镜像仓库存放镜像及分发镜像等场景。

官方漏洞库的生成过程,涉及到这几个项目:

  • trivy-db:制作 Trivy 漏洞库,并发布。(注意不要和 trivy.db 弄混)
  • 早期还有一个 fanal 项目,已经被合并到 trivy-db 项目中。(注意不要和 fanal.db 弄混)
  • vuln-list:存储漏洞信息,并定期发布以 main.tar.gz 压缩包形式发布。
  • vuln-list-update: 负责收集各个来源的漏洞信息。
  • Trivy 官方使用该工具每天从 NVD, RedHat, Debian, Ubuntu, Alpine 等渠道收集漏洞信息,转换成符合要求的 JSON 格式数据,保存在 vuln-list 项目之中。

简单来说就是,trivy-db 会去源头下载漏洞信息库。语言漏洞库,包括 ruby、php 和 node.js,来自各官方项目的漏洞库,常用的数据源包括 NVD(National Vulnerability Database)和 Red Hat CVE 数据库等。其次,trivy-db 会将原始压缩包解压、解析、合并,并生成 bboltDB 格式的 trivy.db 漏洞库文件,同时生成 metadata.json 文件。最后,trivy-db 以 OCI 制品的方式将它们打包生成 db.tar.gz 压缩包,并发布到 ghcr.io/aquasecurity/trivy-db,供 trivy 远程下载。

2.2.2 trivy-db离线漏洞库

trivy-db,是一个包含漏洞数据库的开源项目,用于帮助开发人员和安全团队识别容器镜像中的漏洞。它可以与 trivy 工具配合使用,帮助用户快速发现容器镜像中存在的安全漏洞,并提供修复建议。trivy-db 中包含了各种已知的漏洞信息,Trivy在内部使用 trivy-db 来操作漏洞数据库。此数据库包含来自NVD、Red Hat、Debian等的漏洞信息。用户可以通过更新 trivy-db 来获取最新的漏洞数据以保持镜像的安全性。

2.2.3 trivy-java-db离线漏洞库

trivy-java-db 是 Trivy 工具的一个组件,用于存储 Java 相关的漏洞数据库。Trivy 是一个开源的漏洞扫描工具,用于帮助用户检测容器镜像中的安全漏洞。trivy-java-db 会包含 Java 相关的漏洞信息,用户可以通过更新 trivy-java-db 来获取最新的漏洞数据以保持镜像的安全性。这个组件可以帮助用户识别容器镜像中与 Java 相关的漏洞,并提供修复建议,以提高容器镜像的安全性。

2.2.4 使用oras下载漏洞数据库

Trivy DB v2托管在GHCR上。虽然GitHub默认显示 docker pull 命令,但请注意,它不能使用 docker pull 下载,因为它不是容器映像。

官方推荐使用oras工具 去下载漏洞库。

oras 是一个开源项目,是 Open Container Initiative (OCI) 的一个子项目,用于定义和实现容器镜像的存储和传输规范。它提供了一个统一的标准,使得容器镜像可以在不同的容器运行时中进行共享和交换。oras 支持将容器镜像存储在各种不同的后端存储系统中,如容器注册表、对象存储等,并提供了用于上传、下载和管理容器镜像的工具和库。oras 旨在提供一个开放、灵活和可扩展的容器镜像存储和传输解决方案,使得容器技术更加便捷和可移植。

二进制安装oras

官方下载地址:https://github.com/oras-project/oras/releases/download/v1.1.0/oras_1.1.0_linux_amd64.tar.gz

复制代码
#加速下载地址:
[root@openeuler ~]# wget https://gh.api.99988866.xyz/https://github.com/oras-project/oras/releases/download/v1.1.0/oras_1.1.0_linux_amd64.tar.gz

[root@openeuler ~]# tar -xf oras_1.1.0_linux_amd64.tar.gz

[root@openeuler ~]# mv oras /usr/local/bin/
[root@openeuler ~]# chmod +x /usr/local/bin/oras 
[root@openeuler ~]# which oras
/usr/local/bin/oras

离线库下载地址:

配置离线库

复制代码
#创建离线库数据目录
[root@openeuler ~]# mkdir -p /home/application/trivy-db/{db,java-db}

[root@openeuler ~]#cd  /home/application/trivy-db

#下载trivy-db离线库
[root@openeuler trivy-db]# oras pull ghcr.nju.edu.cn/aquasecurity/trivy-db:2

Downloading b520fb99698f db.tar.gz
Downloaded  b520fb99698f db.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-db:2
Digest: sha256:c62e392709fe1070c397f763535f364a1e273377e7220117dbdde4086eef6a7d

#下载trivy-java-db离线库
[root@openeuler trivy-db]# oras pull ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1

Downloading cd5ea8aec93d javadb.tar.gz
Downloaded  cd5ea8aec93d javadb.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
Digest: sha256:760ebdf834a5772413beda8c126c2f7c04d26cea6baf572e50a69fc698a5f0b9


[root@openeuler trivy-db]# ls -l
总用量 569992
drwxr-xr-x 2 root root      4096  3月 13 13:57 db
-rw-r--r-- 1 root root  46383125  3月 13 13:58 db.tar.gz
drwxr-xr-x 2 root root      4096  3月 13 13:57 java-db
-rw-r--r-- 1 root root 537270294  3月 13 13:59 javadb.tar.gz


#解压离线库
[root@openeuler trivy-db]# tar -xf db.tar.gz -C db
[root@openeuler trivy-db]# tar -xf javadb.tar.gz -C java-db


#查看离线库文件
[root@openeuler trivy-db]# ls -l db
总用量 436256
-rw-r--r-- 1 tsingyun-dev 127       143  3月 13 02:13 metadata.json
-rw------- 1 tsingyun-dev 127 446722048  3月 13 02:13 trivy.db


[root@openeuler trivy-db]# ls -l java-db
总用量 849416
-rw-r--r-- 1 tsingyun-dev 127       143  3月 13 08:45 metadata.json
-rw-r--r-- 1 tsingyun-dev 127 869793792  3月 13 08:45 trivy-java.db

三、Trivy使用

3.1 扫描镜像

使用Trivy扫描镜像的漏洞。

trivy [global flags] command [flags] target

trivy [command]

每种扫描能力,对应一种命令:

  • aws 【实验性】扫描 AWS 账户
  • config 扫描错误配置 Scan config files for misconfigurations
  • filesystem 扫描本地文件
  • image 扫描容器镜像。
  • kubernetes 【实验性】扫描 K8s cluster
  • repository 扫描远程仓库
  • rootfs 扫描 rootfs
  • sbom 根据 SBOM 扫描漏洞(可作为简单的 SCA 工具)。
  • vm 【实验性】扫描虚拟机镜像

我这里以扫描容器镜像为例:

复制代码
$ trivy image {image_name}:{tag}

可选参数:

  • --cache-dir ,指定漏洞数据库的本地缓存目录,默认在是 ~/.cache/trivy

  • --skip-db-update, 扫描启动的时候,会检查本地漏洞库。如果超过 12 小时为更新,会自动下载更新漏洞库。由于官方漏洞库放在 github,下载比较慢,可以使用 --skip-db-update 跳过这一过程。

  • --skip-java-db-update 同样java 的漏洞库,每周四凌晨自动更新,也是存在github上,以使用--skip-java-db-update 跳过这一过程。

  • --severity CRITICAL , 指定扫描的严重程度,分为,CRITICAL[紧急],HIGH[高的],MEDIUM[中等],LOW[低的]

  • --vuln-type , 指定想要扫描的漏洞种类 , os仅扫描目标(比如容器镜像或文件系统)中操作系统包含的已知漏洞; library 应用程序库的漏洞扫描;

    --vuln-type os,library 同时包含操作系统包和应用程序库的漏洞扫描

  • -f ,指定输出的格式,默认的输出格式是 table, 以表格的形式显示扫描结果。-f json 以json 格式输出结果, 配合 -o 输出文件 ,如 trivy -f json -o nginx.1.22.1.json

  • --ignore-unfixed , 会忽略那些当前没有可用修复的已知漏洞,这个选项对于聚焦于立即可行的修复措施特别有用。在一些场景下,特别是在资源有限或时间紧迫的情况下,您可能更希望先关注那些已经有解决方案的漏洞,而将那些暂时无法解决的漏洞留待以后处理。

示例,扫描一个名为 mysql:5.7.44 的本地 Docker 镜像。

复制代码
[root@openeuler ~]# trivy --cache-dir /home/application/trivy-db image mysql:5.7.44 --skip-db-update --severity CRITICAL
2024-03-14T18:44:04.301+0800	INFO	Vulnerability scanning is enabled
2024-03-14T18:44:04.301+0800	INFO	Secret scanning is enabled
2024-03-14T18:44:04.301+0800	INFO	If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2024-03-14T18:44:04.301+0800	INFO	Please see also https://aquasecurity.github.io/trivy/v0.49/docs/scanner/secret/#recommendation for faster secret detection
2024-03-14T18:44:04.407+0800	INFO	Detected OS: oracle
2024-03-14T18:44:04.407+0800	INFO	Detecting Oracle Linux vulnerabilities...
2024-03-14T18:44:04.413+0800	INFO	Number of language-specific files: 2
2024-03-14T18:44:04.413+0800	INFO	Detecting gobinary vulnerabilities...
2024-03-14T18:44:04.414+0800	INFO	Detecting python-pkg vulnerabilities...

mysql:5.7.44 (oracle 7.9)

Total: 0 (CRITICAL: 0)

2024-03-14T18:44:04.417+0800	INFO	Table result includes only package filenames. Use '--format json' option to get the full path to the package file.

Python (python-pkg)

Total: 1 (CRITICAL: 1)

┌─────────────────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────────────────────────────────────────────────────────┐
│         Library         │ Vulnerability  │ Severity │ Status │ Installed Version │ Fixed Version │                           Title                            │
├─────────────────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────────────────────────────────────────────────────────┤
│ cryptography (METADATA) │ CVE-2020-36242 │ CRITICAL │ fixed  │ 3.2.1             │ 3.3.2         │ python-cryptography: Large inputs for symmetric encryption │
│                         │                │          │        │                   │               │ can trigger integer overflow leading to...                 │
│                         │                │          │        │                   │               │ https://avd.aquasec.com/nvd/cve-2020-36242                 │
└─────────────────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────────────────────────────────────────────────────────┘

扫描之后,以 table 形式展示了该镜像包含的漏洞,提示漏洞所在库(Library)、漏洞编号(Vulnerability)、严重程度(Severity)、当前使用版本(Installed Version)、漏洞修复版本(Fixed Version)以及其他信息(Title)。

Title 信息中有一个网站,说明漏洞的详情,可以更好的帮我们去处理漏洞,如: https://avd.aquasec.com/nvd/cve-2020-36242

3.2 了解本地漏洞库结构

刚刚我们已经下载了离线漏洞库,且使用了trivy 扫描了一个mysql 的镜像,现在我们来看下本地漏洞库的结构

注意!!!Trivy默认的漏洞数据库的本地缓存目录在是 ~/.cache/trivy

我这边自己定义了Trivy 本地缓存目录为 /home/application/trivy-db

复制代码
[root@openeuler application]# tree ./trivy-db/
./trivy-db/
├── db
│   ├── metadata.json
│   └── trivy.db
├── fanal
│   └── fanal.db
└── java-db
    ├── metadata.json
    └── trivy-java.db

3 directories, 5 files

3.2.1 metadata.json

metadata.json 是 trivy.db 漏洞库的更新描述文件。记录了:

  • Version,漏洞库格式的版本,目前为 2。

  • UpdateAt,本次漏洞库更新时间。(是指漏洞库更新的发布时间,并非本地更新时间)

  • NetxUpdate,下次漏洞库更新时间。(官方库默认每 6 小时更新发布一次)

  • DownloadedAt,漏洞库下载时间。

    [root@openeuler application]# cat ./trivy-db/db/metadata.json
    {"Version":2,"NextUpdate":"2024-03-13T00:11:44.883502148Z","UpdatedAt":"2024-03-12T18:11:44.883502428Z","DownloadedAt":"0001-01-01T00:00:00Z"}

注意:如果触发 trivy 更新下载漏洞库过程,trivy 会先删除 metadata.json 文件。此时即便中断更新过程【比如无法科学上网】,再次使用--skip-db-update 仍会重新下载漏洞库直到完整更新流程完成,因为检查 metadata.json 已经被删除了。

3.2.2 fanal.db

fanal.db 使用 blotDB 数据存储格式。blotDB,是一个 key-value 形式的数据库,在 go 语言程序中比较常用,可以用 bbolt 等工具查看。

blotDB,是一个 key-value 形式的数据库,在 go 语言程序中比较常用,可以用 bbolt 等工具查看。blotDB 数据库的顶层是一个 Bucket 桶列表,桶可以继续嵌套子桶。每个桶里面最终存放的是一组 key-value 的数据集合,大致结构如下:

复制代码
* Bucket
    * Bucket
       * key:value
       * key:value
    * key:value
* Bucket
    * key:value
* ......

同样 fanal.db 是容器镜像 ImageID 的快速索引库。trivy 在扫描时可以利用 fanal.db 匹配镜像的 ImageID,快速确认镜像的操作系统、版本等信息。fanal.db 目前包含两个桶,artifact、blob。artifact 有 3 个 key,blob 有 19 个 key。key 都是使用"sha256:哈希值"形式的 ImageID。

每个 Docker 容器镜像,都有一个"sha256:哈希值"形式地 ImageID 来标识。

3.2.3 trivy.db

trivy.db,是漏洞信息的存储库。也是使用 blotDB 作为数据存储格式。trivy.db 有很多存储桶(Bucket)

3.2.4 总结

使用 fanal 漏洞库,快速查询操作系统版本信息

trivy 会提取目标镜像的 ImageID,并根据目标镜像记录的生成关系,计算出其基础镜像的 ImageID。然后,在 fanal.db中保存的 ImageID 进行查询。如果命中,就可以快速确基础镜像对应的操作系统、版本信息等信息。

解析基础镜像的系统文件,获得操作系统版本信息

如果没有,则需要解析基础镜像,并根据其中的操作系统版本文件(etc/alpine-release、usr/lib/os-release、/etc/os-release 等),来确定基础镜像的操作系统版本。这种方式,要比查询 fanal.db 慢一些。

示例的 mysql:5.7 的基础镜像 os-release 文件表明,它是一个 Oracle Linux 7 版本的操作系统。

复制代码
$ sudo cat /var/lib/docker/overlay2/7c2ae603cabf55836770978b28dc133719ce2f43f9c36499308cba1ad080c305/diff/etc/os-release
NAME="Oracle Linux Server"
VERSION="7.9"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="7.9"
PRETTY_NAME="Oracle Linux Server 7.9"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:7:9:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 7"
ORACLE_BUGZILLA_PRODUCT_VERSION=7.9
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=7.9

根据操作系统版本信息,使用不同的检测模块和漏洞库进行检测。

trivy 根据目标基础镜像的操作系统和版本,就可以确定具体的扫描器,在 trivy.db 中使用对应的操作系统版本 Buckets 桶。

trivy 解析目标镜像的文件系统,采集模块和版本信息,并根据模块信息去 trivy.db 中匹配对应模块的漏洞信息。如果找到记录下来,最终形成漏洞检测结果。

例如上文的 mysql:5.7 镜像,在扫描镜像包含的 openssl 库时,会根据操作系统版本,去 trivy.db 的"Oracle Linux 7"、"openssl"桶中查询相关漏洞信息,并最终生成 CVE-2023-0286 漏洞告警。

3.3 定期自动下载离线库

创建本地漏洞库缓存目录

复制代码
mkdir -p /home/application/trivy-db/{db,java-db}

创建download_and_extract.sh 脚本, 前提是 安装好trivyoras 工具

复制代码
#切换到缓存目录下
[root@openeuler trivy-db]# cd /home/application/trivy-db/

#编写脚本
[root@openeuler trivy-db]# vim download_and_extract.sh

#!/bin/bash

#创建缓存目录
mkdir -p /home/application/trivy-db/{db,java-db}

# 清空 db 目录下的内容
rm -rf db/*
# 清空 java-db 目录下的内容
rm -rf java-db/*

# 下载离线库文件
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-db:2

# 解压 jdb.tar.gz 文件到 java-db 目录
tar -xvf javadb.tar.gz -C java-db

# 解压 db.tar.gz 文件到 db 目录
tar -xvf db.tar.gz -C db

# 删除压缩包文件
rm -f javadb.tar.gz
rm -f db.tar.gz

给脚本添加可执行权限

复制代码
[root@openeuler trivy-db]# chmod +x /home/application/trivy-db/download_and_extract.sh

验证

复制代码
#执行脚本
[root@openeuler trivy-db]# bash download_and_extract.sh 
Downloading 17e353961a66 javadb.tar.gz
Downloaded  17e353961a66 javadb.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
Digest: sha256:3330dc2c525849b8bf76c9c4ea1b97bfd69f3a86a8e4a62e7fd1cedab4a4d98c
Downloading 3bf672bda57d db.tar.gz
Downloaded  3bf672bda57d db.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-db:2
Digest: sha256:52e79cf2c9deee18f498dde13da653854eab1c60c358c0b51caa74f712e5e01c
trivy-java.db
metadata.json
trivy.db
metadata.json

#查看数据
[root@openeuler trivy-db]# tree .
.
├── db
│   ├── metadata.json
│   └── trivy.db
├── download_and_extract.sh
├── fanal
│   └── fanal.db
└── java-db
    ├── metadata.json
    └── trivy-java.db

3 directories, 6 files

#执行容器镜像扫描
[root@openeuler trivy-db]# trivy --cache-dir /home/application/trivy-db image nginx:1.25 --skip-db-update --severity CRITICAL,HIGH

添加定时任务

每天凌晨 3 点执行 /home/application/download_and_extract.sh 脚本,实现自动下载和解压离线库文件的操作

复制代码
0 3 * * * /bin/bash /home/application/download_and_extract.sh

四、Trivy和Harbor镜像仓库集成

4.1 安装Docker

编写docker.service文件, 使用systemd管理

复制代码
[root@openeuler ~]# cat > /etc/systemd/system/docker.service <<EOF

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=65535
LimitNPROC=65535
LimitCORE=65535
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

EOF

**[可选] ** 挂载docker默认存储路径

docker的默认工作路径在/var/lib/docker ,最好不修改默认存储路径,可以做软链接

复制代码
#建立docker工作目录
[root@openeuler ~]# mkdir  -p /home/application/docker

#格式化磁盘
[root@openeuler ~]# mkfs.ext4 /dev/sdb

#磁盘永久挂载
[root@openeuler ~]# vim /etc/fstab
/dev/sdb  /home/application/docker  ext4 defaults 0 0

#使挂载生效
[root@openeuler ~]# mount -a


#创建软链接
[root@openeuler ~]# ln -s /home/application/docker /var/lib/

添加可执行权限

复制代码
[root@openeuler ~]# chmod +x /etc/systemd/system/docker.service

启动,加载,开机自启动

复制代码
[root@openeuler ~]# systemctl daemon-reload
[root@openeuler ~]# systemctl start docker.service
[root@openeuler ~]# systemctl enable docker.service

配置镜像加速器

复制代码
[root@openeuler ~]# mkdir -p /etc/docker
[root@openeuler ~]# tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://docker.nju.edu.cn/"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF

[root@openeuler ~]# systemctl daemon-reload
[root@openeuler ~]# systemctl restart docker

验证docker

复制代码
[root@openeuler ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

4.2 安装Docker-Compose

docker 和docker-compose 的版本对应关系:https://docs.docker.com/compose/compose-file/compose-versioning/#version-1-to-2x

下载地址:https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-linux-x86_64

复制代码
[root@openeuler ~]# wget https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-linux-x86_64 -O /usr/local/bin/docker-compose

[root@openeuler ~]# chmod +x /usr/bin/docker-compose

[root@openeuler ~]# docker-compose version
Docker Compose version v2.10.2

4.3 离线安装Harbor

离线包下载地址: https://github.com/goharbor/harbor/releases/download/v2.10.1/harbor-offline-installer-v2.10.1.tgz

复制代码
#创建harbor工作目录,数据目录
[root@openeuler ~]#  mkdir -p /home/application/harbor
[root@openeuler ~]#  mkdir -p /home/application/harbor/data



#切换到harbor工作目录下
[root@openeuler ~]# cd /home/application/harbor


#下载软件包
[root@openeuler harbor]# wget https://github.com/goharbor/harbor/releases/download/v2.10.1/harbor-offline-installer-v2.10.1.tgz

#解压
[root@openeuler harbor]# tar -xf harbor-offline-installer-v2.10.1.tgz 


#重命名软件包
[root@openeuler harbor]# mv harbor harbor-offline-install


#删除harbor-offline-installer-v2.10.1.tgz
[root@openeuler harbor]# rm -rf harbor-offline-installer-v2.10.1.tgz


#查看目录下内容
[root@openeuler harbor]# ls -l
总用量 8
drwxr-xr-x 2 root root 4096  3月 15 17:53 data
drwxr-xr-x 2 root root 4096  3月 15 17:52 harbor-offline-install

编辑配置文件harbor.yml

复制代码
#进入到安装目录下
[root@openeuler harbor]# cd /home/application/harbor/harbor-offline-install

#拷贝harbor.yml
[root@openeuler harbor-offline-install]# cp harbor.yml.tmpl harbor.yml

#编辑harbor.yml配置 文件
[root@openeuler harbor-offline-install]# vim harbor.yml

#!!!注意需要修改的地方!!!!


hostname: harbor.srebro.cn


#只开启http
#注释掉https内容
#后面使用外部的nginx 代理这个harbor的https
# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 80

# https related config
#https:
  # https port for harbor, default is 443
  # port: 443
  # The path of cert and key files for nginx
  #certificate: /your/certificate/path
  # private_key: /your/private/key/path
  # enable strong ssl ciphers (default: false)
  # strong_ssl_ciphers: false

#启用外部代理后,将不再使用主机名
external_url: https://harbor.srebro.cn


#修改Harbor默认密码
harbor_admin_password: [email protected]


#修改数据库默认密码
database:
  # The password for the root user of Harbor DB. Change this before any production use.
  password: Harbor@srebro
  
#Harbor数据目录路径
data_volume: /home/application/harbor/data


#配置trivy相关配置,设置离线配置
trivy:
  ignore_unfixed: false
  skip_update: true
  skip_java_db_update: true
  offline_scan: true
  security_check: vuln
  insecure: false

开始安装harbor

复制代码
#进入到安装目录下
[root@openeuler harbor]# cd /home/application/harbor/harbor-offline-install

#开始安装harbor,离线安装速度很快,大概2分钟
[root@openeuler harbor]# ./install.sh --with-trivy

#安装过程省略,当看到下面的这段话时,表示harbor安装成功
✔ ----Harbor has been installed and started successfully.----

查看Harbor运行状态

复制代码
[root@openeuler harbor-offline-install]# docker-compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
harbor-core         "/harbor/entrypoint...."   core                running (healthy)   
harbor-db           "/docker-entrypoint...."   postgresql          running (healthy)   
harbor-jobservice   "/harbor/entrypoint...."   jobservice          running (healthy)   
harbor-log          "/bin/sh -c /usr/loc..."   log                 running (healthy)   127.0.0.1:1514->10514/tcp
harbor-portal       "nginx -g 'daemon of..."   portal              running (healthy)   
nginx               "nginx -g 'daemon of..."   proxy               running (healthy)   0.0.0.0:80->8080/tcp, :::80->8080/tcp
redis               "redis-server /etc/r..."   redis               running (healthy)   
registry            "/home/harbor/entryp..."   registry            running (healthy)   
registryctl         "/home/harbor/start...."   registryctl         running (healthy)   
trivy-adapter       "/home/scanner/entry..."   trivy-adapter       running (healthy)   

编写service文件,使用systemd管理

复制代码
[root@harbor harbor-offline-install]# cat > /lib/systemd/system/harbor.service <<EOF
[Unit]
Description=Docker Harbor
After=docker.service systemd-networkd.service systemd-resolved.service
Requires=docker.service
Documentation=http://github.com/vmware/harbor

[Service]
Type=simple
Restart=on-failure
ExecStart=/usr/bin/docker-compose -f /home/application/harbor/harbor-offline-install/docker-compose.yml up
ExecStop=/usr/bin/docker-compose -f /home/application/harbor/harbor-offline-install/docker-compose.yml down
RestartSec=5

[Install]
WantedBy=multi-user.target


EOF

启动,加载,开机自启动

复制代码
systemctl enable --now harbor.service

4.4 使用NGINX代理Harbor镜像仓库

  • Nginx安装文档省略

代理配置文件,如下

如果需要配置HTTPS访问,需要配置SSL 证书哦

复制代码
server {
        listen       80;
        listen 443 ssl;
        server_name  harbor.srebro.cn;
        root         /usr/share/nginx/html;
        ssl_certificate /home/application/nginx/cert/harbor.srebro.cn/harbor.srebro.cn.crt;
        ssl_certificate_key /home/application/nginx/cert/harbor.srebro.cn/harbor.srebro.cn.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers on;

        location / {
                proxy_pass http://172.16.10.181:80;
				proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
				client_max_body_size       2000m;
                proxy_set_header   X-Forwarded-Proto https;
                proxy_redirect off;
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
		
}

使用域名访问 https://harbor.srebro.cn

使用docker命令行登录Harbor仓库

复制代码
#登录私有仓库harbor.srebro.cn

[root@openeuler harbor-offline-install]# docker login harbor.srebro.cn
Username (admin): admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

4.5 Harbor 配置定期自动下载Trivy离线库

4.5.1 环境前提

需要安装好Trivyoras 工具

4.5.2 查看Trivy-adapter宿主机的漏洞库缓存路径
复制代码
#查看harbor安装时,生成的docker-compose.yml 文件

[root@openeuler ~]#  cat /home/application/harbor/harbor-offline-install/docker-compose.yml

#找到trivy 相关内容
  trivy-adapter:
    container_name: trivy-adapter
    image: goharbor/trivy-adapter-photon:v2.10.1
    restart: always
    cap_drop:
      - ALL
    depends_on:
      - log
      - redis
    networks:
      - harbor
    volumes:
      - type: bind
        source: /home/application/harbor/data/trivy-adapter/trivy
        target: /home/scanner/.cache/trivy
      - type: bind
        source: /home/application/harbor/data/trivy-adapter/reports
        target: /home/scanner/.cache/reports
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "trivy-adapter"
    env_file:
      ./common/config/trivy-adapter/env

通过查看docker-compose.yml 文件,得知容器外部的漏洞库缓存路径,在/home/application/harbor/data/trivy-adapter/trivy目录下

复制代码
#切换到缓存路径下
[root@openeuler ~]# cd /home/application/harbor/data/trivy-adapter/trivy

查看目录的所属为uid,guid 为10000 的 用户,用户组

后面下载离线库到此路径下,需要chown 授权uid,guid 为10000 的 用户,用户组 ,不然容器内无法访问离线库文件

复制代码
[root@openeuler trivy]# ls -ld
drwxr-xr-x 2 10000 10000 4096  3月 15 18:29 .
4.5.3 定期自动下载Trivy离线库

创建download_and_extract.sh 脚本

复制代码
#切换到trivy-adapter缓存目录下

[root@openeuler ~]# cd /home/application/harbor/data/trivy-adapter/trivy

#编写脚本
[root@openeuler harbor]# vim download_and_extract.sh

#!/bin/bash

#创建缓存目录
mkdir -p /home/application/harbor/data/trivy-adapter/trivy/{db,java-db}

# 清空 db 目录下的内容
rm -rf db/*
# 清空 java-db 目录下的内容
rm -rf java-db/*

# 下载离线库文件
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-db:2

# 解压 jdb.tar.gz 文件到 java-db 目录
tar -xvf javadb.tar.gz -C java-db

# 解压 db.tar.gz 文件到 db 目录
tar -xvf db.tar.gz -C db

# 删除压缩包文件
rm -f javadb.tar.gz
rm -f db.tar.gz

#chown赋权
chown -Rf 10000:10000 /home/application/harbor/data/trivy-adapter/trivy

给脚本添加可执行权限

复制代码
[root@openeuler trivy]# chmod +x download_and_extract.sh 

执行脚本,下载离线库文件

复制代码
[root@openeuler trivy]# ./download_and_extract.sh 

Downloading aacb390976a2 javadb.tar.gz
Downloaded  aacb390976a2 javadb.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
Digest: sha256:9c88e77a0d210afb0bad04be6dbc46200462f4da4c8af73f5b541cfcda01fcac
Downloading 3bf672bda57d db.tar.gz
Downloaded  3bf672bda57d db.tar.gz
Pulled [registry] ghcr.nju.edu.cn/aquasecurity/trivy-db:2
Digest: sha256:52e79cf2c9deee18f498dde13da653854eab1c60c358c0b51caa74f712e5e01c
trivy-java.db
metadata.json
trivy.db
metadata.json


[root@openeuler trivy]# ll db/ java-db/
db/:
总用量 436196
-rw-r--r-- 1 10000 10000       143  3月 15 02:11 metadata.json
-rw------- 1 10000 10000 446656512  3月 15 02:11 trivy.db

java-db/:
总用量 850720
-rw-r--r-- 1 10000 10000       143  3月 15 08:49 metadata.json
-rw-r--r-- 1 10000 10000 871129088  3月 15 08:49 trivy-java.db

添加定时任务

每天凌晨 2 点执行 /home/application/harbor/data/trivy-adapter/trivy/download_and_extract.sh 脚本,实现自动下载和解压离线库文件的操作

复制代码
0 2 * * * /bin/bash /home/application/harbor/data/trivy-adapter/trivy/download_and_extract.sh
4.5.4 验证使用离线库扫描镜像
复制代码
#下载一个mysql8 的最新镜像

[root@openeuler ~]# docker pull mysql:8
8: Pulling from library/mysql
Digest: sha256:9d1c923e5f66a89607285ee2641f8a53430a1ccd5e4a62b35eb8a48b74b9ff48
Status: Downloaded newer image for mysql:8
docker.io/library/mysql:8



#登录私有仓库harbor.srebro.cn

[root@openeuler harbor-offline-install]# docker login harbor.srebro.cn
Username (admin): admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded



#推送镜像到私有仓库
[root@openeuler harbor-offline-install]# docker tag mysql:8 harbor.srebro.cn/library/mysql:8

[root@openeuler harbor-offline-install]# docker push harbor.srebro.cn/library/mysql:8
The push refers to repository [harbor.srebro.cn/library/mysql]
14544546851f: Pushed 
5458227f9e0f: Pushed 
ec9a59df23f2: Pushed 
7fafcf5c6ac1: Pushed 
a5d9662dde43: Pushed 
d8fb47b60f94: Pushed 
7d05fbfb31ee: Pushed 
331304b328ea: Pushed 
96549124ed74: Pushed 
18a3ada103a9: Pushed 
8: digest: sha256:4802e59ea1b51506b1f9137baac8440e1bd6b69ab1c748586859dc0f694916a2 size: 2411

Harbor 仓库中,查看镜像

在harbor控制台中, 扫描镜像,并查看报告

五、Jenkins CI/CD 集成Trivy

Trivy专注于CI环境中的容器镜像漏洞扫描,因此它对于持续集成流程的支持非常好。您可以将Trivy集成到您的CI/CD流水线中,以确保每次构建生成的镜像都经过了安全性检查。

Trivy是一个简单但功能强大的容器漏洞扫描工具,适用于将安全性纳入持续集成流程中,以确保生成的容器镜像始终符合安全标准。无论是开发人员、运维团队还是安全专家,都可以从Trivy的漏洞检测功能中受益。

5.1 trivy 部署

安装过程同上,此处省略

5.2 CI 集成Trivy

**说明:**这里我们需要在Jenkins上安装 HTML Publisher 插件,此插件是用来将构建生成的 HTML 报告发布到作业和构建页面,可方便我们进行查阅。

参数说明:

demo流水线

复制代码
pipeline {
    agent any
 
    stages {
        stage('镜像安全扫描') {
            steps{
                script { 
                    def formatOption = "--format template --template \"@/opt/jenkins/html.tpl\""
 
                    sh("""
                        trivy image --skip-db-update --exit-code 1 --severity CRITICAL <IMAGES>:<TAG> --cache-dir trivy_db $formatOption --timeout 10m --output trivy.html
                    """)
 
                    // reportDir 报告所在目录;reportFiles 报告名称;reportName 在Jenkins菜单栏显示的名称 ;reportTitles 点进报告显示的Title
                    publishHTML (target : [allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: '.',
                        reportFiles: "trivy.html",
                        reportName: 'Trivy Scan',
                        reportTitles: 'Trivy Scan'])
                }
            }
        }
    }
}

六、常见问题

6.1 Harbor 安装完之后使用IP地址访问,总是提示密码错误

问题现象:配置文件,安装部署时,密码都是对的,可就是提示密码错误,无法登录

解决方法 :Harbor 配置文件的 values.yaml文件中的externalURL,不是用externalURL配置, 也就是需要使用externalUR 来登录平台,不能再用Harbor 的hostnameIP地址直接登录,这边就需要外部做好代理,配置好NGINX。

如果,不使用域名去登录,就需要注释掉externalURL,使用hostname的IP地址直接登录

6.2 使用Docker 命令行登录Harbor仓库,忽略Https认证

问题现象: docker默认不允许向http的仓库地址推送

解决方法: 通过配置daemon的方式,来跳过证书的验证

复制代码
$ cat /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://docker.nju.edu.cn/"
  ],
  "insecure-registries": [
     "172.16.10.180"
  ]
}

七、参考

相关推荐
moongoblin20 分钟前
行业赋能篇-2-能源行业安全运维升级
运维·安全·协作
Fortinet_CHINA21 分钟前
引领AI安全新时代 Accelerate 2025北亚巡展·北京站成功举办
网络·安全
极简网络科技1 小时前
Docker、Wsl 打包迁移环境
运维·docker·容器
杨浦老苏1 小时前
轻量级Docker管理工具Docker Switchboard
运维·docker·群晖
江湖有缘1 小时前
【Docker管理工具】部署Docker可视化管理面板Dpanel
运维·docker·容器
一加一等于二1 小时前
docker部署postgresql17,并且安装插件
docker·postgresql
这儿有一堆花1 小时前
安全访问家中 Linux 服务器的远程方案 —— 专为单用户场景设计
linux·服务器·安全
猫咪老师19953 小时前
多系统一键打包docker compose下所有镜像并且使用
java·docker·容器
aitav03 小时前
⚡️ Linux Docker 基本命令参数详解
linux·运维·docker
Nazi63 小时前
docker数据管理
运维·docker·容器