Using kexec to change the kernel & init system on DigitalOcean

DigitalOcean don't currently allow you to boot one of their "droplets" (virtual machines) with a custom kernel or kernel command line. This opens you to security flaws if you don't remember to change the kernel setting for your Droplet whenever you upgrade your distro's kernel.

You can work around this by replacing /sbin/init with a short script that uses kexec to load a new kernel, appending custom command line arguments. First of all, ensure you have a recent backup of your droplet--if this goes, wrong, and you have no backup, you will have to get DigitalOcean support to fix your droplet. Use the automatic backup feature, or power your dropplet off and take a snapshot manually. Next, prepare your droplet; assuming you are running Debian:

# apt-get install -t wheezy-backports systemd systemd-sysv
# apt-get install kexec-tools
# dpkg-reconfigure kexec-tools

When prompted whether to use kexec to handle reboots, say no--we don't want to use kexec except manually from our replacement /sbin/init.

Move /sbin/init out of the way so that we can provide the replacement. This file is owned by the package manager, so tell dpkg that you want to move it out of the way:

# dpkg-divert --add --local --rename /sbin/init
Adding 'local diversion of /sbin/init to /sbin/init.distrib'

Finally, provide the new /sbin/init:

   1 #!/bin/bash                                                                              
   2 set -eu
   3 
   4 function unit {
   5         echo "Starting systemd ($1)"
   6         if ! exec /lib/systemd/systemd --system --unit="$1.target"; then
   7                 echo 'Falling back to bash'
   8                 exec /bin/bash
   9         fi
  10 }
  11 
  12 if read -t 5 -p 'Hit enter within 5 seconds to abort kexec...'; then
  13         unit rescue
  14 fi
  15 
  16 if ! (
  17         /sbin/kexec --load /vmlinuz \
  18                 --reuse-cmdline \
  19                 --initrd=/initrd.img \
  20                 --append='init=/lib/systemd/systemd cgroup_enable=memory swapaccount=1' \
  21         && /sbin/kexec --exec
  22 ); then
  23         unit rescue
  24 fi
  25 
  26 unit emergency

Make sure the file is executable: chmod 755 /sbin/init, then reboot.

I'm using the kernel package's /vmlinuz and /initrd.img symlinks; Debian's kernel packages try to keep these pointing at the latest installed kernel, so I install the latest kernel from wheezy-backports (linux-image-i686-pae since my droplet runs the i386 port) and rely on these symlinks, whose names do not change, to load the latest kernel image.

robots.org.uk: DigitalOceanKexecSystemd (last edited 2015-03-29 00:14:11 by sam)

© Sam Morris <sam@robots.org.uk>.
Content may be distributed and modified providing this notice is preserved.