Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Full encrypted headless server with ssh daemon in initramfs
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks
View previous topic :: View next topic  
Author Message
slick
Bodhisattva
Bodhisattva


Joined: 20 Apr 2003
Posts: 3485

PostPosted: Thu Mar 13, 2014 7:43 pm    Post subject: Full encrypted headless server with ssh daemon in initramfs Reply with quote

This explain howto setup a full encrypted server with ssh daemon in initramfs to enter the passphrase to decrypt at boot time.

First, this is not a complete Howto for beginners. You should have some Gentoo background. And sorry for my bad english. I made it successfull and wrote this later. I hope I do not forgot some information.

We will use cryptsetup and lvm. You can use it on hardware or virtual server, if you have full root rights and a real or virtual harddisk. KVM based virtual machines works fine, I use it on.

It is possible to transform a existing server to this (it is full transparent) but you will need a full backup, because we will destroy the existing harddisk.

The easiest way is you have a second (Gentoo running) server with same hardware, use it to compile the source we need.

I do not benchmark the performance. If you server under heavy load this maybe slowdown it more than a lot. The goal for this howto is not performance.

Another important hint: We will create our own initramfs script. I do use a kernel without loadable modules. (I dislike modules on servers.) If you use modules you maybe have add some extra code later.

I assume you have a running Gentoo system and a clean system, both with same hardware. First all build steps are on the working machine, later on the clean one. (I will say.)

First setup your kernel to buildin to following things:

- Your favorite cipher and digest algorithm (aes, twofish, sha*)
- Device mapper support
- Crypt target support
- Initial RAM filesystem and RAM disk (initramfs/initrd) support
- all other to boot the server

Build the kernel (with or without genkernel). I assume we name it /boot/cryptokernel

Now we need all for our custom initramfs. genkernel is nice to prepare it for us. So we emerge it. I do not need lvm1 support, sometimes I get trouble when iI use it.

Add to your /etc/portage/package.use
Code:
sys-fs/lvm2 -lvm1
sys-kernel/genkernel crypt cryptsetup


and

Code:
emerge -av sys-kernel/genkernel


It should pull sys-fs/lvm and sys-fs/cryptsetup. We not make it static. genkernel will prepare it for us later.

Code:
[ebuild   R    ] sys-fs/lvm2-2.02.103  USE="readline thin udev (-clvm) (-cman) -lvm1 -lvm2create_initrd (-selinux) -static -static-libs" 0 kB
[ebuild   R    ] sys-fs/cryptsetup-1.6.2  USE="gcrypt nls -kernel -nettle -openssl -python -reencrypt -static -static-libs -udev -urandom" PYTHON_SINGLE_TARGET="python2_7 -python2_6" PYTHON_TARGETS="python2_7 -python2_6" 0 kB
[ebuild   R    ] sys-kernel/genkernel-3.4.45.1  USE="crypt cryptsetup (-ibm) (-selinux)" 0 kB


Edit your /etc/genkernel.conf. Important is:

Code:
LVM="yes"
LUKS="yes"
BUSYBOX="yes"
E2FSPROGS="yes" # No have to need, but highly suggested!
DISKLABEL="yes"
COMPRESS_INITRD="yes"
COMPRESS_INITRD_TYPE="gzip"


Now build a (temporary) initramfs. (If you use gernkernel normally, it is a good idea so backup your existing initramfs/kernel). Genkernel will put nearly all in we need.

Code:
genkernel initramfs


Create a directory where we can unpack the initramfs. I take /initrd, I will call it $INITRD in futher instructions. Change to it and unpack your iniramfs. After that we can remove our (temporary) created initramfs file.

Code:
mkdir $INITRD
cd  $INITRD
gunzip < /boot/initramfs-genkernel-${arch}-${version}-gentoo | cpio -i --make-directories
# at this point you will maybe see some warnings about already existing files. Dont care us.
rm /boot/initramfs-genkernel-${arch}-${version}-gentoo


Now we add a small ssh daemon. We like to login with ssh keys only to the initramfs, so we need no pam support. But we have to make it static.

Add to your /etc/portage/package.use
Code:
net-misc/dropbear   static minimal -pam -zlib -shadow
dev-libs/libtommath   static-libs


Code:
emerge -av net-misc/dropbear


Now copy the binaries and the libs to the initramfs.

Code:
cp /usr/bin/dhclient $INITRD/usr/bin
cp /usr/bin/dropbearkey $INITRD/usr/bin
cp /usr/sbin/dropbear $INITRD/usr/sbin
cp /lib/libtommath* $INITRD/lib


But we need some more libs. I find it after some trouble (dropbear sayed: nonexistent user) here: http://osdir.com/ml/network.ssh.dropbear/2005-10/msg00016.html

Just copy it too:

