在构建、共享和运行 Docker容器安全应用程序时,您需要考虑一些Docker 安全最佳实践。Docker 是一个开源平台,用于构建、共享和运行您的容器化应用程序。您可以轻松构建包含应用程序的 Docker 映像,在团队内部或团队外部共享它们,并且只需一个命令即可运行您的应用程序。看起来很容易,对吧?然而,确实如此。
您可能已经知道 Docker 是什么以及它是如何工作的。因此,我们不会详细介绍它。本博客将介绍使用 Docker 平台时需要考虑的12 大 Docker 安全最佳实践。
为什么需要保护 Dockerfile、容器?
容器化因其应用程序可以在任何地方部署的灵活性而风靡全球。但是,这也引入了一些安全漏洞。Docker 和 Docker 容器使构建、共享和部署应用程序变得非常容易,因此在部署后很难发现、检测、报告和修复安全问题。通过向左移动安全性,可以防止和最小化大部分开销。因此,保护从 Dockerfile 到 Docker 容器的所有内容以确保Docker 容器安全性至关重要。
12 大 Docker 安全最佳实践
从一开始就可以通过各种专业来提高Docker 容器安全性,即从编写 Dockerfile 到运行 Docker 容器。让我们继续看看可以将 Docker 容器安全性落实到位的 12 大 Docker 安全最佳实践。
1. 使 Docker 主机和 Docker 引擎与 Docker 映像一起保持最新
Docker 容器在主机上可用的 Docker 引擎上运行。这些主机可以是 Linux/Mac 或 Windows。Docker 引擎可以是可用版本之一。 使用最新的稳定版本至关重要,它更新了以前版本中的已知问题。这同样适用于主机操作系统。
例如,截至 2021 年 12 月 27 日,如果您使用 Ubuntu 作为主机操作系统,那么您可以使用 Ubuntu 20.04 LTS 而不是 Ubuntu 16.04 LTS,对于 Docker 引擎,您可以使用 20.10.11。查找Docker 发行说明以获取更多信息,并检查 Docker 支持的操作系统平台。
安装更新或补丁非常重要,因为每个补丁都可以解决CVE-2021-41092等漏洞。这个特定的补丁修复了用于从 CLI 登录 docker 注册表的凭据被发送到“registry-1.docker.io”而不是预期的私有注册表的错误;这通常是由于配置错误的配置文件(通常是 `~/.docker/config.json`)列出了 `credsStore` 或 `credHelpers.
请参考以下截图了解 Ubuntu OS 的发布周期。
2. 避免在 Dockerfile 指令中存储机密数据
Dockerfile 包含用于创建 Docker 映像的指令。COPY、RUN、ADD、CMD、ENTRYPOINT 等。这些是一些可能是 Dockerfile 一部分的命令指令。我们还可以使用 ENV 和 ARGS 在运行时或构建时设置变量,具体取决于要求。您可以使用 ENV 或 ARGS 指令在 Docker 容器中使用环境变量。在设置环境变量时,您应该注意永远不要将机密、凭据、密码等分配给 Dockerfile 中的变量,也不应该在任何命令中进行硬编码。将此视为 Dockerfile 安全最佳实践之一,因为忽略它可能会导致潜在的安全威胁,并且可能会花费您很多钱。
例如,如果您在 Dockerfile 中硬编码数据库的密码或连接详细信息,将它们分配给环境变量,然后将 Dockerfile 上传到公共存储库,则任何有权访问存储库的人都可以获得这些凭据并可以访问详细信息或连接到数据库。
FROM mysql:5.7 ENV DATABASE_USERNAME=admin # < - Setting username is acceptable ENV DATABASE_PASSWORD=mypassword@!@#$ # < - Avoid setting password at any cost
- 1.
3. 避免使用不受信任的镜像注册表
镜像注册表是存储 Docker 镜像的地方。它可以是私有的或公共的。Docker Hub 是 Docker 官方的基于云的 Docker 镜像注册表,它是安装时的默认注册表。如果您未配置任何注册表,则将从该公共存储库中提取图像。
当您从任何公共注册表中提取 Docker 镜像时,请注意来源,因为您可能不知道是谁构建了它们,它们是如何构建的,或者它们是否值得信赖。每当您从不受信任的发布者拉取镜像时,请不要忘记验证源注册表和用于构建镜像的 Dockerfile。此外,您的 Dockerfile 的基本映像,即 FROM 指令。
FROM # < - Verify the base image before you use it
- 1.
4.提防递归复制
在为需要将文件从本地计算机复制到 Docker Image 的应用程序编写 Dockerfile 时,您应该注意使用 COPY 指令复制的内容。您的本地计算机上可能有可能包含机密数据或机密的文件。因此,如果这些文件被复制到 Docker 映像中,任何有权访问容器的人都可以从容器中获取这些文件。因此,仅复制容器中需要的文件而不是复制所有内容非常重要,如下面的说明所示,以提高 Docker 容器安全性。
你可以试一试。dockerignor。它可以帮助排除与模式匹配的文件和目录,并避免使用 ADD 或 COPY 将大型或敏感文件不必要地发送到图像。
例如,在以下 COPY 指令中,当前位置的所有文件都将复制到 Docker 映像中。因此,您应该始终避免“复制”。./ ”,并且应该在 COPY 指令中明确指定文件名为“ COPY package.json ./ ”
FROM node:12.18.4-alpine WORKDIR /app ENV PATH /app/node_modules/.bin:$PATH COPY . ./ # < - Avoid such kind of COPY instruction
- 1.
5. 开发过程中扫描图像
Docker 镜像是从 Dockerfiles 构建的,Dockerfiles 包含使用基础镜像、安装包、启动应用程序等的说明。Dockerfile 也可能包含错误硬编码的凭据。那么,如果您使用的基础镜像存在一些漏洞,并且在 Dockerfile 中硬编码的凭据从使用该 Dockerfile 构建的镜像创建的容器中泄露,该怎么办?
扫描镜像是识别 Docker 镜像中已知安全漏洞的过程,以便您可以在将它们推送到 Docker Hub 或任何其他注册表之前修复它们。
您现在可以直接从 Docker Desktop CLI 运行 Snyk 漏洞扫描,因为 Snyk 和 Docker 已经合作。
例如,您可以通过提供用于创建映像的 Dockerfile 来获取有关 Docker 映像的详细报告。
docker scan --file PATH_TO_DOCKERFILE DOCKER_IMAGE
6. 使用固定标签实现不变性
在 Docker 中,图像上有标签。Docker 镜像最常见和默认的标签是“latest”。因此,如果您没有为图像分配标签,则默认情况下它将具有“最新”标签。可以发布多个具有相同标签的镜像,即 Docker 镜像标签不是不可变的。因此,非常重要的是——
更喜欢为您的图像使用更具体的标签,以便您每次都能获得相同的图像。
更喜欢在您的私人存储库中保留图像的副本。
使用 Docker 内容信任 (DCT) 将数字签名用于客户端或运行时验证特定图像标签的完整性和发布者。访问官方文档以了解更多信息。
例如,让我们说,
- Dev1拉取myimage:latest imag,在他/她的电脑上运行1.1版本的应用,发现应用运行流畅。
- 稍后,Dev2 拉取相同的图像myimage:latest并在他们的计算机上运行该应用程序,并发现该应用程序出现了问题。在这里,您确定它们都在运行相同版本的应用程序吗?
- 答案是否定的,因为在 Dev2 拉取镜像myimage:latest 之前, Dev3 进行了更改并推送了同名myimage:latest 应用的不稳定版本 1.2。
- 现在,当他们部署镜像myimage:latest 时, 它将指向应用程序的不稳定版本 1.2,然后这会破坏生产环境。
7. Lint Dockerfile
市场上有各种 Dockerfile linter 可用于确保 Dockerfile 遵循Dockerfile 安全最佳实践。如果生成警告,Linter 可以帮助您停止构建过程;他们遍历您的 Dockerfile 并在 Dockerfile 不遵循最佳实践的情况下发出警告。您可以利用Hadolint,这是一个用于验证内联 bash 和 linting Dockerfile 的开源项目。
8.限制容器资源
默认情况下,在主机上运行的 Docker 容器可以利用所有的 RAM 和 CPU。在 Docker 容器遭到入侵的情况下,攻击者可能会尝试使用主机资源来执行恶意活动。此外,如果特定容器开始利用主机上的所有资源,则驻留在同一位置的其他容器可能会由于资源不可用而受到影响。为避免这种情况,建议对 Docker 容器设置资源限制,以使它们使用的资源不会超过分配给它们的资源,并有助于提供 Docker 容器安全性。
例如, 如果宿主机有 1 个 CPU,下面的第 1 条命令可以保证容器每秒最多使用 50% 的 CPU,第 2 条命令可以将容器的内存使用限制为 1 GB。
CPU 限制
docker run -it --cpus=".5" ubuntu /bin/bash
- 1.
内存限制
docker run -it --memory="1g" ubuntu /bin/bash
- 1.
9. 不要暴露 Docker Daemon Socket
Docker 与名为 /var/run/docker.sock 的 UNIX 域套接字通信,这是Docker API的主要入口点。如果任何人有权访问 Docker 守护程序套接字,也可以获得 root 访问权限。因此,允许任何用户写入 /var/run/docker.sock 或将套接字暴露给容器对系统的其余部分来说是一个很大的 Docker 容器安全风险,因为这会给它提供 root 权限。因此,永远不要在 Docker 容器内挂载 /var/run/docker.sock。
例如,永远不要使用“-v /var/run/docker.sock:/var/run/docker.sock”之类的选项运行 docker run 命令,并将其视为 Docker 安全最佳实践之一,可以帮助您保持系统保护。
10. 以非 root 用户身份运行容器
根据 sysdig.com 的“ 2021 年容器安全和使用报告”,大多数镜像都过于宽松,58% 的容器以 root 身份运行。这不被视为 Dockerfile 最佳实践;应该避免这样做,因为在极少数情况下您确实需要使用 root 用户在容器中运行您的进程。为确保您不使用 root 用户,请始终使用用户名指定“USER”指令。
在 Docker 容器中使用非 root 用户可确保减轻容器运行时中的潜在漏洞并实现 Docker 容器安全性。
例如,始终尝试创建和使用非 root 用户在容器中运行您的应用程序进程。你需要的非root用户可能不存在;因此,您首先必须在使用它之前创建一个。
FROM alpine:3.12 RUN adduser -D non-root-user && chown -R non-root-user /myapp-data # < - Create a user USER non-root-user # < - use a non-root user
- 1.
11. 保持 Docker 镜像尽可能小
在整个 Dockerfile 构建过程中创建了许多工件,这些工件仅在构建期间是必需的。这些包是编译或运行单元测试、临时文件、机密等的依赖项所必需的。将这些工件保留在基础映像中会增加 Docker 映像的大小,这可能会减慢下载时间并扩大攻击面,因为更多的包是因此,加载是 Docker 支持多阶段构建的原因之一。此功能允许您在构建过程中使用大量临时映像,同时仅保留最新的映像和复制到其中的数据。
结果,您有两个图像:
- 图 1:第一个图像是一个大图像,其中包含许多依赖项,您需要这些依赖项来创建应用程序和运行测试。
- 图 2:在大小和库数量方面非常小且轻量级的图像,只有在生产中运行程序所需的工件副本。
通过这种方式,您可以采用多阶段构建来构建您的 Docker 镜像,这可以减少镜像的大小并避免安装不需要的库,从而增加潜在安全风险的机会。
12. 使用最新的 Docker 镜像
由于定期发现新的安全漏洞,保持最新的安全补丁是 Docker 安全最佳实践。因此,使用经常更新的基础镜像并在它们之上构建自己的镜像非常重要。没有必要总是使用最新的版本,它可能包含重大更改,但您应该有一个版本控制策略。以下是您的基本图像要考虑的几点。
- 坚持使用更可能收到安全更新的稳定或长期支持版本。
- 在您的基础映像版本达到其生命周期结束且不再接收更新之前,请准备好删除旧版本并进行迁移。
- 定期重建你的镜像并使用类似的技术从基本发行版中获取最新的包
结论
我们都知道“预防胜于治疗”,Docker 也是如此。不能简单地忽视其安全性,因为这可能导致一场巨大的灾难。我们现在知道为什么 Docker 容器安全性至关重要以及为什么必须到位。将安全性向左转移对于改善 Docker 环境和减少管理开销至关重要。
上面提到的前 12 条建议侧重于 Dockerfile 安全最佳实践和 Docker 容器安全最佳实践,将帮助您保护 Docker 容器和 Docker 环境。
与经验丰富的团队一起保护您的 Docker 容器。