HowTo: Using Virtualization to Secure MySQL in a Chrooted Environment

Chrooted environments are known to greatly improve system and application security by providing them with a higher degree of isolation. The objective is to separate as much as possible from other executables and resources the runtime environment of an application so that if a hacker get access to it,the rest of the system is not compromised. This technic is commonly used with MySQL.

Traditionally, the chrooting applies at the file system level, by creating a separated and minimal operating system disk-image.  The operation consists in creating a set of directories (such a /chroot/etc, /chroot/tmp, /chroot/var/tmp, /chroot/usr/local/mysql etc.) and duplicate a minimal number of binary and configuration files into this new directory tree. After setting the right permissions on the new directories, the chrootuid utility is used to execute the application in the restricted environment. Again, whoever gains control on the application has only access to the /chroot directory tree, and many tools and services are not available in that environment.

With a bit more complexity, the zone and Crossbow virtualization technologies that come with OpenSolaris allow me to get to the next level in terms of isolation: I can cap the physical resources (RAM, CPU) that an application is allowed to consume, and I can isolate the application not only at the file-system level but also at the network level by having the zone to use its own virtual NIC (vnic), that in turn has its own mac and IP addresses. Also the vnic bandwidth can be capped. Here is what it looks like:

To strengthen network isolation I can also have the application located on a separated virtual network. Here is a picture of the solution:

Worth noting, Crossbow provides better defense against denial-of-service (DoS) attacks. Crossow virtualizes the network stack and NIC around any service (HTTP, HTTPS, FTP, NFS, etc.), protocol or zone. Each virtual stack can be assigned its own priority and bandwidth on a shared NIC without causing any performance degradation. This architecture protects against attacks directed at a particular service or virtual machine by isolating the impact just to that entity. More details about Crossbow features can be found here.

Here are the step-by-step instructions to build these 2 environments and to chroot MySQL in an OpenSolaris zone.

Let's start with the easiest case, without a virtual network: the zone is visible on the public network, and I assume that it gets its IP address through DHCP.

Creating a Virtual NIC for the Chrooted Environment

The first thing I need to do is to create a vnic1 vnic to be used by the zone. It must be create before creating the zone itself. Since the zone is on the public network, I create vnic1 on top of an active NIC - here e1000g0 - and I cap its bandwidth to 1Mbps:

# dladm create-vnic -l e1000g0 -p maxbw=1M vnic1
# dladm show-vnic
LINK         OVER        SPEED  MACADDRESS           MACADDRTYPE         VID
vnic1        e1000g0     1000    2:8:20:7a:fe:3f      random              0

Creating a Zone to be used as a Chrooted Environment

Once the vnic exists, creating the zone is a 2-step process. I first configure the zone with the zonecfg command, then I can install it and eventually boot it with the zoneadm command. Covering these steps and commands in details have been done already so I won't spend time on this. In a nutshell, to create a zone1 zone:

# zonecfg -z zone1 -f