Code:
for i in libc.so.6 libnss_compat.so.2 libnsl.so.1 libnss_nis.so.2 libnss_files.so.2 ; do
   cp /lib/$i $INITRD/lib
done


Hint: There is currently a bug with symlinks in $INITRD/sbin. lvm related symlinks point to $INITRD/sbin/lvm but the binary is in $INITRD/bin. Test it and if necessary add a symlink

Code:
cd $INITRD/sbin ; ln -s ../bin/lvm lvm


Create $INITRD/dropbear and generate your host keys

Code:
mkdir $INITRD/etc/dropbear
/usr/bin/dropbearkey -t dss -f $INITRD/etc/dropbear/dropbear_dss_host_key
/usr/bin/dropbearkey -t rsa -f $INITRD/etc/dropbear/dropbear_dss_host_key


Now we create our own initscript. (Thats the minimum you will need. ) Read the comments and save it as $INITRD/init

Code:
#!/bin/sh

# I suggest to add the next line as comment here, if you later rebuild the initramfs and forgot the command ;)
# find . | cpio --quiet -o -H newc | gzip -9 > /boot/initramfs.gz

export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'

#mount /proc

mount -t proc -o noexec,nosuid,nodev proc /proc >/dev/null 2>&1
mount -o remount,rw / >/dev/null 2>&1
CMDLINE=$(cat /proc/cmdline)

#install busybox

/bin/busybox --install -s

#mount /dev

mount -t devtmpfs -o exec,nosuid,mode=0755,size=10M udev /dev >/dev/null 2>&1
mkdir -m 0755 /dev/pts >/dev/null 2>&1
mount -t devpts -o gid=5,mode=0620 devpts /dev/pts >/dev/null 2>&1

#mount /sys

mount -t sysfs sysfs /sys -o noexec,nosuid,nodev >/dev/null 2>&1

#start mdev

touch /dev/mdev.seq
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

# start busybox dhcp client, work fine if you have only one interface,
# otherwise you have play around with your interfaces here.
# If you do not have dhcp, use ifconfig here to setup your interface

udhcpc -p /run/udhcpc.pid

# prevent a dropbear error message during login

mkdir /var/log
touch /var/log/lastlog

# create a root account so we can login

echo 'root:x:0:0:root:/root:/bin/sh' > /etc/passwd
echo 'root:*:99999:0:::::' > /etc/shadow
chmod 600 /etc/shadow

mkdir -p /root/.ssh

# Place the public rsa key in /root/.ssh/authorized_keys (You can use OpenSSH Keys)
# Insert your rsa public key here.

echo 'ssh-rsa AAAA ..... root@foo'  > /root/.ssh/authorized_keys

# Start dropbear. I highly suggest do not leave it on port 22. Use a port > 1024!

dropbear -I 900 -p 22 -j -k -s -d /etc/dropbear/dropbear_dss_host_key -r /etc/dropbear/dropbear_rsa_host_key -P /run/dropbear.pid 2>&1 > /dev/null

# If you wish to notify the admin about the reboot, this is the right place to do this.
# i.E. do some netcat magic to send a mail or like this. (nc is busybox buildin)
# Keep in mind: DNS should not work, you have to use IPs


# parse cmdline
for x in ${CMDLINE} ; do
        case "${x}" in
                root=*)
                        ROOT=${x#*=}
                ;;
                rootfstype=*)
                        ROOTFSTYPE=${x#*=}
                ;;
                sleep)
                        SLEEP=1
                ;;
        esac
done

# If "sleep" is given at the command line, we will sleep a long time now.
# This is important! We need this later.
if [ "${SLEEP}" != "" ] ; then
     sleep `date +%s`
fi

# wait until the device exists (and decrypted)
while ! test -e /dev/mapper/crypto ; do
     sleep 2
done

# start all lvm devices
vgchange -ay

if [ "${ROOTFSTYPE}" != "" ] ; then
   type="-t ${ROOTFSTYPE}"
fi

# mount rootfs

mkdir /newroot
mount ${type} ${ROOT} /newroot

# Force logout the ssh user. If you do not, you will get a ugly error message on your system later.

ps | grep -- "-sh" | grep -v grep | xargs | cut -d " " -f 1 | xargs kill -9

# kill running daemons

kill -9 `cat /run/dropbear.pid`
kill -9 `cat /run/udhcpc.pid`

#move fs

for fs in /dev /sys /proc ; do
   if grep -qs "$fs" /proc/mounts ; then
      mount --move $fs /newroot$fs
   fi
done

#switch rootfs
exec switch_root  -c "/dev/console" /newroot /sbin/init


Make sure $INITRD/init can execute
Code:
chmod +x $INITRD/init


Now we pack the initramfs to /boot/cryptoinitramfs

Code:
cd $INITRD
find . | cpio --quiet -o -H newc | gzip -9 > /boot/cryptoinitramfs


That was all at the running machine. All next will do on the "clean" machine.

