25.6 ZFS 委托管理

用户级 zfs 管理

zfs 允许非特权用户管理,即 zfs 委托管理。

自 FreeBSD 14.1 以降(请参阅发行说明,是由 这个 变更做出的),bsdinstall(8) 使用的工具 adduser(8):当用户主目录的父目录位于 zfs 数据集上时(即若 /home 是个 zfs 数据集,/home/xxx 亦如此),会为用户的主目录创建一个 zfs 数据集。adduser 的参数 -Z 可禁用这一行为。adduser 对于 zfs 的非特权用户主目录加密功能亦已可用。

以下操作基于 FreeBSD 14.1-RELEASE

基础的用户级 zfs 管理

先来了解一下非特权用户的 zfs 数据集。

我们首先在安装系统时,创建了两个普通用户“aria2”和“safreya”。

查看现在的挂载情况:

% zfs list
NAME                                           USED  AVAIL  REFER  MOUNTPOINT
zroot                                         53.7G   396G    96K  /zroot
zroot/ROOT                                    12.8G   396G    96K  none
zroot/ROOT/14.1-RELEASE-p3_2024-09-17_194642     8K   396G  11.6G  /
zroot/ROOT/default                            12.8G   396G  11.9G  /
zroot/aria2                                    187M   396G   187M  /usr/local/data/aria2
zroot/home                                    7.74G   396G    96K  /home
zroot/home/aria2                               128K   396G   128K  /home/aria2   # 请注意此行
zroot/home/safreya                            7.74G   396G  7.70G  /home/safreya # 请注意此行
zroot/jails                                   3.12G   396G  3.12G  /usr/jails
zroot/sec                                     28.5G   396G  28.5G  /usr/local/data/sec
zroot/tmp                                      102M   396G   102M  /tmp
zroot/usr                                     1.34G   396G    96K  /usr
zroot/usr/ports                               1.34G   396G  1.34G  /usr/ports
zroot/usr/src                                   96K   396G    96K  /usr/src
zroot/var                                     1.58M   396G    96K  /var
zroot/var/audit                                 96K   396G    96K  /var/audit
zroot/var/crash                                 96K   396G    96K  /var/crash
zroot/var/log                                 1.02M   396G  1.02M  /var/log
zroot/var/mail                                 168K   396G   168K  /var/mail
zroot/var/tmp                                  120K   396G   120K  /var/tmp
safreya ~ %

其中:

zroot/home/aria2                               128K   396G   128K  /home/aria2
zroot/home/safreya                            7.74G   396G  7.70G  /home/safreya

即,在创建用户时,已默认为用户 safreyaaria2 分别创建了各自独立的数据集 zroot/home/aria2zroot/home/safreya

接下来,分别查看一下两个数据集上的用户权限。

% zfs allow zroot/home/aria2
---- Permissions on zroot/home/aria2 ---------------------------------
Local+Descendent permissions:
        user aria2 create,destroy,mount,snapshot
safreya ~ % zfs allow zroot/home/safreya
---- Permissions on zroot/home/safreya -------------------------------
Local+Descendent permissions:
        user safreya create,destroy,mount,snapshot

可以看到,在创建用户集时,默认为用户创设了 createdestroymountsnapshot 四项权限。

所以,对于这两个数据集,普通用户亦可使用快照功能:

% zfs snap zroot/home/safreya@snap1
% zfs list -t snap
NAME                                       USED  AVAIL  REFER  MOUNTPOINT
zroot/home/safreya@snap1                     0B      -  7.70G  -

再来看 create, destroy, mount 权限:

% zfs create zroot/home/safreya/dataset_1
cannot mount 'zroot/home/safreya/dataset_1': Insufficient privileges
filesystem successfully created, but not mounted
% su -m root -c 'sysctl vfs.usermount=1'
Password:
vfs.usermount: 0 -> 1
% zfs create zroot/home/safreya/dataset_2
% zfs list
NAME                                           USED  AVAIL  REFER  MOUNTPOINT

      ...此处省略一部分...
      
zroot/home                                    7.79G   396G    96K  /home
zroot/home/aria2                               128K   396G   128K  /home/aria2
zroot/home/safreya                            7.79G   396G  7.68G  /home/safreya
zroot/home/safreya/dataset_1                    96K   396G    96K  /home/safreya/dataset_1
zroot/home/safreya/dataset_2                    96K   396G    96K  /home/safreya/dataset_2

      ...此处省略一部分...
% zfs destroy zroot/home/safreya/dataset_1
% zfs destroy zroot/home/safreya/dataset_2      

可以看到,创建(create)权限、销毁(destroy)权限可以正常使用,但是挂载(mount)权限需要开启内核参数 vfs.usermount,以允许用户级挂载。

到这里,用户级的 zfs 管理需求已经基本满足。但是你够仔细的话会发现 rollback 权限并不可用,可以用 root 用户授权普通用户 rollback 权限。即:

