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.
- LUKS
- RAID -> LUKS
- LUKS -> RAID (I never heard about that, but ...)
- RAID -> LVM-> LUKS
- RAID -> LUKS -> LVM
- LUKS -> LVM
- LVM -> LUKS
- ... Everything is possible
table of contents
- I don't care about background, just let me do it
- initrd, the big picture
- initramfs-tools, the big picture
- troubleshooting
- source
- You have a running Debian system with LUKS encryptet disk (and whatever you like, like lvm, raid ...) which is booting via initrd while you enter the passphrase at the local terminal. Yes, this should work without trouble before you go on. It's really comfortable to set this up with the debian installer if you run the installation in expert mode (just type expert at the boot prompt, and play around with manual partitioning at the debian partitioner, which is only available in the installer not at a running debian system). You may also set this up step by step on a already running system, therefor refer the multiple available relevant HOWTOs
- install busybox on the system (apt-get install busybox)
- install dropbear on the system (apt-get install dropbear)
- make shure dropbear will not be started at the ordinary boot process, while you use openssh-server or other stuff. You can remove the links in /etc/rc[0-6] via:
prompt # update-rc.d -f dropbear remove
If you think drobbear is a god choice for your daily work, skip this step.
- copy the script (view/download) to /etc/initramfs-tools/hooks/ and change permissions to executable
- edit the network setup in /etc/initramfs-tools/hooks/dropbear
- create the initrd via:
prompt # mkinitramfs -o my_name_of_the_initrd
- move the new initrd to /boot and edit your /boot/grub/menu.lst to use it. It's a god idea to double one entry and change only the clone, so you can still boot the original version, if anything failes.
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"
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.
Debian offer a very convenient handlinng to generate initrds. Refer to man itramfs-tools and man mkinitramfs for details.
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 ...
trouble while build initrd
if you get messeges like:
cpio: ./etc/dropbear/log/supervise: No such file or directory
cpio: ./etc/dropbear/log/main: No such file or directory
cpio: ./etc/dropbear/supervise: No such file or directory
while build the initrd.img you can ignor them.
Check out, what's really include in your initrd:
Go to a empty directory and run:
prompt # export test=test1 \
&& sh -x mkinitramfs -o $test 2> log \
&& mkdir `echo -n $test |sed s/test/test_/` \
&& mv $test $test.gz && gunzip $test.gz \
&& cd `echo -n $test |sed s/test/test_/` \
&& cpio -i <../$test && cd ..
This will end up with a file test1 which is the initrd image and a directory test_1 which holds the unpacked initrdfs. So you can check out if everything is really included. Also you will find a file named log, where you find possible errors while processing mkinitramfs .
trouble while booting
Trouble while booting is mostly in reason of missing files, or disorder of running scripts. To understand handling of script order you should read man initramfs-tools.
Include verbose output to your scripts, e.g. you may add a simple ifconfig after the network setup to check the output while booting. If you guess missing libraries or device nodes strace may be helpful. If you like to compare strace output while booting with strace from running dropbear in your already booted system, netcat is a choice to get output out of the box to check differences with diff or whatever. Yes, therefore your network setup must be already in function and you have to include netcat to your initrd.
The homepage for this howto is http://gpl.coulmann.de/ssh_luks_unlock.html. Maybe you like to check out http://gpl.coulmann.de