Overview
WireZTNA consists of three main components connected by WireGuard tunnels:
┌─────────┐ WireGuard ┌──────────┐ WireGuard ┌───────────┐
│ Client │◄─────(overlay)────────►│ Broker │◄────(per-pub ns)───►│ Publisher │
│10.200.x.x│ PSK session │10.200.0.1│ │ LAN access│
└─────────┘ └──────────┘ └───────────┘
│
Control Plane
(API + Web UI)
Policies · DNS · Flows
| Component | Role | Where it runs |
|---|---|---|
| Client | End-user device. Establishes WireGuard tunnel to broker. | macOS, Windows, Linux, iOS, Android |
| Broker | Central hub. Routes traffic, enforces policies, manages sessions. | Managed cloud (EU) |
| Publisher | Network connector. Exposes private CIDRs to authorized clients. | Client's network (any Linux host) |
Access Model
WireZTNA uses a hierarchical permission model:
User ──(member of)──► Group ──(access to)──► Publisher ──(exposes)──► CIDRs + Apps
│
├─ exposed_cidrs: ["10.50.0.0/16"]
├─ published_apps: [{target, port, protocol}]
└─ dns_zones: ["internal.company.com"]
- A user can only reach CIDRs/apps of publishers assigned to their groups
- Access is enforced at the kernel level (nftables) — not just application-layer
- Published apps allow port-specific rules (e.g., only TCP 5432 to a database)
- DNS zones enable split DNS — internal names resolve only through the tunnel
Traffic Flow
When a client sends a packet to a private resource (e.g., 10.50.1.100:5432):
- Client → Broker: Packet enters the WireGuard tunnel (
wg-clientsinterface on broker). Source IP is the client's overlay address (10.200.x.x). - nftables mangle: Broker matches the source IP and destination CIDR against policies. Marks the packet with the correct publisher's
fwmark. - Policy routing: Linux policy routing (
ip rule fwmark N → table 10N) sends the marked packet to the correct veth pair. - Network namespace: Packet enters the publisher's isolated network namespace via the veth bridge.
- Broker → Publisher: Inside the namespace, a dedicated WireGuard tunnel forwards the packet to the publisher.
- Publisher → LAN: The publisher delivers the packet to the real destination on the private network.
- Return path: Reply follows the same path in reverse (tracked by conntrack).
Broker Internals
Network Namespaces
Each publisher gets an isolated Linux network namespace on the broker. This provides:
- Isolation: Publishers cannot see each other's traffic
- Independent routing: Each namespace has its own routing table and WireGuard interface
- Security: A compromised publisher tunnel cannot affect other publishers
Host namespace (broker)
├── wg-clients (all client peers, overlay 10.200.0.0/16)
├── veth-pub1-host ◄──► veth-pub1-ns (namespace: ns-publisher1)
│ └── wg-pub1 (tunnel to publisher-1)
├── veth-pub2-host ◄──► veth-pub2-ns (namespace: ns-publisher2)
│ └── wg-pub2 (tunnel to publisher-2)
└── nftables inet wireztna
├── mangle: mark packets by client→publisher mapping
└── forward: allow/deny based on mark + destination
Reconciliation Loop
The broker agent runs a reconciliation loop every 10–15 seconds:
- Fetches desired state from the Control Plane API (users, groups, publishers, sessions)
- Compares with current kernel state (WG peers, nftables rules, namespaces)
- Converges: adds/removes peers, updates firewall rules, creates/destroys namespaces
This means changes in the admin panel (new user, group change, publisher toggle) take effect within 10–15 seconds automatically.
Session and PSK Management
Each client session has an ephemeral WireGuard Preshared Key (PSK):
- Generated on session creation (login or renew)
- Applied to the client's WG peer on the broker
- Expires after a configurable TTL (default 8 hours)
- When expired, the WG handshake fails → client must renew
- Provides forward secrecy: even if a long-term key is compromised, past sessions remain secure
Split DNS
WireZTNA includes a per-client DNS proxy running on the broker overlay IP (10.200.0.1:53):
- Each client only resolves zones assigned to their accessible publishers
- Queries for internal zones (e.g.,
*.internal.company.com) are forwarded through the publisher's namespace to the client's private DNS server - All other DNS queries use the user's normal system resolver (split DNS)
- DNS routing hints: when a name resolves through a specific publisher, a /32 nftables rule ensures traffic to that IP goes through the correct publisher
Security Boundaries
| Layer | Enforcement | Scope |
|---|---|---|
| WireGuard tunnel | Encryption (ChaCha20-Poly1305) | All traffic in transit |
| PSK session | Forward secrecy + session expiry | Per-client, per-session |
| nftables mangle | Packet marking by policy | Client → publisher routing |
| nftables forward | Allow/deny by CIDR + port | Per-client, per-resource |
| Network namespace | Kernel-level isolation | Per-publisher |
| Policy routing | fwmark → routing table | Per-publisher |
An unauthorized packet (wrong client, wrong destination, expired session) is dropped at the kernel level before it ever reaches userspace or the publisher tunnel.
No Single Point of Decryption
The broker routes encrypted WireGuard packets between peers — it does not terminate or decrypt traffic payloads. The broker holds only public keys and session metadata. Private keys are generated on-device and never leave the client or publisher.
For a deeper look at our cryptographic stack, see the Security page.