rageek

A place for Unix Thoughts and Ideas

Determining global zone name from inside a solaris 11 zone

The default security of Solaris zones masks the name of the host’s global zone.

In my environment we don’t have the requirement to mask the global zone name and it is very useful for our internal customers as wells as our engineering staff to have this info easily available.

There are a couple ways to go about this. I had 2 primary requirements for my solution. The information provided to the zone needed to be consistently accurate and up to date in the case that I migrate a zone to another hosts and I also do not want it to be obvious that this information is being provided to the zone.

One easy solution is to create a file on the global zone and loopback mount it into the zone.
A Very simple solution, but LOFS mounts appear in the zone’s df output and I think that is being a little too obvious.

Previously, I used a trick with the arp cache and probe-based IPMP to figure out the global zone.
But in Solaris 11, transitive probing and virtual nics have put an end to that.

My solution for the problem uses lofi and device mapping to make the information available to the zone.

Lofiadm is great tool which allows you to map files to devices, this is very handy for mounting iso’s or updating boot miniroots. The file can be arbitrary, but must be a multiple of 512bytes. This can be accomplished using the mkfile command and cat.

The first thing I do is generate the file in the global zone. I do by using the hostname command, and then creating another file to pad the original file to 512bytes. 

One issue with sharing the device with a non-global zone is that zone’s root users have the ability to read and write to the device, overwriting the information. Lofiadm has a compression option which compresses the file and incidentally makes it read only. After the file is compressed, writes can still be made to the device file, but it has no effect.

I then assigned a consistent Lofi device minor number of 340 (gsz in ascii added up), and added a line to /etc/minor_perm so the device is world readable by default.

1. Create the file and then compress and add it with Lofiadm

hostname > /etc/gsz_hostname
mkfile $((512-`ls -l /etc/gsz_hostname | awk '{print $5}'`)) /tmp/pad
cat /tmp/pad >> /etc/gsz_hostname
rm /tmp/pad

echo "lofi:340 0444 root sys" >> /etc/minor_perm
lofiadm -C lzma /etc/gsz_hostname
lofiadm -a /etc/gsz_hostname /dev/lofi/340

root@testserver:~# lofiadm
Block Device             File                           Options
/dev/lofi/340            /etc/gsz_hostname              Compressed(lzma)

2. add a match statement to the zone configuration *see reply below on notes for alternate syntax for 11.2 kernel zones.

add match
set device=/dev/lofi/340
end

3. Reboot the zone and test.

root@sunzonetest1:~# ls -l /dev/lofi/340
br--r--r--   1 root     sys       35, 340 Aug 27 21:26 /dev/lofi/340
root@sunzonetest1:~# cat /dev/lofi/340
testserver.testdomain.com

Now this works pretty good, but the lofiadm mount wont survive the reboot of the global zone.

So I created a Solaris Service which runs at boot time on the global which handles mapping the file, prior to the zones being booted.

I have made the following files available for download here:

Here is the install script:

#!/bin/bash

zonename=`zonename`

if [ "$zonename" != "global" ]; then
        printf "This service is meant for only global zones\n"
        exit 0
fi

if [ ! -f /etc/gsz_hostname ];then
        echo "Cannot locate /etc/gsz_hostname, Generating file"

        hostname > /etc/gsz_hostname
        mkfile $((512-`ls -l /etc/gsz_hostname | awk '{print $5}'`)) /tmp/pad
        cat /tmp/pad >> /etc/gsz_hostname
        rm /tmp/pad

        echo "lofi:340 0444 root sys" >> /etc/minor_perm
        lofiadm -C lzma /etc/gsz_hostname
fi

DIR=`dirname $0`
SVC=lofi_mount
echo "copying ${SVC} manifest and script into place"
cp ${DIR}/${SVC}.sh /lib/svc/method/${SVC}.sh
cp ${DIR}/${SVC}.xml /var/svc/manifest/site
chmod +x /lib/svc/method/${SVC}.sh

echo "importing ${SVC} manifest and enabling service"
svcadm restart svc:/system/manifest-import
sleep 5
svcadm enable ${SVC}

sleep 5
svcs ${SVC}

Here is my manifest:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type='manifest' name='lofi_mount'>

<service
    name='system/filesystem/lofi_mount'
    type='service'
    version='1'>

    <single_instance/>
        <dependency
            name='usr'
            type='service'
            grouping='require_all'
            restart_on='none'>
            <service_fmri value='svc:/system/filesystem/local'/>
        </dependency>

        <exec_method
            type='method'
            name='start'
            exec='/lib/svc/method/lofi_mount.sh start'
            timeout_seconds='30' />

        <exec_method
            type='method'
            name='stop'
            exec='/lib/svc/method/lofi_mount.sh stop'
            timeout_seconds='30' />

        <property_group name='startd' type='framework'>
                <propval name='duration' type='astring' value='transient' />
        </property_group>

        <instance name='default' enabled='true' />

        <stability value='Unstable' />

        <template>
                <common_name>
                        <loctext xml:lang='C'>
                               lofi mount
                        </loctext>
                </common_name>
        </template>
</service>
</service_bundle>

and here is my service method script:

#!/bin/sh
#
# lofi_mount.sh
#
case "$1" in
'start')
        #Add lofi commands to be executed at boot
        if [ -f /etc/gsz_hostname ]; then
                lofiadm -a /etc/gsz_hostname /dev/lofi/340
        else
                echo "Error: Can't locate /etc/gsz_hostname"
        fi

        ;;
*)
        echo "Usage: $0 start"
        ;;
esac
exit 0

In my zone, I have updated my script which I previously described here to output the information:

root@sunzonetest1:/# ./global_zone.sh
The Global zone is testserver.testdomain.com

This solution can be adapted to provide other information to a non-global zone that wouldn’t otherwise be available

Advertisements

2 responses to “Determining global zone name from inside a solaris 11 zone

  1. Viswanadh August 20, 2014 at 6:08 am

    My first look. You can run this one liner in all our global zones.
    zoneadm list -cv | nawk -v GZ=”`hostname`” ‘$2!=”global” && $3==”running” { printf “echo \”%s\” > %s/root/etc/global_zone”,GZ,$4}’ | sh

    • jflaster September 1, 2014 at 11:35 am

      That is definitely a straight forward way to do it.

      I had originally gone the route of the lofi device because I wanted a solution that would work 100% time and would be immune to any possible timing issues due to new zone builds, or a failover via VCS.

      Incidentally, this method works with kernel zones in 11.2 by using this alternative syntax in the zone configuration:

      add device
      set match=/dev/rlofi/340
      set id=340
      end

      After a devfsadm and perhaps restarting hal, It then will show up as a block device on the zone side.

      root@:~# rmformat
      Looking for devices…
      1. Logical Node: /dev/rdsk/c1d0p0
      Physical Node: /zvnex/zvblk@0
      Connected Device: kz vDisk 0
      Device Type: Removable
      Bus:
      Size: 16.4 GB
      Label:
      Access permissions:
      2. Logical Node: /dev/rdsk/c1d340p0
      Physical Node: /zvnex/zvblk@340
      Connected Device: kz vDisk 0
      Device Type: Removable
      Bus:
      Size: 0.0 MB
      Label:
      Access permissions:

      The global_zone.sh script could then be enhanced to look for zv device entries in /etc/path_to_inst and then query the correct device file.

      My current global_zone.sh script does not detect kernel zones and I’m not currently planning to update it as I do not have access to a Sparc based 11.2 system and have no way to fully test the changes to the script and verify the devices show up the same.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: