May 14th, 2014 | Tags: , , , ,

Frequently we want a service to execute as a non-root user, this is pretty trivial in the context of the Service Management Facility in Solaris.  This article will go over exactly what goes into that.  The one complexity around that is the environment, if you have environment variables that the user will depend on those, they will need to be setup inside of the SMF.  I will not be going into that in this article.


I am making the following assumptions as part of writing this article.

  • Your user is ebsdev (feel free to substitute your own)
  • Your group is ebsdev (feel free to substitute your own)
  • Both the user and group have been created and have permissions to execute the application binaries
  • Your service is application/xvfb
  • Your service is single_instance, and the instance name is default


We will be using svccfg to navigate the SMF tree to find our service.

# svccfg
svc:> select application/xvfb

Now that we have found our service, we can look at all of our available instances, in this case we are using the default instance as it is a single instance service.

svc:/application/xvfb> list
svc:/application/xvfb> select default

Now lets set our user.

svc:/application/xvfb:default> setprop method_context/user = astring: ebsdev

Lets also set the group for our user.

svc:/application/xvfb:default> setprop method_context/group = astring: ebsdev

If you have additional groups that need to be setup you can use the method_context/supp_groups property to do so.  I am not covering that in this article.

svc:/application/xvfb:default> end


Here we can add our user using a single command

# svccfg -s application/xvfb:default setprop method_context/user = astring: ebsdev

Here we can add our group using a single command.

# svccfg -s application/xvfb:default setprop method_context/group = astring: ebsdev


Assuming that you have not yet defined your service, then you can simply include the following in the service definition.  I insert it after the property_group section or if you don’t use it then after the start/stop/refresh methods.

<instance enabled="true" name="default">
<method_credential user='ebsdev' group='ebsdev'/>

Now the user/group will be defined when you import the service.

May 13th, 2014 | Tags: , , , , ,

In many of the environments that I deliver to a client we have a concept of an “environment account” this account is the credential set that the environment runs as.  Over time and the maturation of the Service Management Facility (SMF) we have been able to simplify this offering and increase its capabilities.  Today we are going to talk about allowing the environment user to manage a service controlled by SMF.

So lets start by defining the problem.  The basics of the problem is that SMF is what we use to control services in Solaris.  It is incredibly robust and allows for very fine grained dependency managements as well as managing service failure.  One of the primary differences between SMF and init.d is that init.d will only start or stop a service during a runlevel change or a request by a user.  SMF will notice the failure of the service and request an immediate restart, resolving simple service failures.  So we have a lot of good reasons to use SMF, but where is the problem.  We the problem here is simple.  Once we add a service into SMF then only root (or a user who can act on behalf of root) can issue commands to change state of that service.

In order to overcome this we can use Role-based Access Control (RBAC) to delegate control over just that one service.  Obviously you could do sudo, and have a granular policy allowing only certain commands to be executed, but honestly this approach is far more elegant, and frankly it doesn’t require the additional command of sudo to be used at time of invocation.

I am assuming that you already have an SMF created for your service, if you do not you can refer to my article on creating one for your service.  In this example we are going to be using our ebsdev user to control an xvfb service.


We are using RBAC to create authorizations, these can go anywhere within the file, Solaris 11 will have a blank file other than some comments, Solaris 10 will have a huge file which includes a bunch of system settings already in there.  I prefer to include them at the end to make a clear delineation between the system and the custom rules.  But this doesn’t matter from a functionality perspective.

# grep xvfb /etc/security/auth_attr
solaris.smf.manage.xvfb:::Manage Xvfb Service States::
solaris.smf.value.xvfb:::Change Xvfb Service Properties::


This authorization allows a user to change the state of the service.  Changing the state is not enabling or disabling, we will be adding that separately.  This only allows for service restart.

# svccfg -s application/xvfb setprop general/action_authorization = astring: solaris.smf.manage.xvfb


