博客

对 Docker 镜像和代码依赖项进行安全扫描基础设施

Filip Pytloun 缩略图
菲利普·皮特隆
2020 年 9 月 21 日发布
彗星缩略图
彗星
2020 年 9 月 21 日发布
ssi1

今年年初,我们的团队被要求增强现有的安全工具和软件开发+测试实践,以满足 PCI-DSS 和 SOC-2 合规性。 我们必须增强的关键领域之一是针对基于 K8s 的微服务和一些单片服务进行漏洞扫描。 因此,我们的 DevOps 团队必须在一些商业工具和开源解决方案之间进行选择,以对我们的软件实施漏洞扫描。 所有这些工具的功能都非常相似:它们扫描依赖项(项目库或操作系统包)并将它们与漏洞数据库(如 NIST 的 NVD 等)进行比较。

建與…… 买?

有一些开源工具可用于构建您自己的漏洞扫描解决方案,或者您可以使用在基本扫描基础上添加了附加功能的商业产品,让您的生活更轻松。 示例包括: 

  • 美观的仪表板,可快速概览项目中的漏洞 
  • 通知(电子邮件、Slack 等) 
  • 与 Git 存储库(GitHub、GitLab)集成 
  • 与其他服务集成(Docker 注册表、Kubernetes) 
  • 与项目管理(例如 Jira)集成 
  • 自动创建合并请求以修复易受攻击的依赖项 
  • 支持团队、项目和 RBAC

大多数商业解决方案都会利用自己的漏洞数据库来增强公共漏洞数据库,以消除误报/漏报并为您提供更相关的结果。 也就是说,随着开发人员数量的增加,所有这些商业工具都会变得非常昂贵。 因此,您需要考虑是购买“更好”还是使用现有的开源工具构建自己的解决方案。

最初,考虑到时间限制,我们认为商业工具最适合我们的需求。 然而,在花费 3 个月的时间部署和测试行业领先的商业产品之后,我们面临着许多挑战 - 对 golang 的支持有限,它会选择错误的依赖项并且不能正常退出,从头开始构建的容器与使用一些基础映像构建的容器存在问题,等等。 因此,我们决定放弃它并转而使用可用的开源技术构建我们自己的工具。

在这篇文章中,如果您选择使用开源,我将为您提供一个坚实的基础。 此外,文章末尾还附有我们的开源仓库链接,帮助您快速入门!

扫描什么?

基本上有两件事你需要扫描漏洞: 

  1. 您的项目的代码依赖项(yarn.lock,Gopkg.lock等)
  2. Docker 镜像中的操作系统依赖项(Debian 包、Alpine 包等)

将来,可能会添加更多功能,例如许可证检查或静态代码分析,但这超出了本文的范围。

什么时候扫描?

首先,您要确保您的代码或 Docker 镜像更改不会引入新的漏洞,因此在合并之前扫描每个合并请求是个好主意。

但您还需要定期扫描,因为随着时间的推移可能会出现新的漏洞。 此外,严重程度可能会发生变化——随着新攻击媒介或漏洞的发现,您最初忽略的低严重程度可能会随着时间的推移变得严重。 虽然商业工具会记住最后一次扫描并会在发现新漏洞时通知您,但在我们的开源解决方案中,我们只是在项目的主分支上重复扫描。

选择工具

有很多开源工具可用,但我们选择的是 Trivy,因为它使用简单、正在积极开发,并且可以扫描多个项目和操作系统类型。

Trivy 是一个简单而全面的容器和其他工件漏洞扫描程序。 软件漏洞是软件或操作系统中存在的故障、缺陷或弱点。 Trivy 检测操作系统软件包(Alpine、RHEL、CentOS 等)和应用依赖项(Bundler、Composer、npm、yarn 等)的漏洞。 Trivy 易于使用——只需安装二进制文件即可进行扫描! 扫描时您需要做的就是指定一个目标,例如容器的图像名称。

它可以轻松地在构建的 Docker 镜像或项目的根目录中本地安装和执行。 它还支持多种输出,包括 JSON 和表格输出:

ssi2

不幸的是,Trivy 无法扫描某些项目(例如 Golang),因此我们不得不依赖OWASP Dependency-Check,因为我们的很多代码都是用 golang 编写的。

Dependency-Check 是一种软件组合分析 (SCA) 工具,它试图检测项目依赖项中包含的公开披露的漏洞。 它通过确定给定依赖项是否存在通用平台枚举 (CPE) 标识符来实现此目的。 如果发现,它将生成一个链接到相关 CVE 条目的报告。

它可以生成带有报告、JUnit 和 JSON 输出(以及一些其他输出)的 html 页面。

报告和仪表板

现在我们离更有趣的东西越来越近了😊

由于我们已经在 DevOps 和 SRE 团队中使用Elasticsearch + Kibana + Fluentd ,因此使用现有基础设施来分析安全扫描的 JSON 输出是自然而然的事情。

我们只需要找到一种方法将数据从不受信任的基础设施(CI 运行器)发送到我们安全的 Elasticsearch。 为了这个目的,我们决定在中间设立一个消息队列。 Fluentd 有 in_sqs 插件来从 Amazon SQS 读取消息,而且使用起来也很简单,最终的架构如下所示:

ssi3
安全扫描架构

一旦数据到达 Elasticsearch,就可以根据需要使用 Kibana 轻松创建一些仪表板或使用 Discover 查询包含所有详细信息的漏洞。

固态硬盘4
漏洞概述
西门子
寻找关键漏洞

解决漏洞

现在我们有了扫描结果和一些漂亮的仪表板,下一步是什么? 我们不能指望开发人员会定期查看这些仪表板。 相反,我们决定在发现高严重程度或更高严重程度的问题且有可用的修复程序时使 CI 失败,这样责任就转移到开发人员和项目所有者身上。

当然,我们需要有一个选项来将某些 CVE 列入白名单或根据每个项目覆盖此默认行为。 因此,我们创建了一个包含安全扫描配置文件的存储库,该存储库由我们的扫描工具使用,该扫描工具包装 Trivy 执行并处理其行为和输出。

现在任何开发人员都可以针对此存储库提交合并请求并请求例外。 kibana项目的示例配置文件:

ssi6

未来的改进

这种安全扫描的实现是一个坚实的基础,可以超越我们最初的用例。 例如: 

  • 添加 Slack 通知,利用安全配置文件指定每个项目的频道和选项 
  • 添加与 Gitlab Issues、Jira 或任何其他票务系统的集成
  • 创建简单的服务或 sidecar 来执行部署在 Kubernetes 集群上的镜像扫描

分叉并使用它

您可以在我们的公共 Gitlab 存储库中找到 Dockerfile 和工具: https://gitlab.com/volterra.io/security-scanning

感谢Jakub Pavlík