Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

.nornir/pairing-design.md

Parning: lådorna hittar varandra själva — design 2026-09-24

Ägarens beslut 2026-09-24: xtasken ska INTE para. Den startar maskinerna med tillräckligt med information för att de ska bilda en tunnel (WireGuard som standard, Tailscale, Mullvad eller ingen) och sedan para sig med varandra. Biblioteket ligger i edda och används av både gunnar och holger. Testas under draupnir.

1. Vad som är fel idag (MÄTT i private-gunnar-ops, 2026-09-23/24)

Laptopens xtask är äktenskapsmäklaren. Tre lådor bootar utan att veta något om varandra; xtasken gör varje presentation över ssh till fronten: bootstrap av primären med frontens konsolnyckel, tre principaler, tvillingens BecomeTwin, certifikat, speglingslista. Varje presentation var ett ställe där kedjan brast (apparat som inte lyssnade än, tvilling som panikade som PID 1, dödad körning). Laptopen är en enda felkälla mitt i en installation som borde vara lådornas egen sak.

2. Idén, i en mening

Parning = gå med i tunneln. Adresserna inne i tunneln är våra (fasta), inte molnets. Bara EN låda behöver en känd adress: fronten (publik IP ur terraform, eller namnet gunnar.rs). De andra ringer fronten; WireGuard lär sig deras endpoints ur handskakningen. Inga förberedda IP:n, inga MAC-adresser.

låda overlay-adress (design, fast) roll
front 10.44.0.1 rendezvous + join-dörr + konsol
main 10.44.0.2 primär
twin 10.44.0.3 tvilling

Tunnel = none: samma design, adresserna är då UpClouds utility-IP:n som terraform vet före installationen.

3. Flödet

  1. xtask (eller holgers motsvarighet) lägger maskinerna och skriver ett frö per låda (virtio-fröet som korp-installer redan läser): tunneltyp, frontens tunnelpublika nyckel och endpoint, lådans overlay-adress och roll, frontens konsol-PUBLIKA nyckel (för-inskriven admin — bootstrapfönstret är stängt från första boot), och en engångs-jointoken (slumpad, 32 byte, skriven i fröet och i frontens lista).
  2. Första boot: lådan präglar sina egna nycklar (tunnel + gunnar-identitet) och anropar frontens join-dörr: {tunnelpubkey, overlay, roll, kapacitet} signerat med token. Fronten verifierar token, lägger till peer, svarar med peer-listan och den beslutade rollen. Ingen privat nyckel lämnar någonsin sin låda.
  3. Inne i tunneln parar lådorna sig själva: primären har admin (konsolnyckeln) från start; tvillingen kör BecomeTwin + certify mot 10.44.0.2 i en loop tills det går; följaren är loopen som redan finns. Kontrollplanet binds till overlay-adressen; mTLS som idag.
  4. Valet (svagast = tvilling) förblir "beslutat en gång": båda gunnar-lådorna skickar kapacitet vid join; fronten beslutar en gång och lämnar rollen i svaret. Lika = lägsta overlay-adress blir tvilling. Beslutet skrivs i frontens journal och ändras aldrig.
  5. Signalen: varje låda rapporterar sitt parningsläge (tunnel: uppe/nere, join: gjord, roll: given, primär: nådd, följer: n av m) på sin statusdörr. xtasken LÄSER bara.

4. Biblioteket: Skidbladnir/crates/installer/nordisk-pairing (flyttad från edda 2026-09-26)

Ren Rust, inga shell-anrop (lagen). Moduler:

gunnar länkar allt; holger länkar seed, tunnel, join, signal (holger har ingen tvilling idag men samma front/apparat-par).

5. Vad som blir kvar i xtask/ops

lay (terraform), frö per låda, media/installation, DNS-växling, down sist, och att LÄSA signalen tills alla tre säger Paired. Stegen elect/pair/twin försvinner.

6. Tester under draupnir

draupnir::boot_fleet_and_await_parallel med tre gäster på ett virtuellt nät (CloudInit/ seed.rs för fröna). Testet skriver tre frön med samma bibliotek, bootar, och läser signalen: PASS = tunneln uppe hos alla tre, join gjord, roller givna, tvillingen följer. Samma test för tunnel = none (utility-adresser) och för varje drivrutin som finns lokalt (WireGuard i kärnan finns på t14s; Tailscale/Mullvad-testerna kräver konto och märks så). Detta ersätter huvuddelen av mock-stegen i private-gunnar-ops.

