写点什么

Docker 容器安全的“终极武器”——AIM

  • 2019-09-27
  • 本文字数:6375 字

    阅读完需:约 21 分钟

Docker 容器安全的“终极武器”——AIM

我们需要关注 Docker 中的安全问题吗?这个得具体分析。Docker 拥有相当强大的安全保障能力,因此如果大家只使用官方 Docker 镜像而且不需要进行机器间通信,就完全没必要为安全而担心。


但是,如果大家使用的是非官方镜像、提供文件或者运行应用程序,情况就完全不同了。在这类场景中,我们必须对 Docker 安全性建立起充分的了解。


我们的主要安全目标,在于防止恶意用户获取有价值信息或者造成严重破坏。为此,我们将立足多个关键领域分享 Docker 安全最佳实践。通过本文,大家将掌握超过 20 项重要的 Docker 安全心得!


在第一节中,我们主要关注以下三个方面:


  • Access management(访问管理)

  • Image safety(镜像安全)

  • Management of secrets(保密信息管理)


首字母相连,就是 AIM。


首先,我们来聊聊容器访问限制问题。

访问管理——限制权限

在启动一套容器后,Docker 会创建一个命名空间组。命名空间的作用是防止容器中的进程被主机上的其他用户/容器看到或者影响。换言之,命名空间正是 Docker 实现不同容器间隔离的主要方式。


Docker 还提供私有容器网络,用于防止同一主机上其它容器的网络接口错误获得访问权限。


由此,Docker 容器建立起了自己的隔离体系——但是,您的用例仍然算不得高枕无忧。


良好的安全性,意味着必须遵循最低权限原则。您的容器应该具备完成任务的必要功能,但除此之外再无其它功能。不过麻烦在于,一旦对能够在容器中运行的进程加以限制,容器很可能无法完成正常任务所需要的各项操作。


目前,我们可以通过多种方式调整容器权限。首先,避免以 root 身份运行(或者在必须使用 root 身份时,避免 re-map)。第二,利用—cap-drop 以及—cap-add 进行功能调整。


避免 root 并调整功能,已经基本可以满足大家对于权限限制的需求。但也有一部分高级用户可能希望调整默认的 AppArmor 以及 seccomp 配置文件。受本文篇幅所限,这里就不深入讨论这种情况啦。

避免以 root 身份运行

Docker 的默认设置认为用户在镜像中以 root 身份进行操作。但大多数人并没有意识到这种情况的危险性。这意味着攻击者能够轻松访问敏感信息甚至是系统内核。


作为一项通行的最佳实践,请千万不要以 root 身份运行容器。


“防止容器内权限提升攻击的最佳方法,就是将容器应用配置为以非高权限用户身份运行。”——Docker 说明文档


大家可以在 build 时通过以下命令指定一个非 root 用户 ID:


docker run -u 1000 my_image
复制代码


其中的—user 或者-u 标记,用于指定用户名或者用户 ID。只要用户 ID 还不存在,这条命令就能顺利起效。


继续看这段命令,其中的 1000 是任意取值的非高权限用户标识。在 Linux 中,用户标识的一般取值在 0 到 499 之间。这里之所以选择超过 500 的标识,是为了避免其被选定为默认系统用户。


相较于通过命令行设置用户,更好的办法是通过 root 对镜像中的用户进行变更。如此一来,大家就不必在 build 时重复设置。在执行完要求使用需要 root 权限功能的 Dockerfile 指令后,我们接下来只需要在镜像里烧录 USER Dockerfile 指令即可。


换言之,首先安装必要的软件包,而后切换用户。例如:


FROM alpine:latestRUN apk update && apk add --no-cache gitUSER 1000

复制代码


如果大家必须以 root 用户身份在容器内运行某些进程,则可以在 Docker 主机上将 root 身份 re-map 至某个权限相对较低的用户。具体请参阅 Docker说明文档


您可以通过变更功能的方式为用户授权必要的权限。

功能

功能,是指一组获准进程的集合。


我们可以通过命令行利用—cap-drop 以及—cap-add 进行功能调整。最佳策略是利用—cap-drop all 清空容器的所有权限,再利用—cap-add 逐一添加必要功能。


