如今 docker
是一个新的流行词,每个人都希望将他们的应用程序部署在 docker
容器上。尽管市场上有很多容器化工具,但文章会更多地谈论 docker
,因为它在所有工具中都很流行。
在这篇文章中,将从信息安全的角度讨论所需的容器基础知识。
传统上,为了隔离开发和部署过程,开发人员使用硬件级隔离技术,即虚拟化技术。在这种情况下,新的hypervisor
层位于主机之上以提供硬件级隔离。因为任何人都可以在主主机上运行多个操作系统, 所以它变得流行起来。
在虚拟化中,两个或多个操作系统与正在运行的主机是完全隔离的,这意味着一个操作系统不知道另一个操作系统的进程,甚至 CPU 和内存也是隔离的。整个事情由hypervisor
管理。只有在hypervisor
中存在漏洞才有可能突破虚拟化。
由于虚拟化技术非常耗费资源,并且guest
操作系统启动时间会增加部署开销,因此在部署中通常不鼓励使用这种技术,但在开发过程中通常会鼓励使用这种技术,用来防止与库发生冲突。另一方面,容器化消除了流程中的资源匮乏和启动时间开销。
当在操作系统中安装容器化引擎时,它也会像虚拟化一样在操作系统之上设置一个容器化层,但提供操作系统级别的隔离,例如,使用相同的 CPU
和内存,但运行在相同操作系统中的容器是隔离并且只有在创建时或通过网络(如 ssh
和 FTP
等服务)进行配置时才能进行交互。由于它为应用程序提供快速启动时间,因此它用于提供零停机应用程序重新部署,这通常在开发人员将新功能推向生产时完成。在这种情况下,容器将只使用应用程序及其依赖项所需的资源,这种方法广泛用于同一操作系统中应用程序的弹性升缩,而不会浪费很多资源。
如果使用默认配置部署容器,它是安全的,但如果有人加载了 docker
套接字或其他linux
能力,则攻击者可以轻松突破容器以读取主机文件系统。
简而言之,在虚拟化中,每个guest
操作系统都使用自己的内核,并且该内核再次使用hypervisor
模拟的硬件来运行系统和应用程序。在容器化的情况下,每个容器都由容器运行时隔离,并使用宿主机的内核。在这种情况下,隔离是通过 pivot root
和 chroot
的组合来完成的。
默认情况下,docker
暴露一个 Unix Domain Socket
。需要通过 root
用户运行 docker
命令行或将 docker
组添加到当前用户
usermod -aG docker $USER
newgrp docker
将自己添加到 docker
组后,最好重新启动 docker
服务
sudo systemctl restart docker.service
首先,使用 pull
命令从远程 docker
仓库中拉取 docker
镜像
一旦从远程 docker
仓库中提取镜像,可以在本地主机中随意使用它,而无需使用互联网访问。为了确保它是否存在于本地系统中,可以使用 images
命令列出所有可用的镜像
镜像的默认标签是最新的。一个镜像可以有多个标签,它主要用于镜像的版本控制。您现在可以通过其名称(在存储库列下)或镜像 ID
引用此镜像
要创建 docker
容器,需要使用 create
命令,然后使用帮助文档中所述的带有适当参数的镜像引用。
执行完毕,该命令将提供容器的 ID
。可以使用带有 -a
选项的容器 ls
命令来确认此操作,以列出所有容器
现在使用创建时设置的名称启动容器了。也可以使用其 ID
执行此操作,但为方便起见,使用名称。为确保其运行状态,稍后可以使用ps
命令和logs
命令从标准错误或标准输出中获取输出
使用带有 -i
标志的 curl
命令通过 localhost
1337 端口向 flask
服务器发出请求。
需要先在 docker 中启用 TCP
网络。这可以通过编辑 docker systemd
服务文件来完成。如下所示更新服务文件,然后在使用 systemctl daemon-reload
重新加载服务配置后
- ExecStart=/usr/bin/dockerd -H fd://
+ ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
要使用 TCP socket
,需要通过将 DOCKER_HOST
环境变量设置为 tcp://127.0.0.1:2375
来明确告诉 docker
当启动 TCP socket
时,它还将启用 HTTP API 以在同一端口上与 docker
交互。信息交换以 JSON
格式完成,所有API
都记录在此处 – https://docs.docker.com/engine/api/v1.41/
由于已经拉取了镜像,将使用相同的镜像。所以首先让列出镜像和容器。列出容器和镜像的端点——List Containers 和 List Images
重用容器名称 flaskapp,但该名称已被使用并且容器正在运行。要重用容器的旧名称,需要停止并删除容器
现在您需要创建容器,然后通过创建容器端点的响应中的 ID 启动它。
现在您可以使用 curl 从 localhost 上的 pot 1337 命中容器请求。
当深入研究 CLI 选项或容器架构时,会出现特权容器的概念。在本节中,将详细了解特权容器以及如何
在正常情况下,看到隔离是在操作系统级别完成的,这是由运行时引擎管理的。它充当操作系统和容器之间的桥梁,将系统调用传递给内核并有效地使用主机资源。
当以特权模式运行 docker
容器时,它将通过运行时引擎层直接访问主机操作系统。由于它可以与宿主操作系统进行交互,因此容器将继承 root
用户的所有能力和宿主的文件系统。这个时候,逃逸简直就是小菜一碟。要运行具有额外权限的容器,需要在创建容器时传递 --privileged
标志。能力对比如下图