Friday, May 23, 2014

ZFS delegated permissions

Finally, here's my first topic on ZFS.
Actually, being didactic isn't my goal at this moment.
I'm just recording something that's very useful.

In general, it may be a good idea to delegate a few basic ZFS permissions to advanced users so that they can manage themselves their dataset tree.

The primary source of information is zfs_allow(1M).
I'm just going to present my own examples.

At first, consider the example of home directories.
As we know, Solaris 11 generally takes care of everything.
It usually creates a ZFS dataset for the user under rpool/export/home.
So for user admin1 there will be the ZFS dataset rpool/export/home/admin1.
This is the case for local accounts, but not remote ones (NIS for instance).
On the remote (networked) case the ZFS dataset tree will be elsewhere.
In this case it's necessary login to the remote host.
But everything else is analogous.

Hence, suppose I'm taking the remote (networked) case.
The NFS server is nfs-1 which has a separate export pool.
The ZFS dataset tree in question will be export/home/admin1.

It's better to group ZFS permissions for a more fine-grained control.
These groupings are called permission sets and their names begin with @.
There should be a "separation" to provide flexibility at no compromise.
Non-privileged users shall not impair their own home directories.
I propose something similar to the following:

nfs-1# zfs allow -s @generic                  \
    "                                         \
    create,mount,send,receive,hold,release,   \
    snapshot,rollback,diff,userprop           \
    "                                         \
    export/home/admin1

nfs-1# zfs allow -s @descendent               \
    "                                         \
    share,sharenfs,                           \
    rename,destroy,                           \
    readonly,compression,                     \
    quota,reservation,                        \
    clone,promote                             \
    "                                         \  
    !!$

nfs-1# zfs allow export/home/user1
---- Permissions on zone/nfs-1/export/home/user1 ----

Permission sets:
    @descendent
        clone,compression,destroy,promote,quota,
        readonly,rename,reservation,share,sharenfs 
    @generic
        create,diff,hold,mount,receive,release,
        rollback,send,snapshot,userprop

NOTE
The special sequence !!$ is particular to BASH. It's a combination of the event designator !! (referring to the previous command) with the word designator $ (referring to the last argument). I other words it means the "last argument of the previous command".
Once those permission sets are fully prepared, it suffices to apply them.
Note however the usage of the -l and -d options.

nfs-1# zfs allow -ldu user1 @generic export/home/user1
nfs-1# zfs allow -du user1 @descendent !!$

nfs-1# zfs allow rpool/export/home/user1
---- Permissions on zone/nfs-1/export/home/user1 ----

Permission sets:
    @descendent
        ...
    @generic
        ...

Descendent permissions:
    user user1 @descendent
 

Local+Descendent permissions:
    user user1 @generic


NOTE
It's important to set the appropriate directory ownership and mode at the mountpoint level as well, as usual. On the previous example that means setting the ownership of export/home/user dataset's mountpoint to user1 by a typical chown command.
But I made a small glitch on the above proposal.
I have defined the permission sets at each home directory level.
There may be thousands of home directories to repeat the task.
There ought to be a better way; and in fact there is!

I forgot to take advantage of ZFS inheritance.
I should have declared permission sets at an upper level.
The ideal place is at /export/home the closest common ancestor.

The final result should be similar to:

nfs-1# zfs allow rpool/export/home/user2
---- Permissions on zone/nfs-1/export/home/user2 ----

Descendent permissions:
    user user2 @descendent


Local+Descendent permissions:
    user user2 @generic


---- Permissions on zone/nfs-1/export/home ----

Permission sets:
    @generic

        ...
    @descendent

        ...

By the way, to remove the delegations and permission sets, it's very easy.
Just use the unallow counterpart of the allow command.

nfs-1# zfs unallow -s @generic export/home/user1
nfs-1# zfs unallow -s @descendent !!$

On the above case everything went fine because the parent dataset is propagating its own permission sets of the same name. Otherwise, the associations (if any) should have been removed beforehand as in:

nfs-1# zfs unallow -ldu user1 @generic export/home/user1
nfs-1# zfs unallow -du user1 @descendent !!$

Naturally I have offered a minimal example. It may be necessary to better distribute the delegated permissions in order to achieve better granularity. For instance, the @descendent is very comprehensive, but perhaps the compression, quota and reservation should belong to a different permission set such as @space. In this scenario, to keep all the delegated privileges of user1 as before I would have to change one of the commands to:

nfs-1# zfs allow -du user1 @descendent,@space export/home/user1
    

GNOME Nautilus scripts

On GNOME Nautilus toolbar I've registered how to tweak the toolbar.
There I've mentioned one limitation of the Create Folder button:
It can't create a ZFS file system.
It can only create a mere directory.
Of course I won't develop a GNOME extension right now (maybe in the future).
Instead, I'll provide a (perhaps ugly) workaround using GNOME Nautilus script.

