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.
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