A Kubernetes Operator that exposes LoadBalancer services through remote Edge VPS nodes with public IPv4 addresses.
kube-edge-router bridges internal Kubernetes services to the public internet through edge nodes connected via WireGuard tunnels. It automates the management of nftables forwarding rules on edge VPS nodes.
flowchart TB
subgraph Internet
User([User])
end
subgraph Edge["Edge VPS (edge-us-east-01)"]
PIP[Public IP<br/>203.0.113.10]
NFT[nftables<br/>DNAT]
WG1[WireGuard<br/>wg0]
end
subgraph Core["Core Cluster"]
Controller[kube-edge-router<br/>Controller]
EN[EdgeNode CRD]
SVC[Service<br/>type: LoadBalancer]
MLB[MetalLB<br/>172.16.10.200]
end
User -->|:25565| PIP
PIP --> NFT
NFT --> WG1
WG1 -->|WireGuard Tunnel| MLB
MLB --> SVC
Controller -->|SSH| NFT
Controller --> EN
Controller -->|Watch| SVC
sequenceDiagram
participant S as Service
participant C as Controller
participant EN as EdgeNode
participant E as Edge VPS
S->>C: Create Service (LoadBalancer)
C->>EN: Find available Public IP
EN-->>C: 203.0.113.10 available
C->>E: SSH: Apply nftables DNAT
E-->>C: Rules applied
C->>EN: Mark IP as allocated
C->>S: Patch status.loadBalancer.ingress
- ๐ Multi-Edge Support: Manage multiple edge VPS nodes with different public IP pools
- ๐ Zero-Trust Edge: Control plane pushes config; edge nodes are stateless gateways
- ๐ Automatic Reconciliation: Watches LoadBalancer services and syncs rules
- ๐ฆ CRD-Based:
EdgeNodecustom resource for declarative edge management
The Edge Node VPS must be provisioned with the following:
- OS: Linux (Debian 12+ recommended)
- Networking:
nftables(enabled),WireGuard - Firewall: UFW MUST BE DISABLED. The controller manages
nftablesdirectly. - Kernel: Forwarding enabled (
net.ipv4.ip_forward=1) - SSH: Key-based access for the controller.
# Install CRDs
kubectl apply -f config/crd/bases/
# Deploy controller
kubectl apply -k config/default/apiVersion: networking.edge-router.io/v1alpha1
kind: EdgeNode
metadata:
name: edge-us-east-01
spec:
managementIP: "10.10.0.2" # WireGuard IP
sshSecretRef: "edge-ssh-key" # Secret with SSH private key
publicIPs:
- address: "203.0.113.10"
interface: "enp1s0"apiVersion: v1
kind: Service
metadata:
name: my-app
annotations:
edge-router.io/edge-routed: "true"
spec:
type: LoadBalancer
ports:
- port: 8080To expose ALL LoadBalancer services within a namespace automatically:
apiVersion: v1
kind: Namespace
metadata:
name: tenant-a
annotations:
edge-router.io/edge-routed: "true"The controller will:
- Detect the internal VIP assigned by MetalLB
- Allocate an available public IP from an EdgeNode
- SSH to the edge and apply nftables rules
- Update the Service status with the public IP
| Environment Variable | Description | Default |
|---|---|---|
SSH_TIMEOUT |
SSH connection timeout | 10s |
RECONCILE_INTERVAL |
Forced reconcile interval | 5m |
# Prerequisites
go 1.25+
kubebuilder 3.x
# Run locally
make run
# Run tests
make test
# Build image
make docker-build IMG=your-registry/kube-edge-router:tagThe Makefile automatically injects the git version into the binary:
- Release: Uses the git tag (e.g.,
v0.3.2). - Development: Uses the tag + commit hash + dirty status (e.g.,
v0.3.2-4-g9c5a1b-dirty).
To override the version manually:
make build VERSION=custom-v1.0.0This project follows Hexagonal Architecture. See AGENTS.md for details.
MIT License - see LICENSE for details.