This authorization allows a user to change values associated with the service.  This is where we are able to allow the disabling and enabling of the service.

# svccfg -s application/xvfb setprop general/value_authorization = astring: solaris.smf.value.xvfb


Here we need to associate our user with the authorizations we have created.  Important to note here that this will overwrite all existing authorizations, so if you have any already existing then you will need to include them comma delimited in this command.

# usermod -A solaris.smf.manage.xvfb,solaris.smf.value.xvfb ebsdev


Here we are just going to give it a quick test and make sure that our user can interact with the services in the way we expect based on our security policies.  Below will test solaris.smf.manage.xvfb

# su - ebsdev
$ svcadm restart xvfb
$ svcs xvfb
STATE          STIME    FMRI
online         May_08   svc:/application/xvfb:default

Now to test solaris.smf.value.xvfb

# su - ebsdev
$ svcadm disable xvfb
$ svcs xvfb
STATE          STIME    FMRI
disabled         12:16:10   svc:/application/xvfb:default
$ svcadm enable xvfb
$ svcs xvfb
STATE          STIME    FMRI
online       12:17:07 svc:/application/xvfb:default


If you already have a service definition, but haven’t yet imported the service you can also include the authorizations into the service definitions to reduce the number of steps which need to be manually executed.  This step is not required for the manual configuration we did above, this is a more sreamlined approach for new services.

# sed -n -e '/property_group/,/\/property_group/ p' xvfb.xml
<property_group name='general' type='framework'>
<propval name='action_authorization' type='astring' value='solaris.smf.manage.xvfb'/>
<propval name='value_authorization' type='astring' value='solaris.smf.value.xvfb'/>

Now when you import it you will be able to avoid the “Modify Service to Allow Service State Authorization” and “Modify Service to Allow Service Statue Authorization” sections.

After you import you can validate that everything got put into the correct place by executing the following.

# svccfg -s application/xvfb listprop general/value_authorization
general/value_authorization  astring  solaris.smf.value.xvfb
# svccfg -s application/xvfb listprop general/action_authorization
general/action_authorization  astring  solaris.smf.manage.xvfb


September 24th, 2013 | Tags: , ,

ZFS gives us the ability to move data with ZFS send and receive.  This can be used to combine snapshots, create full or incremental backups, or replicate data between servers on your LAN or even over the WAN.

Local Backup with Send

This is very simple, simply perform a send of a snapshot then output it to the file, I have complicated it a bit to include a folder which is named off of the current date (as would be helpful with backups).

# zfs send tank/filesystem@now > /backup/`date +%m%d%Y`/tank-filesystem.zsnd

Keep in mind zfs send only makes the backups.  In order to restore them we will need to be familiar with zfs receive as well.

Local Restore with Receive

With the basic restore it is very easy, simply specify the file system to restore to, and then define the file to pull it from.

# zfs receive tank/restoredfilesystem < /backup/03152013/tank-filesystem.zsnd

Notice here we are doing redirection back into the ZFS receive command from the file, also important to note that

Local Copy of a File System – Full Clone

Occasionally you may have the need to perform a full copy clone.  With a normal zfs clone you will end up with a zero copy clone (copy-on-write), you will also have additional dependency when using zfs clones, which require a little extra caution.  If using zfs send and receive to make a copy, then there is no interdependency.

# zfs send tank/originalfilesystem@now | zfs receive tank/copyfilesystem

Here we are able to structure the command with  just a simple pipe to separate the send and receive statements.

Local Compressed Backup with Send

Perhaps you want to store your backups in a compressed form.  All we need to do is insert a gzip into the mix.

# zfs send tank/test@now | gzip > /backup/`date +%m%d%Y`/tank-originalfilesystem.zsnd.gz

This method combines a pipe with a redirect, and will give us a compressed file.

Local Compressed Restore with Receive

Of course backups don’t do any good for us if we cannot restore them.

# gunzip -c -d /backup/03152013/tank-originalfilesystem.zsnd.gz | zfs receive tank/copyfilesystem

