fix(fips,iso): bulletproof FIPS from install — no Activate button needed
Problems addressed (all observed on .198):
* fips_key was written as raw 32 bytes; upstream fips daemon reads it
with read_to_string() and bailed with "stream did not contain valid
UTF-8", crashlooping indefinitely.
* Activate button racy: user had to hit it, and it would keep failing
silently because the daemon couldn't parse its own config.
* FIPS schema drift (already fixed in 7d8a5864) put the config write
path behind the same broken "Activate" flow, so the fix alone
didn't help existing nodes.
* Journal was on tmpfs — every reboot wiped install/onboarding history,
making post-hoc debugging impossible.
Changes:
* identity.rs: write fips_key as bech32 nsec + newline. load_fips_keys
now auto-migrates legacy 32-byte files to bech32 the first time it
reads them, so OTA updates from v1.5.0-alpha self-heal without user
action.
* server.rs: post-onboarding auto-activate task runs on every
archipelago startup. If fips_key exists it ensures /etc/fips/fips.yaml
is schema-current and starts archipelago-fips.service. Pre-onboarding
nodes stay quiet (guarded on fips_key_exists).
* ISO build: un-mask archipelago-fips + archipelago-wg + wg-address —
all use ConditionPathExists on their key files, so systemd silently
skips them pre-onboarding (no MOTD [FAILED]). Only nostr-vpn stays
masked (legacy service, superseded by upstream fips).
* Journald made persistent via /var/log/journal + 500M cap, so
install and first-boot logs survive reboots for diagnosis.
After this, a fresh install + onboarding should bring FIPS up automatically
with no user interaction. The UI "Activate" button can stay as an escape
hatch (the RPC is still there) but is no longer on the critical path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
5eb2d34dd7
commit
b643b30bba
@@ -453,30 +453,24 @@ RUN systemctl enable NetworkManager || true && \
|
||||
systemctl enable archipelago-reconcile.timer || true && \
|
||||
systemctl enable archipelago-tor-helper.path || true && \
|
||||
systemctl enable nostr-relay || true
|
||||
# archipelago-wg + wg-address: enabled by first-boot after WG key is generated
|
||||
# nostr-vpn: enabled by first-boot after Nostr identity is generated
|
||||
# (env file doesn't exist until onboarding, so pre-enabling causes crash-loop)
|
||||
# archipelago-fips: masked by default; archipelago backend unmasks +
|
||||
# starts it via `fips.install` RPC once the seed-derived fips_key is on
|
||||
# disk and the fips daemon package is installed. Pre-onboarding the node
|
||||
# stays dark on FIPS so no traffic leaves an ephemeral identity.
|
||||
RUN systemctl mask archipelago-fips.service || true
|
||||
# archipelago-fips.service + archipelago-wg.service + archipelago-wg-address.service
|
||||
# stay installed and enabled. They all use `ConditionPathExists=` on their
|
||||
# respective seed-derived key files, so on a fresh pre-onboarding boot
|
||||
# systemd quietly skips them with no [FAILED] in the MOTD. Once the user
|
||||
# completes the seed onboarding flow, archipelago writes the key files,
|
||||
# the archipelago backend calls `systemctl start archipelago-fips.service`
|
||||
# (see server.rs post-onboarding auto-activate block) and the WG setup
|
||||
# path runs `archipelago-wg setup` directly. No masking, no user-facing
|
||||
# "Activate" button — install → onboard → FIPS + WG are just running.
|
||||
RUN systemctl enable archipelago-fips.service || true
|
||||
|
||||
# Same rationale for nostr-vpn and wireguard helpers — their env files
|
||||
# don't exist until onboarding completes, so leaving these "enabled"
|
||||
# (the default from WantedBy=multi-user.target) produces a red
|
||||
# [FAILED] in the boot MOTD every reboot. Mask by replacing each
|
||||
# .service with a /dev/null symlink — plain `systemctl mask` refuses
|
||||
# to clobber the real files we just COPY'd in, so the previous
|
||||
# attempt left the services installable via dependency chains
|
||||
# (nostr-relay has Before=nostr-vpn, which pulls it in). Explicit
|
||||
# rm + ln -sf creates the proper masked state. The onboarding flow
|
||||
# removes the symlink and drops in a configured service when env
|
||||
# files are in place.
|
||||
RUN for svc in nostr-vpn archipelago-wg archipelago-wg-address; do \\
|
||||
rm -f /etc/systemd/system/\$svc.service; \\
|
||||
ln -sf /dev/null /etc/systemd/system/\$svc.service; \\
|
||||
done
|
||||
# nostr-vpn is the legacy nostr-tunnel service — deprecated in favour of
|
||||
# the upstream FIPS daemon. It still crash-loops on boot if left enabled
|
||||
# (env file doesn't exist until onboarding) so we mask it outright.
|
||||
# `systemctl mask` alone doesn't stick because the real .service file is
|
||||
# already in place — explicit rm + /dev/null symlink is what sticks.
|
||||
RUN rm -f /etc/systemd/system/nostr-vpn.service && \\
|
||||
ln -sf /dev/null /etc/systemd/system/nostr-vpn.service
|
||||
|
||||
# Remove policy-rc.d so services can start on first boot
|
||||
RUN rm -f /usr/sbin/policy-rc.d
|
||||
@@ -489,6 +483,15 @@ RUN mkdir -p /var/lib/archipelago/data /var/lib/archipelago/config /var/lib/arch
|
||||
cp /etc/archipelago/nostr-relay-config.toml /var/lib/archipelago/nostr-relay/config.toml && \
|
||||
chown -R archipelago:archipelago /var/lib/archipelago /opt/archipelago
|
||||
|
||||
# Persist journalctl across reboots — without /var/log/journal systemd
|
||||
# journal uses tmpfs and everything before the last boot is lost. We
|
||||
# need the full history to diagnose first-boot / install / onboarding
|
||||
# issues after the fact. Size cap keeps it from eating the disk.
|
||||
RUN mkdir -p /var/log/journal && \
|
||||
systemd-tmpfiles --create --prefix /var/log/journal 2>/dev/null || true && \
|
||||
install -d -m 0755 /etc/systemd/journald.conf.d && \
|
||||
printf '[Journal]\nStorage=persistent\nSystemMaxUse=500M\nRuntimeMaxUse=100M\nForwardToSyslog=no\n' > /etc/systemd/journald.conf.d/10-archipelago-persistent.conf
|
||||
|
||||
# Clean up
|
||||
RUN apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
Reference in New Issue
Block a user