Docker Secrets的详细指南

导航到

本文由Talha Khalid撰写,他是一位全栈开发者和数据科学家,喜欢将冷门且复杂的话题变得有趣且易于理解。

没有人会怀疑微服务架构已经证明是高效的。然而,在不可变基础设施环境中实施安全,尤其是安全,已经是一个相当大的挑战。

从如何在镜像中将密码与模板分离到如何在不中断服务的情况下更改访问密码,问题层出不穷。但有一种更好的方法:Docker secrets。在本文中,我们解释了在Docker中什么是secrets,如何创建和更新docker secrets,以及关于它们的其他有用信息。

我们为什么需要Docker secrets呢?

当您在一个项目上工作时,您可能需要将敏感信息传递到环境中,例如密码、私钥、令牌、API密钥等。然而,直接在版本控制系统(如Git)中存储敏感信息可能会很危险。当代码仓库被共享或公开时,这些secrets可能会暴露给未授权的个人,从而导致潜在的安全漏洞。

我们通常使用环境变量来存储此类信息,但这并非最佳实践。环境变量破坏了最小惊讶原理。这是一个设计原则,建议系统和软件应该以最小化用户的困惑和意外为目标。目标是使系统的行为直观和可预测,从而降低意外或不期望后果的可能性。

环境变量破坏了这个原则,因为系统内的各种实体都可以访问和观察到它们。这包括链接的容器、子进程、系统工具如Docker inspect以及日志机制。原因是如果应用程序发生异常,许多框架会将上下文写入日志文件,包括环境变量的值。这正是Docker secrets发挥作用的地方。

什么是Docker secrets?

Docker secrets作为一个保险库,允许您安全地存储敏感信息。只有拥有保险库密钥的个人可以访问这些信息,Docker只为需要它的服务节点分配这个密钥。Raft算法将秘密以加密格式存储在所有管理节点上,并确保将秘密分发到与相关服务关联的容器中。

秘密是Docker在集群模式下处理所有秘密的解决方案,这是一种多节点或多容器集群。秘密仅在集群模式下工作,默认情况下加密所有节点之间的通信。秘密可以包含任何内容,但其最大大小为500 KB。目前,这个小巧的功能只能在Docker集群的上下文中使用——实际上,不清楚这是否会改变。目前,您需要使用服务来部署单个容器。

Docker集群模式

作为DevOps环境中的重要参与者,Docker的功能已经超越了管理容器的基本功能。在将应用程序划分为多个微服务的情况下,与简单的脚本相比,需要更高层次的编排。为了满足这一需求,Docker通过其集群模式引入了一种服务抽象,该模式通过其集群模式在多个主机之间编排容器。Docker提供了两种集群模式。较旧的版本作为独立解决方案运行,需要稍微复杂的设置,包括其键值存储。相比之下,较新的集群模式自Docker Engine 1.12版本以来已集成到Docker Engine中,消除了专门设置的必要性。

传统上使用Docker镜像涉及打包和交换工件或应用程序。最初,基于完整的Ubuntu分发的Docker镜像被广泛使用。然而,这种方法已经被使用自定义操作系统(如Alpine Linux)中的最小二进制文件所超越。容器从作为虚拟机的替代品发展到成为进程胶囊的概念。

然而,Docker服务并未使容器过时,而是引入了额外的配置选项,例如指定所需的副本数量、部署约束和更新策略。

任务是在服务中运行的最低单元。在调度容器作为服务的一部分运行时,Docker将容器称为任务。任务代表由Docker集群管理的容器实例。容器本身可能不知道Docker集群及其服务抽象。由于容器作为进程胶囊运行,任务在集群和它所代表的容器之间充当链接。

启用Docker Swarm

默认情况下,Docker Engine以关闭swarm模式启动。要启用它,请在控制台中输入 docker swarm init

docker swarm init

Docker在当前节点上初始化一个新的swarm并将其指定为管理节点,通过确认此命令。之后,docker生成一个 swarm加入令牌,这是一个唯一的标识符,允许其他节点作为管理节点或工作节点加入swarm。相应的消息会指示你是否之前已将Docker Engine切换到swarm模式。

创建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

检查,尽管其名称如此,但不会显示密钥的内容。相反,它显示了有关密钥的大量信息,包括其创建和修改日期。虽然无法使用Docker CLI实际修改密钥,但Docker Swarm 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路径 下访问该服务的任何容器。在该路径下的容器内,您将找到包含密钥内容的纯文本文件,其名称与密钥名称相同。在我们的例子中,它将在路径 /run/secrets/my_password 中。

访问和更新密钥

创建服务后,密钥将可用于该服务的所有容器,在 /run/secrets目录 内的文件中,以 tmpfs(存储在内存中的临时文件系统)挂载。例如,如果您将密钥命名为 my_password,如示例所示,您可以在 /run/secrets/my_password 中找到其内容。

在将密钥添加到服务时,您可以包含一些参数,例如 target,它更改目标中的文件名;您甚至可以包含安全项,如 uidgidmode

docker service create --detach=false --name app --secret source=my_password,target=password,uid=2000,gid=3000,mode=0400 mongodb:6.0

更新服务的密钥

要更改服务的密钥,您需要创建一个新的密钥并将其添加到服务中。直接修改现有密钥是不支持的,因为密钥被设计为不可变。然而,通过使用Docker Swarm API替换密钥来更新密钥内容,您可以

  • 使用Docker CLI创建新的密钥

  • 获取您想要更新的密钥的ID或名称。您可以使用Docker Swarm API端点: /secrets 获取密钥列表。

  • 使用更新密钥的Docker Swarm API端点,即 /secrets/{secret-id}/update 或 /secrets/{secret-name}/update。

  • 使用CURL或其他HTTP客户端库向适当的API端点发出HTTP请求。指定更新的密钥文件作为有效负载或在请求正文中提供更新的密钥。

  • 最后,将请求发送到Docker Swarm API端点,并成功用新创建的更新后的密钥替换密钥。

结语

使用 Docker secrets 可以确保敏感数据的不变性,并防止它们在磁盘上存储或在网络上以明文形式传输。在考虑在生产环境中使用 Docker Swarm 时,建议使用 Docker secrets,即使是对于本地开发也是如此。

通过将 Docker secrets 集成到您的开发流程中,您可以增强容器化应用程序的整体安全性。这种做法确保了敏感信息的适当处理,有效防止潜在的安全漏洞和未经授权的访问。