Here we unzip the file, and pipe that into the zfs receive statement.

Local Encrypted (and Compressed) Backup with Send

Some workloads have serious security requirements.  This will encrypt and compress the contents of the file system into a backup file.  In this example I am using encrypt/decrypt to perform the encryption with aes, I also was unable to get the piping and redirection working without also injecting gzip as well.

# zfs send tank/test@now | encrypt -a aes | gzip > /backup/`date +%m%d%Y`/tank-originalfilesystem.zsnd.aes.gz
Enter passphrase:
Re-enter passphrase:

Since we aren’t using any keys with encrypt it will prompt us for a passphrase.  Remember when using encryption your data becomes worthless if you do not

Local Encrypted (and Compressed) Restore with Receive

Decrypting and restoring the backup file is pretty straight forward, unzip the file, pipe it through decrypt and pipe it into zfs.

# gunzip -c -d /backup/03152013/tank-originalfilesystem.zsnd.aes.gz | decrypt -a aes | zfs receive tank/copyfilesystem
Enter passphrase:

Use the passphrase that you used when encrypting the backup to decrypt it.

Remote Copy of a File System – Full Clone

Sometimes a full clone is needed from one server to another, perhaps for data migration.

# zfs send tank/originalfilesystem@now | ssh root@ "zfs receive tank/copyfilesystem"
September 23rd, 2013 | Tags: , , , ,

In Solaris 11.1 Oracle decided to change the way that they stored filesystem share information.  I personally loved the change, but that was without understanding what the change really was.  For more information on how to enable NFS exports see my previous article here.

Setup Our Environment

Everything we are doing will be on some test file systems, with no data.  So lets put everything in place.

# zfs create tank/fs1
# zfs set share=name=tank_fs1,path=/tank/fs1,prot=nfs,sec=sys,rw=@ tank/fs1

Now lets create our child filesystem, and export it the same way.

# zfs create tank/fs1/sub1
# zfs set share=name=tank_fs1_sub1,path=/tank/fs1/sub1,prot=nfs,sec=sys,rw=@ tank/fs1/sub1

Now this will simulate a situation that I was in.  I had originally exported everything at a higher level (fs1) and then as the dataset grew it became necessary to export it at the child level (sub1) in order to have more granular control.  So now we have two exports, and only need sub1.

Disable Unused NFS Export

Since fs1 is no longer needed lets disable its export.

# zfs set share.nfs=off tank/fs1

Lets take a look at fs1 to see if our configuration is still active.

# zfs get share tank/fs1

OK it is empty.  But since I don’t need this any more I want to make sure that there are no remaining artifacts.  So lets re-enable it and confirm that the configuration is gone.

 # zfs set share.nfs=on tank/fs1
# zfs get share tank/fs1
tank/fs1  share     name=tank_fs1,path=/tank/fs1,prot=nfs,sec=sys,rw=@  local

OK, so our configuration is still there, but it is disabled by share.nfs=off.  It must be kept elsewhere in the file system.

FYI, this is included in the ZFS metadata, so if you were to export you zpool and take it to another system, it would come over to the other system.

Explore ZFS Properties

Lets disable fs1 and start poking around.

# zfs set share.nfs=off tank/fs1

First thing to do is a get all.  This will list all of the properties of the filesystem.  I trimmed it back to only display the one that I found interesting.

# zfs get all tank/fs1
tank/fs1  share.*               ...                    local

OK so lets look a little bit closer at this share.* property.

# zfs get share.* tank/fs1
bad property list: invalid property specifier 'share.*', use 'share.all'
For more info, run: zfs help get

So share.* is not a valid property, it means that there are sub-properties, apparently share.all will display the sub-properties.

# zfs get share.all tank/fs1
tank/fs1       off        local
tank/fs1  share.autoname              default
tank/fs1  share.desc                  default
tank/fs1  share.nfs        off        local
tank/fs1  share.nfs.*      ...        default
tank/fs1  share.point      /tank/fs1  default
tank/fs1  share.protocols             -
tank/fs1  share.smb        off        default
tank/fs1  share.smb.*      ...        default

