Skip to content

ADR 20: Management Connectivity — IPv6 Direct (v1), WireGuard Mesh (v2)

ADR 20: Management Connectivity — IPv6 Direct (v1), WireGuard Mesh (v2)

Status: Accepted

Context

RezusCloud must reach managed nodes to perform management operations:

  • Collector scrapes the Kubernetes API, Talos API, and node metrics
  • Bare-metal config push via talos_machine_configuration_apply (node API port 50000)
  • Upgrades via talosctl upgrade
  • Health checks during reconciliation

This is connectivity — reachability between RezusCloud and a node. It is a distinct concern from config delivery (how a node first receives its Talos config, addressed in ADR 13 — SideroLink rejected).

The product constraint that drives this decision: RezusCloud is self-contained — the only component needed to run the personal cloud. A common deployment is a Home Assistant container app running in a home network. RezusCloud holds bootstrap credentials and exec's tofu directly (ADR 12, credential isolation reversed). It is not deployed alongside a Sidero server or an external mesh controller.

The reachability scenarios

Scenario Direct reachability?
RezusCloud ↔ cloud APIs (OCI, OpenStack) Yes — public endpoints
RezusCloud ↔ cloud VMs (managed nodes) Yes — public cloud IP / endpoint via kubeconfig/talosconfig
RezusCloud ↔ bare metal on same LAN (home) Yes — LAN IPv6 / IPv4 direct
RezusCloud ↔ bare metal on remote network behind NAT No — both may be behind NAT

Only the last scenario needs a mesh.

What was rejected

SideroLink (Talos's WireGuard-over-gRPC config-pull feature) was considered and rejected in ADR 13. SideroLink solves config delivery, not reachability — it does not expose a general management channel. Rejecting SideroLink does not preclude a separate connectivity mesh.

A confusion to explicitly dismiss: "Kubespan" in casual use often connotes "WireGuard mesh with STUN." Talos ships Kubespan natively, but it is a node-to-node mesh designed for pod networking when Talos nodes sit on different networks. RezusCloud is not a Talos node and cannot join a Kubespan mesh natively. A future mesh is therefore Kubespan-inspired, not literally Kubespan.

Decision

Two phases.

v1: IPv6 direct

Every managed node is reachable from RezusCloud via IPv6 (public IPv6 or same-LAN IPv6). This matches the production talos-iac deployment today: OCI control plane, OpenStack worker, edge bare metal all on IPv6, Cilium providing native IPv6 pod networking. RezusCloud reaches each node's Kubernetes API (kubeconfig) and Talos API (talosconfig) directly.

  • Cloud VMs: reachable via their public/endpoint IP regardless of IP family.
  • Bare metal: reachable via IPv6 on the management LAN.

No mesh, no STUN, no relay. Simplest thing that works for the v1 deployment shape.

v2: WireGuard hub-and-spoke (Kubespan-inspired)

When nodes sit behind NAT on a remote IPv4-only network, RezusCloud runs a WireGuard hub:

  • RezusCloud is the hub; each managed node dials out (outbound — NAT-friendly).
  • RezusCloud receives a virtual IP per node.
  • Bare-metal Talos configs include a WireGuard peer block pointing at RezusCloud's endpoint.
  • STUN discovers RezusCloud's public endpoint when RezusCloud itself runs behind home NAT.
  • Relay fallback (TURN-style) for symmetric NAT topologies where direct peer-to-peer fails.

The mesh provides reachability only. Config still arrives via user_data (cloud VMs) or Talos API push (bare metal). The mesh is not a config channel.

The mesh reuses Talos's native WireGuard config documents — RezusCloud generates the peer block, the node applies it as part of its normal config.

Cold-boot caveat

A node behind NAT that has never been configured presents a chicken-and-egg: RezusCloud cannot push to it (can't reach), and it cannot pull config (SideroLink rejected). The node must obtain its first config via some reachable path:

  • IPv6 (if available),
  • temporary local access on the node's LAN, or
  • a manual step (USB boot into maintenance mode on the RezusCloud LAN).

Once first-config enables the mesh peer, ongoing management flows over the mesh. The mesh solves ongoing reachability, not cold boot. This caveat is documented for v2 operators.

Consequences

  • v1 is IPv6-only for bare metal — operators must have IPv6 to the management LAN, or attach new nodes to RezusCloud's LAN temporarily. Matches talos-iac.
  • v2 adds a WireGuard hub in RezusCloud — the binary gains a STUN client and (optionally) a relay. Self-contained; no external Headscale/Tailscale dependency.
  • RezusCloud is not a Talos node — it does not join a real Kubespan mesh. The v2 mesh is its own WireGuard surface driven by generated Talos peer blocks.
  • Config delivery is unchangeduser_data + Talos API push remain the only config mechanisms regardless of connectivity phase.
  • No SideroLink — confirmed across both phases.

See Also