背景
对于 NFSv4 导出/共享,默认启用的 root_squash 选项将强制 NFS 将客户端的根更改为匿名 ID。这实际上将通过防止一个系统上的根帐户所有权迁移到另一个系统来提高安全性。
Overlayfs 允许将本地透明文件系统挂载在另一个文件系统之上。不幸的是,它似乎使用 root 用户而不是实际用户来访问底层文件系统。至少这是我从以下实验中得出的结论。
为什么要在 NFS 共享上安装 Overlayfs?这是为了让不太可信的机器能够假装自己可以写入共享文件系统。
测试设置
首先安装适合您的发行版的 NFS 内核服务器。然后确保仅导出 NFSv4。(虽然对于这个问题可能并不重要,但这是一种很好的安全预防措施。)
$ sudo cat /proc/fs/nfsd/versions
-2 -3 +4 +4.1 +4.2
如果没有,请查看/etc/nfs.conf
并设置vers3=n
。
然后在稀疏文件中创建 Ext4 文件系统并将其挂载到本地文件系统。这将是我们 NFS 共享的基础文件系统。
$ truncate -s 512M 512BM-ext4.img
$ mkfs.ext4 512BM-ext4.img
$ sudo mkdir /mnt/ext4-file
$ sudo mount -o loop,noacl 512BM-ext4.img /mnt/ext4-file
然后使用 NFSv4 通过网络将此文件系统共享/导出到适当的机器。在此示例中,我将使用 localhost,但它可以是本地网络上的任何机器。通过编辑/etc/exports
以下内容来执行此操作。
/mnt/ext4-file/ localhost(ro,fsid=123123)
然后在您的机器上重新启动 NFS 服务器,服务文件在您的操作系统上可能会有所不同。
$ sudo systemctl restart nfs-server.service nfs-mountd.service
$ sudo exportfs -v
/mnt/ext4-file localhost(sync,wdelay,hide,no_subtree_check,fsid=123123,sec=sys,ro,secure,root_squash,no_all_squash)
确保root_squash
和ro
已启用。
现在就可以在您想要的客户端上安装 NFSv4 共享了。
$ sudo mount -t nfs -o ro localhost:/mnt/ext4-file /mnt/nfs-share/
$ findmnt /mnt/nfs-share
TARGET SOURCE FSTYPE OPTIONS
/mnt/nfs-share localhost:/mnt/ext4-file nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255
然后我们在这个共享上安装 overlayfs2。
$ mkdir -p /tmp/overlay/{work,upper}
$ sudo mkdir /mnt/overlay
$ sudo mount -t overlay overlay -o lowerdir=/mnt/nfs-share/,upperdir=/tmp/overlay/upper/,workdir=/tmp/overlay/work/ /mnt/overlay/
为了进行实验,我们将在文件系统中创建一个文件夹,该文件夹只能由用户读取和写入,只能由组读取。我选择了属于我的用户的组。
$ sudo mkdir /mnt/ext4-file/rovanion
$ sudo chown rovanion:rovanion /mnt/ext4-file/rovanion
$ sudo chmod 2750 /mnt/ext4-file/rovanion
$ touch /mnt/ext4-file/rovanion/hi-from-ext4
$ ls -la /mnt/nfs-share/rovanion/
totalt 8,0K
drwxr-s--- 2 rovanion rovanion 4,0K sep 6 14:14 .
drwxr-xr-x 4 root root 4,0K sep 6 14:12 ..
-rw-rw-r-- 1 rovanion rovanion 0 sep 6 14:14 hi-from-ext4
$ touch /mnt/nfs-share/rovanion/hi-from-nfs
touch: cannot touch '/mnt/nfs-share/rovanion/hi-from-nfs': Read-only file system
我们可以列出 的内容/mnt/nfs-share/rovanion
,但无法触碰文件系统,尽管我们有权限这样做,因为 NFS 共享是以只读方式安装的。一切如预期。
失败
但问题来了。
$ ls -la /mnt/overlay/rovanion/
ls: cannot open directory '/mnt/overlay/rovanion/': Permission denied
$ ls -l /mnt/overlay/
total 28K
drwx------ 2 root root 16K Sep 6 13:04 lost+found
drwxr-s--- 2 rovanion rovanion 4.0K Sep 6 14:14 rovanion
$ whoami
rovanion
$ groups
rovanion sudo
/mnt/overlay/rovanion
尽管权限系统允许我们访问列表,但我们被拒绝访问。
我对所发生的事情的最佳猜测是,Overlayfs 对底层文件系统进行了所有访问,因为root
NFS 的 root squash 会将其映射到nobody
不允许访问该文件夹的人,因为nobody
他们不属于该组rovanion
并且不允许其他人列出该文件夹。
问题
那么我的问题是:是否有可能解决这个问题?允许用户通过 Overlayfs 访问只有选定组才能访问的文件夹,而无需在 NFS 导出/共享上禁用 root_squash 或添加到o+rx
文件夹。
答案1
以下部分有关 Overlayfs 的 Linux 内核文档描述权限模型。
覆盖文件系统中的权限检查遵循以下原则:
1) permission check SHOULD return the same result before and after copy up 2) task creating the overlay mount MUST NOT gain additional privileges 3) non-mounting task MAY gain additional privileges through the overlay, compared to direct access on underlying lower or upper filesystems
这是通过对每次访问执行两次权限检查来实现的
a) check if current task is allowed access based on local DAC (owner, group, mode and posix acl), as well as MAC checks b) check if mounting task would be allowed real operation on lower or upper layer based on underlying filesystem permissions, again including MAC checks
检查 (a) 确保一致性 (1),因为所有者、组、模式和 posix acl 被复制。另一方面,它可能导致服务器强制执行的权限(例如 NFS 使用)被忽略 (3)。
检查(b)确保没有任务获得安装任务没有的底层的权限(2)。这也意味着可以创建一致性规则 (1) 不成立的设置;但是,通常情况下,安装任务将具有足够的权限来执行所有操作。
重点是我。我的理解是,我设法创建了这种情况。以 root 身份运行的挂载任务没有列出文件夹的权限,因此 Overlayfs 不允许用户访问该文件夹。
如果我们以允许访问文件的用户身份挂载 Overlayfs,而不是 root 用户,这样 UID 就不会被压缩,那么我们是否可以列出目录并在其中创建一个文件?
$ unshare --mount --map-root-user
# mount -t overlay overlay -o lowerdir=/mnt/nfs-share/,upperdir=/tmp/overlay/upper/,workdir=/tmp/overlay/work/ /mnt/overlay/
# ls -la /mnt/overlay/
totalt 28K
drwxrwxr-x 1 root root 4,0K sep 6 14:08 .
drwxr-xr-x 7 nobody nogroup 4,0K sep 6 14:09 ..
drwx------ 2 nobody nogroup 16K sep 6 13:04 lost+found
drwxr-s--- 2 root root 4,0K sep 6 14:14 rovanion
# touch /mnt/overlay/rovanion/hi-from-overlay
我们可以做到!而且文件仅存在于覆盖层中。
$ ls /mnt/ext4-file/rovanion/
hi-from-ext4
$ ls /tmp/overlay/upper/rovanion/
hi-from-overlay
不过,这个解决方案本身也有一些有趣的含义。现在我们必须在不是 100% 可信的机器上启用用户命名空间,我们突然处于一个 UID 似乎为 0 的空间,但该空间映射到我们外部世界的正常用户 ID。不幸的是,unshare --mount
没有它--map-root-user
似乎是不可能的。