Skip to main content

Proxmox VE

ZFS Remote Entschlüsselung via SSH

Work in Progress!

Ein zfs pool wird beim Start des Hosts automatisch entschlüsselt. Der Key wird dafür via SSH von einem anderen Host angefragt. Falls das System in einem fremden Netzwerk gebootet wird, kann der Pool nicht entschlüsselt werden.

Vorbereitungen am empfangenden Host

Der Host, welche das verschlüsselte Saveset enthalten soll, muss zuerst ein SSH Schlüsselpaar erzeugen, welches danach für die Anfrage am bereitstellenden Host genutzt wird. Dafür nutze ich ed25519 als Keytype, da dies sicherer ist als RSA und unsere Gegenstelle sowieso ein modernes Debian / Proxmox sein wird.

ssh-keygen -t ed25519 -C "fetch-zfs-key@pve01-test" -f /etc/zfs/fetch-zfs-key_id
chmod 0600 /etc/zfs/fetch-zfs-key_id

Vorbereitungen am bereitstellenden Host

Auf dem Host, welcher den Key bereitstellen soll, muss der Key erzeugt werden und bei einem Aufruf eines bestimmten Kommandos ausgegeben werden.

Erzeugen des Keys

Den Key lege ich hier in diesem Beispiel unter /etc/zfs/remote-keys/<hostname>-<pool>.key ab.

mkdir -p /etc/zfs/remote-keys
openssl rand -hex 32 | tr -d '\n' > /etc/zfs/remote-keys/pve01-test-encrypted.key

Ausgabekommando des Keys

Dieses Skript wird aufgerufen, wenn sich ein bestimmter SSH Key von einem bestimmten Host verbindet und stellt danach den Key bereit. Hierfür wird ein Bash-Skript unter /usr/local/sbin/provide-zfs-key mit folgendem Inhalt erzeugt:

#!/bin/bash
cat /etc/zfs/remote-keys/$1.key

Diese Datei muss noch für den Owner ausführbar gemacht werden.

chmod 0700 /usr/local/sbin/provide-zfs-key

Um zu testen, ob dies funktioniert, kann bereits als root der Befehl provide-zfs-key pve01-encrypted aufgerufen werden.

Anpassen der authorized_keys

Damit der Key an den anfragenden Host ausgegeben wird, muss folgende Zeile der Datei /root/.ssh/authorized_keys hinzugefügt werden. Tauscht unbedingt den Platzhalter <pubkey> mit dem vorhin erzeugtem SSH Public-Key aus und passt die from-Adresse an. ;)

from="10.0.0.41",command="/usr/local/sbin/provide-zfs-key pve01-test-encrypted",no-port-forwarding,no-X11-forwarding,no-agent-forwarding <pubkey>

Erzeugen des verschlüsselten Datasets

Auf dem Host, der nunFür das verschlüsselteErzeugen, Dataset enthalten soll, wird jenes nun erzeugtEntsperren und einmaligSperren des Datasets verwenden wir folgendes Hilfs-Skript welches manuell entsperrt.oder Dafürüber benötigeneine wirsystemd denUnit Hex-Key,beim denStart wirdes vorhinHosts erzeugtaufgerufen haben.wird. Das Skript entsprechend euren Daten anpassen.

Ich habe es unter /usr/local/sbin/encrypted-zfs-pool abgelegt.

#!/bin/bash

set -euo pipefail

ZFS_DATASET="rpool/encrypted"
SSH_REMOTE_HOST="10.0.0.6"
SSH_REMOTE_USER="root"
SSH_KEYFILE="/etc/zfs/fetch-zfs-key_id"

TMPDIR="/tmp/zfs-ramdisk"
KEYFILE="rpool-encrypted.key"

create_tmp_dir() {
    mkdir -p /tmp/zfs-ramdisk
    echo "Create and mount temporary directory: $TMPDIR"
    mount -t tmpfs -o size=1M tmpfs "$TMPDIR"
}

remove_tmp_dir() {
    if [[ -n "$TMPDIR" && -d "$TMPDIR" ]]; then
        echo "Shred temporary keyfile"
        shred -u "$TMPDIR/$KEYFILE"
        echo "Unmount the temporary directory"
        umount "$TMPDIR"
        rmdir "$TMPDIR"
    fi
}

fetch_key_from_remote() {
    create_tmp_dir
    echo "Fetch the key from remote and store it in temporary file."
    ssh -i "$SSH_KEYFILE" "$SSH_REMOTE_USER@$SSH_REMOTE_HOST" > "$TMPDIR/$KEYFILE"
}

create_zfs_dataset() {
    echo "Check if a dataset named $ZFS_DATASET exists."
    if ! zfs list -H -o name "$ZFS_DATASET" &>/dev/null; then
        fetch_key_from_remote
        zfs create \
            -o encryption=on \
            -o keyformat=hex rpool/encrypted
\

Hier-o fügtmountpoint=none man\ nun-o zweimalkeylocation="file://$TMPDIR/$KEYFILE" den\ Key"$ZFS_DATASET" ausecho der"Dataset Zwischenablage$ZFS_DATASET eincreated undsuccessfully." prüftremove_tmp_dir danach,else obecho das"A Savesetdataset auchnamed korrekt$ZFS_DATASET erzeugtalready undexists, entsperrtexiting." wurde:

exit
root@pve01-test:~#1
    fi
}

load_zfs_key() {
    echo "Check if the key is already loaded..."
    if ! zfs get encryption,keylocation,-H -o value keystatus rpool/encrypted"$ZFS_DATASET" NAME| PROPERTYgrep VALUE-v SOURCE"unavailable"; rpool/encryptedthen
        fetch_key_from_remote
        echo "Load ZFS encryption aes-256-gcmkey for $ZFS_DATASET"
        zfs load-key -L rpool/encrypted"file://$TMPDIR/$KEYFILE" keylocation"$ZFS_DATASET"
        promptremove_tmp_dir
    localelse
        rpool/encryptedecho keystatus"Key availablealready loaded for $ZFS_DATASET."
    fi
}

unload_zfs_key() {
    echo "Attempting to unload ZFS encryption key for $ZFS_DATASET"
    zfs unload-key "$ZFS_DATASET"
}

# Command dispatcher
case "${1:-}" in
    create)
        create_zfs_dataset
        ;;
    load)
        load_zfs_key
        ;;
    unload)
        unload_zfs_key
        ;;
    *)
        echo "Usage: $0 {create|load|unload}"
        exit 1
        ;;
esac