Oh boy, now we are getting somewhere, here is our share.nfs, and we can also see that share.nfs has sub-properties as well.  Also notice that smb is also stored here in the same fashion.

# zfs get share.nfs.all tank/fs1
tank/fs1  share.nfs.aclok      off    default
tank/fs1  share.nfs.anon              default
tank/fs1  share.nfs.charset.*  ...    default
tank/fs1  share.nfs.cksum             default
tank/fs1  share.nfs.index             default
tank/fs1  share.nfs.log               default
tank/fs1  share.nfs.noaclfab   off    default
tank/fs1  share.nfs.nosub      off    default
tank/fs1  share.nfs.nosuid     off    default
tank/fs1  share.nfs.sec               default
tank/fs1  share.nfs.sec.*      ...    default

Under share.nfs.all we have a lot of NFS parameters, the most important at this point is share.nfs.sec.all, so lets look there.

# zfs get share.nfs.sec.all tank/fs1
NAME      PROPERTY                 VALUE  SOURCE
tank/fs1  share.nfs.sec.default.*  ...    default
tank/fs1  share.nfs.sec.dh.*       ...    default
tank/fs1  share.nfs.sec.krb5.*     ...    default
tank/fs1  share.nfs.sec.krb5i.*    ...    default
tank/fs1  share.nfs.sec.krb5p.*    ...    default
tank/fs1  share.nfs.sec.none.*     ...    default
tank/fs1  share.nfs.sec.sys.*      ...    default

We are getting warmer.  Now we have the share.nfs.sec.sys.all to take a look at.

# zfs get share.nfs.sec.sys.all tank/fs1
NAME      PROPERTY                        VALUE  SOURCE
tank/fs1  share.nfs.sec.sys.none                 default
tank/fs1                   default
tank/fs1  share.nfs.sec.sys.root                 default
tank/fs1  share.nfs.sec.sys.root_mapping         default
tank/fs1                   default

OK well we have run out of levels to go deeper, but I still don’t see anything.  Perhaps if we call the property by name?

# zfs get tank/fs1
tank/fs1         default

So that is empty as well.  Perhaps that has something to do with the export being disabled?  Lets confirm our export is disabled.

# zfs get share.nfs tank/fs1
tank/fs1  share.nfs  off    local

Doesn’t get any more disabled than that. Well lets check the sub1 file system.

# zfs get share.nfs tank/fs1/sub1
tank/fs1/sub1  share.nfs  on     local

So we can see that it is enabled, lets check the share property to see what our whole string is.

# zfs get share tank/fs1/sub1
tank/fs1/sub1  share     name=tank_fs1_sub1,path=/tank/fs1/sub1,prot=nfs,sec=sys,rw=@  local

Based on that string we should have =

# zfs get tank/fs1/sub1
NAME           PROPERTY              VALUE  SOURCE
tank/fs1/sub1         default

OK well that was unexpected.  Property is empty on the enabled export file system as well.  We must be missing something.

Back to the Drawing Board

Out of pure desperation and a fair bit of luck.  I was attempting to lookup the help command on zfs get, and accidentally typed list instead.  But look at what I found.

# zfs help list
list [-rH][-d max] [-o property[,...]] [-t type[,...]] [-s property] ...
[-S property] ... [filesystem|volume|snapshot|share] ...

There is a share file system type.  Certainly that must have something to do with everything I am seeing?

# zfs list -t share
NAME                                                                   USED  AVAIL  REFER  MOUNTPOINT
tank/fs1%tank_fs1                                                         -      -      -  /tank/fs1
tank/fs1/sub1%tank_fs1_sub1                                               -      -      -  /tank/fs1/sub1

