Aufgabenstellung

Zielsetzung

Ich möchte meinen Kunden erhöhte Datensicherheit bieten. Dazu habe ich mich entschlossen sowohl Backup (hier nicht Bestandteil) aber insbesondere die integrierte Datenfestplatte zu verschlüsseln. Bei Verlust des Datenträgers soll es nicht möglich sein sensible Kundendaten zu erlangen. Eine Laptoptasche kann gestohlen werden und Einbruch kann ebenso einen Verlust des Datenträgers bedeuten, da ist es sehr beruhigend zu wissen, dass die Datenträger mit ziemlicher Sicherheit sicher sind.

Ich habe mich hierzu für eine LUKS Partition auf dem Datenträger entschieden welche mit einer üblichen Passphrase verschlüsselt wird.

Problemstellung

Ich habe meine Datenfestplatte verschlüsselt und möchte die Passphrase aus berechtigen Sicherheitsgründen nicht auf eine lesbare Festplatte ablegen. Die Datenfestplatte ist z.B. eine fest verbaute und integraler Bestandteil meines Systems. Es liegen dort Ordner die genutzt werden nach dem ich mich auf mein KDE System eingeloggt habe. (Hier am Beispiel von KDE). Meine Aktivitäten und Arbeitsplatzeinstellungen sind so konfiguriert, dass der Desktop von dieser Festplatte geladen wird. Dazu muss die Festplatte aber zum Zeitpunkt des Sitzungsstarts eingebunden werden.

Lösungsweg

KDE wird so konfiguriert, dass es zum Zeitpunkt des Sitzungsstarts ein Bash-Script ausführt, dass mit Hilfe von sudo als root die verschlüsselte Festplatte erst mapped zur Entschlüsselung und dann als Gerät einbindet um genutzt zu werden. Beim Abmelden aus der Sitzung soll die Festplatte wieder ausgehängt werden.

Um die Interaktion mit dem Benutzer zu starten verwenden kdialog um die Passwörter abzufragen. (Hierbei wird davon ausgegangen, dass es zwei verschiedene Passwörter sind.)

Umsetzung

Verzeichnisstruktur und Scripte

/home/<username>/mount-data.sh
/home/<username>/umount-data.sh

Anlegen der Dateien und Aktivierung

Das anlegen der Dateien wird hier vorweggenommen, im eigentlichen Sinne sollten diese Dateien erst dann konfiguriert werden, wenn diese auch den abschließenden Test durchlaufen sollen, sonst hätte man defekte Dateien im Sitzungsstart und das kann sehr ärgerlich sein.

Sollten Sie trotzdem Gefahr laufen Ihre Sitzung nicht mehr starten zu können, können Sie über Strg + Alt + F2 ein separates Terminal im Vollbildmodus angezeigt – genauer gesagt ohne grafische Oberfläche.

Die Dateien sind wie unter Verzeichnisstruktur und Scripte abgelegt und müssen KDE bekannt gemacht werden. Das geht sowohl über die GUI als auch über Konsole.

Über die Konsole kann man folgende Befehle ausführen um die Dateien der KDE Sitzung beim starten und beim ausloggen mitzuteilen.

ln -s /home/<username>/mount-data.sh /home/<username>/.config/plasma-workspace/env/mount-data.sh
ln -s /home/<username>/umount-data.sh /home/<username>/.config/plasma-workspace/shutdown/umount-data.sh

Für die Konfiguration über KDE kann man wie in folgendem Bild vorgehen.
Achten Sie hierbei darauf, dass das Mountskript mit der Sitzung startet und das Unmountskript beim beenden. Verwenden Sie hierzu den Skript hinzufügen ... Dialog.

KDE Konfiguration für Autostartprogramme und Skript

Die Skripte

Das mounten einer verschlüsselten Festplatte ist mit etwas Aufwand verbunden. Die Festplatte kann nicht einfach eingebunden werden. Sie muss zuerst einen Mapper/Layer instanziieren welcher die Ver- und Entschlüsselungsaufgaben übernimmt. Hierbei hilft uns cryptsetup das Laufewerk vorerst zu mappen. Dazu benötigen wir root-Rechte und haben somit gleich zwei Passwörter die an das Programm übermittelt werden müssen, bis der eigentliche mount des Laufwerks stattfinden kann.

