Subsections of Security

LUKS Volume mit USB Keystick verknüpfen

Hinweis

Diese Anleitung setzt eine bestehende Installation mit LUKS voraus.
Die Installation wird hier nicht vorgenommen.

Idee

Es wird ein neuer Schlüssel zum LUKS Container hinzugefügt und dieser auf einer beliebigen Position eines USB Stick gespeichert. Beim Booten wird dieser dann ausgelesen und zum Öffnen der verschlüsselten Festplatte genutzt.

Hinweise

Wichtig zu wissen ist, sofern die /boot Partition nicht verschlüsselt ist, die Position des Schlüssels ausgelesen werden kann, da diese in der grub.cfg und ggf. im Init-RamFS liegt, sofern man in der Crypttab weitere Dateisysteme mit dem USB-Stick öffnen möchte.

Möchte man dies umgehen, ist die Verschlüsselung der /boot Partition nötig und eine Eingabe des Kennworts im Bootloader (z.B. Grub) nötig.
Dieses Szenario wird hier nicht thematisiert, kann aber genau so konfiguriert werden.
Durch die Passwort-Eingabe im Bootload wird /boot geöffnet, “/” und ggf. weitere Volumes werden dann über den Schlüssel des USB-Sticks geöffnet.

unterstützte Distributionen
  • Archlinux
  • Debian / Ubuntu
  • in der Regel auch andere Distributionen (mit Anpassungen)

Konfiguration

Software installieren
pacman -Syu ntfs-3g parted
apt-get update && apt-get install ntfs-3g parted
Partitionierung

Es wird eine Partitionstabelle und eine Partition angelegt und mit NTFS formatiert. Dies kann hilfreich sein, damit Dritte, wenn Sie den USB-Stick irgendwo anschließen, ggf. ein Dateisystem angezeigt bekommen und keinen Verdacht schöpfen.
Hierbei muss persönlich abgewogen werden, ob man das Dateisystem vorher noch mit Daten vollschreibt, oder den -f Parameter deaktiviert um das gesamte Dateisystem zu initalisieren.
Je nach Tiefe einer USB-Stick Analyse könnte der Key so ermittelt werden.

# Partitionstabelle anlegen um eine Partition mit Fake Dateisystem zu erzeugen
parted -s /dev/sdc mklabel msdos

# Partition anlegen
parted -s /dev/sdc mkpart primary 1m 100%free

# NTFS Dateisystem erzeugen (kann aber auch jedes andere FS sein!)
# -f aktiviert den Schnellmodus
mkfs.ntfs -f /dev/sdc1

# UUID der Partition (PARTUUID) auslesen (wird später benötigt!)
# blkid  | grep sdc
/dev/sdc1: BLOCK_SIZE="512" UUID="xxxxxxxxxxxxxxxx" TYPE="ntfs" PARTUUID="xxxxxxxx-01"
Schlüssel erzeugen und auf USB Stick schreiben

Der Schlüssel wird in diesem Beispiel 4096 Bit groß und in die Datei /root/keyfile geschrieben.
dd liest einen Block von 4096 Bytes aus der Datei /dev/random und schreibt diesen in das Keyfile.
Danach wird mit dd das Keyfile gelesen und an eine beliebige Stelle der Partition geschrieben.
Hierbei ist die Blocksize wieder 4096, aber mittels seek wird bestimmt, wie viele Blocksizes übersprungen werden sollen.
In diesem Beispiel sind es 1234 * 4096 Bytes, bedeutet es wird ab der Position (4194304. Byte geschrieben. - 4194304 / 1024 (Byte/KiByte)/ 1024 (KiByte / MiByte) / 1024 (MiByte / GiByte) - wodurch der Stick mindestens 4 GiByte groß sein muss …).
Bei einem kleineren USB Stick kann auch ein Wert wie zum Beispiel 7 verwendet werden. Die Verschiebung (Offset) ist aber im späteren Verlauf wichtig und sollte sich notiert werden!

