docker拉取镜像失败_10 个 Docker 镜像安全最佳实践

《Docker 镜像安全较佳实践速查表[1]》列举了 10 个诀窍和指南,确保更安全和更高质量的 Docker 镜像处理。此外,还可以检视有关 Docker 安全的新报告《Docker 安全要趁早[2]》。

55cabb80142c051d15266d2b2aa44fb3.png

1. 选用最小化基础镜像

人们编写项目的 Dockerfile 时,经常使用一个通用的 Docker 容器镜像作为基础,例如 From Node 。 Node 镜像实际上是以一个完整安装的 Debian Stretch 发行版为基础,这意味着构建得到的项目容器镜像将包含一个完整的操作系统。如果该项目不需要任何通用的系统库或者系统工具应用,较好不要使用完整的操作系统作为基础镜像。

Synx 发布的《开源安全报告-2019[3]》指出,Docker Hub 上流行的很多容器镜像,都用到了包含大量已知安全漏洞的基础镜像。例如,执行 docker pull node ,下载并使用 Node 镜像,相当于在应用中引入了一个包含 580 个已知漏洞的操作系统。

06e8cdb2224cff63ca30132665295f8c.png

从上图(摘自《开源安全报告-2019》)可知,Docker Hub 上最流行的 10 个镜像都包含已知的安全漏洞。选用最小化基础镜像,即只包含项目确实需要的系统工具和库的镜像,就能最小化系统的攻击面,确保所用操作系统是安全的。

了解更多 Docker 镜像安全的知识[4]。


2. 设定最小权限的 USER

如果 Dockerfile 中没有指定 USER ,Docker 默认将会以超级用户 root 的身份运行容器,容器所属的命名空间(namespace)因此映射为 root 所有,这意味着容器有可能获取 Docker 宿主机的超级管理权限。不仅如此,以 root 用户身份运行容器,还扩大了攻击面,如果容器应用中存在安全漏洞,很容易造成权限提升。

在实践中,一般不需要容器拥有 root 权限。为了尽量降低安全威胁,创建专门的用户和用户组,在 Dockerfile 中使用 USER 指定用户,确保以最小权限的用户身份运行容器应用。

如果基础镜像中不包含专门的用户,那么就在 Dockerfile 中直接创建。下面就是一个这样的例子,它用到的基础镜像是 Ubuntu :

ea3be4204dd46ee5aa56d121e79a05ff.png

在上例中:

创建一个系统用户( -r 选项),没有密码、没有主目录且没有 shell;

将该用户添加到前面(使用 groupadd )创建的用户组;

最后一段参数设定了用户名以及所属的用户组。

如果你使用的是 Node.js 和 alpine 镜像,已经包含了一个用户 node,直接使用即可:

f52e87a5138716778f2a80cdf283a3f1.png

Node.js 应用开发者请参阅官方的Docker 和 Node.js 较佳实践[5]。


3. 签名和校验镜像,防范中间人攻击

Docker 镜像的认证颇具挑战性。在生产环境使用这些镜像运行我们的代码,意味着我们对这些镜像的极大信任。因此,必须保证我们拉取的容器镜像确实是发布者发布的镜像,没有被任何人篡改。发生镜像篡改,有可能是因为 Docker 客户端和镜像中心之间的中间人攻击,或者是发布者的身份被人盗用并在镜像中心发布了恶意镜像。

校验 Docker 镜像

Docker 默认直接拉取容器镜像,不会校验镜像的来源和发布者。这意味着你有可能使用来源和发布者不明的任何镜像。

无论采用何种策略,较佳实践都是先校验容器镜像,通过验证后再拉取镜像。为了体验镜像校验功能,执行下列暂时开启 Docker Content Trust 的命令:

f3d31c7f8fcac048e5689a7c7c3e482c.png

现在,尝试拉取一个没有签名的容器镜像——请求会被拒绝,不会拉取镜像。

签名 Docker 镜像

优先使用 Docker 认证的镜像,即这些镜像来自经过 Docker Hub 检查和选择的可信提供者。不要使用无法检验来源和发布者的容器镜像。

Docker 支持镜像签名,提供了额外一层的保护。使用 Docker Notary 签名镜像。Notary 会检验镜像的签名,如果签名不合法,它会阻止运行该镜像。

