podman:无根容器:容器用户的权限

podman:无根容器:容器用户的权限

nginxpodman 容器中nginx,用户用于运行nginx服务器。

在主机上ls -alh

drwxrwx--- 2 myuser myuser 4.0K Aug 10 22:23 .
drwxrwx--- 3 myuser myuser 4.0K Aug 10 22:59 ..
-rw-rw---- 1 myuser myuser   46 Aug 10 22:24 .htpasswd

容器内的同一文件夹ls -alh

drwxrwx--- 2 root root 4.0K Aug 10 22:23 .
drwxr-xr-x 1 root root 4.0K Aug 10 11:05 ..
-rw-rw---- 1 root root   46 Aug 10 22:24 .htpasswd

nginx.htpasswd容器内的用户由于无法访问o-rwx

问题:处理此类案件的常用模式是什么?无根容器通用吗?也许可以创建一个组(稍后用作文件组所有者),该组收集来自subuid/subgid针对特定主机用户的所有范围 - 但如何实现这一点?

答案1

通过使用命令行选项,--uidmap您可以指定我的用户UID 和我的用户子 UID 被映射到容器中。(参见手册页为了podman run)。

命令行选项的--gidmap工作方式相同,但针对的是 GID 而不是 UID。

让我们查找用户的 UID 和 GIDnginx在容器镜像中docker.io/library/nginx

$ podman run --rm docker.io/library/nginx grep nginx /etc/passwd
nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false
$

结果:

  • 唯一标识:101
  • 性别识别号码:101

稍后在设置两个 shell 变量时会使用这些数字

$ container_uid=101
$ container_gid=101

(shell 变量container_uid容器_gid在这篇文章之外没有任何意义。它们只是为了让答案更容易阅读而引入的)

查看主机上的文件 /etc/subuid 和 /etc/subgid

用户我的用户具有这些子 UID 和子 GID。

$ grep myuser /etc/subuid
myuser:231072:65536
$ grep myuser /etc/subgid
myuser:231072:65536
$ 

结果:

我的用户有 65536 个子 UID 和 65536 个子 GID。

稍后在设置两个 shell 变量时会使用这些数字

$ subuid_size=65536
$ subgid_size=65536

(shell 变量subuid_sizesubgid_size在这篇文章之外没有任何意义。它们只是为了让答案更容易阅读而引入的)

而不是抬头subuid_sizesubgid_size/etc/subuid/etc/subgid,更通用的方法是运行命令

 subuid_size=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 ))
 subgid_size=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 ))

优点是,当文件/etc/nsswitch.conf用来代替/etc/subuid/etc/subgid。 (看man subuid

演示 1:映射用户我的用户在主机上到用户容器内部

没有必要指定--uidmap--gidmap因为这是标准映射。

创建全世界可写的目录演示1

$ mkdir demo1
$ chmod 777 demo1
$

创建新文件,运行为容器内部:

$ podman run --rm \
    -v ./demo1:/dir:Z \
      docker.io/library/nginx touch /dir/created_by_root
$

创建新文件,运行为nginx容器内部:

$ podman run --rm \
    --user 101:101 \
    -v ./demo1:/dir:Z \
      docker.io/library/nginx touch /dir/created_by_nginx
$

列出主机上的文件

$ ls -l demo1
total 0
-rw-r--r--. 1  231172  231172 0 Aug 27 20:24 created_by_nginx
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:22 created_by_root
$ 

结果:文件由根创建我的用户我的用户

演示 2:映射用户我的用户在主机上到用户nginx容器内部

创建全世界可写的目录演示2

$ mkdir demo2
$ chmod 777 demo2
$

创建新文件,运行为容器内部:

$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
    --uidmap=0:1:$container_uid \
    --uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
    --uidmap=$container_uid:0:1 \
    --gidmap=0:1:$container_gid \
    --gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
    --gidmap=$container_gid:0:1 \
    -v ./demo2:/dir:Z \
      docker.io/library/nginx touch /dir/created_by_root
$

创建新文件,运行为nginx在容器内。

$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
    --user $container_uid:$container_gid \
    --uidmap=0:1:$container_uid \
    --uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
    --uidmap=$container_uid:0:1 \
    --gidmap=0:1:$container_gid \
    --gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
    --gidmap=$container_gid:0:1 \
    -v ./demo2:/dir:Z \
      docker.io/library/nginx touch /dir/created_by_nginx
$

列出主机上的文件

$ ls -l demo2
total 0
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:26 created_by_nginx
-rw-r--r--. 1  231072  231072 0 Aug 27 20:25 created_by_root
$ 

结果:文件由 nginx 创建我的用户我的用户

结论

使用方法--uidmap--gidmap演示 2

故障排除提示

我写了一个故障排除提示: 在无根容器中无法访问传入的设备或文件(UID/GID 映射问题)包含描述的方法演示 2

答案2

你应该弄清楚容器的初始主机 UID 是什么nginxUID(只需使用正在运行的用户从容器中触摸文件nginx,或检查其日志文件,或检查正在运行的nginx进程。然后使用statls -ln来自初始主机用户):一些大的 UID 值,我们假设它是 100030。

然后从初始主机的非特权用户可以使用setfactl授予用户 100030 额外的访问权限。这应该是这样的:

setfacl -R -m u:100030:rX,d:u:100030:rX folder

如果你想要nginx用户能够写入(这可能不是一个好主意),您可以替换rXrwX或仅在选定目录中执行此操作。以开头的重复d:代表默认ACL,因此新创建的目录和文件也会继承相同的附加 ACL。设置 ACL 后,输出将ls显示 a+和 ACL 掩码而不是组,因此看起来可能会令人惊讶。

以下是有关 ACL 的各种参考:

相关内容