大家可以在运行时中调整容器的功能。例如,要删除使用 kill 命令停止容器运行的功能,大家可以通过以下命令移除该默认功能:


docker run --cap-drop=Kill my_image
复制代码


请避免为进程提供 SYS_ADMIN 及 SETUID 权限,因为这两种权限会带来巨大的影响。有这两种功能在,用户几乎相当于拥有了 root 权限(移除这些功能的意义与避免使用 root 权限相同)。


另外,请禁止容器使用 1 到 1023 之间的端口,因为大多数网络服务都运行在这一范围之内。未授权用户可以监听登录等内容,并运行未经授权的服务器应用程序。此外,编号较低的端口在运行中还需要获取 root 身份,或者被明确赋予 CAP_NET_BIND_SERVICE 功能。


要查找容器中是否存在高权限端口访问,大家可以使用 inspect。只需要运行 docker container inspect my_container_name 命令,我们就能看到关于已分配资源与容器安全配置文件的大量细节信息。


点击此处可了解更多关于 Docker 权限的参考资料。


与 Docker 中的大多数设置一样,我们最好是以自动以及自我记录的方式通过文件进行容器配置。利用 Docker Compose,大家可以在服务配置当中指定某项功能,例如:


cap_drop: ALL
复制代码


或者,大家也可以在 Kubernetes 文件中进行调整,详见此处的说明信息。


若需了解完整的 Linux 功能清单,请点击此处

访问管理——资源限制

另外,我们也可以限制容器对系统资源(例如内存以及 CPU)的访问。如果没有资源限制,容器会很快耗尽一切可用的内存。万一发生这种情况,Linux 主机内核将提示内存意外耗尽,并终止内核进程。这可能导致系统整体崩溃。大家可以想象,不少攻击者都利用这种方式尝试关闭目标应用程序。


如果我们在同一台计算机上运行多套容器,则应精心限制各个容器所能使用的内存与 CPU 资源。如果容器内存不足,其将关闭;容器关闭可能导致应用程序崩溃,并直接影响到用户的体验。因此,我们有必要采取隔离机制,防止主机内存不足引发的容器环境崩溃。


Docker Desktop CE for Mac v2.1.0 提供默认资源限制功能。您可以在 Docker 图标->首选项下访问该功能。接下来,您可以点击“资源”选项卡,并通过滑块调整资源限制水平。



Mac 上的资源设置界面


或者,大家也可以通过指定—memory 标识或者-m 通过命令行进行资源限制,命令后面跟上数字加度量单位即可。


4m 代表着 4 MiB,这是容器所能设置的最低分配内存量。MiB 要比 MB 略大一点。目前说明文档的内容有误,希望维护人员在读到本文时已经接受我的修复补丁。


To see what resources your containers are using, enter the command docker stats in a new terminal window. You’ll see running container statistics regularly refreshed.



状态界面


在引擎盖下面,Docker 正使用 Linux 控制组(cgroups)实现资源限制。这项技术已经得到了无数实践场景的验证,相当可靠。


感兴趣的朋友可以点击此处了解 Docker 中的资源限制机制。

镜像安全

从 Docker Hub 当中提取镜像,就像是邀请外人到自家作客。虽然不太安全,但有时候却非常必要。

使用可信镜像

镜像安全的第一原则,就是只使用您信任的镜像。那么,我们如何判断哪些镜像值得信赖?


官方镜像无疑是个理想的安全保障选项。这类镜像包括 alpine、ubuntu、python、golang、redis、busybox 以及 node。这些镜像都已经拥有上千万的下载量,而且无数双眼睛在密切关注它们的动向。


Docker 解释称:


Docker 赞助了支专门的团队,负责审查并发布官方镜像中的所有内容。该团队与上游软件维护人员、安全专家以及更广泛的 Docker 社区开展合作,以确保这些镜像安全可靠。

减少你的攻击面

类似于使用官方镜像,大家也可以选择使用最小基础镜像。


由于代码量更少,因此存在安全漏洞的可能性就更低。较小、复杂度较低的基础镜像,其透明度也更高。


了解 Alpine 镜像里有些什么,要比了解您朋友的镜像里有什么更简单,而这又比弄清朋友的朋友使用的镜像里有什么更简单。总之,关系越单纯,解决起来越容易。