7. Ordning

  1. gunnar.rs upp med dagens kedja (pågår 2026-09-24).
  2. nordisk-pairing i edda: seed + tunnel(none, wireguard) + join + pair + signal, med draupnir-test.
  3. gunnar: installer läser fröet, PID-1-tjänsten kör pair; xtask krymper till §5.
  4. holger: samma.
  5. Tailscale- och Mullvad-drivrutiner.
  6. Riv och bygg om (regeln: nya maskiner först, DNS, gamla sist).

8. Nästa version: installerarens tillfälliga mTLS (ägarens idé 2026-09-24)

Idén: installeraren har ett tillfälligt mTLS-certifikat som de installerade maskinerna känner, så att de kan kontakta installeraren, som matar dem med det de behöver.

Vad det löser

Formen

  1. xtask präglar per ombyggnad en installer-CA (ed25519), giltig i timmar. CA:ns privata nyckel ligger på fronten och lämnar den aldrig.
  2. Mediet bär CA-certifikatet (publikt) och ett bootstrap-klientcert + nyckel med kort livstid och ett enda syfte: anropa join-dörren.
  3. Vid första join skickar lådan en CSR för en nyckel den själv präglat; dörren signerar ett riktigt certifikat per låda (samma utfärdare som redan signerar tvillingens cert). Därefter vägras bootstrap-certet.
  4. Slot-per-adress gäller fortfarande: ett kopierat medium på en annan adress vägras.

Förbehållet: en nyckel på mediet är bara så hemlig som mediet — ISO:n laddas upp till UpCloud-lagringen och kan läsas av den som har kontoåtkomst. Därför kort livstid, ett syfte, bunden till adress, och utbytt direkt vid första join. Aldrig en långlivad nyckel på mediet.

Var installeraren kör: på fronten, som dörren. Maskinerna når inte laptopen, men de når fronten över utility-nätet.

BYGGT 2026-09-24 (edda nordisk-pairing, mtls.rs/join.rs/door.rs): installer-CA, dörrens cert för sin utility-adress, bootstrap-cert på mediet, lådans eget cert från CSR vid första join, bootstrap spent för joinad slot och withdrawn när alla joinat; dörren matar estate-värden (feed). Fleet-testet (draupnir, tre containrar, WireGuard) grönt på mTLS på 33 s.

Ägarens precisering 2026-09-24: installerarens mTLS gäller ENDAST under bootstrap. När lådan har joinat och fått sitt eget certifikat är installerarens cert dött för den lådan, och när estatet är komplett (alla slots joinade) dras installer-CA:n tillbaka helt.

9. Tunneldrivrutinerna bakom trait Tunnel (BYGGT 2026-09-24)

Ägarens ord: "it must provide for more than wireguard; if possible use a trait, for mullvad, tailscale".

10. Det konstanta mediet (ägaren 2026-09-24 kväll, BYGGT i 0.2.0)

Ägarens order: ISO:n ska vara DENSAMMA mellan installationer. Oförändrad gunnar-commit ⇒ samma sha ⇒ mediet tas över, ingen komponering, ingen uppladdning, ingen grind. Inget UpCloud-metadata eller user_data: det ENDA som matar en låda som startar är installerarens mTLS-dörr.

Kvar hos gunnar/ops (samma dag): gunnar skriver wg0.conf ur den matade fronten; mediet bär monetize_pubkey=fed och ingen klocka; dörrens adress deklareras i estate.toml [installer] door_ip så att mediet kan komponeras innan fronten finns, och alla tre maskiner startas samtidigt. Öppen ägarfråga: om UpCloud alls lägger en server på en VALD utility-adress, och att den förra fronten håller sin adress tills down (riv sist) — se ops ANALYS-INSTALL-XTASK-2026-09-24.md.

11. Erbjudandet: det lådan ger installeraren (0.3.1, 2026-09-25)

Installeraren matar lådorna (POST /install/feed); 0.3.1 lägger till den andra riktningen. GET /install/offer svarar med det lådan ERBJUDER — publika värden som bara den kan prägla: primärens ticket-nyckel (som operatörens verktyg för vidare till monetize), tvillingens replikeringsnyckel och signeringsbegäran, certifikatet primären signerade åt tvillingen.