NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

关于 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:002658
用户头像

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

关注

评论

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

守护企业数据安全,华为云数据库 GaussDB(for MySQL)有绝招

科技之光

丧心病狂,竟有Thread.sleep(0)这种神仙写法?

JAVA旭阳

Java JVM

Docker 中的挂载卷

HoneyMoose

无魅友,不魅族!魅族大力推广魅友文化,用行动阐述何为用户共创

Geek_2d6073

DAG任务调度系统 Taier 演进之道,探究DataSourceX 模块

袋鼠云数栈

开源

深耕数字办公,华为云桌面怎样带来高效办公体验?

路过的憨憨

华为云数据库GaussDB(for MySQL)全方位守护企业云上数据安全

爱科技的水月

MAXHUB+腾讯会议:为未来办公造一部动力引擎

脑极体

这一篇让你彻底搞懂微信生态里的二维码

产品海豚湾

产品经理 产品设计 二维码 微信扫码 SaaS 产品

Java高手速成│编写你第一个数据库程序

TiAmo

JDBC 数据库· 12月月更

数据代码如何“产地直销”,做到持续集成持续发布?

数造万象

企业数据上云,华为云数据库 GaussDB(for MySQL)轻松解决

科技之光

如何写一个深度学习编译器

MegEngineBot

深度学习 开源 编译器 MegEngine MegCC

物联网 IOT 设备如何脱离信息孤岛?

eng八戒

物联网 IoT 网络 网络配置 涂鸦智能

基于聚类算法的话术挖掘技术及在营销服场景的落地应用

中关村科金

人工智能 大数据 算法 对话机器人 技术实践

【web 开发基础】PHP数组元素的添加和删除操作 (49)

迷彩

数组 数组操作 PHP基础 先进先出 后进先出

转转AB平台的设计与实现

转转技术团队

大数据 A/B 测试

三个延伸打法,撑起华为云桌面的7年领跑

路过的憨憨

国产ETL 星光不问赶路人 时我不待

weigeonlyyou

oracle Prometheus Clickhouse MySQL 数据库 InfluxDB Cluster

HTTP实体首部字段

穿过生命散发芬芳

HTTP 12月月更

手游“Lord of Dragons Global”进军P2E市场

科技热闻

大咖说·阿里云教育|“网上浙大”数字化之路

大咖说

数字化 高校

【5000字长文】从 S3 到 DataZone,亚马逊云科技用16年讲完一个数据的故事

亚马逊云科技 (Amazon Web Services)

亚马逊云科技 Builder 专栏

架构实战营模块三作业

张贺

华为云数据库助力微鲤科技智能升级

爱科技的水月

2022-12-27:etcd是无界面的,不好看,joinsunsoft/etcdv3-browser是etcd的web可视化工具之一。请问在k3s中部署,yaml如何写?

福大大架构师每日一题

云原生 k8s etcd k3s 福大大

企业金融App评测系列——微众银行以App构筑企业金融服务新生态,成为企业的随身数字银行

易观分析

企业 金融 银行

Code Review到底在关注些什么?

孟君的编程札记

Java CodeReview

Git使用教程之本地仓库的基本操作

智趣匠

git git 学习 Git命令行

「Go框架」http请求处理流程: gin、beego等web框架是如何处理http请求的?

Go学堂

golang 开源 程序员 个人成长 12月月更

DevSecOps 需要知道的十大 K8s 安全风险及建议

SEAL安全

k8s DevSecOps 12 月 PK 榜

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