diff --git a/active/device_raspberry_pi/systemd/README.md b/active/device_raspberry_pi/systemd/README.md new file mode 100644 index 0000000..24e9d47 --- /dev/null +++ b/active/device_raspberry_pi/systemd/README.md @@ -0,0 +1,60 @@ +# Raspberry Pi — boot-time hardening units + +Two reusable runbooks for a headless Pi that must stay reachable over SSH. +Deliberately host-agnostic: **no addresses, key material, or peer identities +live in this repo** — those stay on each host. Set `HOST` and fill in the +placeholders from the runbook before running anything. + +| Runbook | Solves | +| --- | --- | +| [`root-ssh-key.md`](root-ssh-key.md) | root `authorized_keys` gets wiped (imaging, config management) → key is re-installed at boot and re-applied on change | +| [`wireguard.md`](wireguard.md) | SSH through a WireGuard tunnel address fails after reboot / NAT timeout / roaming to another network | + +Verified against Debian 13 (trixie) with systemd 257 and NetworkManager. The +units are plain POSIX `sh` + systemd, so they carry to any other distribution +with the same systemd version or newer. + +## Layout → target path on the host + +| File in this directory | Installs to | +| --- | --- | +| `ensure-root-ssh-key` | `/usr/local/sbin/ensure-root-ssh-key` (`0755`) | +| `ensure-root-ssh-key.service` | `/etc/systemd/system/` | +| `ensure-root-ssh-key.path` | `/etc/systemd/system/` | +| `root-ssh-keys/authorized_keys.example` | `/usr/local/share/root-ssh-keys/authorized_keys` (`0644`) — copy, fill in your public key(s) | +| `wg0-watchdog` | `/usr/local/sbin/wg0-watchdog` (`0755`) | +| `wg0-watchdog.service` | `/etc/systemd/system/` | +| `wg0-watchdog.timer` | `/etc/systemd/system/` | +| `wg-quick@wg0.service.d-10-boot-resilience.conf` | `/etc/systemd/system/wg-quick@wg0.service.d/10-boot-resilience.conf` | +| `wg0.conf.template` | documents `/etc/wireguard/wg0.conf` (`0600`) — the real file is never copied here | + +## Deploy pattern + +Every command in both runbooks follows the same shape, so a fresh Pi needs only +`HOST` and the placeholders: + +```bash +HOST=root@ +D=$PWD # run the snippets from a checkout of this directory +``` + +Files travel over one `tar | ssh` pipe into `/root`, then `install` moves them +into place with explicit modes (no `scp` of a whole tree into `/etc`, no +ambiguous ownership). Reload and enable once at the end: + +```bash +ssh "$HOST" 'systemctl daemon-reload && systemctl enable --now ' +``` + +## Conventions worth keeping on any host + +- Config files under `/usr/local/{sbin,share}` are the source of truth; systemd + units stay thin wrappers so they can be re-imaged independently. +- Idempotent installers over clever state: every script re-derives the desired + state from its own config file and never deletes what it did not create. +- Anything that must heal itself is gap-limited (a minimum interval between + restarts) so a broken dependency cannot make a unit flap. +- Private keys and addresses are excluded from the repo; when dumping a + WireGuard config, redact with a regex that tolerates `PrivateKey = ` spacing + (`wg-quick strip` emits spaces, a `PrivateKey=` regex misses them): + `sed -E 's/^(PrivateKey[[:space:]]*=).*/\1 [REDACTED]/'`