# neuen Schlüssel erzeugen erzeugen
dd if=/dev/random of=/root/keyfile bs=4096 count=1

# Keyfile auf Partition schreiben
dd of=/dev/sdc1 if=/root/keyfile   bs=4096 seek=1234 
Key zu LUKS hinzufügen

Es wird angenommen, dass /dev/sda2 die verschlüsselte Systempartition ist.
Diese kann je nach lokaler Konfiguration (HDD,SSD, NVME, RAID, LVM, …) abweichen! Unbedingt auf die korrekten Werte beim skip achten, der dem seek Wert beim Schreiben auf den USB-Stick entspricht.

# aktuelle Slotbelegung ausgeben
cryptsetup luksDump /dev/sda2

# Keyfile als Schlüssel hinzufügen
cryptsetup luksAddKey /dev/sda2 /root/keyfile

# erneut Slotbelegung ausgeben und ermitteln, welcher dazu gekommen ist
cryptsetup luksDump /dev/sda2


# testen des Keys (ermittelter Slot, z.B. 5)
cryptsetup luksOpen --test-passphrase --key-slot 5 /dev/sda2 -d <(dd if=/dev/sdc1 bs=4096 count=1 skip=1234)
Host Konfiguration anpassen
optionale Nutzung von Crypttab
NAME      UUID=DISK_UUID   /dev/disk/by-partuuid/xxxxxxxx-01   luks,tries=3,keyfile-size=4096,keyfile-offset=4194304
Grub Konfiguration
# UUID der Partition prüfen, diese wurde bereits am Anfang der Anleitung ermittelt. Nun wird noch mal geprüft ob diese stimmt:

ls -hla /dev/disk/by-partuuid/xxxxxxxx-01
lrwxrwxrwx 1 root root 10 16. Nov 22:57 /dev/disk/by-partuuid/xxxxxxxx-01 -> ../../sdc1

# Grub konfigurieren, der Syntax ist wie folgt:
# cryptkey=$PFAD_ZUR_PARTITION$:$SEEK_BYTES:$KEYSIZE
# Die SEEK_BYTES = seek * key_size (z.B. 1234 * 4096 = 
/etc/default/grub
cryptkey=/dev/disk/by-partuuid/xxxxxxxx-01:4194304:4096
Grub Konfiguration generieren
grub-mkconfig -o /boot/grub/grub.cfg
update-grub
Initramfs generieren
# -p linux oder -p linux-lts, je nachdem welches Paket installiert ist
mkinitcpio -p linux
update-initramfs -k all -u

salted SHA512 Passwort Hashes generieren

Hier ein paar Möglichkeiten wie man einfach Passwort-Hashes generieren lassen kann, viele nativ ohne Installation von Paketen.
Oft wird mkpasswd vorgeschlagen, was sich aber nicht auf jeder Distribution gleich verhält, daher ein paar praktische Alternativen.

Python

python -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))'

# oder in der Shell als Alias
alias gen_sha512="python -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))'"

OpenSSL

Sollte im Regelfall bereits installiert sein, weil es für SSL/TLS Verbindungen benötigt wird.

openssl passwd -6

# oder mit festgelegtem Salt
openssl passwd -6 --salt ABCDEF

mkpasswd

Hinweis

Funktioniert mit Debian / Ubuntu

apt update
apt install whois

mkpasswd -m sha-512

# oder wenn der salt selbst bestimmt werden soll
mkpasswd -m sha-512 --salt=abcdefgh

HTPasswd