同样的,只安装您真正需要的软件包。这样能够减少攻击面,并加快镜像的下载与构建速度。

要求使用签名镜像

您也可以使用 Docker 内容信任功能对镜像进行签名。


Docker 内容信任功能强制要求用户使用包含签名的镜像,无签名镜像将无法使用。可信的来源包括由 Docker Hub 提供的官方 Docker 镜像,以及来自用户的可信来源签名图像。


Docker 在默认情况下会禁用内容信任功能。要启用这项功能,请将 DOCKER_CONTENT_TRUST 环境变量设置为 1。在命令行中运行以下命令:


export DOCKER_CONTENT_TRUST=1
复制代码


现在,我尝试从 Docker Hub 下载自己未签名的镜像时,系统即会阻止这项操作。


Error: remote trust data does not exist for docker.io/discdiver/frames: notary.docker.io does not have trust data for docker.io/discdiver/frames
复制代码


这是一种保护自己的有效方式。感兴趣的朋友可以点击此处了解内容信任功能。


Docker 通过对内容进行加密校验的方式存储及访问镜像。这项超酷的内置安全功能,可以防止攻击者创建冲突镜像。

管理保密信息

您的访问受到限制,您的镜像也安全可靠,接下来就是照顾好保密信息了。


管理敏感信息的头号原则:不要将其纳入镜像。恶意人士能够比较轻松地从代码库、日志以及其它位置找到这些未经加密的敏感信息。


原则二:不要在敏感信息中使用环境变量。任何可以通过 docker inspect 或者 exec 进入容器的家伙,都将能够窥探你的秘密。任何人也都可以通过 root 身份运行这些命令。虽然之前提到了应该严格控制 root 身份的分发,但我们得留点冗余空间,这也是实现良好安全性的必要一步。一般来讲,日志会转储环境变量值,大家肯定不希望自己的敏感信息被到处传播。


Docke 存储卷在这方面表现出色。Docker 说明文档也推荐利用它访问敏感信息。存储卷能够去除 docker inspect 与日志记录带来的风险。但是,root 用户仍然能够窥探到你的秘密。总体来说,存储卷是个相当不错的解决方案。


但比存储卷更好的,是使用 Docker secrets。这里的保密信息都将接受加密。


某些 Docker 说明文档中提到,我们只能在 Docker Swarm 中使用 secrets 功能。但实际情况并非如此,没有 Swarm,我们也能享受 Docker 中的 secrets 功能。


如果大家只需要把保密信息存放在镜像里,则可以使用 BUildKit。BuildKit 是一款远超现有 Docker 镜像构建工具的出色后端。它能够显著缩短构建时长,并提供其它一系列出色的功能——包括 build-time secrets 支持。


BuildKit 是一款相对较新的工具——直到 Docker Engine 18.09 版本才第一次出现。我们可以通过三种方式将 BuildKit 指定为后端。未来,BuildKit 将成为 Docker 的默认后端选项。


  1. 利用 export DOCKER_BUILDKIT=1 命令将其设置为环境变量。

  2. 在使用 build 或者 run 命令时加上 DOCKER_BUILDKIT=1。

  3. 默认启用 BuildKit。将/etc/docker/daemon.json 中的配置设置为 true:{ “features”: { “buildkit”: true } }。而后重启 Docker。

  4. 接下来,您就可以在构建时通过—secret 标识使用 secrets 功能了:


docker build --secret my_key=my_value ,src=path/to/my_secret_file .
复制代码


您的文件将把保密信息指定为键值对的形式。


这些保密信息并不会被保存在最终镜像中,同时也不会出现在图像构建缓存当中。安全第一嘛!


如果大家需要将保密信息引入运行中的容器(而不只是镜像构建过程),则可使用 Docker Compose 或者 Kubernetes。


利用 Docker Compose,我们可以将保密信息的键值对添加至某项服务中,并指定对应的 secret 文件。以下示例来自 Stack Exchange 上关于 Docker Compose secrets提示的相关素材。


例如将保密信息放置在 docker-compose.yml 当中:


version: "3.7"
services:
my_service: image: centos:7 entrypoint: "cat /run/secrets/my_secret" secrets: - my_secret
secrets: my_secret: file: ./my_secret_file.txt
复制代码


