文章首发于个人公众号:「阿拉平平」
这篇文章 [1] 来自于 Cloudberry Engineering,作者总结了在编写 Dockerfile 时有哪些安全的注意点,并开源了一个清单 [2] 用来检测 Dockerfile 是否符合规则。我整理了原文,并对部分内容做了精简。由于自己水平有限,文中难免有疏漏错误之处,欢迎大家在留言区指正,以下是正文。
※※※
容器安全虽然是一个很宽泛的问题,但其实有很多小技巧可以帮助我们降低使用的风险。编写 Dockerfile 时遵循一些规则就是一个很好的出发点。
不要在环境变量中存储保密字典
保密字典(secrets)的发布是一个棘手的问题,很容易出错。对于容器化的应用,可以通过挂载卷或者环境变量的方式显示它们。
使用 ENV
存储 secrets 则是一种糟糕的做法,因为 Dockerfile 通常会和应用一起发布,所以这样就和把 secrets 硬编码到代码里没区别了。
仅使用受信任的基础镜像
容器化应用的供应链攻击来自于构建容器本身的分层结构。
很明显,罪魁祸首就是所用的基础镜像。使用不可信的基础镜像会带来很高的风险,应尽量避免。
Docker 为大多数操作系统和应用提供了官方的基础镜像。使用它们,可以最大程度地降低被破坏的风险。
不要使用 latest 作为基础镜像的标签
使用固定的版本作为基础镜像的标签,可以保证正在构建的容器的预期性。
使用 latest 作为标签会隐性地继承升级包,这种情况轻则可能会影响应用的可靠性,重则可能引入漏洞。
避免执行 curl
从网上拉取东西再在 shell 中运行是一种很糟糕的做法。不幸的是,它是一个简化软件安装的普遍解决方案。
wget https://cloudberry.engineering/absolutely-trustworthy.sh | sh
供应链攻击的风险与此相同,归根结底是信任问题。如果你真的需要在 bash 中执行 curl,请正确执行以下操作:
- 使用受信任的源
- 使用一个安全链接
- 验证下载内容的真实性和完整性
不要升级你的系统
这点可能有些夸张,但原因如下:你想固定软件依赖包的版本,但在执行 apt-get upgrade
后,这些依赖包会升级到最新版本。
进行升级并使用 latest 作为基础镜像的标签,会增加依赖树的不可预测性。
你要做的就是固定基础镜像的版本,仅执行 apt/apk update
。
尽量不要使用 ADD 指令
ADD
指令的一个功能是构建时获取远程 URL 的内容。
ADD https://cloudberry.engineering/absolutely-trust-me.tar.gz
讽刺的是,官方文档建议使用 curl 作为替代方案。
从安全的角度来看,我给出同样的建议:不要用 ADD
。先获取所需的内容,验证好再使用 COPY
指令。如果非用不可,请使用安全链接访问受信任的源。
不要使用 root 用户运行
容器里的 root 用户与宿主机相同,但受 Docker 守护进程配置的限制。无论有什么限制,如果用户突破了容器, 他就有办法获取到对宿主机的完全控制权。
所以不要忽略以 root 用户身份运行所带来的风险。
因此,最好始终指定一个普通用户:
USER hopefullynotroot
请注意,在 Dockerfile 显示设置用户只是一层防护,并不能解决整个运行问题。
相反,我们可以也应该采用深度防御的方案,并在整个堆栈中进一步降低风险:严格配置 Docker 的守护进程或者使用无 root 用户的容器,限制运行时的配置(可以的话,设置 --privileged
参数)等。
不要使用 sudo 命令
既然不使用 root 用户,那么也不应该使用 sudo 命令。
即使你使用的是普通用户,也请检查下 sudoers
文件,确保该用户没有特权。
References
[1] 文章: https://cloudberry.engineering/article/dockerfile-security-best-practices/
[2] 清单:https://github.com/gbrindisi/dockerfile-security
网友评论