Einen wundervollen Nachmittag,
in diesem Blogpost möchte ich beschreiben wie man mit Hilfe einer udev-Regel und Systemd eine mit luks verschlüsselte SD-Karte automatisch mounten lassen kann.
Vorwort: SD-Karte verschlüsseln
Damit man die SD-Karte automatisch entschlüsseln lassen kann, bietet es sich an, diese mit einem Keyfile zu verschlüsseln. Dazu erstellt man zunächst ein Keyfile:
sudo dd bs=512 count=4 if=/dev/urandom of=/etc/sdkey iflag=fullblock
Damit nicht jeder diesen Schlüssel lesen kann, verpasst man ihm noch die korrekten Rechte und einen Änderungsschutz:
sudo chmown root:root /etc/sdkey
sudo chmod 500 /etc/sdkey
sudo chattr +i /etc/sdkey
Danach kann man auch schon mit cryptsetup die SD-Karte verschlüsseln:
sudo cryptsetup luksFormat /dev/mmcblk0p1 /etc/sdkey
- /dev/mmcblk0p1 ist die zu verschlüsselnde Partition auf der SD-Karte
- /etc/sdkey ist das Keyfile, dass zur Verschlüsselung genutzt wird
Zuletzt öffnet man die SD-Karte und erstellt ein Dateisystem:
sudo cryptsetup --key-file=/etc/sdkey luksOpen /dev/mmcblk0p1 sdcard sudo mkfs.ext4 /dev/mapper/sdcard
Fertig.
Automatische Entschlüsselung und Einbindung
Zum automatischen Entschlüsseln und Mounten der SD-Karte müssen wir eine neue udev-Regel und ein passendes Systemd Unitfile schreiben.
Systemd Unitfile
Wir beginnen mit dem Systemd Unitfile, da dieses relativ straight forward ist. Man legt eine neue Datei an: ‚/etc/systemd/system/sdcardencrypt.service‘. Der Inhalt kann so aussehen:
[Unit] Description=Automount encrypted sdcard [Service] Type=oneshot ExecStart=/usr/bin/cryptsetup --key-file=/etc/sdkey luksOpen /dev/sdcard sdcard ExecStart=/usr/bin/mount /dev/mapper/sdcard /sdcard
Möchte man in dem Unitfile mehere ‚ExecStart‘-Kommandos ausführen, so ist ‚Type=oneshot‘ zu setzen.
Das erste Kommando ist bereits von oben bekannt und öffnet den luks-Container. Neu ist hier, dass als Device ‚/dev/sdcard‘ statt ‚/dev/mmcblk0p1‘ angegeben wird. Das erklärt sich aber später mit unserer udev-Regel.
Der zweite Befehl mountet den luks-Container in ‚/sdcard‘. Der Mountpoint muss einmalig davor erstellt werden und/oder geändert werden.
Damit Systemd das neue Unitfile korrekt ausführt, müssen wir einen kurzen Reload durchführen:
sudo systemctl daemon-reload
Udev-Regel
Als nächstes machen wir uns an die udev-Regel, welche den Symlink zu ‚/dev/sdcard‘ erstellt und das unser Unitfile aufruft. Dazu erstellen wir eine Datei in ‚/etc/udev/rules.d/‘ mit dem Namen ’10-sdcard.rules‘ und folgendem Inhalt:
ACTION=="add", KERNEL=="mmcblk0p1", SUBSYSTEM=="block", ATTR{size}=="124702720", ATTR{start}=="32768", SYMLINK+="sdcard", ENV{SYSTEMD_WANTS}="sdcardencrypt.service"
Hier passieren mehrere Dinge:
- ACTION: Nur wenn das neue Gerät eingesteckt wird, soll die Regel ausgeführt werden
- KERNEL, SUBSYSTEM, ATTR: Verundete Kriterien; Nur wenn alle matchen, wird die Regel ausgeführt
- SYMLINK: Erzeuge ein Symlink von der gematchten Partition ‚/dev/mmcblk0p1‘ zu ‚/dev/sdcard‘
- ENV: Führe danach das ’sdcardencrypt.service‘ Unitfile aus.
Das einzige, was ihr an der Regel ändern müsst, sind die Werte hinter KERNEL, ATTR{size}, ATTR{start}. Da wir hier von einer SD-Karte reden, wird SUBSYSTEM wahrscheinlich den Wert beibehalten. Alle anderen Werte nutze ich, um meine verschlüsselte SD-Karte (eindeutig) zu identifizieren.
An die entsprechenden Attribute gelangt man die SD-Karte einsteckt und danach das folgende Kommando ausführt:
udevadm info -a -p (udevadm info -q path -n /dev/mmcblk0p1)
Dabei ersetzt man ‚/dev/mmcblk0p1‘ mit der entsprechenden Partition der SD-Karte. Die Ausgabe kann so ähnlich aussehen:
udevadm info -a -p (udevadm info -q path -n /dev/mmcblk0p1) Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1': KERNEL=="mmcblk0p1" SUBSYSTEM=="block" DRIVER=="" ATTR{alignment_offset}=="0" ATTR{discard_alignment}=="8388608" ATTR{inflight}==" 0 0" ATTR{partition}=="1" ATTR{ro}=="0" ATTR{size}=="124702720" ATTR{start}=="32768" ATTR{stat}==" 38 0 1099 136 0 0 0 0 0 56 136" looking at parent device '/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0': KERNELS=="mmcblk0" SUBSYSTEMS=="block" DRIVERS=="" ATTRS{alignment_offset}=="0" ATTRS{capability}=="10" ATTRS{discard_alignment}=="0" ATTRS{ext_range}=="8" ATTRS{force_ro}=="0" ATTRS{inflight}==" 0 0" ATTRS{range}=="8" ATTRS{removable}=="0" ATTRS{ro}=="0" ATTRS{size}=="124735488" ATTRS{stat}==" 52 0 2155 206 0 0 0 0 0 96 206" looking at parent device '/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/mmc_host/mmc0/mmc0:aaaa': KERNELS=="mmc0:aaaa" SUBSYSTEMS=="mmc" DRIVERS=="mmcblk" ATTRS{cid}=="035344534c36344780295762d200f800" ATTRS{csd}=="400e00325b590001dbd37f800a404000" ATTRS{date}=="08/2015" ATTRS{erase_size}=="512" ATTRS{fwrev}=="0x0" ATTRS{hwrev}=="0x8" ATTRS{manfid}=="0x000003" ATTRS{name}=="SL64G" ATTRS{oemid}=="0x5344" ATTRS{preferred_erase_size}=="25165824" ATTRS{scr}=="0245800300000000" ATTRS{serial}=="0x295762d2" ATTRS{type}=="SD" looking at parent device '/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/mmc_host/mmc0': KERNELS=="mmc0" SUBSYSTEMS=="mmc_host" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:1c.0/0000:02:00.1': KERNELS=="0000:02:00.1" SUBSYSTEMS=="pci" DRIVERS=="sdhci-pci" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x080501" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{d3cold_allowed}=="1" ATTRS{device}=="0x16bc" ATTRS{dma_mask_bits}=="64" ATTRS{driver_override}=="(null)" ATTRS{enable}=="1" ATTRS{irq}=="17" ATTRS{local_cpulist}=="0-3" ATTRS{local_cpus}=="0f" ATTRS{msi_bus}=="1" ATTRS{numa_node}=="-1" ATTRS{subsystem_device}=="0x0504" ATTRS{subsystem_vendor}=="0x1025" ATTRS{vendor}=="0x14e4" looking at parent device '/devices/pci0000:00/0000:00:1c.0': KERNELS=="0000:00:1c.0" SUBSYSTEMS=="pci" DRIVERS=="pcieport" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x060400" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{d3cold_allowed}=="0" ATTRS{device}=="0x1c10" ATTRS{dma_mask_bits}=="32" ATTRS{driver_override}=="(null)" ATTRS{enable}=="1" ATTRS{irq}=="17" ATTRS{local_cpulist}=="0-3" ATTRS{local_cpus}=="0f" ATTRS{msi_bus}=="1" ATTRS{numa_node}=="-1" ATTRS{subsystem_device}=="0x0504" ATTRS{subsystem_vendor}=="0x1025" ATTRS{vendor}=="0x8086" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""
Am Besten nimmt man die Attribute von weiter oben. Es stellt allerdings auch kein Problem dar, wenn man Attribute nutzt, die weiter unten stehen, nur sind diese etwas genereller und könnten gegebenenfalls auf andere SD-Karten matchen. Allerdings darf man nur Attribute von einem ‚Parent‘ des Devices nutzen. Für bessere Robustheit könnte man noch zusätzliche folgende Attribute einführen:
- ATTRS{manfid}==“0x000003″
- ATTRS{name}==“SL64G“
- ATTRS{oemid}==“0x5344″
- ATTRS{serial}==“0x295762d2″
- ATTRS{type}==“SD“
Zuletzte sollte man noch die Regeln neu einlesen. Das klappt einfach mit einem:
sudo udevadm trigger
Fazit
Es braucht nicht viel Bastelei, um eine verschlüsselte SD-Karte automatisch einzubinden. Möglicherweise möchte man sich aber noch Gedanken darüber machen, dass der Mountpoint bzw. Luks-Container geschlossen wird, wenn die SD-Karte ausgehängt wird. Da ich das nicht häufig/wirklich benötige, ist dies dem interessierten Leser überlassen.
~ Sebastian