# zoneadm -z zone1 install
A ZFS file system has been created for this zone.
   Publisher: Using (
       Image: Preparing at /rpool/zone1/root.
       Cache: Using /var/pkg/download.  
Sanity Check: Looking for 'entire' incorporation.
  Installing: Core System (output follows)
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                  20/20   3021/3021   42.55/42.55 

PHASE                                        ACTIONS
Install Phase                              5747/5747 
  Installing: Additional Packages (output follows)
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                  37/37   5598/5598   32.52/32.52 

PHASE                                        ACTIONS
Install Phase                              7329/7329 

        Note: Man pages can be obtained by installing SUNWman
 Postinstall: Copying SMF seed repository ... done.
 Postinstall: Applying workarounds.
        Done: Installation completed in 197.150 seconds.

  Next Steps: Boot the zone, then log into the zone console
             (zlogin -C) to complete the configuration process

The file looks like this:

create -b
set zonepath=/rpool/zone1
set autoboot=true
add capped-cpu
  set ncpus=0.5
set ip-type=exclusive
add net
set physical=vnic1

A couple of things to note:

The zone disk-image is installed from a network repository

Unlike Solaris 10 zones, which are copying their disk-image from the host, OpenSolaris zones gets their image in the form of packages availabe in a network repository which defaults to the host  preferred authority that is set to (yes, by default you need access to the internet to install a zone). The preferred authority is the propagated into the zone. If you want to override that by using the new -a argument to zoneadm install:

# zoneadm -z zone1 install -a ipkg=

Zones are small

With Solaris 10, zones are installed with all of the same software that the host contains. In the case of "whole root" zones, this means that zones are about the same size the host -- easily at least a gigabyte in size.

On OpenSolaris, the installation is limited to the minimum: with OpenSolaris 2009.06 the default installation is 237MB, and has a decent set of basic tools. Reducing the disk-image size improves speed: from my office located in France the install from - somewhere in the United States - takes 3min 16sec.

Configuring the Zone OS

The zone OS is configured with the traditional sysidcfg file. It sets the hostname, the root password, and many other OpenSolaris parameters:

network_interface=vnic1 {

I must copy this file in the /etc of zone1, and for /etc to be accessible I need to ready zone1. To have the DNS working properly I also copy resolv.conf and nsswitch.conf from the OpenSolaris host into zone1. When done, I can boot the zone:

 # zoneadm -z zone1 ready
 # cp sysidcfg /rpool/zone1/root/etc/sysidcfg
 # cp /etc/resolv.conf /rpool/zone1/root/etc/resolv.conf
 # zoneadm -z zone1 boot
 # cp /etc/nsswitch.conf /rpool/zone1/root/etc/nsswitch.conf

Installing MySQL

To install MySQL in zone1 I just need to login into the zone and run the pkg install command. From the OpenSolaris host:

# zlogin zone1
[Connected to zone 'zone1' pts/5]
Last login: Tue Dec 15 15:49:18 on pts/5
Sun Microsystems Inc.    SunOS 5.11    snv_111b    November 2008
root@dhcp-epar07-50-76:~# pkg install SUNWmysql51
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                    2/2     335/335   84.19/84.19 

PHASE                                        ACTIONS
Install Phase                                427/427 

Moving to a Complete  Virtual Network

Let's move to the second solution that includes a completely separate virtual network.

Since I want to move zone1 to another network with a fix IP address (as opposed to dhcp), the first thing I need to do is to login into zone1 and unconfigure it:

#zlogin zone1
[Connected to zone 'zone1' pts/5]
Sun Microsystems Inc.	SunOS 5.11	snv_111b	November 2008
root@dhcp-epar07-50-149:~# sys-unconfig

This program will unconfigure your system.  It will cause it
to revert to a "blank" system - it will not have a name or know
about other systems or networks.

This program will also halt the system.

Do you want to continue (y/n) ? y
sys-unconfig started Tue Dec 15 16:48:21 2009
rm: //etc/vfstab.sys-u: No such file or directory
grep: can't open //etc/dumpadm.conf
sys-unconfig completed Tue Dec 15 16:48:22 2009
Halting system...

[Connection to zone 'zone1' pts/5 closed]

Next I create the virtual nework which is nothing else than an ethernet stub vswitch0. It is used as virtual switch on which I create vnics. I must re-create vnic1 to have it set up on top of vswitch0 and I also create a vnic0 vnic that is the default router for the virtual network:

# dladm create-etherstub vswitch0
# dladm create-vnic -l vswitch0 vnic0
# dladm delete-vnic vnic1
# dladm create-vnic -l vswitch0 -p maxbw=1M vnic1
# dladm show-vnic
LINK         OVER        SPEED  MACADDRESS           MACADDRTYPE         VID
vnic0       vswitch0     0      2:8:20:aa:a1:58      random              0
vnic1       vswitch0     0      2:8:20:7a:fe:3f      random              0
At this point I can already configure vnic0:
# ifconfig vnic0 plumb
# ifconfig vnic0 up
# ping is alive

Re-configuring the Zone OS

A few changes in the sysidcfg to move to a static IP address. Also I must create a hostname.vnic1 file that is required to have vnic1 automatically plumb into zone1. It consists of a single line with the zone IP address. Here is the sysidcfg file:

network_interface=vnic1 {

I must copy both files in  /etc of zone1 before booting the zone:

    # zoneadm -z zone1 ready
    # cp sysidcfg /rpool/zone1/root/etc/sysidcfg
    # cp hostname.vnic1 /rpool/zone1/root/etc/hostname.vnic1
    # zoneadm -z zone1 boot

I am done!


Post a Comment:
Comments are closed for this entry.

Technical insights for and about ISV applications on Solaris and SPARC.
Application Availability, How-tos, Best Practices, Application Tuning and Results


« August 2016