% zfs rollback zroot/home/safreya@snap1
cannot rollback 'zroot/home/safreya': permission denied
% su -m root -c 'zfs allow safreya rollback zroot/home/safreya'
Password:
% zfs rollback zroot/home/safreya@snap1

用户级 zfs 加密功能

FreeBSD 14.1 中,在用户级使用 zfs 加密功能,需要为用户授予特定权限。

% su -m root -c 'zfs allow safreya change-key,load-key,keyformat,keylocation,encryption zroot/home/safreya'
Password:
% zfs allow zroot/home/safreya
---- Permissions on zroot/home/safreya -------------------------------
Local+Descendent permissions:
        user safreya change-key,create,destroy,encryption,keyformat,keylocation,load-key,mount,snapshot

change-keyload-keykeyformatkeylocationencryption 这五个权限属性都用于 zfs 加密功能。

现在创建一个加密数据集 zroot/home/safreya/secret

% zfs create -o encryption=on -o keyformat=passphrase zroot/home/safreya/secret
Enter new passphrase:     # 在此处输入密码,密码不会回显,就是什么也没有
Re-enter new passphrase:  # 在此处重复输入上述密码,密码不会回显,就是什么也没有

查看加密情况:

% zfs get mounted zroot/home/safreya/secret
NAME                       PROPERTY  VALUE    SOURCE
zroot/home/safreya/secret  mounted   yes      -

查看 mounted 属性,加密数据集创建即挂载,现在创建一个文件,然后卸载加密数据集:

% cd secret
% echo "a secret makes a man mad" > abc.txt
% cd ..
% zfs unmount zroot/home/safreya/secret
% zfs unload-key zroot/home/safreya/secret
% zfs get mounted zroot/home/safreya/secret
NAME                       PROPERTY  VALUE    SOURCE
zroot/home/safreya/secret  mounted   no       -
% ls secret # 并无输出

卸载加密数据集必须记得也要同时卸载密钥。挂载加密数据集亦要先加载密钥:

% zfs load-key zroot/home/safreya/secret
Enter passphrase for 'zroot/home/safreya/secret':
% zfs mount zroot/home/safreya/secret
% ls secret
Permissions Size User    Date Modified Name
.rw-r--r--    25 safreya 19 Sep 20:26  abc.txt

注意

无论数据集是否挂载,子命令 destroy 都可以成功销毁数据集,因为 destroy 权限是默认就授予的,所以如果非用户本人操作系统的话,可能出现“我得不到的,就毁灭”的情况。

切记,“授权”是授予普通用户“代理权限”,操作有授权的数据集时就相当于 root,过程中无需密码。因此在授予权限时还要综合考量,合理的限制授权范围和权限属性,如禁用 destroy 权限属性等。

% su -m root -c 'zfs unallow safreya destroy zroot/home/safreya'
Password:
% zfs allow  zroot/home/safreya
---- Permissions on zroot/home/safreya -------------------------------
Local+Descendent permissions:
        user safreya change-key,create,encryption,keyformat,keylocation,load-key,mount,rollback,snapshot

这里 zroot/home/safreya/secret 继承了数据集 zroot/home/safreya 的权限属性,授权/反授权都针对 zroot/home/safreya,对 zroot/home/safreya/secret 的操作不起作用(操作后属性不变,原因未知)。

adduser 与用户主目录加密

adduser 命令中可以直接使用加密的用户主目录数据集,但默认给出的权限不足,一经卸载就无法由普通用户直接挂载

# adduser
Username: test
Full name:
Uid (Leave empty for default):
Login group [test]:
Login group is test. Invite test into other groups? []:
Login class [default]:
Shell (sh csh tcsh zsh rzsh git-shell bash rbash nologin) [sh]:
Home directory [/home/test]:
Home directory permissions (Leave empty for default):
Enable ZFS encryption? (yes/no) [no]: yes #该功能为新增功能
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]:
Use a random password? (yes/no) [no]:
Enter password:
Enter password again:
Lock out the account after creation? [no]:
Username    : test
Password    : *****
Full Name   :
Uid         : 1003
ZFS dataset : zroot/home/test
Encrypted   : yes
Class       :
Groups      : test
Home        : /home/test
Home Mode   :
Shell       : /bin/sh
Locked      : no
OK? (yes/no) [yes]:
Enter encryption keyphrase for ZFS dataset (zroot/home/test):
Enter new passphrase:
Re-enter new passphrase:
adduser: INFO: Successfully created ZFS dataset (zroot/home/test).
adduser: INFO: Successfully added (test) to the user database.
Add another user? (yes/no) [no]: no
Goodbye!

查看权限:

# zfs allow zroot/home/test
---- Permissions on zroot/home/test ----------------------------------
Local+Descendent permissions:
        user test create,destroy,mount,snapshot

卸载:

# zfs unmount zroot/home/test
# zfs unload-key  zroot/home/test

切换到普通用户 test 挂载尝试:

# su test
$ zfs load-key zroot/home/test
Enter passphrase for 'zroot/home/test':
Key load error: Permission denied.

Permission denied 即权限不足,拒绝访问。

参考文献

最后更新于

这有帮助吗?