ZFS 委托管理
Table of Contents
ZFS 提供全面的权限委托系统,允许非特权用户执行 ZFS 管理操作
例如,如果每个用户的主目录是一个数据集,用户需要获得创建和销毁其主目录快照的权限 执行备份的用户可以获得使用复制功能的权限
ZFS 还允许使用统计脚本,仅访问所有用户的空间使用数据。权限的委托能力本身也可委托。权限委托适用于每个子命令和大多数属性
用户级 ZFS 管理
ZFS 委托管理 ZFS delegation 提供细粒度的权限控制,让系统管理员将特定的 ZFS 管理权限授予非特权用户。自 FreeBSD 14.1 起,adduser 会自动为非特权用户的 ZFS 主目录创建独立数据集并支持加密
该变更使 adduser(8) 在用户主目录的父目录为 ZFS 数据集时,自动为用户创建独立 ZFS 数据集 例如 /home/xxx 继承自 /home
adduser 的 -Z 参数可禁用此行为,同时支持为非特权用户的 ZFS 主目录启用加密
基础用户级 ZFS 管理
以非特权用户的 ZFS 数据集为例 安装系统时手动创建了两个普通用户 aria2 和 safreya
列出系统中所有 ZFS 文件系统及其属性:
$ 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
其中:
zroot/home/aria2 128K 396G 128K /home/aria2 zroot/home/safreya 7.74G 396G 7.70G /home/safreya
即在创建用户时,系统已默认为用户 aria2 和 safreya 分别创建了各自独立的数据集 zroot/home/aria2 和 zroot/home/safreya
接下来,分别查看两个数据集上的用户权限
$ zfs allow zroot/home/aria2 # 显示或设置 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
由输出可知,系统在创建用户时,会默认为其数据集授予 create、destroy、mount 和 snapshot 四项权限
ZFS 委托权限存储在数据集的元数据中
Local+Descendent permissions 表示该权限设置既适用于当前数据集,也会继承到其子数据集
zfs allow <用户> allow <数据集> 赋予指定用户在目标数据集或其子数据集上将他们所拥有的任何权限委派给其他用户的能力
如果某用户拥有 snapshot 权限和 allow 权限,该用户可以将 snapshot 权限授予其他用户
因此,对于这两个数据集,普通用户也可使用快照功能:
$ zfs snapshot zroot/home/safreya@snap1 # 为 zroot/home/safreya 文件系统创建快照 snap1 $ zfs list -t snap # 列出所有 ZFS 快照 NAME USED AVAIL REFER MOUNTPOINT zroot/home/safreya@snap1 0B - 7.70G -
再来看 create、destroy 和 mount 权限:
$ zfs create zroot/home/safreya/dataset_1 # 在 zroot/home/safreya 下创建一个新的 ZFS 数据集 dataset_1 cannot mount 'zroot/home/safreya/dataset_1': Insufficient privileges filesystem successfully created, but not mounted
创建新数据集涉及挂载,这要求将 FreeBSD 的 sysctl vfs.usermount 设置为 1,以允许非 root 用户挂载文件系统
$ su -m root -c 'sysctl vfs.usermount=1' Password: vfs.usermount: 0 -> 1 $ zfs create zroot/home/safreya/dataset_2 # 在 zroot/home/safreya 下创建一个新的 ZFS 数据集 dataset_2 $ zfs list # 列出所有 ZFS 文件系统及其属性 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 数据集 zroot/home/safreya/dataset_1 $ zfs destroy zroot/home/safreya/dataset_2 # 删除 ZFS 数据集 zroot/home/safreya/dataset_2
由输出可知,创建和销毁权限可正常运行 为了防止滥用,还有另一个限制:非 root 用户必须拥有挂载点的所有权,才能挂载文件系统
至此,用户级 ZFS 管理的基本功能已就绪。但 rollback 权限默认不可用,需由 root 用户为普通用户单独授予。将 zroot/home/safreya 文件系统回滚到 snap1 快照状态:
$ zfs rollback zroot/home/safreya@snap1
cannot rollback 'zroot/home/safreya': permission denied
以 root 用户授予 safreya 用户对 zroot/home/safreya 文件系统执行回滚操作的权限:
$ su -m root -c 'zfs allow safreya rollback zroot/home/safreya'
Password:
$ zfs rollback zroot/home/safreya@snap1
用户级 ZFS 加密功能
在 FreeBSD 14.1 中,如果要在用户级使用 ZFS 加密功能,必须为用户授予特定权限
授权用户 safreya 对 zroot/home/safreya 文件系统执行密钥管理和加密操作:
$ su -m root -c 'zfs allow safreya change-key,load-key,keyformat,keylocation,encryption zroot/home/safreya' Password: # 此处输入 root 账户密码随后按回车键
显示 zroot/home/safreya 文件系统的当前权限授权设置:
$ 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-key 、load-key 、keyformat、keylocation 和 encryption 这五项权限属性用于 ZFS 的加密功能
创建启用加密的 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 # 查询 zroot/home/safreya/secret 数据集是否已挂载 NAME PROPERTY VALUE SOURCE zroot/home/safreya/secret mounted yes -
查看 mounted 属性,加密数据集创建即挂载,现在创建一份文件,随后卸载加密数据集:
$ cd secret # 进入 secret 数据集目录 $ echo "a secret makes a man mad" > abc.txt # 在 secret 数据集中创建文件 abc.txt 并写入内容 $ cd .. # 返回上一级目录 $ zfs unmount zroot/home/safreya/secret # 卸载 secret 数据集 $ zfs unload-key zroot/home/safreya/secret # 卸载 secret 数据集的加密密钥 $ zfs get mounted zroot/home/safreya/secret # 查询 secret 数据集是否已挂载 NAME PROPERTY VALUE SOURCE zroot/home/safreya/secret mounted no - $ ls secret # 并无输出
卸载加密数据集时必须同时卸载其密钥,挂载数据集时也必须先加载密钥:
$ zfs load-key zroot/home/safreya/secret # 加载 secret 数据集的加密密钥 Enter passphrase for 'zroot/home/safreya/secret': # 提示输入密钥密码 $ zfs mount zroot/home/safreya/secret # 挂载 secret 数据集 $ ls secret # 列出 secret 数据集中的文件 Permissions Size User Date Modified Name .rw-r--r-- 25 safreya 19 Sep 20:26 abc.txt
因为 destroy 权限默认已授予用户,所以无论数据集是否挂载,destroy 子命令都可以成功销毁数据集 因此如果操作者不是该用户本人,仍可能删除数据集 授权即授予普通用户代理权限,使其在操作授权的数据集时拥有类似 root 的权限,无需输入密码 因此,在授予权限时应合理限制授权范围和权限属性,例如禁用 destroy 权限属性等
撤销用户 safreya 对 zroot/home/safreya 文件系统的销毁权限:
$ su -m root -c 'zfs unallow safreya destroy zroot/home/safreya' Password: # 此处输入 root 账户密码随后按回车键
显示 zroot/home/safreya 文件系统的当前权限授权设置:
$ 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 上“Local+Descendent”权限的作用范围覆盖
“Local+Descendent”表示该权限的作用范围同时覆盖本数据集及其子孙数据集
- 在父数据集上撤销权限时,其 Descendent 范围也会移除,子孙数据集上的用户将失去相应权限
- 如果需要对子孙数据集单独控制权限,需要显式地在子孙数据集上授权或撤销
ZFS 委托权限不存在继承机制,权限存储在授予它的数据集上
adduser 与用户主目录加密
adduser 命令可直接使用加密的用户主目录数据集,但默认授予的权限不足,卸载后普通用户无法直接挂载
$ adduser # 在系统中添加新用户,按照提示输入用户名、密码及其他信息 Username: test ……省略无关内容…… Enable ZFS encryption? (yes/no) [no]: yes #该功能为新增功能 ……省略无关内容…… ZFS dataset : zroot/home/test 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.
查看 zroot/home/test 文件系统的当前权限授权设置:
$ zfs allow zroot/home/test ---- Permissions on zroot/home/test ---------------------------------- Local+Descendent permissions: user test create,destroy,mount,snapshot
卸载数据集和密钥:
$ zfs unmount zroot/home/test # 卸载 zroot/home/test 数据集 $ zfs unload-key zroot/home/test # 卸载 zroot/home/test 数据集的加密密钥
切换到普通用户 test 尝试挂载:
$ su test # 切换到普通用户 test $ zfs load-key zroot/home/test # 加载 zroot/home/test 数据集的加密密钥 Enter passphrase for 'zroot/home/test': Key load error: Permission denied.
Permission denied 表示权限不足,访问被拒绝
| Next: 启动环境 | Previous: 数据集管理 | Home: ZFS文件系统 |