From 54e1e88a4e0c06aeaf358b1006e2fe4ce204332f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:43:54 +0000 Subject: [PATCH] Add Aegis TPM-backed btrfs storage Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com> --- README.md | 7 +++- ansible/bootstrap/aegis.bu | 75 +++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e4b8e6a..c942289 100644 --- a/README.md +++ b/README.md @@ -117,12 +117,17 @@ ansible-playbook ansible/site.yml --limit prometheus \ ## Aegis `aegis` is a Raspberry Pi 4 running Fedora CoreOS. Provision it once with -`ansible/bootstrap/aegis.bu`, after replacing the SSH public-key placeholder: +`ansible/bootstrap/aegis.bu`, after replacing the SSH public-key placeholders: ```bash butane --strict --pretty --output aegis.ign ansible/bootstrap/aegis.bu ``` +The bootstrap reserves partition 5 on `/dev/mmcblk0` for `/var/lib`. On the first boot it +generates a random LUKS2 key, enrolls it in the attached TPM2 device, and formats the unlocked +volume as btrfs. This is destructive for that partition and requires a TPM2 module/device; a +Raspberry Pi 4 has no TPM onboard. The `core` and `pi` users both receive the configured SSH key. + The controller then manages it remotely as `core@aegis`; unlike local desktop profiles, Aegis is intentionally an SSH inventory target. `profile_aegis` manages rootful Podman Quadlets for AdGuard Home and iCloudPD, persistent data under `/var/lib`, the Podman auto-update timer, and diff --git a/ansible/bootstrap/aegis.bu b/ansible/bootstrap/aegis.bu index c283a11..ee052c3 100644 --- a/ansible/bootstrap/aegis.bu +++ b/ansible/bootstrap/aegis.bu @@ -1,5 +1,5 @@ # Bootstrap monouso per Fedora CoreOS su Aegis. -# Sostituire la chiave SSH prima di generare Ignition con butane --strict. +# Sostituire le chiavi SSH prima di generare Ignition con butane --strict. variant: fcos version: 1.6.0 passwd: @@ -7,10 +7,83 @@ passwd: - name: core ssh_authorized_keys: - "ssh-ed25519 CHANGEME_AEGIS_SSH_PUBLIC_KEY" + - name: pi + ssh_authorized_keys: + - "ssh-ed25519 CHANGEME_AEGIS_SSH_PUBLIC_KEY" storage: + disks: + - device: /dev/mmcblk0 + wipe_table: false + partitions: + - label: aegis-data + number: 5 + size_mib: 0 files: - path: /etc/hostname mode: 0644 contents: inline: | aegis + - path: /etc/crypttab + mode: 0644 + contents: + inline: | + aegis-data /dev/disk/by-partlabel/aegis-data - tpm2-device=auto + - path: /etc/fstab + mode: 0644 + contents: + inline: | + /dev/mapper/aegis-data /var/lib btrfs defaults,compress=zstd 0 0 + - path: /usr/local/sbin/aegis-storage-init + mode: 0750 + user: + name: root + group: + name: root + contents: + inline: | + #!/bin/bash + set -euo pipefail + + device=/dev/disk/by-partlabel/aegis-data + mapper=aegis-data + key_file=/run/aegis-storage/key + marker=/etc/aegis-storage.initialized + + if [[ -e "$marker" ]]; then + exit 0 + fi + + trap 'rm -f "$key_file"' EXIT + install -d -m 0700 /run/aegis-storage + dd if=/dev/urandom of="$key_file" bs=64 count=1 status=none + chmod 0600 "$key_file" + + cryptsetup luksFormat --batch-mode --type luks2 --key-file="$key_file" "$device" + systemd-cryptenroll --tpm2-device=auto --unlock-key-file="$key_file" "$device" + cryptsetup open --key-file="$key_file" "$device" "$mapper" + mkfs.btrfs -L aegis-data "/dev/mapper/$mapper" + mount "/dev/mapper/$mapper" /var/lib + touch "$marker" + + - path: /etc/systemd/system/aegis-storage-init.service + mode: 0644 + contents: + inline: | + [Unit] + Description=Initialize the TPM-backed Aegis data volume + Wants=systemd-udev-settle.service + After=systemd-udev-settle.service + Before=local-fs.target + ConditionPathExists=!/etc/aegis-storage.initialized + + [Service] + Type=oneshot + ExecStart=/usr/local/sbin/aegis-storage-init + + [Install] + WantedBy=local-fs-pre.target + systemd: + units: + - name: aegis-storage-init.service + enabled: true