写点什么

关于 Dockerfile 安全加固的那些事

  • 2017-02-02
  • 本文字数:2675 字

    阅读完需:约 9 分钟

来自 MicroBadger 的 Ross Fairbanks 从两个关于容器安全的视频里总结了几个针对 dockerfile 的安全调整,有助于构建更加安全的容器镜像。以下内容翻译自 Ross 的文章。

最近我观看了两个有关容器安全的演讲视频,其中一个视频的演讲者是来自Docker 的Justin Cormack,另一个是来自Container Solutions 的Adrian Mouat。我们已经遵循了很多安全方面的建议,不过仍然有改进的空间。所以,我们觉得是时候对我们的dockerfile 来一次安全大调整。

官方镜像

我们是 Alpine Linux 镜像的忠实用户,因为相比于 Debian 或 Ubuntu,它的体积更小,并且具有更小的可攻击表面。所以,我们使用官方的 Alpine 镜像作为其它镜像的基础。除此以外,官方镜像还有另一个好处——Docker 有一个专门的团队在维护它,并一直遵循着最佳实践。

我们的主要开发语言是 Go,不过有时候也会用 Ruby 来处理一些基于 Web 和脚本的任务。我们使用 ruby:2.3-alpine 作为这些镜像的基础。ruby:2.3-alpine 的 Ruby 是从源代码安装的,并非来自 Alpine 包。通过语义化版本控制( Semantic Versioning ),Ruby 2.3 能够接收到来自 Ruby 核心团队的安全更新。同时,Docker 团队会更新标签 2.3-alpine。

如果不使用 ruby:2.3-alpine,我们就要自己从源代码安装 Ruby,并持续跟进 Ruby 新版本的发布情况,或者使用 Alpine 包,并持续检查 Alpine 包内是否有新的 Ruby 版本。

通知和 Web 钩子(Webhook)

从 Ruby 的例子可以看到,当底层的基础镜像接收到安全更新时,你的整个镜像也要跟着重新构建。这个时候,我们的 MicroBadger 通知系统可以帮我们完成一些事情。我们在 Alpine 和 Ruby 的官方镜像上使用了通知。我们会从 Slack 接收到我们所关心的公共镜像的变更通知。

当基础镜像发生变更时,我们还会利用通知来自动触发镜像的构建。Docker Hub 也有这个功能,不过我们的通知可以用于任何支持 Web 钩子的系统,比如 CI 系统或安全扫描器。

非授权用户

容器和虚拟机之间的一个关键区别是容器与主机共享内核。在默认情况下,Docker 容器运行在 root 用户下,这会导致泄露风险。因为如果容器遭到破坏,那么主机的 root 访问权限也会暴露。

使用非授权用户来运行容器可以降低这种风险。下面是一个有关 Rails 应用的例子:

复制代码
# Create working directory.
WORKDIR /app
# Copy Rails app code into the image
COPY . ./
# Create non privileged user, set ownership and change user
RUN addgroup rails && adduser -D -G rails rails \
&& chown -R rails:rails /app
USER rails

安全扫描

在容器注册中心运行安全扫描可以为我们带来额外的价值。除了存放镜像,镜像注册中心定期运行安全扫描可以帮助我们找出薄弱点。Docker 为官方镜像和托管在 Docker Cloud 的私有镜像提供了安全扫描

来自CoreOS 的 Clair 也很不错,它是开源的,并被用于 Quay.io 的镜像注册中心安全扫描。Clair 将支持 Alpine,这是一个好消息,希望可以尽快在 Quay 上面看到它。还有其它一些扫描器,比如 TwistLock Aqua ,它们都是付费产品。

经过 Docker 的安全扫描,我们可以得到一个干净的 Go 镜像。我们把一个二进制版本拷贝到镜像里,然后加入一个 CA 认证依赖,这样我们就可以建立 HTTPS 连接。我们的 Rails 应用会有更多的依赖,因为 Ruby 是解释型语言。我们需要为我们的应用安装所有的 Ruby gem,同时需要为这些 gem 安装所有的操作系统依赖。

安全扫描会把扫描结果保存到 libxml2 和 libxslt 文件里。Nokogiri 是 XML 和 JSON 解析器,在构建镜像时,它会依赖前面提到的两种文件。为了得到更好的性能,Nokogiri 使用了编译过的 C 语言扩展,不过一旦安装完毕,就不再需要 libxml2 和 libxslt 文件了。

下面我们来移除构建依赖,这些命令有点复杂:

复制代码
# Cache installing gems
WORKDIR /tmp
ADD Gemfile* /tmp/
# Update and install all of the required packages.
# At the end, remove build packages and apk cache
RUN apk update && apk upgrade && \
apk add --no-cache $RUBY_PACKAGES && \
apk add --no-cache --virtual build-deps $BUILD_PACKAGES && \
bundle install --jobs 20 --retry 5 && \
apk del build-deps

Gemfile 包含了需要安装的 gem,同时 Gemfile.lock 用来管理依赖关系链。通过把这些文件缓存在 /tmp 目录,只有当 Gemfile 发生变更时,bundle install 命令才会被执行。如果 Gemfile 没有发生变更,它会使用缓存里的文件。这个缓存很有用,因为安装 gem 是一个很耗时的任务,还会占用很多带宽。

run 命令跨了很多行,只有一个层会被添加到镜像里,这个层包含了 apk 和 gem 包。构建包是作为虚拟包被添加进去的,在安装完毕之后它们可以很容易被移除。

更新:编译过的二进制仍然可能是不安全的

移除构建依赖会为我们带来一些好处,不过为了 gem 的扩展,镜像里仍然会存留一个二进制包。这个二进制包很难被扫描器发现,所以它或许仍然是一个会暴露薄弱点的地方。