如果开启了 Docker Content Trust ,构建 Docker 镜像的同时也会对镜像签名。如果是第一次签名,Docker 会为当前用户生成一个私钥,保存在 ~/docker/trust 。后续所有的镜像都会使用这个私钥签名。

请参考Docker 官方文档[6],了解签名镜像的详细指令。


4. 找出、修正和监控开源漏洞

指定容器的基础镜像,同时也引入了该镜像包含的操作系统及系统库有可能存在的所有安全风险。

较好选用能够正常运行应用代码的最小化镜像,这有助于减少攻击面,因为限制了可能的安全漏洞数量。不过,这么做并没有对镜像进行安全审计,也不能防范将来发现的新漏洞。

因此,防范安全软件漏洞的一种方法是使用像 Snyk 这样的工具,持续扫描和监控 Docker 镜像各层可能存在的漏洞。

使用下列命令扫描容器镜像,检查是否存在已知漏洞:

2eae08635cdf7e1f9033af1098cebeb7.png

Snyk 能够监控指定的容器镜像,一旦有新发现的安全漏洞,通知用户并给出修补建议:

b6e0a51dc29c6a5b3b60e5c9d3a3f5cc.png

根据 Snyk 用户执行的镜像扫描,我们发现大约 40% 的 Docker 镜像包含已知漏洞,实际上弥补这些漏洞的新版本基础镜像已经有了。 Synx 提供了绝无仅有的修正建议功能,用户可以根据建议采取行动,升级 Docker 镜像。

Snyk 还发现在扫描的所有镜像中,为了减少漏洞的数量,大约 20% 的镜像需要重新构建。更多信息请参阅《开源安全报告-2019[3]》。


5. 不要在容器镜像中包含机密信息

有时候,构建包含应用的容器镜像时,需要用到一些机密信息,例如从私有仓库拉取代码所需的 SSH 私钥,或者安全私有软件包所需的令牌。如果 Dockerfile 中包含复制机密信息的命令,构建镜像时,这行命令对应的中间容器会被缓存,导致机密数据也被缓存,有可能造成机密信息泄漏。因此,像令牌和密钥这样的机密信息必须保存在 Dockerfile 之外。

使用多阶段构建

利用 Docker 的多阶段构建功能,用一个中间镜像层获取和管理机密信息,然后清除中间镜像,这样在应用镜像构建阶段不涉及敏感数据。如下面例子所示,使用代码将机密信息添加到中间层:

3babf2ada7b4a5ae9ae40c9407c6e3ef.png

使用 Docker 的 secret 管理功能

使用 Docker 的 secret 管理功能(alpha 阶段),加载敏感信息文件且不会缓存这些信息:

7e950fa6e1e6bedaf51743406e33e46d.png

想了解有关 Docker secret 的更多信息,请访问 Docker 官方站点[6]。

避免无意中复制机密信息

往镜像中复制文件时,也要当心,避免无意中添加了机密信息。例如,下面的命令将整个构建上下文文件夹复制到 Docker 镜像,有可能把敏感文件也复制进去了:

74256ca514d3debe8ea6606140f08e60.png

如果文件夹中有敏感文件,要么先移除这些文件,要么将这些文件包含在 .dockerignore 中,复制时会忽略这些文件:

cd46514f6f8c9c540a6e1fbfa62a7962.png

6. 设定镜像的标签,保证镜像的不可更改性

每个 Docker 镜像可以有多个标签(tag),代表该镜像的不同变体。最常见的标签是 latest ,表示这是该镜像的版本。镜像标签是可更改的,也就是说镜像的作者可以多次发布相同标签的镜像。

因此,即使你的 Dockerfile 明确指定了使用的基础镜像及其标签,这次镜像构建和下次镜像构建仍然可能用到了不同的基础镜像。解决这个问题,有多种办法:

优先选用最详细的镜像标签。例如,镜像有 :8、:8.0.1 和 :8.0.1-alpine 等标签,选择最后这个,因为它提供了最详细的信息。不要使用像 latest 这样过于泛泛的标签。

记住,镜像的发布者有可能删除镜像的某个标签。如果设定了所用镜像的标签,一旦这个标签被删除,镜像构建会因为找不到基础镜像而失败。为了避免这个问题,可以提前把该镜像复制到私有镜像中心或者公有镜像中心的私人账户下面。这么做,保证了镜像的不可更改性,同时也带来了维护私有镜像中心的负担。