之后即可利用 docker-compose up --build my_service 正常启动 Compose。


如果大家使用 Kubernetes,它也支持 secrets 管理功能。Helm-Secrets 能够帮助我们更轻松地在 K8s 当中实现保密信息管理。此外,K8s 还提供基于角色的访问控制(RBAC)功能,这一点与 Docker Enterprise 相同。RBAC 使得 Secrets 访问流程更具可管理性,同时也为团队提供了更强的安全保障。


保密信息的另一项最佳管理实践是利用 Vault 等 secret 管理服务。Vault 是一项由 HashiCorp 推出的服务,专门用于管理保密信息。其还能为保密信息设置时间限定。感兴趣的朋友可以点击此处了解更多关于 Vault Docker 镜像的细节信息。


AWS Secrets Manager 以及其他云服务供应商提供的类似产品,也能帮助大家在云端保护自己的保密信息。


请记住,管理保密信息的要诀,在于保持其保密性质。绝对不要将其烧录至镜像当中,或者转换为环境变量。

更新

与其它代码一样,我们应当保证镜像中的语言与库的及时更新,从而享受最新安全修复补丁带来的保障。


如果大家在镜像当中引用基础镜像版本,请确保该基础版本始终保持更新。


同样的,大家还应及时更新自己的 Docker 版本,以便修复并增强功能,进而实现新的安全功能。


最后,保证您的主机服务器软件及时更新。如果在托管服务上运行容器系统,服务商应该会替您完成更新工作。


更高的安全性,源自更及时的更新维护。

考虑使用 Docker Enterprise

如果您的组织当中有很多员工和一大堆 Docker 容器,那么 Docker Enterprise 可能更适合您。管理员可以借此为所有用户设置策略限制。Docker Enterprise 提供的 RBAC、监控与日志记录功能也将使您的团队更轻松地实现安全管理。


在 Enterprise 的帮助下,您还可以在 Docker Trusted Registry 中行托管您的镜像。Docker 提供内置安全扫描,可确保您的镜像中不存在已知漏洞。


Kubernetes 虽然也免费提供一系列类似的功能,但 Docker Enterprise 还具有其它与容器及镜像相关的附加安全功能。最重要的是,Docker Enterprise 3.0 发布于 2019 年 7 月,其中包含“具有合理安全默认设置”的 Docker Kubernetes 服务。

其它提示

  • 不要以-- privileged 的方式运行容器,除非您需要在 Docker 容器之内运行 Docker,而且很清楚自己到底在干什么。


  • 在 Dockerfile 中,使用 COPY 而非 ADD。ADD 会自动提取压缩文件,并可以从 URL 处复制文件。COPY 没有这些功能。尽量避免使用 ADD,这能帮助您免受远程 URL 与 Zip 文件攻击的影响。

  • 如果您在同一服务器上运行有其它进程,务必将其运行在 Docker 容器当中。

  • 如果您使用 Web 服务器与 API 来创建容器,请认真检查各项参数,以确保不会意外创建不需要的容器。

  • 如果您公开 REST API,请使用 HTTPS 或者 SSH 保护 API 端点。

  • 考虑使用 Docker Bench for Security 进行检查,以了解您的容器是否遵循安全准则以及具体遵循程度。

  • 仅在存储卷中保存敏感数据,绝不要将其保存在容器中。

  • 如果使用具有网络功能的单主机应用程序,请不要使用默认桥接网络。其存在技术缺陷,不适用用于生产。一旦公布端口,则桥接网络上的所有容器都将可供外部人士访问。

  • 使用 Lets Encrypt for HTTPS 进行证书交付。点击此处查看 NGINX 示例。

  • 如果只需要读取存储卷,注意将其挂载为只读状态。点击此处查看具体操作方式。

总结

大家可以了解到多种能够提升 Docker 容器安全水平的方法。安全性不是那种一次部署、无需再管的机制。我们需要时刻保持警惕,方可实现镜像与容器的长治久安。


  1. 考虑安全性时,别忘了 AIM Access management(访问管理)


  • 避免以 root 身份运行。如果必须使用 root,请配合 re-map。

  • 先删除所有功能,再添加必要功能。

  • 如果需要细粒度权限调节,请深入了解 AppArmor。

  • 资源限制。


