Unlocking a LUKS encrypted root partition via ssh

Posted by wulf on Tue 5 Feb 2008 at 15:03

I'm 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. This article describes how I achieved that.

To get remote access to my machine, via ssh, without the root filesystem being mounted I include dropbear in the initrd and some functionality for easy use. You may also combine this with RAID and LVM (as I do) but this is not relevant for this article.

We only need to hook in before the cryptosetup step of the initrd runs, and don't care what type of layer we're working with.

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/sh

# We add dropbear to the initrd to be able do 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


# load the prepared functions of debians initramfs enviroment
source /usr/share/initramfs-tools/hook-functions



# build the directorys
DIRS='/usr/sbin/ /proc/ /root/ /var/ /var/run/ /var/run/' 

for now in $DIRS ; do
    if [ ! -e ${DESTDIR}$now ] 
    then
       mkdir -p ${DESTDIR}$now

    fi
done

# copy the main ssh-daemen including libarys
copy_exec /usr/sbin/dropbear 
copy_exec /usr/bin/passwd 
copy_exec /bin/login 

# some libarys not autoincludet by copy_exec
copy_exec /lib/libnss_compat.so.2 
copy_exec /usr/lib/libz.so.1  
copy_exec /etc/ld.so.cache  
copy_exec /lib/i686/cmov/libutil.so.1



# we copy config and key files
cp -pr /etc/dropbear ${DESTDIR}/etc/
cp -pr /etc/passwd ${DESTDIR}/etc/          # quick and dirty, to keep file attributs  
cp -pr /etc/shadow ${DESTDIR}/etc/

cp -pr /etc/group ${DESTDIR}/etc/                        
cp -pr /root/.ssh ${DESTDIR}/root/
cp -pr /etc/nsswitch.conf  ${DESTDIR}/etc/                         

cp -pr /etc/localtime  ${DESTDIR}/etc/                         

# we don't have bash in our initrd 
# also we only add the root account
cat  /etc/passwd | grep root | sed s/\\/bash/\\/sh/  > ${DESTDIR}/etc/passwd   


# the blocker script to request input action befor running cryptroot
# this let us run cryptroot on local terminal or inside ssh
# dirty but effektive 
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


cat >${DESTDIR}/scripts/local-top/network_ssh << 'EOF'

#!/bin/sh

# we start the 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 enviroment
[ -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

# the Network setup edit ipaddres and gateway to your needs 

ifconfig eth0 192.168.1.10 netmask 255.255.255.0
route add default gw 192.168.1.100
# If you like to use dhcp make shure you include dhclient or pump in 
# /etc/initramfs-tools/hooks/dropbear via
#     copy_exec /sbin/dhclient


# for debugging ssh-server you may run it in forgound  
#      /usr/sbin/dropbear -E -F
# for more debugging you may run it with strace
# therfor you have to include strace and nc at top of 
# /etc/initramfs-tools/hooks/dropbear via
#     copy_exec /usr/bin/strace
#     copy_exec /usr/bin/nc
# then start nc on an other host and run
#     /usr/sbin/dropbear -E -F  2>&1 | /bin/nc -vv <ip of other host> <nc port of other host>   
#     e.g.: 
#     /usr/sbin/dropbear -E -F  2>&1 | /bin/nc -vv 192.168.1.2 8888   
/usr/sbin/dropbear  -b /etc/dropbear/banner
EOF
chmod 700 ${DESTDIR}/scripts/local-top/network_ssh


cat >${DESTDIR}/etc/dropbear/banner << 'EOF'

     To unlock root-partition run
        unlock

     
EOF


# script to unlock luks via ssh 
# dirty but effektive 
cat >${DESTDIR}/usr/bin/unlock << 'EOF'
#!/bin/sh

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

EOF

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

# make shure we exit dropbear at the end of the startup process
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
# we kill dropbear ssh-server 

killall dropbear

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





syntax highlighted by Code2HTML, v. 0.9.1

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 an arbitrarily complex Linux environment. The initrd is accessible along with 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 built in (mostly they will have) and you provide an initrd with your grub/lilo configuration, 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, end evaluate them before you go on. Maybe these hints will help you :

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

This article can be found online at the Debian Administration website at the following bookmarkable URL (along with associated comments):

This article is copyright 2008 wulf - please ask for permission to republish or translate.