Dockerfile安全最佳做法

2020-10-14 22:55:31

集装箱安全是一个广阔的问题空间,有许多低垂的果实可以收获,以降低风险。一个很好的起点是在编写Dockerfile时遵循一些规则。

我整理了一份常见安全问题的清单,以及如何避免这些问题。对于每个问题,我还编写了一个开放策略代理(Open Policy Agent,OPA)规则,可以使用conftest静态分析您的Dockerfile。你不能再往左移了!

您可以在此存储库中找到.rego规则集。我感谢反馈和贡献。

秘密分发是一个毛茸茸的问题,很容易弄错。对于容器化的应用程序,可以通过挂载卷从文件系统显示它们,也可以更方便地通过环境变量来显示它们。

使用ENV存储机密是不好的做法,因为Dockerfile通常是随应用一起分发的,所以在代码中与硬编码机密没有区别。

Secrets_env=[";密码";,";密码";,##34;密码";,##34;密码";,';不能使用此密码";密码";,";密钥";,";访问";,";api_key";,";apiKey";,";令牌&34;,";TKN";]DENY[msg]{input[i].Cmd==";env";val:=input[i].value包含(LOWER(val[_]),secrets_env[_])msg=sprintf(";第%d行:在ENV密钥中找到潜在秘密:%s";,[i,val])}}。

针对容器化应用的供应链攻击还将来自用于构建容器本身的层的层次结构。

主要的罪魁祸首显然是使用的基本图像。不受信任的基本映像风险很高,应尽可能避免。

Docker为最常用的操作系统和应用提供了一套官方基础镜像。通过使用它们,我们利用与Docker本身分担的某种责任,将危害风险降至最低。

拒绝[msg]{input[i].Cmd==";from";val:=Split(input[i].value[0],";/";)count(Val)>;1 msg=sprintf(";第%d行:使用受信任的基本映像";,[i])}}。

此规则针对DockerHub的官方图片进行调整。这非常愚蠢,因为我只检测到名称空间的缺失。

固定基础映像的版本将使您在构建的容器的可预测性方面获得一些安心。

如果您依赖于LATEST,您可能会静默继承更新的包,在最坏的情况下可能会影响您的应用程序的可靠性,在最坏的情况下可能会引入漏洞。

拒绝[msg]{input[i].Cmd==";From";val:=Split(Input[i].value[0],";:";)包含(LOWER(VAL[1]),";LATEST";])msg=spintf(";第%d行:不要对基本图像使用';LATEST';标记";,[i])}。

从互联网上拉东西,然后把它们输送到一个外壳里,这是最糟糕的事情了。不幸的是,这是一种广泛使用的简化软件安装的解决方案。

供应链攻击的风险也是如此,归根结底是信任。如果你真的要卷曲狂欢,那就做对了:

拒绝[消息]{Input[i].Cmd==";Run";val:=Concat(";";,Input[i].value)匹配:=regex.find_n(";(curl|wget)[^|^>;]*[|>;]";,下限(Val),-1)计数(匹配)>;0消息=短跑(";行%d:避免卷曲打击";,[i])}。

这可能有点牵强,但理由如下:您希望固定软件依赖项的版本,如果您执行apt-get升级,您将有效地将它们全部升级到最新版本。

如果您进行了升级,并且使用的是基本映像的最新标记,则会放大依赖关系树的不可预测性。

您要做的是固定基本映像版本,然后只更新apt/apk。

UPGRADE_COMMANDS=[";apk Upgrade";,";apt-get Upgrade";,";,]Deny[msg]{input[i].Cmd==";run";val:=Concat(";";,input[i].value)包含(val,Upgrade_Commands[_])msg=sprintf(“行:%d:不升级系统包";,[i])}。

Add命令的一个小功能是,您可以将其指向远程url,它将在构建时获取内容:

从安全的角度来看,同样的建议也适用:不要。在获取您需要的任何内容之前,对其进行验证,然后复制。但是,如果您真的必须这样做,请使用受信任的来源,而不是安全的连接。

注意:如果您有一个可以动态生成Dockerfile的奇特构建系统,那么Add实际上就是一个请求利用的接收器。

拒绝[msg]{input[i].Cmd==";add";msg=sprintf(";第%d行:使用复制而不是添加";,[i])}。

容器中的root与主机上的root相同,但受docker守护进程配置的限制。不管有什么限制,如果一个演员冲出了容器,他仍然能够找到一种方法来完全访问主持人。

当然,这并不理想,您的威胁模型不能忽略以root身份运行所带来的风险。

请注意,在Dockerfile中显式设置用户只是一层防御措施,并不能解决以根用户身份运行的整个问题。

相反,我们可以(也应该)采用纵深防御方法,并在整个堆栈中进一步缓解:严格配置docker守护进程或使用无根容器解决方案,限制运行时配置(如果可能,则禁止--特权,等等),等等。

Any_user{input[i].Cmd==";user";}拒绝[msg]{不是any_user msg=";不要以root身份运行,改用user";}。

即使您以用户身份运行,也要确保该用户不是sudoers俱乐部的成员。

拒绝[msg]{input[i].Cmd==";run";val:=Concat(";";,input[i].value)包含(较低(Val),";sudo";)msg=spintf(";行%d:请勿使用';sudo';命令";,[i])}

这幅作品受到了马杜·阿库拉的启发,是对马杜·阿库拉现有技术的迭代。