Thursday, August 14, 2014

mount-image-callback: easily modify the content of a disk image file

Lots of times when dealing with virtualization or cloud you find yourself working with "images".  Operating on these images can be difficult.  As an example, often times you may have a disk image, and need to change a single file inside it.

There is a tool called 'mount-image-callback' in cloud-utils that takes care of mounting and unmounting a disk image.  It allows you to focus on exactly what you need to do. It supports mounting partitioned or unpartitioned images in any format that qemu can read (thanks to qemu-nbd).

Heres how you can use it interactively:

  $ mount-image-callback disk1.img -- chroot _MOUNTPOINT_
  % echo "I'm chrooted inside the image here"
  % echo "" >> /etc/hosts
  % exit 0

or non-interactively:

  mount-image-callback disk1.img -- \
   sh -c 'rm -Rf $MOUNTPOINT/var/cache/apt'

or one of my typical use cases, to add a package to an image.

  mount-image-callback --system-mounts --resolv-conf --
    chroot _MOUNTPOINT_ apt-get install --assume-yes pastebinit

Above, mount-image-callback handled setting up the loopback or qemu-nbd devices required to mount the image and then mounted it to a temporary directory.  It then runs the command you provide, unmounts the image, and exits with the return code of the provided command.

If the command you provide has the literal argument '_MOUNTPOINT_' then it will substitute the path to the mount.  It also makes that path available in the environment variable MOUNTPOINT.  Adding '--system-mounts' and '--resolv-conf' address the common need to mount proc, dev or sys, and to modify and replace /etc/resolv.conf in the filesystem so that networking will work in a chroot.

mount-image-callback supports mounting either an unpartitioned image (ie, dd if=/dev/sda1 of=my.img) or the first partition of a partitioned image (dd if=/dev/sda of=my.img).  Two improvements I'd like to make are to allow the user to tell it which partition to mount (rather than expecting the first) and also to do so automatically by finding an /etc/fstab and mounting other relevant mounts as well.

Why not libguestfs?

libguestfs is a great tool for doing this.  It operates essentially by launching a qemu (or kvm) guest, and attaching disk images to the guest and then letting the guest's linux kernel and qemu to do the heavy lifting.  Doing this provides security benefits, as mounting untrusted filesystems could cause kernel crash.  However, it also has performance costs and limitations, and also doesn't provide "direct" access as you'd get via just mounting a filesystem.

Much of my work is done inside a cloud instance, and done by automation.  As a result, the security benefits of using a layer of virtualization to access disk images are less important.  Also, I'm likely operating on an official Ubuntu cloud image or other vendor provided image where trust is assumed.

In short, mounting an image and changing files or chrooting is acceptable in many cases and offers more "direct" path to doing so.