Docker 密钥详解
作者:社区 / 开发者
2023 年 7 月 19 日
导航至
本文由 Talha Khalid 撰写,他是一位全栈开发者和数据科学家,热衷于让枯燥乏味的主题变得有趣且易于理解。
毫无疑问,微服务架构已被证明是高效的。然而,实施安全,尤其是在不可变基础设施的背景下,一直是一项相当大的挑战。
从如何在镜像中将密码与模板分离,到如何在不中断服务的情况下更改服务的访问密码,解决办法层出不穷。但有一种更好的方法:Docker 密钥。在本文中,我们将解释什么是 Docker 中的密钥,如何创建和更新 Docker 密钥,以及关于密钥的其他值得了解的内容。
我们为什么需要 Docker 密钥?
在处理项目时,您可能需要将敏感信息传递给环境,例如密码、私钥、令牌、API 密钥等。但是,直接在版本控制系统(如 Git)中存储敏感信息可能存在风险。当代码存储库被共享或公开时,这些密钥可能会暴露给非预期的人员,从而导致潜在的安全漏洞。
我们经常使用环境变量来存储这些信息,但这不是最佳实践。环境变量违反了最小惊讶原则。这是一种设计原则,建议系统和软件的行为应尽量减少用户的困惑和惊讶。目标是使系统的行为直观且可预测,从而降低意外或非预期后果的可能性。
环境变量违反了该原则,因为系统内的各种实体都可以访问和观察到它们。这包括链接的容器、子进程、Docker inspect 等系统工具以及日志记录机制。原因是,如果应用程序发生异常,许多框架会将上下文(包括环境变量的值)转储到日志文件中。这就是 Docker 密钥的用武之地。
什么是 Docker 密钥?
Docker 密钥充当一个保险库,允许您安全地存储敏感信息。只有拥有保险库密钥的人员(Docker 仅将密钥分配给需要它的服务节点)才能访问信息。Raft 算法以加密格式将密钥存储在所有管理器节点上,并确保将密钥分发到与相关服务关联的容器。
密钥是 Docker 用于处理集群模式集群(多节点或多容器集群)中所有密钥的解决方案。密钥仅在集群模式下工作,集群模式默认加密节点之间的所有通信。密钥可以包含任何内容,但最大大小为 500 KB。目前,这个小巧而强大的功能在 Docker 集群之外不可用——事实上,目前尚不清楚这种情况是否会改变。目前,您需要使用服务来部署单个容器。
Docker 集群模式
作为 DevOps 环境中的重要参与者,Docker 的功能不仅仅是管理容器。对于分为多个微服务的应用程序,与简单的脚本相比,需要更高级别的编排。为了满足这种需求,Docker 引入了服务抽象,通过其集群模式促进跨多个主机的容器编排。Docker 提供两个版本的集群。旧版本作为独立解决方案运行,需要稍微复杂的设置,包括其键值存储。相比之下,较新的变体集群模式自 1.12 版本以来已集成到 Docker Engine 中,无需专门设置。
Docker 镜像的传统用法包括打包和交换工件或应用程序。最初,基于完整 Ubuntu 发行版的 Docker 镜像被普遍使用。然而,这种方法已被在 Alpine Linux 等定制操作系统中使用最小二进制文件所取代。容器的概念已从虚拟机的替代品演变为进程胶囊。
然而,Docker 服务并没有使容器过时,而是引入了额外的配置选项,例如指定所需的副本数量、部署约束和更新策略。
任务是在服务中运行的最小单元。当 Docker 集群计划将容器作为服务的一部分运行时,会将容器称为任务。任务表示由 Docker 集群管理的容器实例。容器本身可能不知道 Docker 集群及其服务抽象。由于容器充当进程胶囊,因此任务充当集群与其表示的容器之间的链接。
启用 Docker 集群
默认情况下,Docker Engine 启动时集群模式已禁用。要启用它,请在控制台中键入 docker swarm init。
docker swarm init
Docker 在当前节点上初始化一个新的集群,并通过确认此命令将其指定为管理器节点。之后,Docker 生成一个集群加入令牌,这是一个唯一的标识符,允许其他节点作为管理器或工作节点加入集群。相应的消息指示您是否之前已将 Docker Engine 切换到集群模式。
创建 Docker 密钥
您可以通过两种方式创建密钥
使用 STDIN
$ echo "mysecretpassword" | docker secret create my_password -
或通过读取文件
$ docker secret create new-secret $HOME/my_password.txt
列出、检查和删除密钥
要列出容器中现有的密钥
$ docker secrets ls
要检查密钥
$ docker secret inspect my_password
与名称相反,Inspect 不会显示密钥的内容。相反,它会显示有关密钥的大量信息,包括其创建和修改日期。虽然实际上无法使用 Docker CLI 修改密钥,但 Docker 集群 API 中有一个端点可以更新密钥
update secret -- "/secrets/{id}/update
要删除密钥,请键入
docker secret rm my_password
使用 Docker 密钥
如上所述,服务会使用密钥,这通过显式关联发生,在创建服务时使用 –secret 标志。您可以使用一个简单的命令创建使用密钥的服务
$ docker service create --name db --secret my_password mongodb:6.0
此示例创建密钥并将其用作 MongoDB 数据库的密码。
或者您可以将密钥添加到某些现有服务
$ docker service update --secret-add my_password app
当您将密钥附加到服务时,您可以访问在该服务上运行的任何容器,路径为 /run/secrets path。在该路径上的容器内,您会找到一个纯文本文件,其中包含密钥的内容,其名称与密钥名称中定义的名称相同。在我们的示例中,它将位于路径 /run/secrets/my_password 中。
访问和更新密钥
创建服务后,该服务的所有容器都可以使用密钥,密钥位于 /run/secrets 目录内的文件中,该文件挂载在 tmpfs(存储在内存中的临时文件系统)中。例如,如果您将密钥命名为 my_password,如示例中所示,您可以在 /run/secrets/my_password 中找到其内容。
在向服务添加密钥时,您可以包含一些参数,例如 target,它可以更改目标文件中文件的名称;您甚至可以包含安全项,例如 uid、gid 和 mode
docker service create --detach=false --name app --secret source=my_password,target=password,uid=2000,gid=3000,mode=0400 mongodb:6.0
更新服务的密钥
要更改服务的密钥,您需要创建一个新密钥并将其添加到服务。直接修改现有密钥不受支持,因为密钥被设计为不可变的。但是,要通过使用 Docker 集群 API 替换密钥的内容来更新密钥,您可以
-
使用 Docker CLI 创建新密钥
-
获取您要更新的密钥的 ID 或名称。您可以使用 Docker 集群 API 端点检索密钥列表:/secrets。
-
使用 Docker 集群 API 端点更新密钥,即 /secrets/{secret-id}/update 或 /secrets/{secret-name}/update。
-
使用 CURL 或任何其他 HTTP 客户端库向相应的 API 端点发出 HTTP 请求。将更新后的密钥文件指定为负载,或在请求正文中提供更新后的密钥。
-
最后,将请求发送到 Docker 集群 API 端点,它将成功地将密钥替换为新创建的、更新后的密钥。
最后的话
Docker 密钥确保了敏感数据的不可变性,并防止其存储在磁盘上或通过网络以纯文本形式传输。在生产环境中考虑使用 Docker 集群时,建议使用 Docker 密钥,即使对于本地开发也是如此。
通过将 Docker 密钥集成到您的工作流程中,您可以增强容器化应用程序的整体安全性。这种做法确保了对敏感信息的正确处理,有效地防止了潜在的漏洞和未经授权的访问。