Clearly we are onto something here.  We have a share file system type for both our enabled and our disabled NFS export.  Lets see what kind of properties these new file system types have.

ZFS File System Share Type

# zfs get all tank/fs1%tank_fs1
NAME               PROPERTY    VALUE                  SOURCE
tank/fs1%tank_fs1  creation    Sat Sep 21 10:09 2013  -
tank/fs1%tank_fs1  mountpoint  /tank/fs1              -
tank/fs1%tank_fs1  share.*     ...                    local
tank/fs1%tank_fs1  zoned       off                    default

Well there is a share.* so that must be what we are looking for.  Lets try our previous command against this new file system and take a look at what we get.

# zfs get share.nfs.sec.sys.all tank/fs1%tank_fs1
NAME               PROPERTY                        VALUE       SOURCE
tank/fs1%tank_fs1  share.nfs.sec.sys.none                      default
tank/fs1%tank_fs1                        default
tank/fs1%tank_fs1  share.nfs.sec.sys.root                      default
tank/fs1%tank_fs1  share.nfs.sec.sys.root_mapping              default
tank/fs1%tank_fs1            @  local

Well there is that elusive read write statement.

Updating NFS Security Statements

Now lets see what happens when we change it.

# zfs set tank/fs1%tank_fs1

Here we have added a second IP address to be allowed to read and write, on our disabled NFS export.

# zfs get share.nfs.sec.sys.all tank/fs1%tank_fs1
NAME               PROPERTY                        VALUE                  SOURCE
tank/fs1%tank_fs1  share.nfs.sec.sys.none                                 default
tank/fs1%tank_fs1                                   default
tank/fs1%tank_fs1  share.nfs.sec.sys.root                                 default
tank/fs1%tank_fs1  share.nfs.sec.sys.root_mapping                         default
tank/fs1%tank_fs1            @  local

The property is successfully updated on the share file system type.  Lets see if it also enabled the NFS export.

# zfs get share tank/fs1

Still disabled, that is perfect.  Now lets see what happens on an enabled NFS export.

# zfs set tank/fs1/sub1%tank_fs1_sub1

Now we have added 2 new IPs to have read only access to this export.  Lets check its effect.

# zfs get share.nfs.sec.sys.all tank/fs1/sub1%tank_fs1_sub1
NAME                         PROPERTY                        VALUE                  SOURCE
tank/fs1/sub1%tank_fs1_sub1  share.nfs.sec.sys.none                                 default
tank/fs1/sub1%tank_fs1_sub1            @  local
tank/fs1/sub1%tank_fs1_sub1  share.nfs.sec.sys.root                                 default
tank/fs1/sub1%tank_fs1_sub1  share.nfs.sec.sys.root_mapping                         default
tank/fs1/sub1%tank_fs1_sub1            @             local

The properties were successfully updated.  Lets check the file system to see if the share properties were brought over.

# zfs get share tank/fs1/sub1
tank/fs1/sub1  share     name=tank_fs1_sub1,path=/tank/fs1/sub1,prot=nfs,sec=sys,ro=@,rw=@  local

That looks perfect, and lets ask NFS what it knows.

# showmount -e
export list for server1:
/tank/fs1/sub1                      @,@,@

Wonderful!  That is exactly what we wanted.  Now one final thing.

Removing NFS Export Configuration Permanently

Now since there is this whole different type of file system to store the share configuration, removing it becomes incredibly easy.

# zfs destroy tank/fs1%tank_fs1

That pretty much wraps up everything.

September 10th, 2013 | Tags: , , ,

In this article we are going to go over some basics of using IPMP in Solaris.  We will discuss this on the latest versions of Solaris 10 and 11 on the SPARC platform, these instructions should also work on the x86 platform, but will be dependent on the listed version numbers, as the networking stack has changed alot of the past few minor versions of Solaris 10 and 11.

Solaris 11.1

Create an IPMP Group

The first step is to create an IPMP group, in this case named ipmp1.

solaris11~# ipadm create-ipmp ipmp1

