ZFS设计师竭尽全力为系统管理员简化存储管理。减少你所做工作量的最好方法之一是让别人为你做这项工作。ZFS具有功能齐全的委派系统,允许您指定用户或用户组可以在每个数据集上使用的命令和功能。您可以允许用户创建和销毁自己的快照、创建子数据集、生成空间消耗报告或控制数据集的属性。ZFS基于委托功能构建,为jails提供特殊支持。
ZFS允许您根据每个数据集的每个属性和每个命令将管理任务委托给用户。您可以让数据库管理员完全控制数据库池,或者让web服务器管理员控制网站数据集上的快照。使用 zfs allow 命令委派权限。
将池或数据集作为参数给予 zfs allow 将显示该设备上的权限。下面示例中,我获得池 remotepool 的权限。
xxxxxxxxxx# zfs allow remotepool---- Permissions on remotepool ---------------------------------------Local+Descendent permissions: user replicator compression,create,destroy,mount,mountpoint,receive对于用户 replicator ,此池具有单个权限条目。该用户具有 compression 和 mountpoint 属性以及 zfs 的 create 、destroy 、mount 和 receive 子命令的权限。(第4章讨论了这些特定权限的重要性。)
应用程序和用户可以定义自己的属性。像 zfstools 这样的程序创建属性来管理快照。还有一个特殊的权限 userprop ,允许用户创建用户定义的属性。用户定义的属性被分配为单个权限:不能单独分配不同的用户定义属性。
虽然 root 在这里并没有被列为具有任何权限,但 root 可以做任何它喜欢做的事情。因为这就是Unix的运行方式。
将池或数据集的权限委派给用户或组。-u 标志允许您指定 zfs allow 的用户名,-g 指定组。
x# zfs allow -u username permissions pool/dataset假设我们有一个麻烦的用户,叫他Lucas。他一直在尝试愚蠢的Unix技巧来破坏他的主目录。让我们允许Lucas创建自己的快照,这样他就不必每次破坏环境时都打扰系统管理员。
# 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委派将自动继承。当Lucas获得快照其主目录数据集的能力时,他也获得了对其主目录的所有子数据集的权限。出于某种原因,他有一个名为 blackmail 的数据集。这可能是他用来让BSD开发人员帮助他进行研究和技术审查的所有照片和录音的地方。
xxxxxxxxxx# zfs allow mypool/usr/home/lucas/blackmail---- Permissions on mypool/usr/home/lucas ----------------------------Local+Descendent permissions: user lucas rollback,snapshotLucas应该有权创建快照。然而,在告诉他这是有效的之前,请模仿Lucas并创建一个快照。
xxxxxxxxxx# su lucas$ zfs snapshot mypool/usr/home/lucas/blackmail@bsdcan_drunken_escapades$ zfs list -t all -r -o name mypool/usr/home/lucasNAMEmypool/usr/home/lucasmypool/usr/home/lucas/blackmailmypool/usr/home/lucas/blackmail@bsdcan_drunken_escapades我们知道这是有效的。让我们在Lucas得到任何他还没有的想法之前把快照处理掉。
xxxxxxxxxx$ zfs destroy mypool/usr/home/lucas/blackmail@bsdcan_drunken_escapadescannot destroy snapshots: permission denied创建新的数据集涉及挂载它们,而销毁数据集显然应该包括卸载它们。为了使用 clone、create 和 destroy 命令都需要 mount 权限。要授予 lucas 权限,请运行 zfs allow -u lucas 并列出所需的权限和数据集。
xxxxxxxxxx# zfs allow -u lucas destroy,mount mypool/usr/home/lucas现在检查您的工作会显示您在 zfs allow 的两次运行中分配的每个权限。
xxxxxxxxxx# zfs allow mypool/usr/home/lucas---- Permissions on mypool/usr/home/lucas ----------------------------Local+Descendent permissions: user lucas destroy,mount,rollback,snapshotLucas现在可以通过破坏他的主目录所在的数据集来打击自己。他肯定会为此而抱怨。
您可以授予用户创建和装载数据集的权限,但操作系统在这里也有发言权。FreeBSD使用sysctl vfs.usermount 来确定用户是否可以装载分区。将此sysctl设置为 1 以允许用户装载分区。
即使有了这个sysctl,允许普通用户装载文件系统也有一个安全带,可以防止用户做坏事。用户必须拥有要挂载任何内容的目录。这可以防止用户将其新数据集挂载为 /etc 并劫持您的系统。数据集可能对其具有限制性权限,但拥有装入点并具有 mount 特权的用户可以挂载它。
要允许常规用户 lucas 在其主目录下创建、克隆和挂载数据集,请设置sysctl,并确保他拥有您让他控制的目录。
xxxxxxxxxx# sysctl vfs.usermount=1# zfs allow -u lucas create,clone,mount mypool/usr/home/lucas再次以 lucas 身份登录以验证它是否工作。
xxxxxxxxxx# su lucas$ zfs create mypool/usr/home/lucas/evil_plot$ zfs mountmypool/ROOT/default /…mypool/usr/home /usr/homemypool/usr/home/lucas /usr/home/lucasmypool/usr/home/lucas/blackmail /usr/home/lucas/blackmailmypool/usr/home/lucas/evil_plot /usr/home/lucas/evil_plot记住将 vfs.usermount=1 添加到 /etc/sysctl.conf 中,以便他在重新启动后仍然可以挂载数据集,否则他会向您抱怨。
将权限(和工作)让给其他人可以是自由的,但没有什么比得上剥夺权限的感觉。使用 zfs unallow 从数据集中删除权限。该命令遵循与 zfs allow 完全相同的语法。
在这里,用户 lucas 创建了太多的孩子,我们决定不再允许他生育。取消他的 create 权限。
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的委托权限将自动继承。如果您授予用户对 zroot/db 的权限,则她会自动获得对 zroot/db 的所有子级的相同权限。zfs allow 子命令还可以限制权限继承。继承的权限可以是本地的,也可以应用于后代。
本地权限仅应用于指定的数据集。我们可能允许 lucas 权限快照 zroot/usr/home/lucas ,但不允许快照子数据集。他将不得不用老式的方法来管理他的勒索材料。使用 -l 标志将特权设置为仅本地。
xxxxxxxxxx# zfs allow -lu lucas clone,destroy,mount,rollback,snapshot zroot/home/lucas权限现在仅显示为本地,而不是本地和子级。
x
# zfs allow zroot/home/lucas---- Permissions on zroot/home/lucas --------------------------------Local permissions: user lucas clone,destroy,mount,rollback,snapshot您还可以仅将权限应用于子数据集,而不是命令中的数据集。-d 标志告诉 zfs allow 权限仅应用于子数据集,而不是创建权限的父数据集。这可以用于允许用户销毁子数据集,但不销毁父数据集。
在这里,我希望允许 lucas 销毁他创建的快照,但不销毁他的整个主目录。我使用 -d 指定这些权限仅应用于他的主目录的子数据集,而不是主目录本身。我将 snapshot 和 rollback 命令的权限保留在他的主目录中,这样,如果他没有太糟的话,他可以自救。
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,mountLocal+Descendent permissions: user lucas rollback,snapshot再次模拟Lucas并测试权限。
xxxxxxxxxx$ zfs destroy -v mypool/usr/home/lucas/descwill destroy mypool/usr/home/lucas/desc$ zfs destroy -v mypool/usr/home/lucascannot unmount '/home/lucas': Operation not permitted现在,在Lucas的主目录上运行 zfs destroy 是系统管理员的荣幸。
ZFS允许您立即为下周二或未来某个时间之前不存在的数据集创建权限。创建时间(create time)权限应用于创建数据集的用户。他们就像是授权的“粘性物(sticky bit)”。使用 -c 定义创建时间权限。
这些类型的权限的常见愿望是将权限授予每个人,而不是指定系统上的每个用户或定义包含所有用户的组。使用 -e 标志来指示每个人(所有用户),而不是 -u 或 -g 和用户名或组名。
使用创建时间权限需要仔细控制继承。您希望将创建时间权限应用于子数据集,而不是父数据集。父数据集应该有自己的权限,用 -l 设置。
假设我们有一个 scratch 数据集,每个人都可以使用。它类似于 /tmp,但具有ZFS功能。我们希望每个人都能够在这个空间中创建和装载数据集,但不能将数据集作为一个整体丢弃。这些权限必须限制(通过 -l 标志)到该数据集,而不是由新的子级自动继承
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,snapshotLocal 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,snapshotLocal 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,snapshotLocal+Descendent permissions: user lucas allow---- Permissions on mypool/scratch -----------------------------------Permission sets: destroy,snapshotLocal permissions: everyone create,mountLucas现在可以将他拥有的任何权限委托给 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,snapshotLocal+Descendent permissions: user lucas allow user liz snapshot---- Permissions on mypool/scratch -----------------------------------Permission sets: destroy,snapshotLocal permissions: everyone create,mount但Lucas不能放弃他没有的权限:
xxxxxxxxxx$ zfs allow -u liz clone mypool/scratch/lucascannot set permissions on 'mypool/scratch/lucas': permission denied系统管理员可以将权限委托给用户,并让用户负责进一步委托自己的数据集。
运行 zfs allow 会显示您可以授予用户的60多个权限的列表。我们不会在这里全部列出它们,但您可以单独授予对每个 zfs(8) 子命令以及每个池和数据集属性的访问权限。
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 和 groupused 属性的访问权限:
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,sendLocal+Descendent permissions: user billbot @billing group managers @basic_properties,@datasetZFS委托可能很快变得复杂。与许多其他权限方案一样,使用组可以帮助简化管理。仅在需要时分配权限,而不是因为你认为你知道系统如何发展。
FreeBSD支持一种称为 jails 的轻量级虚拟化方法。您将找到许多关于使用jails的教程,因此我们不会深入讨论jails的复杂性。FreeBSD的ZFS实现对jails有特殊的支持。
数据集可以被标记为只能在jail中使用。jail中的 root 用户可以完全控制数据集。她可以创建子数据集并更改任何她想要的属性。
无法在主机系统上挂载jailed数据集。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后,可以创建一个新的数据集:
xxxxxxxxxxjail# zfs create zroot/jails/lucas/jail/foo新的数据集和jail的父数据集都是可见的:
xxxxxxxxxxjail# zfs list -o name,mountpointNAME MOUNTPOINTzroot /zrootzroot/jails /zroot/jailszroot/jails/lucas /zroot/jails/lucaszroot/jails/lucas/jail /jailzroot/jails/lucas/jail/foo /jail/foozroot/jails 中是否还有其他数据集,或实际上,在这个jail的主机中是否有其他数据集?jail里的用户永远不会知道。
用户 lucas 现在可以设置挂载点、创建和销毁数据集、将数据集委托给jail内的普通用户等等。要是能让Lucas用户在现实世界中不破坏东西就好了。
你的jail用户可能不想要如上所述的简陋jail。他们可能想要一个真正的用户区,有程序和运行服务的能力。这意味着在jailed数据集上安装FreeBSD。jails可能非常复杂,因此我们不会在这里完全涵盖它们。我们将在jailed数据集上进行基本的FreeBSD安装,因此您可以将ZFS添加到现有的jail进程中。
首先,创建一个jail数据集:
xxxxxxxxxx# zfs create -p mypool/jails/lucas/zroot现在在该数据集上安装操作系统。可以直接从FTP站点安装,就像我们在这里对FreeBSD 10.3的amd64版本所做的那样:
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创建一个条目:
xxxxxxxxxxnogelatoforyou { 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/shjail# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 5.21G 13.1G 96K nonemypool/jails 180M 13.1G 96K /mypool/jailsmypool/jails/lucas 180M 13.1G 180M /mypool/jails/lucasmypool/jails/lucas/zroot 96K 13.1G 96K /zroot这个新jail在 rc.conf 中没有启用ZFS,因此默认情况下不会挂载新数据集。启用ZFS并重新启动jail:
xxxxxxxxxxjail# sysrc zfs_enable=”YES”更改配置后,重新启动并重新进入jail:
xxxxxxxxxx# service jail onerestart nogelatoforyou# jexec nogelatoforyou /bin/sh将看到新创建的数据集:
xxxxxxxxxxjail# zfs create mypool/jails/lucas/zroot/testjail# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 5.21G 13.1G 96K nonemypool/jails 180M 13.1G 96K /mypool/jailsmypool/jails/lucas 180M 13.1G 180M /mypool/jails/lucasmypool/jails/lucas/zroot 192K 13.1G 96K /zrootmypool/jails/lucas/zroot/test 96K 13.1G 96K /zroot/testjail管理员必须使用完整路径,包括jail外的部分,来创建新的数据集。
但如果Lucas无能或邪恶怎么办?你给了他拍摄自己快照的权限,他试图创建一百万个快照“只是为了看看会发生什么”。你知道这样的人。
ZFS支持您处理这些困难的用户。ZFS提供 snapshot_limit 和 filesystem_limit 属性,允许您限制可以在特定数据集下创建的快照或子文件系统的数量。将这些属性设置为大于希望用户创建的快照或数据集数量的一个。也就是说,如果将 snapshot_limit 设置为 10 ,则用户可以创建九个快照。第十个产生错误。
为了遏制Lucas的纯粹邪恶,将他可以创建的快照数量限制为两个。
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@fourcannot create snapshot 'zroot/usr/home/lucas': out of space只读 filesystem_count 和 snapshot_count 属性允许您快速查看存在多少个文件系统或快照,并将该数字与限制进行比较。
委派和jails是存储空间行政管理的强大工具。现在,让我们讨论与ZFS的共享。