如何使用 Docker 命令添加或删除 capabilities

DockerBeginner
立即练习

介绍

Docker 是一个强大的容器化应用程序工具,理解如何管理容器的 capabilities(能力)对于优化安全性和性能至关重要。本教程将指导你使用 Docker 命令添加和删除 capabilities 的过程,帮助你根据特定需求定制你的容器环境。

在这个实验(Lab)中,你将学习 Docker capabilities 是什么,它们如何增强容器安全性,以及如何有效地管理它们。通过本教程,你将能够自信地从你的 Docker 容器中添加和删除 capabilities。

理解 Docker Capabilities(能力)

Docker capabilities 是一种安全特性,它允许你向容器授予或撤销特定的 Linux 内核权限。在我们开始试验 capabilities 之前,让我们先了解它们是什么以及为什么它们很重要。

什么是 Docker Capabilities?

Docker 中的 capabilities 基于 Linux 内核的 capability 系统,该系统将传统上与 root 用户关联的特权划分为不同的单元。这种方法比传统的全有或全无的 root 特权模型更安全。

默认情况下,Docker 容器以有限的 capabilities 集运行,在功能和安全性之间提供了合理的平衡。但是,你可能需要根据你的应用程序需求添加或删除 capabilities。

让我们检查一下 Docker 容器的默认 capabilities。运行以下命令来启动一个容器并查看其 capabilities:

docker run --rm -it ubuntu:22.04 capsh --print

你应该看到类似这样的输出:

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Ambient set =
Current IAB: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) gid=0(root) groups=0(root)

此输出显示了默认情况下授予容器的 capabilities。这些 capabilities 控制容器在系统内可以做什么。

为什么 Capabilities 重要

正确管理 Docker capabilities 对于以下方面至关重要:

  1. 增强安全性:通过限制 capabilities,你可以减少容器被入侵时可能造成的损害。
  2. 细粒度控制:你可以在不授予完全 root 访问权限的情况下,允许特定的特权操作。
  3. 最小权限原则:容器应该只拥有它们正常运行所需的 capabilities。

接下来,让我们探讨如何向 Docker 容器添加 capabilities。

向 Docker 容器添加 Capabilities

在这一步中,我们将学习如何使用 --cap-add 标志向 Docker 容器添加特定的 capabilities。当你的应用程序需要默认集合中未包含的某些特权时,这非常有用。

添加 Capabilities 的基本语法

向 Docker 容器添加 capability 的基本语法是:

docker run --cap-add=<CAPABILITY> <IMAGE> <COMMAND>

让我们尝试添加 NET_ADMIN capability,它允许容器执行各种与网络相关的操作:

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 capsh --print

输出将显示 NET_ADMIN capability 已被添加到容器中:

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap,cap_net_admin=ep

请注意 capabilities 列表末尾添加的 cap_net_admin

添加多个 Capabilities

通常,你可能需要向容器添加多个 capabilities。你可以通过多次指定 --cap-add 标志来做到这一点:

docker run --rm -it --cap-add=NET_ADMIN --cap-add=SYS_TIME ubuntu:22.04 capsh --print

此命令将 NET_ADMINSYS_TIME capabilities 都添加到容器中。SYS_TIME capability 允许容器修改系统时钟。

实际示例:修改网络接口

为了演示 capabilities 的实际应用,让我们创建一个具有 NET_ADMIN capability 的容器,并尝试修改网络接口设置:

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 /bin/bash

你现在位于带有 bash shell 的容器内。让我们安装 iproute2 包来处理网络接口:

apt-get update && apt-get install -y iproute2

现在,尝试创建一个虚拟网络接口:

ip link add dummy0 type dummy
ip link show dummy0

你应该看到显示新创建的虚拟网络接口的输出:

6: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:d5:cd:70:91:f4 brd ff:ff:ff:ff:ff:ff

如果没有 NET_ADMIN capability,此操作将失败。你可以通过键入 exit 来退出容器。

查看容器 Capabilities

