写点什么

Dockerfile 安全最佳实践

  • 2020-11-19
  • 本文字数:2376 字

    阅读完需:约 8 分钟

Dockerfile安全最佳实践

容器安全涉及问题很多,有许多“唾手可得”的方案能用来降低风险。不过,一个好的开始是编写 Dockerfile 文件时遵循一些规则。


在本文,我列出了一些常见的安全问题和如何规避它们。对于每一个问题,我还写了一个开放策略代理(Open Policy Agent,OPA)规则来使用conftest静态分析你的 Dockerfile 文件。


你可以在这个库找到.rego规则集。

不要在环境变量中存放密钥


密钥部署是一个很棘手的问题,而且很容易出错。对于容器化的应用程序,可以通过挂载卷从文件系统中显示它们,也可以更方便地通过环境变量显示。


使用ENV来存储密钥通常是不好的,因为 Dockerfile 文件通常与应用程序一起部署,因此这与在代码中硬编码密钥没有什么差别。


如何检测这一点:

secrets_env = [    "passwd",    "password",    "pass", #  "pwd", can't use this one       "secret",    "key",    "access",    "api_key",    "apikey",    "token",    "tkn"]
deny[msg] { input[i].Cmd == "env" val := input[i].Value contains(lower(val[_]), secrets_env[_]) msg = sprintf("Line %d: Potential secret in ENV key found: %s", [i, val])}
复制代码

只使用信任的根镜像


针对容器化应用程序的攻击链也来自构建容器本身所使用的层次结构。其中,主要的罪魁祸首明显是使用的根镜像。不受信的根镜像是一个高风险,任何时候都应该避免使用。


Docker 为大多数使用的操作系统和应用程序提供了一组官方根镜像。使用这些镜像,我们通过 Docker 自身分担的一些责任降低了协议风险。


如何检测这一点:

deny[msg] {    input[i].Cmd == "from"    val := split(input[i].Value[0], "/")    count(val) > 1    msg = sprintf("Line %d: use a trusted base image", [i])}
复制代码

这条规则针对的是 DockerHub 的官方镜像。由于我只检测到了 namespace 的缺失,这是非常愚蠢的。


信任的定义取决于你的上下文:可以相应地更改这条规则。


不要对根镜像使用'latest'标签


固定基础镜像的版本将使你对正在构建的容器的预期比较安心。


如果你依赖最新的(latest)版本,你可能会不知不觉地继承更新包,这在最好的坏情况下可能会影响你应用程序的可靠性,在最差的坏情况下可能会引入一个漏洞。


如何检测这一点:

deny[msg] {    input[i].Cmd == "from"    val := split(input[i].Value[0], ":")    contains(lower(val[1]), "latest"])    msg = sprintf("Line %d: do not use 'latest' tag for base images", [i])}
复制代码

避免 curl 命令


从互联网上拉取东西,并通过管道将它放到一个 shell 脚本中是非常糟糕的。不幸的是,这是一个比较广泛应用的方案来流式安装软件。


wget https://cloudberry.engineering/absolutely-trustworthy.sh | sh
复制代码


供应链攻击的风险与此相同,归根结底就是信任。如果你不得不使用 curl 命令,就请正确使用:


  • 使用可信来源

  • 使用安全连接

  • 验证下载内容的真实性和完整性


如何检测这一点:

deny[msg] {    input[i].Cmd == "run"    val := concat(" ", input[i].Value)    matches := regex.find_n("(curl|wget)[^|^>]*[|>]", lower(val), -1)    count(matches) > 0    msg = sprintf("Line %d: Avoid curl bashing", [i])}
复制代码

不要更新你的系统包


这可能有点儿牵强,但理由如下:你想要固定你的软件依赖的版本,如果你运行apt-get upgrade,你会将它们都更新到最新的版本。


如果你做了更新,而且你对根镜像使用latest标签,那么你就放大了你的依赖树的不确定性。


你要做的是固定根镜像的版本,并且只运行apt/apk update


如何检测这一点:

upgrade_commands = [    "apk upgrade",    "apt-get upgrade",    "dist-upgrade",]
deny[msg] { input[i].Cmd == "run" val := concat(" ", input[i].Value) contains(val, upgrade_commands[_]) msg = sprintf(“Line: %d: Do not upgrade your system packages", [i])}
复制代码

尽可能不要使用 ADD 命令


ADD命令的一个小功能是,将它指向一个远程 url,然后它会在构建时获取 url 的内容:

ADD https://cloudberry.engineering/absolutely-trust-me.tar.gz
复制代码

比较讽刺的是,官方文档建议使用 curl 命令来代替它。


从安全角度来看,不要这么做。事先获取你需要的内容,对其进行验证,然后COPY。但是,如果你真的需要,在安全连接上使用可靠信源


注意:如果你有一个奇特的构建系统,动态生成 Dockerfile 文件,那么ADD肯定会被使用到。


如何检测这一点:

deny[msg] {    input[i].Cmd == "add"    msg = sprintf("Line %d: Use COPY instead of ADD", [i])}
复制代码

不要使用 root 用户


容器中的 root 和主机上的 root 相同,但会受到 docker 守护程序配置的限制。无论有什么限制,如果一个人突破了容器,他也能够找到一种方法来获取访问主机的完整权限。


当然,这是不理想的,你的威胁模型不能忽视作为 root 用户运行所带来的风险。


因此,最好始终指定一个用户:

USER hopefullynotroot
复制代码


需要注意的是,在 dockerfile 中明确设定一个用户只是一层防线,不会解决所有以root用户运行所带来的问题


相反,我们可以——也应该采用层次防御方案并在整个堆栈中一步步缓解:严格配置 docker 守护进程或者使用一个非 root 容器方案,限制运行时配置(如果可能的话,禁止--privileged)等等。


如果检测这一点:

any_user {    input[i].Cmd == "user" }
deny[msg] { not any_user msg = "Do not run as root, use USER instead"}
复制代码

不要使用 sudo 命令


既然不能使用root用户,那你自然也不能使用 sudo 命令。


即使你作为一个普通用户运行,也要确保这个用户不属于sudoers

deny[msg] {    input[i].Cmd == "run"    val := concat(" ", input[i].Value)    contains(lower(val), "sudo")    msg = sprintf("Line %d: Do not use 'sudo' command", [i])}
复制代码

原文链接:


https://cloudberry.engineering/article/dockerfile-security-best-practices/


2020-11-19 12:422175
用户头像

发布了 165 篇内容, 共 75.7 次阅读, 收获喜欢 343 次。

关注

评论

发布
暂无评论
发现更多内容

WordPress 基于亚马逊云的部署实践(二)- 资源申请

王坤祥

Amazon EC2 亚马逊云 EFS

Rhino 8 for Mac「犀牛 3D建模工具」

繁星

犀牛3D建模软件 3d建模 Rhino 8

专业核磁数据处理软件MestReNova 14破解版

iMac小白

Modern CSV for mac(适用于Mac的CSV文件编辑器)

iMac小白

vmware fusion pro 13破解版下载 支持MacOS14

iMac小白

Mate Translate for Mac(翻译软件) v8.1.3激活特别版

mac

翻译软件 苹果mac Windows软件 Mate Translate

JixiPix Rip Studio for mac(照片拼接合成工具)v1.1.18激活版

iMac小白

Donemax DMmenu for mac(Windows风格的MacOS开始菜单)v1.9激活版

iMac小白

NCH PhotoPad for Mac(照片编辑软件)v11.87注册版

iMac小白

Topaz Photo AI for Mac(图像处理AI软件) 2.1.2激活版

iMac小白

纯CSS动态渐变文本特效

南城FE

CSS 前端 动画 css3渐变 渐变

Photo Image Editor Pixelstyle for Mac(图像编辑器)v4.3.0激活版

iMac小白

Topaz DeNoise AI for Mac(图片降噪软件) v3.7.2完美激活版

mac

苹果mac Windows软件 图片降噪软件 Topaz DeNoise AI

JProfiler 14 序列号激活 附 完整安装教程

繁星

JAVA开发 JProfiler 14

iTubeGo for Mac(网页视频下载软件)完美激活版

mac

视频下载工具 苹果mac Windows软件 iTubeGo

文心一言 VS 讯飞星火 VS chatgpt (138)-- 算法导论11.4 2题

福大大架构师每日一题

福大大架构师每日一题

Wirecast Pro for Mac(视频直播制作工具)v16.0.3中文免激活版

iMac小白

Amazon EC2的出现,是时代的选择了它,还是它选择了时代

淼.

高性价比的轻量应用服务器

Hanson

WordPress 基于亚马逊云的部署实践(三)- 服务部署

王坤祥

AWS WordPress Amazon EC2 亚马逊云

JixiPix PuzziPix Pro for mac(强大的拼图软件)v1.0.18激活版

iMac小白

Dockerfile安全最佳实践_文化 & 方法_Gianluca Brindisi_InfoQ精选文章