Disk Encryption in CentOS6 with remote password entering
I played a bit with disk encryption in CentOS6. For this, I checked the "encryption" checkbox in the Anaconda installer during installation, which encrypts at the PV (Physical Volume) partition level. Therefore, all partitions except /boot are encrypted.
Disadvantage is, that you need to enter the decryption password on the local console during boot.
Inspired by RedHat Bug #524727 for Fedora, I setup a "Early-SSH" functionality which allows ssh login to the system at the earliest stage (before the decryption password is asked). With this, I'm able to ssh into a freshly started system and enter the decryption pw without local access.
Early-SSH is a initramfs hook which installs Dropbear SSH server into the initramfs image and starts it at an early stage during boot (before the disks are mounted), so you can perform many things there (Unlock encrypted disks, checking file systems, etc.). The hook gets installed as a Dracut module, therefore it is ensured that every time you update the kernel, the early-SSH module gets installed automatically.
(As usual, try at your own risk)
Disadvantage is, that you need to enter the decryption password on the local console during boot.
Inspired by RedHat Bug #524727 for Fedora, I setup a "Early-SSH" functionality which allows ssh login to the system at the earliest stage (before the decryption password is asked). With this, I'm able to ssh into a freshly started system and enter the decryption pw without local access.
Early-SSH is a initramfs hook which installs Dropbear SSH server into the initramfs image and starts it at an early stage during boot (before the disks are mounted), so you can perform many things there (Unlock encrypted disks, checking file systems, etc.). The hook gets installed as a Dracut module, therefore it is ensured that every time you update the kernel, the early-SSH module gets installed automatically.
(As usual, try at your own risk)
Remote password entering (early-SSH)
- Normally you can only continue booting after you entered the decryption password on the local console.
- We will add support for early-ssh to be able to enter the decryption pw remotely.
- There are some instructions available for Fedora Core and Debian, but not for RHEL/CentOS. So here I explain this feature on CentOS6 (tested on 6.3 x86_64)
- See https://bugzilla.redhat.com/show_bug.cgi?id=524727 for details on Fedora.
Backup your initrd file
First, backup your current initrd image file to be able to fall back to it in case something goes wrong:
cp /boot/initramfs-`uname -r`.img /boot/initramfs-`uname -r`.img_
If you need to fall back to the original inited file, simply add an "_" to the Grub line pressing "e" during Grub boot stage.
Create dracut module
rpm -Uvh http://ftp-stud.hs-esslingen.de/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
Install dropbearyum install dropbear
Install compileryum install gcc
cd /usr/share/dracut/modules.d/
mkdir 40earlyssh
cd 40earlyssh # Generate public/private DSS and RSA host keys for the server. dropbearkey -t dss -f dropbear_dss_host_key dropbearkey -t rsa -f dropbear_rsa_host_key # Create config files echo 'multi on' > host.conf echo -en '127.0.0.1\tlocalhost\n::1\tlocalhost\n' > hosts echo 'root:x:0:0:root:/home/root:/bin/sh' > passwd echo '/bin/sh' > shells
Create install file
- CentOS uses an old Dracut utility (Version 004). Due to this, we must separate check, installkernel and install into separate scripts. But we keep them also together in the "install" script as functions if the upstream vendor switches to a newer Dracut version, later.
- If on newer Dracult version (>= 008), this file is named "module-setup.sh"
- Updated: 2014-10-20 (pkill and remote-ssh-delete.sh added)
vi install
#!/bin/bash # On newer Dracult versions, this file is named "module-setup.sh".
# These functions are currently ignored by CentOS6 Dracut.
check() { # do not add this module by default: return 255 return 0 } depends() { return 0 } installkernel() { instmods eth0instmods vmxnet3 # vmware ethernet driver in this example. } # CentOS6 uses an old version of Dracut.Therefore, install() is not called, so we comment the function definition out for now, so statements are always called.
#install() { dracut_install -o ip
# Need to use inst_library insead of dracut_install for libnsl as it is a symlink inst_library /usr/lib64/libnsl.so dracut_install /lib64/libnss_compat.so.2 dracut_install /lib64/libnss_files.so.2 dracut_install /lib64/libnss_dns.so.2 dracut_install -o dropbear inst_dir "/etc/dropbear" inst_simple "${moddir}/dropbear_dss_host_key" "/etc/dropbear/dropbear_dss_host_key" inst_simple "${moddir}/dropbear_rsa_host_key" "/etc/dropbear/dropbear_rsa_host_key" inst_dir "/home" inst_dir "/home/root" inst_dir "/home/root/.ssh" inst_simple "${moddir}/authorized_keys" "/home/root/.ssh/authorized_keys" inst_simple "/etc/localtime" inst_simple "${moddir}/nsswitch.conf" "/etc/nsswitch.conf" inst_simple "${moddir}/resolv.conf" "/etc/resolv.conf" inst_simple "${moddir}/host.conf" "/etc/host.conf" inst_simple "${moddir}/hosts" "/etc/hosts" inst_simple "${moddir}/passwd" "/etc/passwd" inst_simple "${moddir}/shells" "/etc/shells" inst_simple "${moddir}/local.conf" "/etc/modprobe.d/local.conf" inst_hook pre-trigger 01 "$moddir/remote-ssh.sh"
inst_hook pre-trigger 01 "$moddir/remote-ssh-delete.sh" inst_binary "${moddir}/auth" "/bin/auth" inst_binary "${moddir}/tiocsti" "/bin/tiocsti" # Binaries dracut_install -o ps find lsof grep egrep sed less more cat tac head tail true false mkdir rmdir rm strace touch vi ip ping ping6 traceroute ssh scp pkill # fsck tools so you can check disks when logged in.... # dracut_install -o fsck fsck.ext2 fsck.ext4 fsck.ext3 fsck.ext4dev fsck.vfat e2fsck #}
Create check file
vi check
#!/bin/sh
# add this module by default
exit 0
Create installkernel file
You must add the Network kernel module for your network card and place an alias to eth0. Use "ethtool -i eth0" to get the driver name (use your device name if other than eth0)
vi installkernel
#!/bin/bash
# install kernel module script for older dracut.
# Note: You must add your network module, here.
instmods eth0
instmods vmxnet3
Create local.conf (modprobe) file
vi local.conf
# /etc/modprobe.d/local.conf
# device to name mapping.
# Call "ethtool -i eth0" to get your driver name
# Note: You MUST add the network module to installkernel file in this dir, also!
alias eth0 vmxnet3
Alternatively, you can use the "biosdevname" utility, but I haven't done that.
Create nsswitch.conf file
vi nsswitch.conf
passwd: files
shadow: files
group: files
initgroups: files
hosts: files dns
bootparams: files
ethers: files
netmasks: files
networks: files
protocols: files
rpc: files
services: files
automount: files
aliases: files
Create resolv.conf file
vi resolv.conf
search example nameserver 192.168.3.100 nameserver 192.168.3.200
Create remote-ssh.sh file
This script is called during boot. It sets up the IP-Address, default gateway and starts the dropbear ssh daemon.
Note: When the system switches context, the initramfs and all processes are closed, therefore security is not harmed after successful boot. But it is absolutely necessary to keep your ssh private key for early-stage ssh secure!
Note: When the system switches context, the initramfs and all processes are closed, therefore security is not harmed after successful boot. But it is absolutely necessary to keep your ssh private key for early-stage ssh secure!
vi remote-ssh.sh
#!/bin/sh
# Setup network card static IP and SSH server on port 222
# In this example 192.168.3.10/24 with gateway 192.168.3.1
/sbin/ip link set dev lo up
/sbin/modprobe eth0
/sbin/ip addr add 192.168.3.10/24 broadcast + dev eth0
/sbin/ip link set dev eth0 up
/sbin/ip route add default via 192.168.3.1
mkdir -p /var/log
> /var/log/lastlog
/usr/sbin/dropbear -E -m -s -p 222 -a -K 600
Create remote-ssh-delete.sh file
This script is called on exit of dracut after disk decryption key was entered. It clears the set IP-Address and frees the interface. (added 2014-10-20)
vi remote-ssh-delete.sh
#!/bin/sh# Unsetup network card and kill SSH daemon/sbin/ip link set dev lo down/sbin/ip link set dev eth0 down/sbin/ip addr delete 192.168.121.3.10/24 broadcast + dev eth0/sbin/ip route del default via 192.168.3.1[ -f /tmp/dropbear.pid ] || exit 0read main_pid </tmp/dropbear.pidkill -STOP ${main_pid} 2>/dev/nullpkill -P ${main_pid}kill ${main_pid} 2>/dev/nullkill -CONT ${main_pid} 2>/dev/null
Create authorized_keys
vi authorized_keys
<Add all public ssh keys you want be able to login into this ssh server as you normally do in your regular authorized_keys file for ssh>
Compile some helper programs
auth
vi auth.c
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
int main (int argc, const char * argv[]) {
char *passphrase;
const char *prompt="Passphrase: ";
int i;
if (argc != 2) {
printf("Usage: auth 'passwd'\n");
return 1;
}
int fd = open("/dev/console", O_RDONLY);
if (fd < 0) {
return 2;
}
passphrase=getpass(prompt);
for (const char * str = passphrase; *str; ++str){
ioctl(fd, TIOCSTI, str);
}
ioctl(fd, TIOCSTI, "\r");
// clear string immediately
int len=strlen(passphrase);
for (i=0;i<len;i++) {
passphrase[i]=0;
};
return 0;
}
tiocsti
vi tiocsti.c
// gcc -std=gnu99 -O2 -Wall tiocsti.c -o tiocsti
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
void stuff(int fd, const char * str) {
printf("stuff [%s]\n", str);
for (; *str; ++str) {
// printf("(%c)", *str);
int rv = ioctl(fd, TIOCSTI, str);
if (rv < 0) perror("ioctl(TIOCSTI)");
}
}
int main (int argc, const char * argv[]) {
if (argc < 3) {
printf("Usage: tiocsti /dev/ttyX text string\n");
return 1;
}
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
return 2;
}
for (int i = 2; i < argc; ++i) {
if (i != 2) stuff(fd, " ");
stuff(fd, argv[i]);
}
close(fd);
return 0;
}
Compile helper programs
gcc -std=gnu99 -O2 -Wall tiocsti.c -o tiocsti gcc -std=gnu99 -O2 -Wall auth.c -o auth
Fix permissions
You need to ensure the permissions of the files are correct, otherwise dropbear and the helper files are not included in the initramfs (Thanks to Ben Curtis):
chmod 755 check install installkernel remote-ssh.sh chmod 600 authorized_keys
Build new initramfs
So you end up with the following files in /usr/share/dracut/modules.d/40earlyssh:
authauth.c authorized_keys check dropbear_dss_host_key dropbear_rsa_host_key host.conf hosts install installkernel local.conf nsswitch.conf passwd README remote-ssh.sh resolv.conf shells tiocsti tiocsti.c
Create new initrd image:
dracut --force
Reboot, test
- Now reboot.
- Once the machine is booted and at it's waiting for the password, it should be pingable from the network.
- Login remotely:
ssh -p 222 root@<machine_name_or_its_ip>
- Enter the preboot password:
tiocsti /dev/console "$(echo -n '<your_decryption_password>\r')"
# example: tiocsti /dev/console "$(echo -n 'verySecurePw!\r')"