要检查正在运行的容器的 capabilities,你可以使用 docker inspect 命令。首先,让我们以分离模式启动一个带有已添加 capabilities 的容器:

docker run -d --name cap-test --cap-add=NET_ADMIN ubuntu:22.04 sleep 3600

现在,检查容器以查看其 capabilities:

docker inspect cap-test | grep -A 20 CapAdd

输出将显示已添加 NET_ADMIN capability:

            "CapAdd": [
                "NET_ADMIN"
            ],

请记住在此步骤后进行清理:

docker stop cap-test
docker rm cap-test

了解如何向 Docker 容器添加 capabilities 可以让你更好地控制容器可以做什么,同时仍然保持安全性。

从 Docker 容器中移除 Capabilities

在这一步中,我们将学习如何使用 --cap-drop 标志从 Docker 容器中移除 capabilities。这是一个重要的安全实践,遵循最小权限原则——容器应该只拥有它们绝对需要的 capabilities。

移除 Capabilities 的基本语法

从 Docker 容器中移除 capability 的基本语法是:

docker run --cap-drop=<CAPABILITY> <IMAGE> <COMMAND>

让我们尝试移除 CHOWN capability,它允许更改文件所有权:

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 capsh --print

在输出中,你将注意到 cap_chown 不再列在 capabilities 之中:

Current: cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep

移除多个 Capabilities

你可以通过多次指定 --cap-drop 标志来移除多个 capabilities:

docker run --rm -it --cap-drop=CHOWN --cap-drop=NET_RAW ubuntu:22.04 capsh --print

此命令从容器中移除 CHOWNNET_RAW capabilities。

实际示例:测试 Capability 限制

让我们创建一个已删除 CHOWN capability 的容器,并尝试更改文件所有权:

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 /bin/bash

在容器内部,让我们创建一个测试文件并尝试更改其所有权:

touch test_file
ls -l test_file
chown nobody:nogroup test_file

你应该看到一条错误消息,指示该操作不允许:

chown: changing ownership of 'test_file': Operation not permitted

这表明,即使容器以 root 身份运行,移除 CHOWN capability 也会阻止容器更改文件所有权。键入 exit 以离开容器。

同时使用 --cap-add 和 --cap-drop

你可以在同一命令中使用 --cap-add--cap-drop 标志来精确控制容器的 capabilities:

docker run --rm -it --cap-add=NET_ADMIN --cap-drop=CHOWN ubuntu:22.04 capsh --print

此命令添加 NET_ADMIN capability,同时移除 CHOWN capability。

移除所有 Capabilities 并添加特定的 Capabilities

为了获得最大的安全性,你可以移除所有 capabilities,然后仅添加你的应用程序需要的特定 capabilities:

docker run --rm -it --cap-drop=ALL --cap-add=NET_BIND_SERVICE ubuntu:22.04 capsh --print

此命令创建一个仅具有 NET_BIND_SERVICE capability 的容器,该 capability 允许绑定到特权端口(低于 1024)。

测试一个已删除所有 Capabilities 的容器

让我们创建一个已删除所有 capabilities 的容器,并观察限制:

docker run -d --name no-caps --cap-drop=ALL ubuntu:22.04 sleep 3600

现在,让我们附加到容器并尝试执行各种操作:

docker exec -it no-caps /bin/bash

在容器内部,尝试 ping 一个外部主机:

apt-get update && apt-get install -y iputils-ping
ping -c 1 google.com

你可能会看到一个错误,因为容器没有创建 ping 所需的原始网络套接字的必要 capabilities。

通过键入 exit 退出容器,然后进行清理:

docker stop no-caps
docker rm no-caps

通过了解如何从 Docker 容器中移除 capabilities,你可以通过严格限制每个容器可以做什么来显著增强容器化应用程序的安全性。

将 Capabilities 管理与安全最佳实践相结合

在最后一步中,我们将探讨如何将 Docker capabilities 管理与其他安全最佳实践相结合,以创建安全的、最小权限的容器。

