![授予非 root 用户使用一个端口的权限](https://linux22.com/image/771181/%E6%8E%88%E4%BA%88%E9%9D%9E%20root%20%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8%E4%B8%80%E4%B8%AA%E7%AB%AF%E5%8F%A3%E7%9A%84%E6%9D%83%E9%99%90.png)
我托管一个实验室服务器,我是根用户(也是普通用户)。
域名是 example.org,我为每个成员分配了一个子域名,例如 Bob 的子域名是 bob.example.org,而用户 Anna 的子域名是 anna.example.org。我想你明白了。:) 使用 nginx 将子域名反向代理到特定端口。
我的问题是,我有什么办法可以授权非 root 用户在其特定端口范围内启动 docker 容器。例如,Anna 被赋予范围 1300-1350,其中端口 1300 绑定到 anna.example.org,其他端口保留。
该系统运行Debian 11 Bullseye和最新的Docker版本。
答案1
在 Debian Bullseye 安装中,docker 守护进程默认以 root 身份运行。将用户添加到docker
组将为该用户提供伪 root 访问权限,因为该用户拥有对 docker 守护进程的控制权,并具有该访问权限。docker 组中的每个用户都将完全控制主机和其他容器,并且可以运行使用--publish
任何端口的容器。
有几种选项可以为用户的 Docker 访问提供安全性。
- 无根 Docker
sudo
- API
1. 无根docker
A无根 docker 设置将允许每个用户运行 docker 守护进程。对于低于 1024 的端口,它需要遵守非特权端口信息bob 提供,因为每个用户将“拥有”自己的守护进程。Docker 还提供了相关指导。这不会阻止安娜占用鲍勃的港口。
2.sudo
允许用户运行 docker 命令的最简单方法是通过 sudo 提供一个 root 控制的脚本,该脚本可以是静态的,也可以控制用户输入的可选参数:
#!/bin/bash
docker run --detach --publish 1300:1300 anna/app-image
anna ALL=(root) NOPASSWD: /usr/local/bin/start-anna-image
如果你希望用户能够添加自己的选项,你需要非常小心地控制他们的输入,因为
3. Docker 的授权插件或 API
由于 Docker 没有在守护进程上提供任何授权层,因此您需要添加一些内容来控制用户访问。
Docker 提供了内置授权插件实现这一点的框架。以下是一些示例:opa-docker-authz和casbin-authz-插件
您可以让用户访问某种形式的代理 API,该 API 提供对传递给 Docker REST API 的内容的身份验证和授权。大多数编程语言都有 docker 库。Kubernetes+RBAC 是一个位于 Docker 守护进程前面并控制访问的 API 示例(只是一个非常大/复杂的 API,可以做更多事情)。
答案2
据我所知,Linux 只有特权端口与非特权端口的概念。
Linux 内核调优参数 net.ipv4.ip_unprivileged_port_start 定义哪些端口是特权端口。0 到 之间的所有端口net.ipv4.ip_unprivileged_port_start
都是特权端口。
特权端口只能由 root 用户启动的进程或具有 root 权限的进程使用,或者由分配了能力 CAP_NET_BIND_SERVICE
例如sudo setcap cap_net_bind_service=ep /path/bin/application
所有其他端口都不是特权端口,任何用户都可以使用,只要这些端口尚未被使用。
我不知道有任何替代方法可以允许特定用户使用特定端口。
答案3
只要端口是非特权的,非 root 用户就可以绑定到任何端口(超过 1024)。他们可以使用以下命令启动容器:
docker run --expose 1300-1350 <image-name>
先到先得。如果两个程序尝试绑定到同一个端口,则只有第一个绑定的程序会成功。
对于特权端口(小于 1024),您需要 root 或 CAP_NET_BIND_SERVICE 功能。请参阅man capabilities
了解详情。
答案4
只是想增加另一个视角...当然还需要做更多工作!但很有趣...
考虑运行一个容器编排器,例如 Kubernetes。 查看KIND(Kubernetes-in-Docker)了解仅使用 Docker 在单个节点上运行 Kubernetes 集群的有趣方法。
然后你可以做类似的事情
- 创建命名空间对于每个用户,例如
bob-ns
和anna-ns
。 - 创建一个
service
在每个命名空间中,暴露指定的端口 - 为每个用户提供一个角色让他们能够创造
pods
(容器分组)在其命名空间中,从而允许它们接受来自service
其命名空间中给定的流量。
如果您正确地构建角色,那么可以允许用户在其命名空间中启动他们想要的任何容器,但不允许修改service
定义公开端口的容器。
这是为了节省空间而简化的,但是像 k8s 这样的原语提供的功能对于像这样的多租户系统来说非常好。