The README merged with #323 lists svc-swarm-node as a 1:1 dependent, but no role on main references svc-net-wireguard. make docs regenerates the Cosmos block from the actual dependency graph and drops the edge. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
6.6 KiB
WireGuard
Description
WireGuard is an in-kernel VPN protocol. Peers authenticate each other with Curve25519 keypairs and exchange encrypted UDP datagrams, so a tunnel needs no session state, no certificate authority and no daemon of its own.
Overview
This role puts WireGuard under a swarm deployment so that swarm control, overlay and storage traffic never crosses an untunnelled network. It configures the hub-and-spoke meshes the deployment declares, any number of them, with the swarm manager as the hub of each. The manager forwards between them, which is how a worker reaches an NFS export it is not a member of.
Without a swarm manager, as in a Compose deployment spread over several hosts, every declared mesh is a full mesh instead. Each member knows the key of every other member and dials it directly, and nothing forwards between meshes: a host reaches exactly the members of the meshes it joined.
The meshes are inventory values, and every role ships them empty.
networks.meshes of this role declares them in the hub's host_vars, or in
the host_vars of every member when there is no hub, and networks.meshes of
every other role lists the meshes its hosts join. The
development lab declares two, swarm and data, in
wireguard.yml;
wireguard-three-meshes
declares three. Consumers read a host's mesh address through
lookup('mesh_address', <host>) instead of naming a mesh.
The role plans nothing. Every key, address and peer list is written into the
inventory beforehand by cli.administration.inventory.mesh, the one pass that
sees every host at once; this role renders what its own host was handed and
then proves the result. It acts on every host in the svc-net-wireguard
group; outside swarm mode a host the mesh CLI gave no mesh is skipped.
Cosmos
The diagram places WireGuard in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
flowchart LR
subgraph role [svc-net-wireguard 💻]
svc_wireguard["wireguard"]
end
Solid 1:1 edges are fixed relationships; dashed 0..1 edges are conditional (enabled only in matching deployments); red 0..0 edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in meta/main.yml.
Features
- Any number of hub-and-spoke meshes around one hub, so the planes stay separate while remaining mutually reachable.
- Full meshes when the inventory has no hub, each member peered with every other and no route between meshes.
- A host may be a spoke of several meshes: it routes the pool through its first declared one and only the mesh subnet through the others, so no two interfaces claim one route.
- Per-host interfaces rendered from inventory state, with each private key
vault-encrypted in exactly one host's
host_vars. - Forwarding enabled only on the hub, which is the only member with peers in every plane.
- A hard gate that fails the deploy before swarm initialises when any peer is unreachable or the path will not carry a full-size payload.
Quick Setup
Development
Clone, set up the workstation, and deploy WireGuard onto the local stack:
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=svc-net-wireguard full_cycle=false
Production
Install WireGuard directly onto the target machine: clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
git clone https://github.com/infinito-nexus/core.git
cd core
bash scripts/install/package.sh
make install
source scripts/meta/env/load.sh
APP=svc-net-wireguard
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
INVENTORY=inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host localhost \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv
Administration
The mesh must exist in the inventory before the play runs. Write it once over every inventory of the deploy, including any sibling file that holds hosts the cluster inventory does not:
python3 -m cli.administration.inventory.mesh \
--inventory /tmp/inv/devices.yml \
--inventory /tmp/inv/backup.yml \
--host-vars-dir /tmp/inv/host_vars \
--vault-password-file /tmp/inv/.password
It reads the declarations and memberships from the host_vars it writes to,
and records each host's addresses, keys and peers in that host's
svc-net-wireguard.networks.interfaces.
Re-running is a no-op. To replace every keypair, add --rotate; that rewrites
the whole mesh in one pass, because rotating one member alone partitions it.
Compose hosts
For Compose hosts the inventory holds no svc-swarm-manager, so the writer
plans full meshes. Put the same svc-net-wireguard.networks.meshes
declaration into the host_vars of every member, list the meshes a host joins
under networks.meshes of a role it carries, add the hosts to the
svc-net-wireguard group, write the mesh as above and deploy. Each member
listens on the mesh port, so that UDP port must be open between the members.
The role brings the interfaces up and gates on a handshake with every peer;
an application uses the tunnel only where it is pointed at a peer's mesh
address, which lookup('mesh_address', <host>) returns.
Inspect a live interface on any member:
wg show <mesh-name>
A peer with no recent handshake is either unreachable on the underlay or
carrying a key its peer does not know. The second case means the inventory and
the running interface disagree: re-run the mesh writer and redeploy rather than
editing /etc/wireguard by hand, which the next deploy overwrites.
Credits
Implemented by Evangelos Tsakoudis. Part of the Infinito.Nexus Project and maintained by Kevin Veen-Birkenbach. Licensed under the Infinito.Nexus Community License (Non-Commercial).