写点什么

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:422507
用户头像

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

关注

评论

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

优化独立站网页布局,提升30%用户留存

九凌网络

一文解释Linux的内存分页管理

伤感汤姆布利柏

数云引领,神州数码荣获CSA2023安全创新奖

科技热闻

lazada商品详情数据接口(lazada.item_get)丨lazada API接口

tbapi

lazada商品详情数据接口 lazada商品数据接口 lazada商品API接口 lazada API接口

玩转低代码可视化平台,软件开发如此简单!

互联网工科生

软件开发 低代码 可视化开发 JNPF

喜讯丨上海和今信息科技有限公司入选2023年上海市专精特新中小企业名单

ModelWhale

人工智能 科技 专精特新企业

自动化接口测试工具 AREX 0.6.2 版本发布

AREX 中文社区

开源 自动化测试 接口测试

全新升级!腾讯云大数据ES Serverless服务开启日志分析新体验

腾讯云大数据

ES

前端技术-调试工具(上)

不在线第一只蜗牛

前端 框架 前端技术

和鲸携手上海交大医学院张维拓老师,混合式教学聚焦R语言医学数据分析,从图表开始复现顶刊论文

ModelWhale

人工智能 数据分析 R语言 代码复现 医学

DAPP代币燃烧质押项目系统开发丨详情开发

l8l259l3365

移动图形工作站分类、结构和功能

青椒云云电脑

图形工作站

和鲸解放军总医院连续生理数据分析引擎入选爱分析数据智能最佳实践案例

ModelWhale

人工智能 大数据 数字化转型 企业管理 数智化

软件测试开发/全日制丨自动化测试定位策略 学习笔记

测试人

软件测试 测试开发

lazada商品列表数据接口(lazada.item_search)丨lazada API接口

tbapi

lazada商品详情数据接口 lazada商品数据接口 lazada API接口 lazada商品列表数据接口

Lazada商品详情API(lazada.item_get)获取商品的评论和评分信息

技术冰糖葫芦

API

云桌面有什么技术特点?应用场景是什么?

青椒云云电脑

桌面云 云桌面 云桌面解决方案

图形工作站有必要么?图形工作站电脑特点

青椒云云电脑

图形工作站 移动图形工作站

数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换

阿里云瑶池数据库

数据库 List 阿里云 云原生 adb

2024 AIGC 应用层十大趋势;iPhone 遭史上最复杂攻击!丨 RTE 开发者日报 Vol.119

声网

构建企业级AI中台,实现业务场景价值闭环

ModelWhale

AI 数字化转型 中台架构 AI中台

SEO内容页面性能优化全攻略

九凌网络

普及旗舰音质,一加 Buds 3正式发布 售价499元

编程猫

官宣|硬核阵容曝光!PolarDB开发者大会全议程公布

阿里云瑶池数据库

数据库 阿里云 云原生 开发者大会

Databend 的算力可扩展性

Databend

2023 年最先进认证方式上线,Authing 推出 Passkey 无密码认证

Authing

身份认证 Authing 无密码认证 Passkey

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