Raspberry Pi Vault

Provisioning systems with PXE network boot typically involves wide-open TFTP server yet a fresh OS could use some secret keys to e.g. join existing Kubernetes cluster. Some platforms may utilise built-in TPM module to decrypt a bit of data but it’s unavailable on Raspberry Pi 4. Fortunately, the EEPROM can be (ab)used to store a per-machine or per-cluster key which later will decrypt other secrets with tools like GnuPG or OpenSSL.
Raspberry Pi 4 EEPROM
The boot configuration EEPROM looks like:
$ vcgencmd bootloader_config
[all]
BOOT_UART=0
WAKE_ON_GPIO=1
...
It’s an ini-file with textual
key-value pairs. Unknown keys are ignored by the firmware, so a custom one can
be used to store a small secret as long as it’s hex encoded.
The rpi-eeprom-update(1) and rpi-eeprom-config(1) man pages describe how to
change the boot configuration parameters. A short version follows but please
verify that the correct firmware file is used:
$ vcgencmd bootloader_version
Apr 16 2020 18:11:26
version a5e1b95f320810c69441557c5f5f0a7f2460dfb8 (release)
timestamp 1587057086
Obtaining the EEPROM file:
. /etc/default/rpi-eeprom-update
EEPROM_FILENAME=pieeprom-$(date -d "$(vcgencmd bootloader_version | head -n 1)" +%Y-%m-%d).bin
EEPROM_PATH="/lib/firmware/raspberrypi/bootloader/$FIRMWARE_RELEASE_STATUS/$EEPROM_FILENAME"
test -f "$EEPROM_PATH" || { echo "No eeprom file found"; exit 1; }
cp "$EEPROM_PATH" pieeprom.bin
The bootloader configuration could be extracted from
pieeprom.binfile:rpi-eeprom-config pieeprom.bin --out bootconf.txtthe EEPROM chip:
vcgencmd bootloader_config > bootconf.txt
To add the custom secret just put a line like SECRET_STR=aabbccdd to the end
of [all] section. Replace the value with e.g. output of sha512sum command
fed with random data. Example:
$ vcgencmd bootloader_config
[all]
BOOT_UART=0
...
NET_BOOT_MAX_RETRIES=2
SECRET_STR=952de772210118f043a4e2225da5f5943609c653a6736940e0fad4e9c7cd3cfdd348abebbf28af7b4438c55515e5a351b87cc60c808673f4d23cf12237debf41
[none]
...
Flash it to the EEPROM:
rpi-eeprom-config pieeprom.bin --config bootconf.txt --out pieeprom-new.bin
sudo rpi-eeprom-update -d -f ./pieeprom-new.bin
Notice the “EEPROM update pending. Please reboot to apply the update.” message.
Cleaning up:
read -N 1 -p "Remove temporary files? [y/N]"
[ "$REPLY" != "y" ] || rm -f pieeprom.bin bootconf.txt pieeprom-new.bin
The Vault
Secrets encryption
Let’s assume that
plaintext_fileholds shell variables that should be confidential like K3s Node Token.gpg --symmetric --cipher-algo AES256 plaintext_fileThe resulting
*.gpgfile is encrypted with 256-bit AES symmetric cipher and can be safely stored on a TFTP server.Extracting the EEPROM key:
EEPROM_KEY=$(vcgencmd bootloader_config | grep -e "^SECRET_STR=" | cut -d= -f2)Decrypting secrets
umask 0077 GNUPGHOME=/root { echo $EEPROM_KEY; cat /etc/rpi-vault/k3s_env.gpg; } | \ gpg --no-options --batch --passphrase-fd 0 -o /etc/rancher/k3s/k3s_env -d -
Security
The boot configuration memory is accessible to the root user or any member of
video group on Raspberry Pi OS. The vcgencmd command uses /dev/vchiq
character device:
$ ls -l /dev/vchiq
crw-rw---- 1 root video 242, 0 Jun 10 22:18 /dev/vchiq