Deprecated

Debian has its nativ solution for this since end of 2008, so this script is deprecated and will not be maintaind anymore.
since cryptsetup (2:1.0.7-2)
see: /usr/share/doc/cryptsetup/README.remote.gz

HOWTO unlock LUKS encrypted root partition via ssh

done by ssh-server install at initrd

Im running a debian server with LUKS encrypted root partition and want to be able to enter the pass phrase local at the terminal or via ssh. Therefore I include dropbear in the initrd and some functionality for easy use. You may also combine this with raid and lvm (like I do) but this is not relevant for this howto. We only hock in before the cryptosetup runs, don't care if and what kind of layer comes before ore after.

table of contents

  1. I don't care about background, just let me do it
  2. initrd, the big picture
  3. initramfs-tools, the big picture
  4. troubleshooting
  5. source

1. I don't care about background, just let me do it

That's it! If you build your next kernel.deb via make-kpkg kernel_image --initrd the initrd will still hold the added functionality. If you didn't compile the kernel yourself, you have to run mkinitramfs and copy the initrd to /boot manually after every kernel update. The initrd will hold the root pw and ssh-pub-key from the day you build it.



#!/bin/bash

# add dropbear to the initrd to be able to mount crypto partitions from remote

PREREQ=""
prereqs()
{
        echo "${PREREQ}"
}

case $1 in
 prereqs)
        prereqs
        exit 0
        ;;
esac

# Begin real processing below this line

# copyright Wulf Coulmann
# GNU GPL
# http://www.gnu.org/licenses/gpl.html
#
# Download me here: http://gpl.coulmann.de/dropbear
# get infos about this script here:
# http://gpl.coulmann.de/ssh_luks_unlock.html
# version 0.9a
#
# The following Debian releases were tested:
#   4.0r7 with version 0.8a
#   5.0r0 with version 0.8a (incl. DHCP)
#
# Changelog 1.0
# - this all is deprecated and will not be maintaind anymore Debian has its nativ solution now for this see:
#   /usr/share/doc/cryptsetup/README.remote.gz  
echo 'this all is deprecated and will not be maintaind anymore Debian has its nativ solution now for this see:
       /usr/share/doc/cryptsetup/README.remote.gz' 
exit 72

# Changelog 0.9.1:
# - add /lib/libnsl.so.1 (thanks Gijs)
#
# Changelog 0.9a:
# - further code clean-up
#
# Changelog 0.9:
# - added quotes to ${INPUT}
#
# Changelog 0.8a:
# - changes from german c't magazine, 12/2008, S.188, article "Fernverschluesselt: Verschluesselte Root-Partition fuer Linux-Systeme":
#   - /usr/bin creation
#   - copy urandom seed
#   - copy only root password from /etc/shadow
#   - use more significant marker __EOF
# - changes from Maddes.net, 2009-02-18:
#   - merged c't changes into version 0.8
#   - added mkdir commands to make it work with Debian 4.0
#   - added commands for DHCP to make it work with Debian 5.0
#   - default to DHCP
#   - explicitly stated variables ${}
#   - added comments about disabling passwort logins for ssh and empty /etc/shadow
#   - fixed typos
#   - tested functionality with Debian 4.0r7 and 5.0r0

# load the prepared functions of Debian's initramfs environment
source /usr/share/initramfs-tools/hook-functions

# build the directories
DIRS='/usr/sbin/ /usr/bin/ /proc/ /root/ /var/ /var/lib/ /var/lib/urandom/ /var/run/'

for now in ${DIRS} ; do
        if [ ! -d "${DESTDIR}${now}" ] ; then
                mkdir -p "${DESTDIR}${now}"
        fi
done

# copy the main ssh-daemon including libaries
copy_exec /usr/sbin/dropbear /usr/sbin/
copy_exec /usr/bin/passwd /usr/bin/
copy_exec /bin/login /bin/
copy_exec /sbin/dhclient /sbin/
copy_exec /sbin/dhclient-script /sbin/
cp -pr /etc/dhcp3/ "${DESTDIR}/etc/"
cp -pr /var/lib/dhcp3 "${DESTDIR}/var/lib/"

# some libraries are not autoincluded by copy_exec
copy_exec /lib/libnss_compat.so.2 /lib/
copy_exec /etc/ld.so.cache /etc/
copy_exec /lib/libnsl.so.1 /lib/

# copy config and key files
cp -pr /etc/dropbear "${DESTDIR}/etc/"
cp -pr /etc/passwd "${DESTDIR}/etc/"    # quick and dirty, to keep file attributes
cp -pr /etc/shadow "${DESTDIR}/etc/"    # quick and dirty, to keep file attributes
cp -pr /etc/group "${DESTDIR}/etc/"
[ -d /root/.ssh ] && cp -pr /root/.ssh "${DESTDIR}/root/"
cp -pr /etc/nsswitch.conf "${DESTDIR}/etc/"
cp -pr /etc/localtime "${DESTDIR}/etc/"
cp -pr /var/lib/urandom/random-seed "${DESTDIR}/var/lib/urandom/"

# there is no bash in the created initrd, so create a link to sh for it
ln -s /bin/sh "${DESTDIR}/bin/bash"

# missing stuff for DHCP
# --> already inside busybox and working
ln -s /bin/busybox "${DESTDIR}/bin/hostname"
ln -s /bin/busybox "${DESTDIR}/bin/ifconfig"
ln -s /bin/busybox "${DESTDIR}/bin/mv"
ln -s /bin/busybox "${DESTDIR}/bin/rm"
ln -s /bin/busybox "${DESTDIR}/bin/route"
# --> extras where busybox is not compatible/working
copy_exec /bin/chmod /bin/
copy_exec /bin/chown /bin/
copy_exec /bin/run-parts /bin/
# --> libraries
copy_exec /lib/libncurses.so.5 /lib/

