分析 Docker 镜像安全性
AWS AI 直播!
注:本文最初发布于martinheinz.dev
很多人认为 Docker 镜像和容器默认是安全的,但遗憾的是,事实并非如此。有很多因素会影响 Docker 镜像的安全性。无论是镜像中安装的软件包、应用程序使用的库,甚至是基础镜像本身,所有这些组件都可能给应用程序带来漏洞。不过,很多这类问题其实都很容易避免……
安克尔和克莱尔
查找 Docker 镜像漏洞的最简单方法是使用Anchore或Clair等工具对其进行检查:
-
Anchore Engine:Anchore是一个集中式容器镜像检查、分析和认证服务。它使用来自Red Hat、Debian或Alpine等操作系统厂商的漏洞数据(源)扫描镜像。对于非操作系统数据,它使用NVD(国家漏洞数据库) ,其中包含RPM、Deb、APK以及Python (PIP)、Ruby Gems等的漏洞。
-
Clair:Clair是由CoreOS开发的用于 Docker 和 APPC 容器的静态分析器。它使用来自类似Anchore(Red Hat 安全数据)、NVD、Ubuntu CVE Tracker、Alpine SecDB、Debian 安全漏洞追踪器等来源的漏洞元数据。
设置
现在我们已经知道要使用的工具,是时候启动它们了。Anchore和Clair都包含各种集成,并且可以部署到Kubernetes或OpenShift,但为了演示的目的,我们将在本地机器上进行设置:docker-compose
要设置Anchore,请运行以下命令:
mkdir ~/aevolume
cd ~/aevolume
docker pull docker.io/anchore/anchore-engine:latest
docker create --name ae docker.io/anchore/anchore-engine:latest
docker cp ae:/docker-compose.yaml ~/aevolume/docker-compose.yaml
docker rm ae
docker-compose pull
docker-compose up -d
export ANCHORE_CLI_USER=admin
export ANCHORE_CLI_PASS=foobar
docker run --net=host -e ANCHORE_CLI_URL=http://localhost:8228/v1/ -it anchore/engine-cli
要设置Clair,请运行以下命令:
# Download Clair Scanner from https://github.com/arminc/clair-scanner/releases
chmod +x clair-scanner
docker run -p 5432:5432 -d --name db arminc/clair-db:$(date +%F)
docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.6
至此,我们就可以开始分析了!
注:本文稍后会再提到克莱尔。
检查图像是否存在漏洞
我们先从Anchore和基本的Debian镜像开始。要分析我们的镜像,我们需要执行以下操作add,wait以便分析完成:
# inside anchore-cli Docker container
~ $ anchore-cli image add docker.io/library/debian:latest
Image Digest: sha256:121dd2a723be1c8aa8b116684d66157c93c801f2f5107b60287937e88c13ab89
Parent Digest: sha256:a63d0b2ecbd723da612abf0a8bdb594ee78f18f691d7dc652ac305a490c9b71a
Analysis Status: analyzed
Image Type: docker
Analyzed At: 2020-03-07T10:46:20Z
Image ID: 971452c943760ab769134f22db8d3381b09ea000a6c459fbfa3603bb99115f62
Dockerfile Mode: Guessed
Distro: debian
Distro Version: 10
Size: 126607360
Architecture: amd64
Layer Count: 1
Full Tag: docker.io/library/debian:latest
Tag Detected At: 2020-03-07T10:45:48Z
~ $ anchore-cli image wait docker.io/library/debian:latest
Status: analyzing
Waiting 5.0 seconds for next retry.
...
~ $ anchore-cli image list
Full Tag Image Digest Analysis Status
docker.io/library/debian:latest sha256:121dd2a723be1c8aa8b116684d66157c93c801f2f5107b60287937e88c13ab89 analyzed
通过对图像的分析,让我们来看看发现了哪些漏洞:
~ $ anchore-cli image vuln docker.io/library/debian:latest all
Vulnerability ID Package Severity Fix CVE Refs Vulnerability URL
CVE-2005-2541 tar-1.30+dfsg-6 Negligible None CVE-2005-2541 https://security-tracker.debian.org/tracker/CVE-2005-2541
CVE-2007-5686 login-1:4.5-1.1 Negligible None CVE-2007-5686 https://security-tracker.debian.org/tracker/CVE-2007-5686
...
~ $ anchore-cli evaluate check docker.io/library/debian:latest
Image Digest: sha256:121dd2a723be1c8aa8b116684d66157c93c801f2f5107b60287937e88c13ab89
Full Tag: docker.io/library/debian:latest
Status: pass
Last Eval: 2020-03-14T13:25:24Z
Policy ID: 2c53a13c-1765-11e8-82ef-23527761d060
我们首先运行image vuln带有标志的命令all,列出镜像中存在的操作系统和软件包漏洞。所有漏洞均为Negligible或Unknown,这相当不错。接下来,我们运行evaluate check命令来检查此镜像是否通过默认策略检查,如上所示(Status: pass),它通过了。这类基础镜像在这方面通常表现良好,因为它们被广泛使用,因此受到严格的审查。
但是,如果使用 Python 3 Debian Buster镜像构建一个简单的“Hello World” Python 应用程序呢?我们先来看一下 Dockerfile:
# debian.Dockerfile
FROM python:3-slim AS build-env
ADD . /app
WORKDIR /app
FROM python:3-buster
COPY --from=build-env /app /app
WORKDIR /app
CMD ["python", "hello.py", "/etc"]
这看起来一点也不像“脆弱”和“不安全”的体现,对吧?那么,让我们把它搭建出来并进行分析:
~ $ docker build -f debian.Dockerfile -t martinheinz/debian-python-anchore .
~ $ docker run martinheinz/debian-python-anchore:latest
~ $ docker push martinheinz/debian-python-anchore:latest
# From anchore Docker CLI
~ $ anchore-cli image add martinheinz/debian-python-anchore:latest
~ $ anchore-cli image wait martinheinz/debian-python-anchore:latest
~ $ anchore-cli image list
Full Tag Image Digest Analysis Status
docker.io/library/debian:latest sha256:121dd2a723be1c8aa8b116684d66157c93c801f2f5107b60287937e88c13ab89 analyzed
docker.io/martinheinz/debian-python-anchore:latest sha256:59dff8bdf4af5cd8e9ba0754d25a43a96dfb47b46b771549a0d79d35bc3cc1aa analyzed
debian.Dockerfile我首先使用上述简单方法构建了镜像hello.py。然后我将其推送到 Docker Hub,之后它被添加到Anchore并最终进行了分析。现在我们可以查看结果了:
~ $ anchore-cli image vuln docker.io/martinheinz/debian-python-anchore:latest os
Vulnerability ID Package Severity Fix CVE Refs Vulnerability URL
CVE-2007-3476 libwmf-dev-0.2.8.4-14 Low None CVE-2007-3476 https://security-tracker.debian.org/tracker/CVE-2007-3476
CVE-2007-3476 libwmf0.2-7-0.2.8.4-14 Low None CVE-2007-3476 https://security-tracker.debian.org/tracker/CVE-2007-3476
CVE-2007-3477 libwmf-dev-0.2.8.4-14 Low None CVE-2007-3477 https://security-tracker.debian.org/tracker/CVE-2007-3477
CVE-2007-3477 libwmf0.2-7-0.2.8.4-14 Low None CVE-2007-3477 https://security-tracker.debian.org/tracker/CVE-2007-3477
CVE-2016-8660 linux-libc-dev-4.19.98-1 Low None CVE-2016-8660 https://security-tracker.debian.org/tracker/CVE-2016-8660
CVE-2007-3996 libwmf-dev-0.2.8.4-14 Medium None CVE-2007-3996 https://security-tracker.debian.org/tracker/CVE-2007-3996
CVE-2007-3996 libwmf0.2-7-0.2.8.4-14 Medium None CVE-2007-3996 https://security-tracker.debian.org/tracker/CVE-2007-3996
CVE-2009-3546 libwmf-dev-0.2.8.4-14 Medium None CVE-2009-3546 https://security-tracker.debian.org/tracker/CVE-2009-3546
CVE-2009-3546 libwmf0.2-7-0.2.8.4-14 Medium None CVE-2009-3546 https://security-tracker.debian.org/tracker/CVE-2009-3546
...
~ $ anchore-cli image vuln docker.io/martinheinz/debian-python-anchore:latest os | wc -l
1056
~ $ anchore-cli evaluate check docker.io/martinheinz/debian-python-anchore:latest
Image Digest: sha256:59dff8bdf4af5cd8e9ba0754d25a43a96dfb47b46b771549a0d79d35bc3cc1aa
Full Tag: docker.io/martinheinz/debian-python-anchore:latest
Status: fail
Last Eval: 2020-03-07T12:15:00Z
Policy ID: 2c53a13c-1765-11e8-82ef-23527761d060
哎呀,情况不妙。我们只是切换到了官方的 Python Debian镜像,结果突然就出现了 1000 多个漏洞,其中一些Low还是非常严重的漏洞,而之前使用普通的DebianMedium镜像时只有几个漏洞。更糟糕的是,在运行镜像评估后,我们发现评估失败了()。NegligibleStatus: fail
所以,即使我们使用了官方且看似安全的镜像,并且创建了一个非常简单、没有明显漏洞的应用程序,我们仍然遇到了很多安全问题。那么,我们该如何改进呢?
寻找更佳形象
就安全性而言,最佳的基础镜像选择是scratch——也就是空容器。然而,从零开始构建我们自己的基础镜像并不实际,而且考虑到我们大多数人并非安全专家,这样做可能会带来更多安全问题。
scratch在我看来,第二好的选择是Distroless ,这是一套由Google创建的镜像,旨在确保安全性。这些镜像只包含应用所需的最低限度组件,这意味着其中不包含任何 shell、包管理器或其他会使镜像臃肿并给安全扫描器(例如CVE )带来干扰的工具,从而避免了合规性方面的挑战。我在之前的博文中已经详细介绍过Distroless,如果您想了解更多信息,可以去看看。
好了,现在Distroless是我们安全镜像的首选,但在分析任何内容之前,让我们先来看看新的Dockerfile:
# distroless.Dockerfile
FROM python:3-slim AS build-env
ADD . /app
WORKDIR /app
FROM gcr.io/distroless/python3
COPY --from=build-env /app /app
WORKDIR /app
CMD ["hello.py", "/etc"]
与Debian版本相比,变化不大。我们只是将Runner镜像切换到了新版本gcr.io/distroless/python3。现在,我们可以继续构建它、推送它并将其添加到Anchore Engine中:
docker build -f distroless.Dockerfile -t martinheinz/distroless-python-anchore .
docker run martinheinz/distroless-python-anchore:latest
docker push martinheinz/distroless-python-anchore:latest
# From anchore Docker CLI
anchore-cli image add martinheinz/distroless-python-anchore:latest
最后,是时候看看Distroless版本是否比Debian版本表现更好了:
~ $ anchore-cli image vuln docker.io/martinheinz/distroless-python-anchore:latest os
Vulnerability ID Package Severity Fix CVE Refs Vulnerability URL
CVE-2019-16935 libpython3.5-minimal-3.5.3-1+deb9u1 Low None CVE-2019-16935 https://security-tracker.debian.org/tracker/CVE-2019-16935
CVE-2019-16935 python3.5-minimal-3.5.3-1+deb9u1 Low None CVE-2019-16935 https://security-tracker.debian.org/tracker/CVE-2019-16935
...
~ $ anchore-cli image vuln docker.io/martinheinz/distroless-python-anchore:latest os | wc -l
53
~ $ anchore-cli evaluate check docker.io/martinheinz/distroless-python-anchore:latest
Image Digest: sha256:29b5288e934dc724377f2ff187e8a0664246c95b0e70bd9a13f6874628dc8662
Full Tag: docker.io/martinheinz/distroless-python-anchore:latest
Status: pass
Last Eval: 2020-03-07T12:15:20Z
Policy ID: 2c53a13c-1765-11e8-82ef-23527761d060
确实如此!与第一个例子相比,我们只有 53 个漏洞,其中只有 2 个是Low严重漏洞。此外,查看策略评估——这个镜像通过了评估,而Debian镜像则失败了!
因此,我们可以得出结论,就容器化应用程序的安全性而言, Distroless是更优的选择。不过,我们还可以检查和改进一些其他方面——例如,我们可以尝试使用不同的评估策略:
~ $ anchore-cli policy hub list
Name Description
anchore_security_only Single policy, single whitelist bundle for performing
security checks, including example blacklist known malicious
packages by name.
anchore_default_bundle Default policy bundle that comes installed with vanilla
anchore-engine deployments. Mixture of light vulnerability
checks, dockerfiles checks, and warning triggers for common
best practices.
anchore_cis_1.13.0_base Docker CIS 1.13.0 image content checks, from section 4 and
5. NOTE: some parameters (generally are named 'example...')
must be modified as they require site-specific settings
上述命令列出了所有可用于检查镜像的策略。默认情况下,它使用anchore_default_bundle默认策略,这完全没问题。但如果我们想查看使用不同白名单和规则执行的检查,可以尝试例如anchore_cis_1.13.0_base:
~ $ anchore-cli policy hub get anchore_cis_1.13.0_base
Policy Bundle ID: anchore_cis_1.13.0_base
Name: anchore_cis_1.13.0_base
Description: Docker CIS 1.13.0 image content checks, from section 4 and 5. NOTE: some parameters (generally are named 'example...') must be modified as they require site-specific settings
Policy Name: CIS File Checks
Policy Description: Docker CIS section 4.8 and 4.10 checks.
Policy Name: CIS Dockerfile Checks
Policy Description: Docker CIS section 4.1, 4.2, 4.6, 4.7, 4.9 and 5.8 checks.
Policy Name: CIS Software Checks
Policy Description: Docker CIS section 4.3 and 4.4 checks.
Whitelist Name: RHEL SUID Files
Whitelist Description: Example whitelist with triggerIds of files that are expected to have SUID/SGID, for rhel-based images
Whitelist Name: DEB SUID Files
Whitelist Description: Example whitelist with triggerIds of files that are expected to have SUID/SGID, for debian-based images
Mapping Name: default
Mapping Rule: */*:*
Mapping Policies: CIS Software Checks,CIS Dockerfile Checks,CIS File Checks
Mapping Whitelists: DEB SUID Files,RHEL SUID Files
~ $ anchore-cli policy hub install anchore_cis_1.13.0_base
Policy ID: anchore_cis_1.13.0_base
Active: False
Source: local
Created: 2020-03-07T12:20:46Z
Updated: 2020-03-07T12:20:46Z
~ $ anchore-cli policy list
Policy ID Active Created Updated
2c53a13c-1765-11e8-82ef-23527761d060 True 2020-02-17T11:10:20Z 2020-02-17T11:10:20Z
anchore_cis_1.13.0_base False 2020-03-07T12:20:46Z 2020-03-07T12:20:46Z
~ $ anchore-cli policy activate anchore_cis_1.13.0_base
Success: anchore_cis_1.13.0_base activated
从以上内容可以看出,我们首先运行命令查看了该特定策略的描述policy hub get。之后,我们安装了该策略并运行policy list命令,结果显示现在有两条策略可用,其中新策略处于非活动状态。因此,我们使用最后一个命令(policy activate)激活它。
在运行新策略的检查之前,我们先来谈谈它包含哪些内容。鉴于这是Docker CIS 1.13.0 的检查,它将主要依据本文档提供的指导。以下是它会查找的一些问题示例:
ADD代替命令COPY- 未列入白名单的已开放端口
- 丢失的
HEALTCHECK - 使用不受信任的基础镜像
root有效利用
要查看此策略中的所有规则,您可以运行以下命令anchore-cli --json policy hub get anchore_cis_1.13.0_base。现在,我们已经知道它会查找什么,是时候运行它了:
~ $ anchore-cli evaluate check docker.io/martinheinz/distroless-python-anchore:latest --detail
...
dockerfile instruction Dockerfile directive 'HEALTHCHECK' not found, matching condition 'not_exists' check stop
dockerfile instruction Dockerfile directive 'FROM' check 'not_in' matched against 'example_trusted_base1,example_trusted_base2' for line 'scratch' stop
dockerfile effective_user User root found as effective user, which is explicity not allowed list stop
...
输出中存在一些已安装软件包的警告信息,但与此策略相关的警告信息仅列出上述几项。这些问题/漏洞会导致镜像无法通过策略评估,需要进行分析。其中一项(第二项)是由于使用了Distroless镜像造成的,因为它不在白名单中,因此可以忽略。至于另外两项——这些都是需要修复的实际问题,但它们都有简单直接的解决方案。
这告诉我们,根据我们的需求选择具体的策略,甚至使用多种策略来尽可能多地发现问题是明智之举。
漏洞类型/级别
并非所有漏洞都同等重要,有些漏洞甚至可能与我们的应用程序/容器/环境无关。因此,我们不仅应该关注漏洞的严重性,还应该关注影响严重性的各项因素。这些因素包括攻击向量、攻击复杂性、机密性影响、完整性影响等等。这些因素最终会通过CVSS 计算器生成最终的严重性评分。具体的评分等级为 -、- None、Low-Medium和High- Critical。更多信息请访问 NIST 网站:https://nvd.nist.gov/vuln-metrics/cvss。
修复漏洞
上述示例中的漏洞很容易修复,但并非总是如此。您可能会遇到严重性评分高的漏洞,或者针对您特定用例造成问题的漏洞。如果是基础镜像或其中包含的软件包的问题,您不应该负责修复,因为这是相关工具的开发者和/或发布者的责任。尽管如此,您仍然应该通过移除攻击向量来预防或至少减轻现有和未来漏洞的利用风险,例如使用不包含任何 shell 的Distroless。此外,最好定期使用构建/部署管道运行漏洞检查,以便在漏洞出现时尽快发现,理想情况下应使用多种扫描工具。
安克尔对阵克莱尔
说到运行多个扫描工具…… Clair怎么样?它和Anchore相比如何?以下是我们如何使用它扫描示例Debian和Distroless镜像:
# Run setup steps from beginning of article...
~ $ clair-scanner --ip 192.168.1.56 martinheinz/debian-python-anchore:latest
2020/03/07 17:54:11 [INFO] ▶ Start clair-scanner
2020/03/07 17:54:18 [INFO] ▶ Server listening on port 9279
2020/03/07 17:54:18 [INFO] ▶ Analyzing 55db4dd701c0a4eea04ba231e74bd04d6c1cdbd86cf8084e988648aa7cf5af9b
2020/03/07 17:54:18 [INFO] ▶ Analyzing 1938b02d46a5b801035965c5680d11c513a679e0ad4a560276df9a8ececa0bed
2020/03/07 17:54:18 [INFO] ▶ Analyzing 90bd3e8e4e9f1dd7624ecdd1ee35c36072e582a2cd5c606f290d2b3cb4a1559c
2020/03/07 17:54:18 [INFO] ▶ Analyzing ced4f27972d40674b72da7b1a51b63a8396bbca3a4fca86dffa8031228ab88cb
2020/03/07 17:54:18 [INFO] ▶ Analyzing 7abae7ca0ef88724a59f51748b1658136bdbb1eae246550478f5939484358d94
2020/03/07 17:54:18 [INFO] ▶ Analyzing 62547b912c7f2d5d69eaca3cd5ad1cb053c39886cb7276b0cb753b3824c32358
2020/03/07 17:54:18 [INFO] ▶ Analyzing cb7076fa495a6c437ac374b1b67a62075b94db45400c10e8849b5db75ffbce21
2020/03/07 17:54:18 [INFO] ▶ Analyzing a3ffe04a8073815ecfa94620efbbccf412b85ca80b6550c029617eed51c5edb6
2020/03/07 17:54:18 [INFO] ▶ Analyzing 715fd7b0b1161fa57f74a843f4525f1ab7035c9a8051a6559c91ff360e44f20f
2020/03/07 17:54:18 [INFO] ▶ Analyzing 20519035fc6a7d347a1540a633c461ac321dc8db7cb8c163283c1d802097697b
2020/03/07 17:54:18 [WARN] ▶ Image [martinheinz/debian-python-anchore:latest] contains 356 total vulnerabilities
2020/03/07 17:54:18 [ERRO] ▶ Image [martinheinz/debian-python-anchore:latest] contains 356 unapproved vulnerabilities
... List of vulnerabilities follows
~ $ clair-scanner --ip 192.168.1.56 martinheinz/distroless-python-anchore:latest
2020/03/07 17:56:08 [INFO] ▶ Start clair-scanner
2020/03/07 17:56:09 [INFO] ▶ Server listening on port 9279
2020/03/07 17:56:09 [INFO] ▶ Analyzing 51756e4adf1ad2b5a00c36dcc9e799a69d72462d60e6f88c87f96eed832b8a2a
2020/03/07 17:56:09 [INFO] ▶ Analyzing 49905beb7372788afbefede92af761383ad2bac7f8d21b2f2d6fb165afff48e8
2020/03/07 17:56:09 [INFO] ▶ Analyzing 3d9fd80998dc9ea371366e1ef54046fbe86e6e360d17ece650ea8a3ea5023c63
2020/03/07 17:56:09 [INFO] ▶ Analyzing 83b671756e1e2cc132505e55c87c5c5b1da185665f9bb875d771568959dc05a2
2020/03/07 17:56:09 [INFO] ▶ Analyzing b80190979f279448d479a3ed0450f6d2912662e12edd1fe477a2b74d0568e1f0
查看上述命令的输出,它与Anchore的结果非常相似——Debian镜像存在大量问题,而Distroless则没有问题。在第一次扫描的输出中,漏洞列表很长,我省略了所有漏洞,但我检查了所有漏洞Low及其严重程度,发现它们在Anchore和Clair 的Medium扫描结果中都存在,但情况并非总是如此。因此,我建议运行多个扫描工具,最好是使用不同来源漏洞元数据的工具。
您可能还想了解一下其他一些工具,例如Docker Bench for Security或IBM Container Registry中包含的漏洞扫描工具。
结论
在安全方面,最好是防患于未然,在漏洞演变成实际问题之前就加以规避。本文介绍的工具可以为此提供极大的帮助。我认为这些工具的使用和部署都非常简单,任何人都能将其融入日常工作流程,理想情况下,甚至可以集成到自动化流程/任务中。我们创建的应用程序的安全性在某种程度上是每位开发人员的责任,而不仅仅是安全专家或渗透测试人员的责任。因此,我们都应该参与到确保应用程序安全性的行动中来,比如定期运行漏洞扫描。😉
文章来源:https://dev.to/martinheinz/analyzing-docker-image-security-1o9a