如何在不使用 sudo 的情况下将文件 chown 为 subuid

如何在不使用 sudo 的情况下将文件 chown 为 subuid

基本上,这里发生了什么以及我不明白什么?

我为我的用户设置了一组 subuid。我想将某个文件 chown 到属于该用户分配的特定 subuid

administrator@host:/home/administrator$ cat /etc/subuid
root:100000:65536
administrator:165536:65536
administrator:1000000:9000001

administrator@host:/home/administrator$ cat /etc/subgid
root:100000:65536
administrator:165536:65536
administrator:1000000:9000001

尽管此 subuid 是分配的一部分,但尝试 chown 此文件仍失败。

administrator@host:/home/administrator$ ls -lhat
...
-rw-rw-r-- 1 administrator administrator  229 Aug  2 13:00 file
drwxrwxr-x 7 administrator administrator 4.0K Aug  2 13:00 ..

administrator@host:/home/administrator$ chown 1500000:1500000 file
chown: changing ownership of 'file': Operation not permitted

administrator@host:/home/administrator$ stat file
  File: file
  Size: 229             Blocks: 8          IO Block: 4096   regular file
Device: 802h/2050d      Inode: 658357      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/administrator)   Gid: ( 1004/administrator)
Access: 2018-08-02 13:00:36.529197108 +0000
Modify: 2018-08-02 13:00:36.529197108 +0000
Change: 2018-08-02 13:00:36.529197108 +0000
 Birth: -
administrator@host:/home/administrator$

但是,如果我使用 sudo 来 chown 该文件,我可以以用户身份删除该文件 - 但当我这样做时,它会显示为写保护文件。这表明我确实有权修改具有此 subuid 的文件。

administrator@host:~$ touch file
administrator@host:~$ chown 1500000:1500000 file
chown: changing ownership of 'file': Operation not permitted

administrator@host:~$ sudo chown 1500000:1500000 file    
administrator@host:~$ rm file
rm: remove write-protected regular empty file 'testfile.txt'?
administrator@host:~$

有人能解释一下这里的内部工作原理吗?我可能误解了某些基本知识。我无法将其标记为 subuid,因为没有足够的代表,所以我将使用 uid。

谢谢!

答案1

有一个lxc-usernsexec随附的程序。它允许您使用地图和lxc重新映射用户 ID 。/etc/subuid/etc/subgid

具体来说,可以做如下操作。

  1. lxc-usernsexec -- touch /tmp/test
  2. ls -l /tmp/test将显示该文件的所有者:组与地图中第一个 subuid:subgid 对相同。
  3. rm /tmp/test由于您当前没有正确的 uid/gid,因此应该会出现错误。
  4. lxc-usernsexec -- rm /tmp/test应该删除该文件。

希望这能有所帮助!以上内容可能需要为非特权 LXC 容器使用设置各种设置。特别是,我认为/proc/sys/kernel/unprivileged_userns_clone应该是 1。

答案2

Subuid 并非按照您期望的方式工作。它们旨在将用户命名空间中的 UID 映射到该命名空间之外的不同 UID,这对于容器来说非常有用(实际上也是设计用来这样做的)。

但是,一个进程仍然只能有一个 UID 集(用户命名空间),并且出于明显的安全原因,用户不得更改文件的所有权。就进程本身而言,如果用户实际上是命名空间之外的其他人,这并不重要。

这就是chown命令失败的原因:无论你可以有其他 UID,命名空间应该不同,此时,您没有该 UID,因此,您无法更改任何文件的所有权(因为您不是 root)。

至于为什么可以删除文件:它实际上与子用户无关,相反,这完全取决于您是否拥有文件所在目录的所有权。由于文件删除会更改目录,而不是文件本身,因此,如果您可以写入目录,则可以从中删除任何文件(“粘性”目录除外)。

答案3

作为@Kapil 答案的补充,并且由于如果您不是 root 身份则可能难以安装其他工具,因此您还可以使用podman unshare(随 Podman 一起提供)或rootlesskit(随无根 Docker 一起提供)作为lxc-usernsexec(随 LXC 一起提供)的替代方案。

答案4

许多人会遇到与 docker/podman rootless 或 --userns 相关的 subuid/subgid 问题。因此,这里有一个可能的解决方案。@user2580621 提到了 docker 项目提供的名为“rootlesskit”的实用程序。我相信 Podman 也有自己的解决方案。rootlesskit 附带了来自 docker 项目的 rootless docker 包,适用于所有主要的 linux 发行版(也可以下载,但您可以自己研究)。安装完成后。要使用它,您需要发出,例如:rootlesskit -- chmod 1001:0。请记住,您提供的 uid 和 gid 会抵消根据您的 /etc/sub[ug]id 条目。它指的是您的用户命名空间中的 uid 1001 和组 id 0。在本地文件上,当 Dockerfile 将非默认目录所有权/权限应用于 VOLUME 和/或在容器中以非 root 身份运行时,您经常会发现自己需要执行此操作您想将该卷绑定到本地文件系统上的目录。这会成为一个问题,因为该本地目录需要足够宽松才能容纳该卷。您该怎么做?

一个很好的例子就是官方的 mysql docker 镜像。读取 Dockerfile 后,它们会创建一个 mysql 用户 (1001) 和组 (1001),然后继续安装 mysqld 和chown mysql:root /var/lib/mysqlchmod 775 ... 假设您工作站上的 uid 和 gid 为 1000:1000。您mysql-data在主目录中创建一个名为的文件夹,默认情况下,它将由您的用户和组拥有(可能)755 权限。现在您继续:

docker run -v "$HOME/mysql-data:/var/lib/mysql" ... mysql

您会经常看到(除非天公不作美)mysql 会由于权限错误而无法初始化。这是因为/var/lib/mysql(就容器而言,它由 root:root 拥有,权限为 755(请记住,在您的情况下,主机系统上的 1000:1000 相当于容器中的 0:0)。mysql docker 镜像USER mysql在容器内运行(即 uid 1001/gid 1001)。当容器启动时,它会尝试初始化/创建 /var/lib/mysql 文件夹中的文件,但它缺乏写入该文件夹的权限。那么解决办法是什么?使用我们从 Dockerfile 中了解到的信息,我们只需:

rootlesskit -- chown 1001:0 $HOME/mysql-data
rootlesskit -- chmod 775 $HOME/mysql-data

如果你查看本地文件系统上的权限,你会发现它们被转换为你的用户命名空间

现在,当我们运行我们的docker镜像时,你会看到它运行完美。

不读取 Dockerfile 即可查看这些权限的另一种方法是简单地允许 Docker 创建没有绑定挂载的容器,并为其指定一个卷名,例如:

docker run ... mysql

注意,我们不再有-v ...。现在 Docker 容器正在运行,您可以:

docker exec -it mysql ls -lnd /var/lib/mysql

您将看到该文件夹​​对应的 1001:0 uid/gid 和 775 权限。现在您可以停止/删除容器。现在您无需阅读 Dockerfile 即可获得所需的信息。

祝你好运!

相关内容