使用比签名更具体的 SHA256 引用指明要使用的镜像,这能保证每次拉取都是相同内容的镜像。这么做也有风险,如果镜像改变了,以前的 SHA256 引用(散列值)也不存在了。

8f8579aae1c62c46db4edb99cd7704da.png

7. 使用 COPY ,不要使用 ADD

译者警告:这部分对 ADD 和 COPY 的描述,与 Docker 官方文档并不吻合,译者按照自己的理解修改了这部分内容。如果要了解作者原意,请阅读英文原文[7]。

从宿主机复制文件到容器镜像中的 Docker 命令有两个:COPY 和 ADD ,这两个命令本质上很相似,但具体功能并不相同:

COPY - 将本地文件或者目录(递归)复制到容器镜像中的目标目录,复制来源和目标都必须明确指定。

ADD - 与 COPY 类似的功能,有两个不同:(1)如果复制来源是本地压缩文件,ADD 将把该文件解压缩到目标目录;(2)ADD 也可以将远程 URL 指定的文件下载到目标目录。

为了避免可能导致的安全问题,请记住 COPY 和 ADD 的不同:

使用 ADD 从远程 URL 下载文件,存在中间人攻击的风险,文件内容有可能因此被篡改。必须确保远程 URL 必须是安全的 TLS 链接,校验远程 URL 的来源和身份。译者注:实际上,官方文档并不鼓励使用 ADD 添加远程文件。

如果复制的是本地压缩文件, ADD 自动将它解压缩到目标目录,这有可能触发 zip 炸弹或者 zip 任意文件覆盖漏洞。

相比较而言,使用 COPY 复制文件或目录,会创建一个缓存的中间镜像层,优化镜像构建的速度。


8. 使用 LABEL 指定镜像元数据

镜像元数据有助于用户更好地理解和使用该镜像。最常见的元数据是 maintainer ,它说明了镜像维护者的电邮地址和名字。使用 LABEL 命令添加镜像的元数据:

82b9fa76da535ca7f2e6cdea827d52e8.png

除了镜像的维护者信息,添加其他你认为重要的元数据,包括提交对象的散列值、相关构建的链接、质量状态(通过所有测试了吗?)、源代码链接、SECURITY.TXT 文件的位置等。

SECURITY.TXT (RFC5785)[8] 文件说明了镜像维护者的安全披露政策。较好在镜像元数据中加上 SECURITY.TXT 的链接,例如:

7f1650f1434fec6eef38c37a0b3f720c.png

想了解镜像元数据的更多信息,请访问 https://label-schema.org/rc1/ 。

译者注:这个规范好像已经废止了,请直接访问 OCI 镜像规范[9]。


9. 使用多阶段构建小而安全的镜像

使用 Dockerfile 构建应用容器镜像时,会生成很多只是构建时需要的镜像层,包括编译时所需的开发工具和库,运行单元测试所需的依赖、临时文件、机密信息等等。

如果保留这些镜像层,不仅会增加镜像的大小,影响镜像下载速度,而且会因为安装更多软件包而面临更大的攻击危险。这对用到的镜像也是成立的——需要使用一个专门构建应用的镜像,但不会用它来运行应用代码。

Go 语言就是一个很好的例子。构建一个 Go 应用需要用到 Go 编译器。编译得到的 Go 应用能够在任何操作系统上直接运行,没有任何依赖,包括 scratch 镜像。

Docker 因此提供了多阶段构建的功能,允许在构建过程中使用多个临时镜像,只保留最后一个镜像。这样,用户得到两个镜像:

第一个镜像——非常大的镜像,包含了构建应用和运行测试所需的所有依赖;

第二个镜像——非常小的镜像,只包含运行应用所需的极少数依赖。


10. 使用静态分析工具

使用静态分析工具,能够避免常见的错误,建立工程师自动遵循的较佳实践指南。

例如,hadolint 分析 Dockerfile 并列出不符合较佳实践规则的地方。

2492c7198906378597a6769d10b087e7.png

在集成开发环境(IDE)中使用 hadolint 更好。例如,安装 VS Code 的 hadolint 扩展后,编写 Dockerfile 时,边写边检查,既快又好。

了解更多 Docker 镜像安全的知识[10]。