Add Interfaces to an IPMP Group

Once the group is created we can add interfaces to it, in this case net1 and net2.

solaris11~# ipadm add-ipmp -i net1 -i net2 ipmp1

Create an IPMP Group and Add Interfaces

We can also combine the above steps so that we create the group and add the interfaces in one step.

solaris11~# ipadm create-ipmp -i net1 -i net2 ipmp1

Set Interface as Standby in an IPMP Group

In the event that you prefer to have a standby interface you can change an interface to be a standby, by default all interfaces are active.

solaris11~# ipadm set-ifprop -p standby=yes net2

Remove Interfaces from an IPMP Group

Prior to deleting an IPMP group you must remove all interfaces first.

solaris11~# ipadm remove-ipmp -i net1 -i net2 ipmp1

Delete an IPMP Group

Now we can delete the IPMP group.

solaris11~# ipadm delete-ipmp

Assign an Address

After we created everything then we can assign an address.  We will need an address for the IPMP group interface, in addition if we want to use probe-based IPMP then we will need to assign them on the underlying interfaces as well, otherwise you will be using the link-based version of IPMP.

Here is an example for probe-based IPMP.

solaris11~# ipadm create-addr -T static -a ipmp1/v4
solaris11~# ipadm create-addr -T static -a net1/v4
solaris11~# ipadm create-addr -T static -a net2/v4

Here is an example for link-based IPMP.

solaris11~# ipadm create-addr -T static -a ipmp1/v4

Multipath Configuration File

If you want to be able to control some of the specifics of multipath behavior, like failback for example, you can do so using the mpathd configuration file.

solaris11~# grep -v "^#" /etc/default/mpathd

That completes our configuration on Solaris 11.1.

Solaris 10 1/13

The Solaris 10 version of these instructions are very similar to the way you would configure an IP on a normal interface, but with some additional parameters.

Interface Configuration Files (Active-Active) Link-based IPMP

In Solaris 10, we control everything with the interface configration files, named hostname.interfacename where the interface name is net1 and net2 in this environment, please change your link names or configuration file names to match your server.

solaris10~# cat /etc/hostname.net1
machinehostname netmask + broadcast + group ipmp1 up
solaris10~# cat /etc/hostname.net2
group ipmp1 up

Interface Configuration Files (Active-Active) Probe-based IPMP

solaris10~# cat /etc/hostname.net1
machinehostname-net1 depracated -failover netmask + broadcast + group ipmp1 up addif machinehostname netmask + broadcast + up
solaris10~# cat /etc/hostname.net2
machinehostname-net2 depracated -failover netmask + broadcast + group ipmp1 up

Interface Configuration Files (Active-Standby) Link-based IPMP

The only time that I see a value in an Active-Standby configuration is when you have to guarantee a level of service, even in a failed state.  In my environments the increased performance is of a much higher value than the non-reduced workload.

solaris10~# cat /etc/hostname.net1
machinehostname netmask + broadcast + group ipmp1 up
solaris10~# cat /etc/hostname.net2
group ipmp1 standby up

Interface Configuration Files (Active-Standby) Probe-based IPMP

solaris10~# cat /etc/hostname.net1
machinehostname-net1 depracated -failover netmask + broadcast + group ipmp1 up addif machinehostname netmask + broadcast + up
solaris10~# cat /etc/hostname.net2
machinehostname-net2 depracated -failover netmask + broadcast + group ipmp1 standby up

Hosts File

solaris10~# grep machinehostname /etc/hosts      machinehostname.localdomain machinehostname      machinehostname-net1.localdomain machinehostname-net1 # only needed for probe-based ipmp      machinehostname-net2.localdomain machinehostname-net2 # only needed for probe-based ipmp

Netmasks Configuration File

solaris10~# grep /etc/netmasks

Multipath Configuration File

solaris10~# grep -v "^#" /etc/default/mpathd
Page 3 of 2712345...1020...Last »