Svc-net-wireguard Role¶
Description: Kernel WireGuard tunnels, hub-and-spoke meshes under a swarm manager and full meshes between Compose hosts
Variables¶
author: Evangelos Tsakoudis
description: Kernel WireGuard tunnels, hub-and-spoke meshes under a swarm manager and full meshes between Compose hosts
license: Infinito.Nexus Community License (Non-Commercial)
company: Kevin Veen-Birkenbach https://www.veen.world
galaxy_tags: [‘wireguard’, ‘vpn’, ‘network’, ‘swarm’]
issue_tracker_url: https://s.infinito.nexus/issues
min_ansible_version: 2.9
platforms: [{‘name’: ‘ArchLinux’, ‘versions’: [‘all’]}, {‘name’: ‘Debian’, ‘versions’: [‘all’]}, {‘name’: ‘EL’, ‘versions’: [‘all’]}, {‘name’: ‘Fedora’, ‘versions’: [‘all’]}, {‘name’: ‘Ubuntu’, ‘versions’: [‘all’]}]
README¶
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"]
endSolid 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).