Manche Distributionen ziehen verhältnismäßig viele Abhängigkeiten nach, weswegen diese Option nicht immer attraktiv ist.
Einfach selber entscheiden ob die anderen Wege nicht sinnvoller sind.
Außerdem existiert die Option erst in Apache >= 2.5 (https://httpd.apache.org/docs/trunk/programs/htpasswd.html).

htpasswd -n -d -5 $USERNAME

transparent verschlüsselte VMs mit Libvirt

Vorwort

Diese Anleitung soll einen kurzen Überblick ermöglichen, wie mittels Libvirt und LUKS Images virtueller Maschinen verschlüsseln kann.
Hierbei findet die Verschlüsselung nicht in der virtuellen Maschine selbst statt, sondern wird außerhalb angewendet, sodass das Gastsystem nichts von der Verschlüsselung mitbekommt (transparent).
Somit ist keine VNC- / Spike- / serielle Verbindung beim booten, oder gar ein Dropbear Server von nötigen um das Gastsystem zu booten.

Libvirt vorbereiten

Secret anlegen

Zuerst muss ein Kennwort (bzw. ein Keyfile) generiert werden, was zum Öffnen des LUKS-Containers genutzt wird. Jedes Image hat zwar in seiner Struktur einen individuellen Schlüssel mit dem die symmetrische Verschlüsselung realisiert wird, allerdings muss eben jener mittels Keyfile geöffnet werden.

# UUID generieren und in Variable UUID speichern
UUID=$(uuidgen)

# Anlegen der Datei mysecret.xml mit Nutzung der UUID Variablen
cat <<EOF > mysecret.xml
<secret ephemeral='no' private='yes'>
   <description>my luks secret</description>
   <uuid>${UUID}</uuid>
</secret>


virsh secret-define --file mysecret.xml

# 128 Zeichen langes Kennwort generieren und in Base64 speichern
# die Nutzung von -base64 statt -hex sorgt dafür, dass der Key binäre Daten enthält. Hier kann man selbst entscheiden ob der Schlüsel lesbar sein soll ;). Ich empfehle die Konstellation mit -hex | base64 zu nutzen.

PASSWORD=$(openssl rand -hex 128 | base64)

# Passphrase / Key setzen
virsh secret-set-value "${UUID}" "${PASSWORD}"

# Secrets auflisten, hier sollte das Secret angezeigt werden!
virsh secret-list
Volume anlegen
UUID=<UUID des Libvirt Secrets>

V_NAME=my_volume
# in GB, ohne Einheit (siehe <capacity>)
V_SIZE=100
V_PATH="/srv/images/${V_NAME}"


cat <<EOF > myvolume.xml
<volume>
  <name>${V_NAME}</name>
  <capacity unit='G'>${V_SIZE}</capacity>
  <target>
    <path>${V_PATH}</path>
    <format type='raw'/>
    <encryption format='luks'>
       <secret type='passphrase' uuid='${UUID}'/>
       <cipher name='aes' size='256' mode='xts' hash='sha512'/>
       <ivgen name='plain64' hash='sha512'/>
    </encryption>
  </target>
</volume>

# Volume anlegen, bitte falls ein anderer Pool gewünscht ist, entsprechend anpassen
virsh vol-create --pool default --file myvolume.xml

Libvirt erzeugt danach mittels QEMU-IMG ein Image, welches außen mittels LUKS gesichert ist und im inneren mit RAW-Format verwendet wird, nicht dass man plötzlich wunderbare QCOW2 Funktionen erwartet ;)

Image in VM einbinden

In der XML Defintion der virtuellen Maschine müssen Parameter gesetzt sein, damit das Image angezogen werden kann. Deshalb hier ein Beispiel aus dem Kontext heraus gezogen, mit aufgelösten Variablen:

<domain type='kvm'>
<!-- INHALT AUF DISK CONFIG REDUZIERT! -->
    <disk type='file' device='disk'>
      <!-- cache deaktivieren und io=native bringen Geschwindigkeit -->
      <driver name='qemu' type='raw' cache='none' io='native'/>
      <!-- PFAD wie in der my_volume.xml! -->
      <source file='/srv/images/my_volume'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <encryption format='luks'>
        <!-- unbedingt die UUID mit der Secret-UUID beibehalten, darüber wird der Schlüssel zum öffnen des LUKS Containers gefunden -->
        <secret type='passphrase' uuid='16cd518f-35ee-4a55-acc3-376bb0c9152e'/>
      </encryption>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
</domain>