diff --git a/scripts/fleet-fips-pair.sh b/scripts/fleet-fips-pair.sh new file mode 100755 index 00000000..78bce572 --- /dev/null +++ b/scripts/fleet-fips-pair.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# LAN fast-path pairing for our 4 dev fleet nodes. +# +# ── Is this needed for every archipelago install? No. ──────────────── +# For nodes deployed anywhere in the world, FIPS-to-FIPS routing by +# npub works via the anchor peer network (fips.v0l.io ships by default +# in /etc/fips/fips.yaml on every install — that anchor bootstraps DHT +# routing for any npub the node has ever heard about). The peer's +# fips_npub is advertised in our federation invite codes (since v1.4), +# so accepting an invite is enough for `dial::peer_base_url(npub)` to +# reach the peer through the anchor mesh. +# +# ── Why this script exists ─────────────────────────────────────────── +# Our 4 fleet nodes are all on 192.168.1.0/24. Hopping through the +# fips.v0l.io anchor for intra-LAN traffic is wasteful when the peers +# are on the same wire. This script writes per-node fips.yaml with: +# 1. The public anchor (fips.v0l.io) so internet peers still route. +# 2. The other 3 fleet nodes as static LAN peers (UDP 2121 / TCP +# 8443) so LAN traffic stays on LAN. +# 3. `persistent: true` so the npub is stable across restarts — +# without this the daemon rolls a new keypair on every restart +# and any federation invite we advertised goes stale. +# +# Idempotent: re-running picks up any newly-added or removed nodes. +# +# For a production install on an unknown LAN, this script isn't the +# mechanism — the ISO install writes the anchor-only fips.yaml and +# identity comes from the archipelago seed; peer discovery is purely +# through the DHT + federation invites. +# +# Usage: +# scripts/fleet-fips-pair.sh # apply to all nodes +# scripts/fleet-fips-pair.sh --verify # just print the peer state + +set -eo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +. "$SCRIPT_DIR/lib/common.sh" + +# Fleet roster: " " +NODES=( + "116 enp0s25 npub1mxavs6scfgl056k6lm4mk73ddnrhjewg78zlyzfn2lmr0rfyrs5qhcr03g" + "198 enp2s0 npub13cy4lml94cj4rdu8runrr945z2muszuvr5tql8mr9m063d7xzpqqu3k8se" + "228 enp2s0 npub1a0xxcqce2tsv8ulwastep23jtf3h4wvvry8r8nklnl36jtrdnefqh5qn6h" + "253 enx9cbf0d0129f9 npub1dl0m0yfzfw6467c3z6q63s7ggzd77yg97j90ptfrheprxeypt3msj0mq4g" +) + +LAN_PREFIX="192.168.1" +UDP_PORT=2121 +TCP_PORT=8443 + +if [ "${1:-}" = "--verify" ]; then + for row in "${NODES[@]}"; do + read -r node _nic _npub <<< "$row" + echo "=== .$node ===" + ssh_cmd "$LAN_PREFIX.$node" "sudo fipsctl show peers 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(f\"{len(d[\"peers\"])} authenticated peers\"); [print(\" npub=\", p.get(\"npub\",\"?\"), \"alias=\", p.get(\"alias\",\"?\")) for p in d[\"peers\"]]' || echo ' fipsctl show peers failed'" + done + exit 0 +fi + +TMP_ROOT=$(mktemp -d) +trap 'rm -rf "$TMP_ROOT"' EXIT + +generate_yaml() { + # $1 = self node octet, $2 = self nic + local self_node="$1" + local self_nic="$2" + local out="$TMP_ROOT/fips.yaml.$self_node" + + cat > "$out" <> "$out" </dev/null 2>&1; then break; fi + sleep 0.5 + done + sudo systemctl is-active fips.service + ' +} + +for row in "${NODES[@]}"; do + read -r node nic _npub <<< "$row" + deploy_to "$node" "$nic" +done + +echo +log_info "Waiting 10s for peer handshakes to settle…" +sleep 10 + +echo +log_info "Post-pair peer state:" +for row in "${NODES[@]}"; do + read -r node _nic _npub <<< "$row" + count=$(ssh_cmd "$LAN_PREFIX.$node" "sudo fipsctl show peers 2>/dev/null | grep -c '\"npub\"' || echo 0") + log_info " .$node: $count authenticated peers" +done