NOTE
I assume that judicious ZFS delegated permissions are in place. 
A non-privileged user will be able to perform the operation.
Also see zfs_allow(1M) for additional detail.

I also assume that some SSH transparent authentication is in place.
That's because in most cases the operation is typically remote.
By the way, environment variables should help detect this.

Initially, when there's no GNOME Nautilus scripts, things are hidden.
For instance, on the File menu there's no Scripts menu item.


And context menus won't show Scripts either:


But as soon as executable scripts are created it will appear.

$ cd ~/.gnome2/nautilus-scripts/
$ touch create-zfs-filesystem; chomd a+x !!*

$ cat create-zfs-filesystem
#!/bin/bash

zenity --info --text="Hello, world!"

From that point on you can easily remember the scripts folder location.
If you select Scripts | Open Scripts Folder you'll see the following:
(under File or context menus where meaningful)


Expanding the details helps remembering some environment variables.
Most (there are exceptions for remote locations) are available to any script:


 
By the way, check this other post on how to enable the handy Nautilus context terminals.
  

GNOME Nautilus toolbar

The events of life are always interposing with our plans.
My goals have been delayed and added since my original plans.
Never mind, I'll persevere and keep on working on them.

By the way, I've been busy with another University degree.
This month I've also attended to the 30 years meeting of my Air Force class.
It was great; memories, regrets, new hopes, but still the same ideals and values.

OK, all that isn't Solaris.
Let's focus :-)

Let me register how to somewhat enhance GNOME Nautilus toolbar.
This is just a collection of a few Internet and personal findings.

GNOME Nautilus is delivered with a reasonable configuration in Solaris 11.
Here's how it typically looks like:


Actually there's not so much to tweak and extend.
Even so, I'd like to customize the toolbar to something that better fit my needs.
Here's the final result of my attempt:


I hope the change will be well apparent.
There's a new separator and 2 buttons were added and 1 moved:
  
  • The ZFS snapshots button has been moved.
    IMO the ZFS snapshot button was misplaced, so I've "corrected" it.
      
  • A button for deleting files (move to Trash).
    I'm still not sure of the advantage of the move to Trash button.
    The Del key is always available anyway (at least on English keyboards).
       
  • A create folder (not a ZFS file system) button.
    I think it frequently saves a click which seems good to me.
    But there may be cases where a ZFS file system would be better.
    (see GNOME Nautilus scripts)
       
Here's how it's done:

# cd /usr/share/nautilus/ui
# cp -p nautilus-navigation-window-ui{,-original}.xml
# vim nautilus-navigation-window-ui.xml

BEFORE

# tail -19 nautilus-navigation-window-ui-original.xml  
<toolbar name="Toolbar">
    <toolitem name="Back" action="Back"/>
    <toolitem name="Forward" action="Forward"/>
    <toolitem name="Up" action="Up"/>
    <toolitem name="Stop" action="Stop"/>
    <toolitem name="Reload" action="Reload"/>
    <toolitem name="Restore" action="Restore"/>
    <separator/>
    <toolitem name="Home" action="Home"/>
    <toolitem name="Computer" action="Go to Computer"/>
    <separator/>
    <toolitem name="Zoom" action="Zoom"/>
    <toolitem name="ViewAs" action="ViewAs"/>
    <toolitem name="Search" action="Search"/>
    <placeholder name="Extra Buttons Placeholder">
        <placeholder name="Extension Actions"/>
    </placeholder>
</toolbar>
</ui>


AFTER

# tail -24 nautilus-navigation-window-ui.xml
<toolbar name="Toolbar">
    <toolitem name="Back" action="Back"/>
    <toolitem name="Forward" action="Forward"/>
    <toolitem name="Up" action="Up"/>
    <toolitem name="Stop" action="Stop"/>
    <toolitem name="Reload" action="Reload"/>
    <separator/>
    <toolitem name="Home" action="Home"/>
    <toolitem name="Computer" action="Go to Computer"/>
    <separator/>
    <toolitem name="Zoom" action="Zoom"/>
    <toolitem name="ViewAs" action="ViewAs"/>
    <toolitem name="Search" action="Search"/>

    <!-- Begin customizations -->
    <separator/>

    <toolitem name="Restore" action="Restore"/>
    <toolitem name="Trash" action="Trash"/>
   
<toolitem name="New Folder" action="New Folder"/> 
    <!-- End customizations -->
    <placeholder name="Extra Buttons Placeholder">
        <placeholder name="Extension Actions"/>
    </placeholder>

</toolbar>
</ui>


Finally, back to the regular user GNOME session, kill all Nautilus processes (in order to refresh for the new settings):

$ pkill nautilus
   
Alternatively, you could have attempted to issue the more graceful:

$ nautilus -q