Docker 和 Podman 中的 Linux Capabilities
在运行 Docker (或 Podman) 容器时,有时即使使用 root 用户或者使用了 sudo,也会出现 Operation not permitted 的错误信息。这是因为容器中的 root 并不具有完整的 root 权限。这种权限的控制是通过 Linux capabilities 实现的。本文将首先介绍 Linux capabilities 的概念,然后以 Docker 为例介绍如何调整容器的 capabilities,最后介绍 Docker 和 Podman 在默认 capabilities 上的差异,以为容器的开发者和用户提供参考。
Linux Capabilities
经典的 Linux 权限控制模型将用户分为普通用户和特权用户 (例如 root 用户和具有 sudo 权限的用户)。特权用户拥有系统上的所有权限,容易导致安全问题。例如,一个 Web 服务器需要特权以监听 443 或 80 端口,但不应当访问其他用户的文件或修改系统内核;而如果 Web 服务器被攻破,攻击者将获得系统上的所有权限。
Linux capabilities 将系统中的特权分为多个不同的 capabilities,可以通过赋予进程部分特权而不是完整的 root 权限来降低系统的风险。例如,CAP_NET_BIND_SERVICE 允许进程绑定小于 1024 的端口,而不需要完整的 root 权限。Linux capabilities 的列表可以通过 man 7 capabilities 查看。
Docker 中的 Linux Capabilities
与服务器不同,容器不需要完整的 root 权限,因为容器的目的是运行一个或一些特定的应用程序,而不是整个系统。例如:
- 容器通常不需要管理网络和日志,因为容器的网络和日志是由 Docker Engine 管理的。
- 容器通常不需要设置时间,因为它的时间由宿主机提供
- 容器通常不需要运行
reboot命令,因为容器的生命周期由 Docker Engine 管理
因此,Docker 通过白名单的方式限制了容器的 capabilities,即容器默认仅具有特定的 capabilities。Docker 所使用的 capabilities 可以在这里查看。
如果你希望进一步限制容器的 capabilities 以增加安全性,可以通过 --cap-drop 选项来删除 capabilities。如果容器中的程序确实需要某些 Capabilities,可以通过 --cap-add 选项添加这些 capabilities。对于容器的开发者,在需要额外的 capabilities 时,建议在 README 中明确说明。
Podman 与 Docker 的 Capabilities 差异
Podman 通过进一步限制容器的 capabilities 来获得比 Docker 更高的安全性。Podman 的 capabilities 默认值可以在这里查看。
Podman 的默认 capabilities 比 Docker 更加严格,因此在 Podman 中运行的容器可能会出现更多的 Operation not permitted 错误,例如 sudo 将无法使用 CAP_AUDIT_WRITE Capability。Podman 用户在运行容器时如果遇到 Operation not permitted 错误而其他人却无法复现,很有可能就是 Podman 的 capabilities 额外限制导致的。
参考资料
Docker 和 Podman 中的 Linux Capabilities
https://blog.caomingjun.com/linux-capabilities-in-docker-and-podman/