2. Image safety(镜像安全)


  • 使用官方、高人气以及最小基础镜像。

  • 不要安装任何您不需要的东西。

  • 要求对镜像进行签名。

  • 保持 Docker、Docker 镜像以及其它软件及时更新。


3. Management of secrets(保密信息管理)


  • 使用 secrets 或者存储卷。

  • 考虑使用 Vault 等 secrets 管理器。


保证 Docker 容器安全的实质,就是利用 AIM 建立安全体系。


别忘了更新 Docker、语言与库、镜像以及主机软件。最后,如果您需要在团队当中使用 Docker,可以考虑选择 Docker Enterprise。


原文链接:


https://towardsdatascience.com/top-20-docker-security-tips-81c41dd06f57


2019-09-27 14:455871

评论

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

Kosmos实战系列:MySQL Operator有状态服务的跨AZ集群平滑迁移

畅聊云原生

基于 Webpack5 Module Federation 的业务解耦实践

快乐非自愿限量之名

Web 技术栈 核心技术栈

都是植物补光,为什么你的没效果?

电子信息发烧客

打造绿色计算数智动力 HashData 入选“绿色计算最具价值解决方案”

酷克数据HashData

企业网络新阶段:SD-WAN在云时代的关键作用

Ogcloud

云计算 网络 SD-WAN 云时代 WAN

多云网络互通问题怎么解决——SD-WAN

Ogcloud

云计算 网络 多云服务 多云架构 SD-WAN

Milvus 老友汇|AI、云原生与向量数据库的精彩碰撞回顾!

Zilliz

云原生 Milvus AIGC KubeBlocks

学习Motoko:开启加密编程世界的全新篇章

TinTinLand

区块链 编程

低代码与自动化:加速软件开发的新趋势

不在线第一只蜗牛

运维 自动化 低代码

【活动回顾】Databend 云数仓与 Databend Playground 扩展组件介绍

Databend

利用机器学习实现客户细分:提升市场营销效果的技术策略

快乐非自愿限量之名

机器学习 框架 客户细分

一位CSDN的博主怀疑我抄袭他

Loken

音视频开发

在 Excel 里研发俄罗斯方块;全国首例「AI 声音侵权案」审理丨 RTE 开发者日报 Vol.106

声网

拍卖直播电商平台的终局之战:开发拍品增值服务功能

软件开发-梦幻运营部

浅析JAVA日志中的几则性能实践与原理解释

阿里技术

Java 原理 性能实践

深入学习 C++编程,数据结构与算法关系

高端章鱼哥

c++ 数据结构 算法结构

从“卷智商”到“卷情商”我们能从一场华为海外发布会学到什么?

脑极体

PC

用户指南|使用 Helm Chart 部署单机版 GreptimeDB

Greptime 格睿科技

Kubernetes 时序数据库 #数据库 Helm Charts

统一观测丨使用 Prometheus 监控 Memcached 最佳实践

阿里巴巴云原生

阿里云 云原生

SD-WAN的降本增效作用是如何体现的

Geek一起出海

C 语言注释和变量详解

小万哥

c c++ 程序员 后端 软件开发

软件测试/人工智能丨卷积神经网络,与普通的神经网络有何不同

测试人

人工智能 软件测试

企业用户混合云组网的新方式——SD-WAN

Ogcloud

网络 SD-WAN 混合云 混合云架构 组网

某公司案例分析

尚思卓越

运维 堡垒机

软件测试/人工智能丨计算机视觉常见业务场景,原理和测试指标

测试人

人工智能 软件测试

SAP数据一键拉取!利用零代码ETL工具快速实现数据同步

RestCloud

数据同步 ETL SAP

【写作训练营打卡|08】写作的四大问题踩坑点总结

写作

文心一言 VS 讯飞星火 VS chatgpt (156)-- 算法导论12.3 3题

福大大架构师每日一题

福大大架构师每日一题

马上2024年了,现在去开发一款App需要投入多少资金?

编程的平行世界

开发 Android Studio 成本管理

雅高与亚马逊云科技合作为宾客提供卓越体验

财见

Python 函数式编程让代码直接优雅起来

秃头小帅oi

Docker 容器安全的“终极武器”——AIM_容器_Jeff Hale_InfoQ精选文章