#!/bin/bash

# Working directory in which the logfile will be stored
log_file="/home/sven-ullmann/mount-data.log"

# Message which will popup and ask for sudo password
sudo_login_message="Please enter sudo password in order to mount encrypted file system."

# Simple user abort message
user_abort_message="Could not mount encrypted filesystem. User abort."

# ups, mounting failed
could_not_mount_message="Could not mount encrypted file system.";

# which encrypted drive we want to mount
data_drive="/dev/sdb2"

# mapping name
mapping_name="Data"

# where we will finaly mount the drive
mount_dir="/media/sven-ullmann/Data"

# used variables for the script to hold current states
is_root=0
mapped=0
mounted=0

# this loop can only be fullfilled by a right password or the cancel button
while [ $is_root = 0 ]; do

    # ask for a valid sudo password
    sudo_password=$(kdialog --password "$sudo_login_message")
    # why the $() wrapper:
    # Since passwords could contain any kind of characters, 
    # there will be for example a problem with the $ sign.
    # if we print the output of this variable with "$sudo_password" 
    # we encounter to the problem, that the $ sign
    # will be interpretet from bash.
    # There are many ways to solve this problem and i tried a lot, 
    # but the best solution for me was to escape
    # the variable directly on input - that is what $() will do. 
    # It tells the bash not to interpret the $ sign.
    
    # - Yes in my passwords could be $'s ... one char at any position 
    # is clearly know which reduce the security of 
    # my password by ... nevermind - password is long enough
    
    # if the cancel button has been klicked, break the loop
    if [ $? != 0 ]; then
        break;
    fi
    
    # we want to know who we are if we using sudo
    whoami=`echo $sudo_password | sudo -kS whoami 2>> $log_file`
    # whoami:   prints the current user which is using the 
    #           programm - after sudo this will be root
    # sudo -k:  -k tell sudo to forgett about the password - 
    #           this will help us to avoid, that the password prompt 
    #           for sudo will not be prompted.
    #           We expect to passwords after each other for luks mapping. 
    #           First is sudo, second is passphrase for drive
    #           The program will not work, if sudo does not prompt for a password.
    # sudo -S:  -S tell sudo to take the input not from the stdin 
    #           instead of, for example, the keyboard
    # echo | sudo: the pipe will output our password and chain this 
    #           to the stdin of sudo, as we expect this with sudo -S
    #           A Pipe will put it's output to the given programm after |.
    # 2>>:      There are 2 output streams. The stdout is the normal 
    #           output, which has the number 1, and the second
    #           output is the stderr for out errors with the number 2. 
    #           So we tell number 2 to output > or output in order
    #           to append to the file >> to our given logfile.          
    
    # so if we can act as root, save the state and break the loop - success
    if [ "root" = $whoami ]; then        
        is_root=1
        break
    fi    
done

# simple abort message
if [ $is_root = 0 ]; then
    #[ $... ] does not thread variables as commands if we not use "$..."

    # show a error dialog which says, that the user abort 
    # this script and we can't mount drive
    kdialog --error $user_abort_message
    # kdialog will support multiple types of little interactive 
    # dialogs were we can choose one, here for example --error 
    # which will display a error message, in the simplest form it will
    # take a string for what is to say
fi

