add README index for the Raspberry Pi systemd runbooks
Ties the two runbooks together as one host-agnostic directory: which runbook solves which problem, a file -> target-path map for the units, and the shared deploy pattern (one tar | ssh pipe into /root, then install with explicit modes rather than copying a whole tree into /etc). States the conventions both units follow - configs under /usr/local as the source of truth with thin systemd wrappers, idempotent installers that re-derive desired state and never delete what they did not create, and gap-limited self-healing so a broken dependency cannot make a unit flap. Also documents the redaction recipe for pasting a WireGuard config: match `PrivateKey[[:space:]]*=` because wg-quick strip emits spaces around the `=`, which a `PrivateKey=` regex misses. LLM-Generated: true
This commit is contained in:
@@ -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@<pi-address>
|
||||
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 <units>'
|
||||
```
|
||||
|
||||
## 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]/'`
|
||||
Reference in New Issue
Block a user