使用GitlabCI和Trivy介绍镜像安全扫描如今变得越来越流行。这个想法是分析Docker镜像并根据CVE数据库查找漏洞。这样,我们在使用之前就可以知道镜像包含哪些漏洞,所以我们只能在生产中使用“安全”的镜像。有多种分析Docker镜像的方法(取决于您使用的工具)。安全扫描可以从CLI执行,或者直接集成到ContainerRegistry中,或者更好(在我看来),您可以将安全扫描集成到您的CI/CD管道中。最后一种方法很酷,因为它允许我们自动化流程并持续分析生成的图像,从而与DevOps理念保持一致。这是一个简单的示例:所以今天我将向您展示如何设置集成到CI/CD管道中的图像安全扫描。工具有多种工具可以执行图像安全扫描:Trivy:由AquaSecurity开发。Anchore:由AnchoreInc.开发。Clair:由Quay开发。DockerTrustedRegistry:如果您使用DockerEnterprise,尤其是DockerTrustedRegistry,您可以使用直接集成到注册表中的开箱即用的安全扫描器。Azure/AWS/GCP:如果您使用这些云提供商之一,您可以轻松设置安全扫描。事实上,您不需要进行任何设置,只需您的信用卡即可。:)当然,还有更多开源或专有工具可以实现该目标。对于本教程,我将在GitlabCI管道之上使用Trivy。Trivy快速概述Trivy是一款易于使用但准确的图像安全扫描仪。安装非常简单:$curl-sfLhttps://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh|sh-s--b/usr/local/bin$sudomv./bin/trivy/usr/local/bin/trivy$trivy--version及其用法:$trivyimagenginx:alpine给我们这个输出:soeasy。更多信息:Trivy的Github添加了一个简单的Docker镜像为了说明在CI/CD管道中包含安全扫描,我们需要一个Docker镜像作为示例。我将使用这个简单的Dockerfile:FROMdebian:busterRUNapt-getupdate&&apt-getinstallingnginx-y这个Dockerfile非常简单。它从官方的debianbuster镜像开始,并添加nginx安装。我们稍后将在CI/CD管道中构建此映像,但我们可以按如下方式构建它:$dockerbuild-tsecurity_scan_example:latest。现在,我们只需要创建一个Gitlab项目并将Dockerfile推送到其中。创建一个简单的CI/CD管道现在我们已经为示例图像创建了一个Dockerfile,我们可以创建一个CI/CD管道来构建图像并使用Trivy扫描它。毫不奇怪,因为我们使用的是Gitlab,所以我们将在我们的CI/CD管道中使用GitlabCI。首先,让我们添加构建部分:build:stage:buildimage:docker:stableservices:-docker:dindtags:-dockerbefore_script:-dockerlogin-u"$CI_REGISTRY_USER"-p"$CI_REGISTRY_PASSWORD"$CI_REGISTRYscript:-dockerbuild-t$CI_REGISTRY_IMAGE:latest.-dockerpush$CI_REGISTRY_IMAGE:latest作业在基于docker:stable镜像的容器上运行。它根据我们之前推送的Dockerfile构建项目的镜像,然后将镜像推送到Gitlab容器注册中心。现在让我们添加有趣的部分:security_scan:stage:testimage:name:aquasec/trivy:latestentrypoint:[""]services:-docker:dindtags:-dockerscript:-trivy--no-progress--outputscanning-report.txt$CI_REGISTRY_IMAGE:latestartifacts:reports:container_scanning:scanning-report.txt这个作业就是我们的安全扫描作业。这次,它运行在基于Trivy官方镜像的容器上。它根据简单的命令扫描镜像,并将报告输出到名为scanning-report.txt的文件中。太棒了!让我们看一下我们的GitlabCI管道,它应该在推送后自动运行。我们可以看到我们的两个作业都运行成功:让我们看一下安全扫描作业:报告的图像在哪里?正如您在扫描作业的结果中看到的那样,我们有多个漏洞,更准确地说是114个“低”漏洞和8个“中”漏洞,24个“高”漏洞和1个“严重”漏洞。我们希望获得有关这些漏洞的更多详细信息。默认情况下,Trivy将报告打印到标准输出。在这个例子中,我们告诉trivy将报告输出到一个文件,并从该文件创建一个作业工件。因此可以按如下方式下载报告:images下载后,我们可以查看报告以获取更多详细信息:images我们可以看到我们有更多关于扫描器发现的漏洞的信息,例如受影响的库/二进制文件,CVEID,严重性、可能的修复等。现在怎么办?好的,现在我们已经将图像扫描集成到我们的CI/CD管道中,问题是如何处理这些信息?目前,安全扫描作业永远不会失败,因为trivy命令默认返回0。如果镜像“不安全”,则通过使作业失败来改善这种情况,否则使作业成功。问题是,它什么时候失效?显然,我们不能简单地说“每次发现漏洞时都失败”,因为我们的图像很可能至少有一些漏洞。答案很难说,因为这取决于您想要达到的安全级别。一般来说,我们希望尽可能避免严重漏洞。答案还取决于您获得的漏洞。你能忽略其中的一些吗?这取决于你。这就是为什么与您的安全团队持续协作可以从这些扫描中获益匪浅。对于这个例子,如果我们只有一个严重漏洞,我们的CI/CD管道就会失败,否则它就会成功。幸运的是,trivy允许我们使用“严重性”选项来仅查找特定严重性的漏洞。我们还可以在“退出代码”选项的帮助下处理退出代码,告诉trivy如果发现漏洞则返回1,否则返回0。因此,如果发现一个或多个“关键”漏洞,我们将扫描作业更改为失败,例如:script:-trivy--no-progress--outputscanning-report.json$CI_REGISTRY_IMAGE:latest-trivy--exit-code1--no-progress--severityCRITICAL$CI_REGISTR_IMAGE:latest因此在执行我们的作业时,我们仍然可以下载完整的报告,但这一次,CI/CD作业的成功或失败取决于trivy是否发现了Criticbug:最后步骤...好的,我们的CI/CD流水线看起来很棒!我们需要处理的最后一件事......目前,只有在构建/推送图像时才会对其进行分析。这很酷,但还不够。事实上,我们的扫描工具使用的CVE数据库每天都在开发新的漏洞。今天“安全”的东西明天可能(而且很可能)不安全。所以我们需要在第一次推送后继续扫描图像。好吧,让我们添加一个预定的管道,比如每晚凌晨2点扫描镜像。我们需要进入CI/CD->Schedules->NewSchedule:注意:我们定义了一个名为SCHEDULED_PIPELINE的变量,其值为“security_scan”。我们稍后会看到这个变量的用途。这样做,我们的管道将被完全执行,包括构建部分。这不是我们真正想要的。因此,我们将修改gitlabCI文件,使计划的管道只执行扫描作业。我们将添加一个额外的扫描作业,其定义与之前的作业完全相同,并带有一个额外的“仅”选项,仅当变量SCHEDULED_PIPELINE(我们之前在预定管道中定义)等于“scanning_scan”时才可以执行。为避免代码冗余,我们将使用作业模板。所以我们最终的gitlabCI文件看起来像这样:-outputscanning-report.json$CI_REGISTRY_IMAGE:latest-trivy--exit-code1--no-progress--severityCRITICAL$CI_REGISTR_IMAGE:latestartifacts:reports:container_scanning:scanning-report.jsonbuild:stage:buildimage:docker:stableservices:-docker:dindtags:-dockerbefore_script:-dockerlogin-u"$CI_REGISTRY_USER"-p"$CI_REGISTRY_PASSWORD"$CI_REGISTRYscript:-dockerbuild-t$CI_REGISTRY_IMAGE:latest.*scanning-templateexcept:variables:-$SCHEDULED_PIPELINEsecurity_scan:on-schedule:<<:*scanning-templateonly:variables:-$SCHEDULED_PIPELINE="security_scan"这样当我们推送一些代码时,我们的标准管道(build+scan)将执行通常情况下,预定管道将在每天凌晨2点执行安全扫描作业。我们如何解决这些漏洞?通常,通过升级映像。在我们的例子中,我们可能会升级基础镜像(或者可能使用另一个镜像,例如Alpine)或升级我们的nginx安装。另一个答案可能是从图像中删除不必要的内容,无论如何构建docker图像是一个很好的做法。安全扫描可以帮助您检测未实际使用的组件。在我们的例子中,让我们更改基本映像并改用Alpine:FROMalpine:3.12RUNapkupdate&&apkaddnginx-y这一次,我们的管道成功了……:……没有一个洞。结论因此,我们已经了解了如何将安全扫描作业集成到GitlabCI管道中,这非常简单(至少使用Trivy是这样)。当然,在我的示例中,我在一个主分支中完成了所有操作。在现实世界中,我们将进行多分支项目,这需要进行一些调整。