if [ $is_root = 1 ]; then

    # only exit on abort or success - infinite loop
    while [ $mapped = 0 ]; do
    
        # grep the drives passphrase
        luks_password=$(kdialog --password "Please enter LUKS encrypted drive password.");
        
        if [ $? != 0 ]; then
            kdialog --error $user_abort_message
            break;
        fi
        
        # send the passwords to sudo and cryptsetup
        (echo $sudo_password; echo -n $luks_password) | sudo -kS cryptsetup luksOpen $data_drive $mapping_name --key-file=- 2>> $log_file
        # ok, this was a bit triggier to implement, there are 
        # many concept of bash belonging to this more or less 
        # simple operation first, you know the pipe, we try to 
        # give 2 passwords to the stdin for the programm - as 
        # sudo -k from the last command has dropped his login we 
        # can expect this.
        # () is a construct to pair the commands we will send, 
        # it's a kind of concatenation ";" ends the first command, 
        # as we expect the first prompt for sudo.
        # Then we use echo with -n option. The -n option avoids to 
        # send a new line sequence. With it, the passphrase for luks 
        # will fail there is no newline in our passphrase 
        # Lets have look to our cryptsetup command.
        # luksOpen <drive> <mappingName> is the usage, 
        # solved: cryptsetup luksOpen /dev/sdb2 Data
        # This command will store a mapping under /dev/mapper/Data - 
        # it not have to be created, it will create it by own
        # --key-file=-  In bash the - sign has a meaning of taking 
        #               for example file content from stdin. Normaly 
        #               this funktion expects a filepath and what we 
        #               send to this stdin is our "echo -n $luks_password"
        
        
        if [ -e "/dev/mapper/${mapping_name}" ]; then
        # there are two types of file exists checking, one with -f 
        # which checks a regular file and -e which checks any kind of file
        # this notation is shorthand for "if [ test -e "..." ]
        # test is the programm that is executed, have a look to documentation 
        # using "man test"
        
            mapped=1
            echo "LUKS Drive mapped" >> $log_file
            break;
        fi
    done
fi

if [ $mapped = 1 ]; then

    # so, the drive is mapped and we ready to mount it regularly
    echo $sudo_password | sudo -kS mount "/dev/mapper/${mapping_name}" $mount_dir 2>> $log_file
    
    if [ "$(ls -A $mount_dir)" ]; then
        echo "Data disk mounted" >> $log_file
        mounted=1;        
    fi
fi

if [ $is_root = 1 ]; then
    if [ $mapped = 1 ]; then
        if [ $mounted = 0 ]; then
            kdialog --error $could_not_mount_message    
        fi    
    fi
fi

Und beim logoff wieder aushängen.


#!/bin/bash

sudo_password_message="Please enter sudo password to unmount data drive on session logout."

could_not_umount_message="WARNING, data drive could not be unmounted."
could_not_unmap_message="WARNING, could not unmount encrypted device."

log_file="/home/sven-ullmann/mount-data.log"
mount_dir="/media/sven-ullmann/Data"
mapping_name="Data"

is_root=0

while [ $is_root = 0 ]; do
    sudo_password=$(kdialog --password "$sudo_passtail word_message")
    
    if [ $? != 0 ]; then	    
        break;
    fi    
    
    iamroot=`echo $sudo_password | sudo -S whoami`;	

    if [ "root" = $iamroot ]; then
        is_root=1
        break;
    fi
done

if [ 0 = $is_root ]; then
    kdialog --error $could_not_umount_message
fi

echo $sudo_password | sudo -S umount $mount_dir 2>> $log_file
echo $sudo_password | sudo -S cryptsetup luksClose "/dev/mapper/${mapping_name}" 2>> $log_file

if [ -d "/dev/mapper/${mapping_name}" ]; then
    kdialog --error $could_not_unmap_message
fi

Problembehandlung

Es kann immer wieder vorkommen, dass es zu größeren Problemen kommt wenn man mit den Startskripten eines Linuxsystem arbeitet und dabei den ein oder anderen Fehler macht. Mögliche Fehlerbehebung, die mir während der Entwicklung aufgetreten sind, können wie folgt behoben werden.

– Meine Sitzung kann nicht mehr gestartet werden.

Mir ist es passiert, das die Sitzung nicht mehr gestartet werden konnte und KDE in einer Bootschleife stecken blieb. In diesem Fall müssen die hinterlegten Startskripte gefixt oder deaktiviert werden.

Starten Sie das nicht grafische Terminal mit Strg + Alt + F2 und loggen sich ein und entfernen die KDE Scripten:

rm /home/<username>/.config/plasma-workspace/shotdown/umount-data.sh
rm /home/<username>/.config/plasma-workspace/env/mount-data.sh