减少工作量的最好方法之一就是让别人来完成工作。
ZFS有一个功能齐全的委托系统,允许指定用户或用户组可以在每个数据集上使用哪些命令和功能。
可以允许用户创建和销毁自己的快照、创建子数据集、生成空间销毁报告或控制数据集的属性。ZFS基于委托功能和jail提供特殊支持。
ZFS允许根据每个数据集的每个属性和每个命令将管理任务委托给用户。
可以让数据库管理员完全控制数据库池,或者让web服务器管理员控制网站数据集上的快照。
使用zfs allow命令委派权限。
xxxxxxxxxx
# zfs allow remotepool
---- Permissions on remotepool ---------------------------------------
Local+Descendent permissions:
user replicator compression,create,destroy,mount,mountpoint,receive
以上示例获取remotepool池的权限列表。
此池只有一个用户复制器的权限条目。此用户有权使用zfs的压缩和挂载点属性,以及创建、销毁、挂载和接收子命令。
应用程序和用户可以定义自己的属性。像zfstools这样的程序创建属性来管理快照。
还有一个特殊权限userprop,允许用户创建用户定义的属性。
用户定义的属性被分配为单个权限:不能单独分配不同的用户定义属性。
root用户不会列出任何权限,但root却可以做任何事情。因为它是root。
使用-u选项指定要委派的用户,或使用-g选项指定要委派的组:
xxxxxxxxxx
# zfs allow -u lucas snapshot,rollback mypool/usr/home/lucas
查看数据集权限时,将显示分配的两个权限:
xxxxxxxxxx
# zfs allow mypool/usr/home/lucas
---- Permissions on mypool/usr/home/lucas ----------------------------
Local+Descendent permissions:
user lucas rollback,snapshot
委托会自动继承。当用户获得为主目录创建快照能力时,他也获得了对主目录中所有子数据集的许可。
xxxxxxxxxx
# su lucas
$ zfs snapshot mypool/usr/home/lucas/blackmail@bsdcan_drunken_escapades
$ zfs list -t all -r -o name mypool/usr/home/lucas
NAME
mypool/usr/home/lucas
mypool/usr/home/lucas/blackmail
mypool/usr/home/lucas/blackmail@bsdcan_drunken_escapades
$ zfs destroy mypool/usr/home/lucas/blackmail@bsdcan_drunken_escapades
cannot destroy snapshots: permission denied
创建新数据集需要挂载它们,销毁数据集显然应该包括卸载数据集。
要使用clone、create和destroy命令都需要mount权限。以下命令委托销毁和挂载权限给用户:
xxxxxxxxxx
# zfs allow -u lucas destroy,mount mypool/usr/home/lucas
现在查看一下权限:
xxxxxxxxxx
# zfs allow mypool/usr/home/lucas
---- Permissions on mypool/usr/home/lucas ----------------------------
Local+Descendent permissions:
user lucas destroy,mount,rollback,snapshot
用户有权销毁他的主目录数据集。
你可以授予用户创建和挂载数据集的权限,但操作系统在这里也有发言权。
FreeBSD使用sysctl vfs.usermount来确定用户是否可以挂载分区。将此sysctl设置为1,以允许用户挂载分区。
即使有了sysctl,允许普通用户挂载文件系统也会附带一条安全带(safety belt),以防止用户误操作。
用户必须拥有他想要挂载任何东西的目录。这可以防止用户将新数据集挂载为/etc并劫持系统。数据集可能具有限制权限,但拥有挂载点并具有mount权限的用户可以挂载它。
要允许普通用户在其主目录中创建、克隆、挂载数据集,应设置sysctl并确保他拥有相应的控制目录:
xxxxxxxxxx
# sysctl vfs.usermount=1
# zfs allow -u lucas create,clone,mount mypool/usr/home/lucas
使用普通登录并检查:
xxxxxxxxxx
# su lucas
$ zfs create mypool/usr/home/lucas/evil_plot
$ zfs mount
mypool/ROOT/default /
…
mypool/usr/home /usr/home
mypool/usr/home/lucas /usr/home/lucas
mypool/usr/home/lucas/blackmail /usr/home/lucas/blackmail
mypool/usr/home/lucas/evil_plot /usr/home/lucas/evil_plot
记得添加vfs.usermount=1行到/etc/sysctl.conf文件。
使用zfs unallow从数据集中删除权限。此命令遵循与zfs完全相同的语法。
以下示例取消了lucas创建子数据集的权限:
xxxxxxxxxx
# zfs unallow -u lucas create mypool/usr/home/lucas
# zfs allow mypool/usr/home/lucas
---- Permissions on mypool/usr/home/lucas ----------------------------
Local+Descendent permissions:
user lucas clone,destroy,mount,rollback,snapshot
权限也可以使用-r选项递归删除,若某个子数据集被手动设置过权限,也会被删除。
ZFS的委托权限会自动继承。zfs allow命令还以限制权限继承。
继承的权限可以是本地的,也可以用于后代。
本地权限仅适用于指定的数据集。以下示例允许用户快照他的主目录,但不快照子数据集。
-l选项将权限设置为仅本地权限(不能被继承)。
xxxxxxxxxx
# zfs allow -lu lucas clone,destroy,mount,rollback,snapshot zroot/home/lucas
# zfs allow zroot/home/lucas
---- Permissions on zroot/home/lucas --------------------------------
Local permissions:
user lucas clone,destroy,mount,rollback,snapshot
-d选项则与-l选项相反,它仅允许对子数据集进行委托。
以下示例中,我想允许lucas销毁他创建的快照,但不要销毁他的整个主目录。我使用-d指定这些权限仅适用于他的主目录的子数据集,而不适用于主目录本身。我在他的主目录中保留了快照和回滚命令的权限,这样如果他没有搞砸,他就可以自救了。
xxxxxxxxxx
# zfs allow -d lucas destroy,mount mypool/usr/home/lucas
# zfs allow mypool/usr/home/lucas
---- Permissions on mypool/usr/home/lucas -------------------
Descendent permissions:
user lucas destroy,mount
Local+Descendent permissions:
user lucas rollback,snapshot
测试一下:
xxxxxxxxxx
$ zfs destroy -v mypool/usr/home/lucas/desc
will destroy mypool/usr/home/lucas/desc
$ zfs destroy -v mypool/usr/home/lucas
cannot unmount '/home/lucas': Operation not permitted
只有系统管理员才能在Lucas主目录上运行zfs destroy。
ZFS允许在今天为未来时间不存在的数据集创建权限。
create time权限应用于创建数据集的用户。使用-c定义。
对这类权限的一个常见愿望是将权限授予每个人,而不是指定系统上的每个用户或定义一个包括所有用户的组。使用-e选项表示所有人(所有用户),而不是-u或-g表示某个人或组。
-l选项设置父数据集的权限。假设我们有一个可供所有人使用的临时数据集,比如/tmp。
我们需要每个人都能在这个空间创建和挂载数据集,但不能访问整个数据集。这些权限必须限制到该数据集,并且不能由新的子数据集继承。
xxxxxxxxxx
# zfs allow -l -e create,mount mypool/scratch
现在使用-c指定分配给新创建的数据集的创建时间权限:
xxxxxxxxxx
# zfs allow -c snapshot,rollback,destroy mypool/scratch
检查您的工作将显示创建时间权限作为权限集。
xxxxxxxxxx
# zfs allow mypool/scratch
---- Permissions on mypool/scratch -----------------------------------
Permission sets:
destroy,rollback,snapshot
Local permissions:
everyone create,mount
当然,真正的测试是以普通用户的身份运行这些命令。让lucas在mypool/strack下创建一些数据集。
xxxxxxxxxx
# su lucas
$ zfs create mypool/scratch/lucas
$ zfs allow mypool/scratch/lucas
---- Permissions on mypool/scratch/lucas -----------------------------
Local permissions:
user lucas destroy,rollback,snapshot
---- Permissions on mypool/scratch -----------------------------------
Permission sets:
destroy,rollback,snapshot
Local permissions:
everyone create,mount
现在,lucas,而且只有lucas,可以创建和销毁他的数据集的快照。其他用户可以创建只有他们才能访问的自己的数据集。
有权访问allow命令的用户可以委派他已经拥有的任何其他权限。这使您能够让团队负责人或项目经理负责其团队的权限。
考虑前面的划痕数据集示例。假设lucas想允许liz用户在他的新scratch数据集上创建快照。
首先,通过允许lucas使用zfs-allow命令,赋予他委派权限的能力。
xxxxxxxxxx
# zfs allow -u lucas allow mypool/scratch/lucas
# zfs allow mypool/scratch/lucas
---- Permissions on mypool/scratch/lucas -----------------------------
Local permissions:
user lucas destroy,snapshot
Local+Descendent permissions:
user lucas allow
---- Permissions on mypool/scratch -----------------------------------
Permission sets:
destroy,snapshot
Local permissions:
everyone create,mount
Lucas现在可以将他拥有的任何权限委托给liz帐户。通过以他的身份登录来测试这一点。
xxxxxxxxxx
# su lucas
$ zfs allow -u liz snapshot mypool/scratch/lucas
$ zfs allow mypool/scratch/lucas
---- Permissions on mypool/scratch/lucas -----------------------------
Local permissions:
user lucas destroy,snapshot
Local+Descendent permissions:
user lucas allow
user liz snapshot
---- Permissions on mypool/scratch -----------------------------------
Permission sets:
destroy,snapshot
Local permissions:
everyone create,mount
但Lucas不能放弃他没有的权限:
xxxxxxxxxx
$ zfs allow -u liz clone mypool/scratch/lucas
cannot set permissions on 'mypool/scratch/lucas': permission denied
系统管理员可以将权限委托给用户,并让用户负责进一步委托自己的数据集。
运行zfs allow命令会显示一个列表,其中包含可以授权给用的60多个权限。可以单独授予对每个zfs子命令以及每个池和数据集属性的访问权限。
ZFS允许定义权限集,而不是必须向每个用户授予一长串权限,并且不可避免地会忘记或记错一个。
使用-s选项并给出一个以@符号开头地权限集名称,然后列出该集中地权限以及该权限集有效的数据集的名称。
xxxxxxxxxx
# zfs allow -s @permissionset permission,permission,permission… dataset
以下示例创建一个名为@dataset的权限集,包括管理数据集的权限,并将其应用于mypool/teams数据集上:
xxxxxxxxxx
# zfs allow -s @dataset create,destroy,mount,rename,snapshot,rollback,clone,promote,hold,release mypool/teams
以下是一个名为@replication的权限集,它提供了在同一数据集上进行复制所需的特权:
xxxxxxxxxx
# zfs allow -s @replication send,receive mypool/teams
@billing权限集授予对数据集上通常无法访问的userused和pgroupused属性的访问权限:
xxxxxxxxxx
# zfs allow -s @billing userused,groupused mypool/teams
以下是一个@quotas权限集,允许某人管理数据集空间配额:
xxxxxxxxxx
# zfs allow -s @quotas userquota,groupquota,quota,refquota,reservation,refreservation mypool/teams
最后,这里有一个权限集,可以让人们调整一些基本的数据集属性。据推测,系统管理员将这些设置为合理的默认值,但用户可能具有特殊要求的特定数据集:
xxxxxxxxxx
# zfs allow -s @basic_properties compression,copies,atime,primarycache,secondarycache mypool/teams
一旦建立了权限集,就可以将它们分配给用户和组。此例中,managers组可以访问其数据集中的@dataset和@basic_properties集中的权限:
xxxxxxxxxx
# zfs allow -g managers @dataset,@basic_properties mypool/teams
然后,我们允许运行计费系统(billing system)的billbot用户访问在mypool/teams上设置的billing权限:
xxxxxxxxxx
# zfs allow -u billbot @billing mypool/teams
运行zfs allow命令显示数据集上的权限集和分配的权限:
xxxxxxxxxx
# zfs allow mypool/teams
---- Permissions on mypool/teams -------------------------------------
Permission sets:
@basic_properties atime,compression,copies,primarycache,secondarycache
@billing groupused,userused
@dataset clone,create,destroy,hold,mount,promote,release,rename,rollback,snapshot
@quotas groupquota,quota,refquota,refreservation,reservation,userquota
@replication receive,send
Local+Descendent permissions:
user billbot @billing
group managers @basic_properties,@dataset
ZFS委托可能很快变得复杂。与许多其他权限方案一样,使用组可以帮助简化管理。
仅在需要时分配权限,而不是因为你认为你知道系统如何发展。
FreeBSD支持一种称为jail的轻量级虚拟化方法。FreeBSD的ZFS实现对jail有特殊的支持。
数据集可以被标记为只能在jail中使用。jail中的root用户可以完全控制数据集。
无法在主机系统上挂载jail数据集。jail数据集不受信任,并且可能具有与主机不兼容或对主机充满敌意的属性设置。
举个例子,jail可能有一个挂载点为/etc的数据集。记住,BSD文件系统是可堆叠的。如果主机挂载了jail数据集,jail的/etc将堆叠在主机的/etc上。主机将突然拥有jail的/etc/password、rc.conf、sshd_config和其他重要的文件系统。最坏的情况是,jail的系统管理员可以声称控制主机。最好的情况是,主机的系统管理员会度过非常不愉快的一天。
据jail的root用户所知,他几乎完全控制了数据集。他唯一不能改变的属性是配额。编辑配额可能会让他比分配给他的系统管理员更多的访问权限。
然而,jail的root用户可以看到它存在于jail中。root账户可以看到其数据集的每个父数据集,直到池的根。如果你有一个jail池,并且jail存在于例如jails/ccustomers/lucas中,则root用户可以看到该路径。然而,它们看不到在jail外任何数据集。其他客户数据集是不可见的。
将数据集的jailed属性设置为on,主机将无法再挂载这个数据集。
以下示例为Lucas创造一个jail,创建一个新的数据集作为他的jail的根,在这里,我们使用zroot/jails/lucas/jail数据集作为jail数据集:
xxxxxxxxxx
# zfs create -o jailed=on -o mountpoint=/jail zroot/jails/lucas/jail
一旦有了数据集,就在这个数据集中建立一个临时的jail:
xxxxxxxxxx
# jail -c path=/zroot/jails/lucas mount.devfs allow.mount allow.mount.zfs \
host.hostname=lucas ip4.addr=”lo0|127.0.0.2” exec.poststart = \
"/sbin/zfs jail lucas zroot/jails/lucas/jail" command=/bin/sh
现在进入jail:
xxxxxxxxxx
# jexec lucas sh
当我们进入到jail后,可以创建一个新的数据集:
xxxxxxxxxx
jail# zfs create zroot/jails/lucas/jail/foo
新的数据集和jail的父数据集都是可见的:
xxxxxxxxxx
jail# zfs list -o name,mountpoint
NAME MOUNTPOINT
zroot /zroot
zroot/jails /zroot/jails
zroot/jails/lucas /zroot/jails/lucas
zroot/jails/lucas/jail /jail
zroot/jails/lucas/jail/foo /jail/foo
zroot/jails中是否还有其他数据集,或实际上,在这个jail的主机中是否有其他数据集?jail里的用户永远不会知道。
用户lucas现在可以设置挂载点、创建和销毁数据集、将数据集委托给jail内的普通用户等等。要是能让lucas用户在现实世界中不破坏东西就好了。
你的jail用户可能不想要如上所述的简陋jail。他们可能想要一个真正的用户区,有程序和运行服务的能力。
这意味着在jail数据集上安装FreeBSD。
首先,创建一个jail数据集:
xxxxxxxxxx
# zfs create -p mypool/jails/lucas/zroot
现在在该数据集上安装操作系统。可以直接从FTP站点安装:
xxxxxxxxxx
# fetch -o - ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.3-RELEASE/base.txz | tar -xJf - -C /mypool/jails/lucas/
如果打算安装多个jail,请下载对应版本的base.txz,并在每个jail中提取它:
xxxxxxxxxx
# tar -xf base.txz -C /mypool/jails/lucas/
将操作系统复制到jail数据集中后,将该数据集标记为不受信任。这使得主机无法访问数据集:
xxxxxxxxxx
# zfs set mountpoint=/zroot mypool/jails/lucas/zroot
# zfs set jailed=on mypool/jails/lucas/zroot
现在有了数据集,在jail配置文件/etc/jail.conf中为no.gelato.for.michaelwlucas.com这个jail创建一个条目:
xxxxxxxxxx
nogelatoforyou {
host.hostname = "no.gelato.for.michaelwlucas.com";
ip4.addr = "em0|198.51.100.200";
path = "/mypool/jails/lucas";
persist = true;
mount.devfs = true;
allow.mount = true;
allow.mount.zfs = true;
enforce_statfs = 1;
exec.poststart = "/sbin/zfs jail nogelatoforyou mypool/jails/lucas/zroot";
exec.poststop = "/sbin/zfs unjail nogelatoforyou mypool/jails/lucas/zroot";
}
有了jail.conf条目,我们可以使用标准的FreeBSD工具启动jail:
xxxxxxxxxx
# service jail onestart nogelatoforyou
最后一段设置需要在jail内进行。或者,在安装操作系统时,可以做一些疯狂的事情,比如提前计划,但这会让事情失去乐趣。让我们进入jail,看看我们的数据集:
xxxxxxxxxx
# jexec nogelatoforyou /bin/sh
jail# zfs list
NAME USED AVAIL REFER MOUNTPOINT
mypool 5.21G 13.1G 96K none
mypool/jails 180M 13.1G 96K /mypool/jails
mypool/jails/lucas 180M 13.1G 180M /mypool/jails/lucas
mypool/jails/lucas/zroot 96K 13.1G 96K /zroot
这个新jail在rc.conf中没有启用ZFS,因此默认情况下不会挂载新数据集。启用ZFS并重新启动jail:
xxxxxxxxxx
jail# sysrc zfs_enable=”YES”
更改配置后,重新启动并重新进入jail:
xxxxxxxxxx
# service jail onerestart nogelatoforyou
# jexec nogelatoforyou /bin/sh
将看到新创建的数据集:
xxxxxxxxxx
jail# zfs create mypool/jails/lucas/zroot/test
jail# zfs list
NAME USED AVAIL REFER MOUNTPOINT
mypool 5.21G 13.1G 96K none
mypool/jails 180M 13.1G 96K /mypool/jails
mypool/jails/lucas 180M 13.1G 180M /mypool/jails/lucas
mypool/jails/lucas/zroot 192K 13.1G 96K /zroot
mypool/jails/lucas/zroot/test 96K 13.1G 96K /zroot/test
jail管理员必须使用完整路径,包括jail外的部分,来创建新的数据集。
对于充满好奇心或又菜又爱玩的用户,ZFS提供了snapshot_limit和filesystem_limit属性,可以限制在特定数据集下可以创建的快照或子文件系统的数量。
将这些属性设置为大于你希望用户创建的快照数或数据集的数量。也就是说,将snapshot_limit设置为10,则用户可以创建9个快照,第十个会产生错误。
为了遏制某些用户存粹的邪恶,将他可以创建的快照数量限制为两个:
xxxxxxxxxx
# zfs set snapshot_limit=3 zroot/usr/home/lucas
# su lucas
$ zfs snapshot zroot/usr/home/lucas@three
$ zfs snapshot zroot/usr/home/lucas@four
cannot create snapshot 'zroot/usr/home/lucas': out of space
只读的filesystem_count和snapshot_count属性允许快速查看存在多少个文件系统或快照,并将该数字于限制进行比较。