# only copy the root account with its password and changed shell (all other users are left out)
grep -e "^root" < /etc/passwd | sed s/\\/bash/\\/sh/ > "${DESTDIR}/etc/passwd"
echo -n > "${DESTDIR}/etc/shadow"
# if password logins via ssh are forbidden (dropbear: -s)
#   then do not copy /etc/shadow here, as the initrd is not encrypted
grep -e "^root" < /etc/shadow > "${DESTDIR}/etc/shadow"

# the blocker script to request input action before running cryptroot
# this let us run cryptroot on the local terminal and also inside ssh
# dirty but effective
[ -d "${DESTDIR}/scripts/local-top/" ] || mkdir -p "${DESTDIR}/scripts/local-top/"
cat > "${DESTDIR}/scripts/local-top/cryptroot_block" << '__EOF'
#!/bin/sh
PREREQ="network_ssh"
prereqs()
{
        echo "${PREREQ}"
}

case $1 in
 prereqs)
        prereqs
        exit 0
        ;;
esac

# Begin real processing below this line

echo Type "ok" and press enter to put in passphrase:

INPUT='wait'

while [ "${INPUT}" != 'ok' ] ; do
        read INPUT
done

__EOF
chmod 700 "${DESTDIR}/scripts/local-top/cryptroot_block"


[ -d "${DESTDIR}/scripts/local-top/" ] || mkdir -p "${DESTDIR}/scripts/local-top/"
cat > "${DESTDIR}/scripts/local-top/network_ssh" << '__EOF'
#!/bin/sh

# start network and ssh server

PREREQ=""
prereqs()
{
        echo "${PREREQ}"
}

case $1 in
 prereqs)
        prereqs
        exit 0
        ;;
esac

# Begin real processing below this line


# build up helpful environment
[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir --mode=0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys
mount -t proc -o nodev,noexec,nosuid none /proc

mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts

# network setup: edit ip address, mask and gateway to the server's needs
#ifconfig eth0 192.168.1.10 netmask 255.255.255.0
#route add default gw 192.168.1.100
# to configure via dhcp make sure to include dhclient or pump in
# /etc/initramfs-tools/hooks/dropbear via
#     copy_exec /sbin/dhclient /sbin/
ifconfig eth0 up
/sbin/dhclient eth0

# for debugging the ssh server force it to the foreground
#      /usr/sbin/dropbear -E -F -b /etc/dropbear/banner
# for more debugging run it with strace
# therefore include strace and nc at top of
# /etc/initramfs-tools/hooks/dropbear via
#     copy_exec /usr/bin/strace
#     copy_exec /bin/nc
# then start nc on another host and run
#     strace -f /usr/sbin/dropbear -E -F 2>&1 | /bin/nc -vv <ip of other host> <nc port of other host>
#     e.g.:
#     strace -f /usr/sbin/dropbear -E -F 2>&1 | /bin/nc -vv 192.168.1.2 8888

# to forbid password logins via ssh use -s
#   then also empty /etc/shadow above, as the initrd is not encrypted
/usr/sbin/dropbear -b /etc/dropbear/banner
__EOF
chmod 700 "${DESTDIR}/scripts/local-top/network_ssh"

[ -d "${DESTDIR}/etc/dropbear/" ] || mkdir -p "${DESTDIR}/etc/dropbear/"
cat > "${DESTDIR}/etc/dropbear/banner" << '__EOF'

     To unlock root-partition run
        unlock

__EOF


# script to unlock luks via ssh
# dirty but effective
[ -d "${DESTDIR}/usr/bin/" ] || mkdir -p "${DESTDIR}/usr/bin/"
cat > "${DESTDIR}/usr/bin/unlock" << '__EOF'
#!/bin/sh

/bin/sh /scripts/local-top/cryptroot && mv /scripts/local-top/cryptroot /root && kill `ps | grep -e "cryptroot_block" | grep -v -e "grep" | awk '{ print $1 }'`

__EOF
chmod 700 "${DESTDIR}/usr/bin/unlock"

# make sure to exit dropbear at the end of the startup process
[ -d "${DESTDIR}/scripts/local-bottom/" ] || mkdir -p "${DESTDIR}/scripts/local-bottom/"
cat > "${DESTDIR}/scripts/local-bottom/rm_dropbear" << '__EOF'
#!/bin/sh
PREREQ=""
prereqs()
{
        echo ""
}

case $1 in
 prereqs)
        prereqs
        exit 0
        ;;
esac

# Begin real processing below this line
# kill dropbear ssh server

killall dropbear

__EOF
chmod 700 "${DESTDIR}/scripts/local-bottom/rm_dropbear"



2. initrd, the big picture

The initrd image is nothing than a directory tree where you can include anything you like. So it is possible to build a more or less complex Linux environment. The initrd is accessible simultaneous to the kernel z-image. So it's the workaround for hen-egg-problems. E.g. you need tools from the hard disk to mount the hard disk ...
If the kernel has initrd functionality build in (mostly they will have) and you provide an initrd with your grub/lilo/... whatever conf, the kernel unpack the initrd and mount it as a ramdisk to load provided modules and tools, then mount the harddisk partitions and after booting the kernel drops the initramfs.

3. initramfs-tools, the big picture

Debian offer a very convenient handlinng to generate initrds. Refer to man itramfs-tools and man mkinitramfs for details.

4. troubleshooting

If you get trouble, try to to split your tasks in small steps, and evaluate them before you go on. Maybe this hints, help you to walk trough ...

5. source

The homepage for this howto is http://gpl.coulmann.de/ssh_luks_unlock.html. Maybe you like to check out http://gpl.coulmann.de