创建具有自定义 Capabilities 配置文件的容器

让我们创建一个更复杂的示例,将 capability 管理与其他安全功能结合起来:

docker run -d --name secure-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --read-only \
  --tmpfs /tmp \
  ubuntu:22.04 sleep 3600

此命令:

  • 移除所有 capabilities
  • 仅添加 NET_BIND_SERVICE capability
  • 使容器文件系统只读
  • /tmp 处创建一个临时文件系统用于写操作

让我们检查此容器以查看其配置:

docker inspect secure-container | grep -A 5 CapAdd
docker inspect secure-container | grep -A 5 CapDrop
docker inspect secure-container | grep ReadonlyRootfs

你应该看到确认这些安全设置的输出:

            "CapAdd": [
                "NET_BIND_SERVICE"
            ],
            "CapDrop": [
                "ALL"
            ],
"ReadonlyRootfs": true,

测试限制

让我们连接到我们的安全容器并测试限制:

docker exec -it secure-container /bin/bash

在容器中,尝试修改一个系统文件:

echo "test" > /etc/test

你应该看到一个错误,因为文件系统是只读的:

bash: /etc/test: Read-only file system

现在,尝试写入 /tmp 目录:

echo "test" > /tmp/test
cat /tmp/test

这应该有效,因为我们在 /tmp 处挂载了一个可写 tmpfs:

test

通过键入 exit 退出容器。

将 Capabilities 与非 root 用户一起使用

为了获得额外的安全性,你可以在运行容器时使用非 root 用户,同时仍然管理 capabilities。首先,让我们创建一个新容器,该容器将非 root 用户与特定 capabilities 结合起来:

docker run -d --name nonroot-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --user 1000:1000 \
  ubuntu:22.04 sleep 3600

请注意,即使我们添加了 NET_BIND_SERVICE capability 并且以非 root 用户身份运行,Linux capabilities 默认也仅应用于以 root 身份运行的进程。为了允许非 root 用户使用 capabilities,需要额外的配置,例如 setuid 二进制文件或 ambient capabilities。

在 docker-compose 中使用 Capabilities

如果你使用 docker-compose 来管理多个容器,你可以在你的 docker-compose.yml 文件中指定 capabilities:

version: "3"
services:
  webapp:
    image: ubuntu:22.04
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /tmp

这提供了一种在你的容器部署中管理 capabilities 的一致方法。

清理

让我们清理我们创建的容器:

docker stop secure-container nonroot-container
docker rm secure-container nonroot-container

最佳实践总结

以下是管理 Docker capabilities 的一些最佳实践:

  1. 移除所有 capabilities,并且仅添加你需要的
  2. 将 capability 管理与其他安全功能结合起来
    • 只读文件系统
    • 非 root 用户
    • Seccomp 配置文件
    • AppArmor 或 SELinux
  3. 定期审计容器 capabilities
  4. 保持 Docker 和容器镜像更新
  5. 使用容器漏洞扫描工具

通过遵循这些实践,你可以显著提高 Docker 容器的安全性。

总结

在这个实验中,你已经学会了如何有效地管理 Docker 容器 capabilities,以增强安全性和功能性。以下是你完成内容的总结:

  1. 你了解了 Docker capabilities 是什么,以及它们为什么对容器安全至关重要。
  2. 你学习了如何使用 --cap-add 标志将 capabilities 添加到容器中,从而使容器能够执行特定的特权操作。
  3. 你练习了使用 --cap-drop 标志移除 capabilities,从而实现了最小权限原则。
  4. 你探索了将 capability 管理与其他安全功能相结合的最佳实践,以创建安全的容器环境。

通过应用这些技术,你可以创建具有恰好所需权限的容器,不多也不少。这种方法显著减少了容器化应用程序的潜在攻击面,同时确保它们具有正常运行的必要功能。

继续探索 Docker 安全功能,并记住定期审计和更新你的容器配置,以在你的容器化环境中保持强大的安全态势。