ops(fips): fleet LAN fast-path pairing script (dev nodes only)
scripts/fleet-fips-pair.sh writes a deterministic /etc/fips/fips.yaml on each of our 4 dev fleet nodes (.116/.198/.228/.253), listing the other three as static FIPS peers over their LAN IPs (UDP 2121 / TCP 8443). Also flips `node.identity.persistent: true` so the npub stays stable across restarts — without this the daemon rolls a new keypair on every restart and federation invites that carried the previous npub go stale. The script is NOT the general deployment mechanism: - Every archipelago install already ships fips.v0l.io as an anchor peer, so any node can DHT-route to any npub that has ever announced on the public mesh. - Federation invites (v1.4+) carry the peer's fips_npub, so accepting an invite is enough for crate::fips::dial::peer_base_url(npub) to reach the peer through the anchor network. - This script is a LAN fast-path optimization so intra-fleet traffic stays on the wire instead of bouncing through fips.v0l.io. Usage: scripts/fleet-fips-pair.sh # apply to all nodes scripts/fleet-fips-pair.sh --verify # print current peer state Verified: all 4 fleet nodes now report 3 authenticated peers each (their 3 fleet siblings), plus fips.v0l.io in the identity cache. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
176
scripts/fleet-fips-pair.sh
Executable file
176
scripts/fleet-fips-pair.sh
Executable file
@@ -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: "<ip-last-octet> <nic-name> <fips-npub>"
|
||||
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" <<YAML
|
||||
# FIPS Node Configuration — managed by scripts/fleet-fips-pair.sh
|
||||
# DO NOT hand-edit: re-run the script to regenerate.
|
||||
|
||||
node:
|
||||
identity:
|
||||
# Persistent identity so the npub stays stable across restarts.
|
||||
# Without this, every restart rolls a new keypair and federation
|
||||
# peer lists go stale.
|
||||
persistent: true
|
||||
|
||||
tun:
|
||||
enabled: true
|
||||
name: fips0
|
||||
mtu: 1280
|
||||
|
||||
dns:
|
||||
enabled: true
|
||||
bind_addr: "127.0.0.1"
|
||||
port: 5354
|
||||
|
||||
transports:
|
||||
udp:
|
||||
bind_addr: "0.0.0.0:$UDP_PORT"
|
||||
tcp:
|
||||
bind_addr: "0.0.0.0:$TCP_PORT"
|
||||
|
||||
ethernet:
|
||||
interface: "$self_nic"
|
||||
discovery: true
|
||||
announce: true
|
||||
auto_connect: true
|
||||
accept_connections: true
|
||||
|
||||
peers:
|
||||
# Public anchor — bootstraps DHT routing for any npub heard via
|
||||
# federation invites. Every archipelago install ships this peer.
|
||||
- npub: "npub1zv58cn7v83mxvttl70w5fwjwuclfmntv9cnmv5wmz2nzz88u5urqvdx96n"
|
||||
alias: "fips.v0l.io"
|
||||
addresses:
|
||||
- transport: tcp
|
||||
addr: "fips.v0l.io:8443"
|
||||
- transport: udp
|
||||
addr: "fips.v0l.io:2121"
|
||||
connect_policy: auto_connect
|
||||
|
||||
# Fleet LAN fast-path — other archipelago nodes on this subnet.
|
||||
YAML
|
||||
|
||||
for other_row in "${NODES[@]}"; do
|
||||
read -r o_node _o_nic o_npub <<< "$other_row"
|
||||
[ "$o_node" = "$self_node" ] && continue
|
||||
cat >> "$out" <<YAML
|
||||
- npub: "$o_npub"
|
||||
alias: "archi-$o_node"
|
||||
addresses:
|
||||
- transport: udp
|
||||
addr: "$LAN_PREFIX.$o_node:$UDP_PORT"
|
||||
- transport: tcp
|
||||
addr: "$LAN_PREFIX.$o_node:$TCP_PORT"
|
||||
connect_policy: auto_connect
|
||||
YAML
|
||||
done
|
||||
echo "$out"
|
||||
}
|
||||
|
||||
deploy_to() {
|
||||
local node="$1"
|
||||
local nic="$2"
|
||||
local ip="$LAN_PREFIX.$node"
|
||||
local yaml
|
||||
yaml=$(generate_yaml "$node" "$nic")
|
||||
|
||||
log_info "[.${node}] uploading fips.yaml"
|
||||
scp_cmd "$yaml" "archipelago@${ip}:/tmp/fips.yaml.new"
|
||||
|
||||
log_info "[.${node}] installing + restarting fips.service"
|
||||
ssh_cmd "$ip" '
|
||||
set -e
|
||||
sudo install -o root -g root -m 0600 /tmp/fips.yaml.new /etc/fips/fips.yaml
|
||||
rm -f /tmp/fips.yaml.new
|
||||
sudo systemctl restart fips.service
|
||||
# Give the daemon a beat to come up before we ask about peers
|
||||
for i in $(seq 1 10); do
|
||||
if sudo systemctl is-active fips.service >/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
|
||||
Reference in New Issue
Block a user