所以,对这个二进制包进行安全检查是必要的。对于 Nokogiri 来说,我们使用了 1.6.8 版本,这个版本包含了最新的 libxml 和 libxslt 安全补丁。不过这些包的 CVE 元数据可能存在一个问题,我已经向 Docker 安全扫描团队反馈过这个问题。

自动构建

关于容器安全很关键的一点是,当镜像或基础镜像有安全方面的更新时,需要对镜像进行重新构建。镜像被关联到 Git 仓库,所以自动构建会让整个过程变得很容易。当仓库分支上有新的提交时,如果我们对其进行了跟踪,那么一个构建就会被触发。在之前的例子里我们已经看到,当基础镜像发生变更时也会自动触发构建。

我们的 Ruby 镜像自动构建会简单一些,因为自动构建可以直接使用本地的 Dockerfile。不过我们的 Go 镜像就麻烦一些,因为在把二进制包加入镜像之前需要先通过编译,我们通过使用本地的 makefile 来完成编译。

我们可以使用钩子来进行自动构建,并使用 Docker 容器来编译二进制包。来自 CenturyLinkLabs Prometheus 的 Go 语言构建器镜像都是很不错的选择。

可以通过钩子来调用这些构建器镜像。我们也可以使用钩子往镜像里添加动态的元数据,就像我最近在博客里所说的那样。

我无法覆盖视频里所提到的所有主题,所以如果有可能,大家可以自己去看视频。最后我想说的是,我们在MicroBadger 里添加了对私有仓库的支持,所以你们可以为Docker Hub 上的私有仓库使用通知。

本文已获得原作者翻译授权,查看英文原文: Dockerfile security tuneup


感谢木环对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-02-02 18:002777
用户头像

发布了 322 篇内容, 共 141.3 次阅读, 收获喜欢 146 次。

关注

评论

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

非标自动化行业ERP选型与案例展示!

积木链小链

ERP

Hume AI 语音控制功能:创建个性化语音;李飞飞空间智能首个模型:单图生成 3D 交互场景丨 RTE 开发者日报

声网

如何选择团队网盘?企业常用的8款工具盘点

易成研发中心

NFTScan | 11.25~12.01 NFT 市场热点汇总

NFT Research

NFT\ NFTScan

大厂Java面试经验套路总结

开心学Java

程序员 高并发 架构师 java面试 大厂

什么工具可以解决团队协作障碍?

秃头小帅oi

Java面试无分布式微服务经验,该如何弥补?

了不起的程序猿

分布式 微服务 后端 架构师 java面试

签约案例|GreptimeDB 为数据驱动的汽车应用带来安全高效的车云一体解决方案

Greptime 格睿科技

数据库 车联网 汽车 车云一体

企业如何构建自己的 AI 编码能力

cloud studio AI应用

编码 #人工智能 腾讯云AI代码助手 #AI #大语言模型

怎么把域名解析到IP地址上?怎么去设置域名解析?

国科云

让每笔营销费用发挥更大价值,为生意持续增长创造可预见的未来!

赛博威科技

数字营销 营销费用管理 赛博威

小程序SDK在跨端app开发是否有优势?

FinFish

跨端应用开发 小程序容器技术 跨端技术 跨端app开发 小程序SDK

手撕单例的 5 种写法!

王磊

CDN的作用以及哪些企业适合使用CDN?

Ogcloud

CDN 网络加速 CDN加速 CDN技术 CDN网络加速

Web自动化测试中的元素定位与显式等待

测试人

软件测试

SOL项目开发代币Dapp的基本要求

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 交易所开发代币开发

中国恩菲:有色金属行业如何使用 IoTDB?|用户零距离第一期

Apache IoTDB

OKR工作法软件大盘点,7款优秀工具助力目标管理

易成研发中心

向量检索服务RAM授权

DashVector

人工智能 阿里巴巴 向量检索 大模型 向量数据库

打造去中心化交易平台:公链交易所开发全解析

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 代币开发

云服务器的故障率比物理服务器更低吗?

Ogcloud

云主机 云服务器 香港云服务器 美国云服务器 云服务器租用

官方提供平台,导师倾情陪练,助力学生玩转开源|Greptime 参与「开源之夏」的第二年正式收官!

Greptime 格睿科技

数据库 开源 活动 开源之夏

Java日志手机号脱敏工具类

EquatorCoco

Java 工具

Spring Cloud+Nacos+KMS 动态配置最佳实践

阿里巴巴云原生

阿里云 云原生

加速和扩大洞察|如何做好半结构化数据分析

AI数据云Relyt

非结构化数据 数据分析、 AI-ready JsonB

Java学习如何进阶?

了不起的程序猿

Java 程序员 并发编程 架构师 Java进阶

赛博威携手百度智能云,开启数字营销新未来

赛博威科技

人工智能 AI 百度智能云 数字营销 赛博威

赛博威数字营销一体化高效运维,更高效、更全面、更稳定、更创新

赛博威科技

运维 数字营销 赛博威

深入编码规则:构建灵活且可扩展的编号生成器

inBuilder低代码平台

低代码

边学边赛 等你来战 | 昇腾AI原生创新算子挑战赛华中科技大学专场赛完美收官

Geek_2d6073

TinyPro Vue 1.1.0 正式发布:增加细粒度权限、页签模式、多级菜单,支持Vite/Rspack/Farm等构建工具

OpenTiny社区

开源 前端 组件库 OpenTiny TinyVue

关于Dockerfile安全加固的那些事_语言 & 开发_Ross Fairbanks_InfoQ精选文章