把速查表打印出来,贴在某处,时刻提醒自己构建容器镜像时应该遵循的较佳安全实践!

原文:https://snyk.io/blog/10-docker-image-security-best-practices/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我来回答您关于 Docker 镜像失败的问题。 Docker 镜像失败可能有多种原因,下面列举一些可能的解决方法: 1. 检查网络连接:在 Docker 镜像之前,首先需要确保您的网络连接正常。可以尝试使用 ping 命令检查您的网络连接是否正常,如: ``` ping www.baidu.com ``` 2. 检查 Docker Hub 是否正常:如果您是从 Docker Hub 镜像,可以访问 Docker Hub 的网站查看是否有任何公告或故障信息。另外,您也可以尝试通过其他网络环境或者使用 VPN 连接 Docker Hub。 3. 检查 Docker 镜像名称和标签:如果您正在Docker 镜像名称或标签有误,可能会导致失败。请检查您的命令是否正确,特别是镜像名称和标签是否与实际镜像名称和标签相匹配。 4. 清理 Docker 缓存:有时候 Docker 缓存可能会导致镜像失败,您可以尝试清理 Docker 缓存并重新镜像。清理 Docker 缓存的命令如下: ``` docker system prune -a ``` 5. 更换 Docker 镜像源:如果您从 Docker Hub 镜像速度较慢,可以考虑更换 Docker 镜像源。例如,阿里云和腾讯云都提供了 Docker 镜像加速器服务,可以显著提高 Docker 镜像的下载速度。 以上是一些可能的解决方法,您可以根据实际情况尝试解决问题。希望能帮助到您! ### 回答2: Docker镜像失败可能是由于多种原因引起的。下面是一些可能导致失败的常见问题和解决方案: 1. 网络问题:检查网络连接是否正常,尝试通过ping命令或者访问其他网站来验证网络连接是否正常。 2. 仓库访问权限问题:某些镜像可能需要登录到仓库才能进行操作,确保使用了正确的凭据进行登录。 3. 镜像不存在或不可用:确保镜像存在于Docker仓库中,并且可用。如果是自己搭建的私有仓库,确保仓库正常运行并且镜像可用。 4. 部分问题:有时候,当Docker镜像过程中出现网络中断或其他原因导致部分镜像,但是镜像标签没有完全下载导致失败。这时候可以尝试删除局部下载的镜像,并重新。 5. 防火墙问题:如果你正在使用防火墙,可能需要检查防火墙设置,确保允许Docker进行网络通信。 6. 版本不匹配问题:有时候,镜像与当前Docker版本不兼容,这可能导致失败。可以尝试更新Docker版本,并重新尝试镜像。 总结:Docker镜像失败可能涉及多个方面,包括网络连接、访问权限、镜像可用性、部分问题、防火墙和Docker版本不匹配等。通过检查这些方面,逐一解决可能的问题,可以解决镜像失败的情况。 ### 回答3: 在使用Docker镜像时,可能会遇到各种失败的情况。这些问题可能由于网络连接问题、Docker源不可用、权限限制或镜像仓库问题等引起。以下是一些常见的解决方法: 1. 网络连接问题:首先检查网络连接是否正常。可以尝试使用ping命令测试镜像仓库的可访问性。如果网络连接有问题,可以尝试重启或重置网络设置。 2. Docker源不可用:有时候Docker源可能无法访问或不稳定。可以尝试更换使用其他可用的Docker源。可以在Docker配置文件中修改registry-mirrors的值来更改Docker源,并重启Docker服务。 3. 权限限制:在某些情况下,由于权限限制,用户可能无法镜像。可以尝试以管理员身份运行Docker命令或者将用户添加到Docker用户组中来解决权限问题。 4. 镜像仓库问题:有时候镜像仓库本身可能出现问题,无法正常镜像。可以尝试使用其他镜像仓库或等待一段时间再次尝试。 5. 镜像标签不存在:有时候可能会输入错误的镜像标签,导致无法镜像。可以仔细检查镜像的名称和标签是否正确。 在解决问题时,可以结合Docker命令的输出信息进行排查。可以查看Docker的日志或者使用-d参数来查看详细的错误信息,以便更好地定位问题所在。 总之,解决Docker镜像失败的问题需要仔细排查各种可能的原因,并尝试不同的解决方法,以确定最佳的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值