Go to your clean machine and prepare the harddisk. Use fdisk to create two partitions. A boot partition and a large partition for the crypto container. The boot partition should not to small. I suggest 2G. So there is enough space to place a whole gentoo-system incl. portagetree in it if you need to rebuild your initramfs in case of emergency or like this. If you do so, use mke2fs -i ... to be sure there are enough inodes. (RTFM)

Hint: Partition type for the boot partition should be 83, for the large crypto partition (whole rest of your harddisk) do not use 8e! Use 0 instead (empty).

Format your boot partition (ext2-4) and do some magic to install grub in bootsector. (Yes, thats for experts. How do I install grub on a clean system? ;) )

Copy the cryptokernel and cryptoinitramfs to the boot partition.

Create a grub.conf. As root use the lvm device and optional filesystem you will use later. (I use UUIDs usually, but with another initscript. I hope it works without too.) Important is the "sleep" in command line. This force the initscript to sleep during the next setup process.

Code:
title Encrypted Gentoo Linux
root (hd0,0)
kernel /boot/cryptokernel rootfstype=ext4 root=/dev/mapper/vg-root sleep
initrd /boot/cryptoinitramfs


Reboot, hope I wrote all down you need and pray...

After rebooting the machine you should able to login to your server as root with your private rsa key.

Now we "format" the crypto partition. Use your preferred cipher. I suggest aes, for more performance try twofish. (RTFM about secure ciphers/digests.) Use a keyfile at your own risk (Keep in mind: you have to pipe it later through ssh). I suggest use a looooong passphrase you can type instead. (Hint: Maybe test your keyboard layout before.) Remember it.

I think we should not trust /dev/urandom, so do not use: --use-urandom

(I assume /dev/sda2 is your empty large partition)

Code:
cryptsetup -c aes-xts-plain64:sha512 --use-random -y -s 512 luksFormat /dev/sda2


Now create the decrypted device with name "crypto" (keep this name, it is hardcoded in the initscript)

Code:
cryptsetup --allow-discards luksOpen /dev/sda2 crypto


(At this point, you know why we need the sleep command in boot command line. If you forget it, initscript detect the device exists and will resume and logout you now.)

Now /dev/mapper/crypto is your decrypted device. Create your lvm volumes on it now.

Example:
Code:
pvcreate  /dev/mapper/crypto
vgcreate vg /dev/mapper/crypto
lvcreate -L1G -nswap  vg
lvcreate -l100%FREE -nroot  vg


More help about lvm see http://wiki.gentoo.org/wiki/LVM

At this point resume as a normal Gentoo Installation.

Code:
mke2fs -t ext4 ... /dev/mapper/vg-root
mkdir /gentoo
mount /dev/mapper/vg-root /gentoo
...


mkswap does not exists in initramfs. Do it later.

If you wish to copy a existing system in, thats a bit tricky. You can not use scp or rsync. Use tar over ssh to the remote machine (Sometimes it will break with "tar: short read". I dont know why. Please let me know.) You have to use the IP to your source maschine, dns does not work in initramfs.
Code:
cd /gentoo
/usr/bin/dbclient root@1.2.3.4 "cd /sourcedir; tar -pczf - ." | tar -xpzvf -


If your system in /dev/mapper/vg-root ready umount all and close lvm and crypto. (Alternate let crypto open after umount all and kill the sleep and resume to boot in your system)

Code:
umount /gentoo
umount ...
vgchange -an
cryptsetup luksClose crypto


Edit your grub.conf and check the real root and filesystem and remove the sleep, i.E:

Code:
title Encrypted Gentoo Linux
root (hd0,0)
kernel /boot/cryptokernel rootfstype=ext4 root=/dev/mapper/vg-root
initrd /boot/cryptoinitramfs


If you wish to reboot in the initramfs use:

Code:
reboot -f


This will reboot like a "reset" without stopping anything. Dont care us if we umount all devices before.

After this finish reboot the initramfs will wait until root login and open the cryptodevice with this command and the passphrase
Code:
cryptsetup --allow-discards luksOpen /dev/sda2 crypto


Then it boot the system configured as root in grub.conf

some other hints:

- It is possible to use more than one passphrase. Do it and use more than one passphrase and store it at different safe places.
- Backup the $INITRD directory.
- Backup the working cryptokernel and cryptoinitramfs, maybe enable config.gz support in kernel to review your configuration later
- lvm support is not need at your running system, but will be fine if you like to manage your lvm devices on your real system
- RTFM about:
-- suggested ciphers/digests (for really secure ssh connections too)
-- cryptsetup / LUKS
-- lvm
-- encryption pro and cons
- If you are a bit more paranoid, remember: A attacker who has (physical) access to your server can replace the initramfs/kernel in boot and just wait until you login to enter the passphrase to get full access. Find your own solution and please add a comment.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum