← Back to Docs

Architecture

How WireZTNA routes traffic securely from clients to private networks.

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
ComponentRoleWhere it runs
ClientEnd-user device. Establishes WireGuard tunnel to broker.macOS, Windows, Linux, iOS, Android
BrokerCentral hub. Routes traffic, enforces policies, manages sessions.Managed cloud (EU)
PublisherNetwork 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):

  1. Client → Broker: Packet enters the WireGuard tunnel (wg-clients interface on broker). Source IP is the client's overlay address (10.200.x.x).
  2. nftables mangle: Broker matches the source IP and destination CIDR against policies. Marks the packet with the correct publisher's fwmark.
  3. Policy routing: Linux policy routing (ip rule fwmark N → table 10N) sends the marked packet to the correct veth pair.
  4. Network namespace: Packet enters the publisher's isolated network namespace via the veth bridge.
  5. Broker → Publisher: Inside the namespace, a dedicated WireGuard tunnel forwards the packet to the publisher.
  6. Publisher → LAN: The publisher delivers the packet to the real destination on the private network.
  7. 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:

  1. Fetches desired state from the Control Plane API (users, groups, publishers, sessions)
  2. Compares with current kernel state (WG peers, nftables rules, namespaces)
  3. 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

LayerEnforcementScope
WireGuard tunnelEncryption (ChaCha20-Poly1305)All traffic in transit
PSK sessionForward secrecy + session expiryPer-client, per-session
nftables manglePacket marking by policyClient → publisher routing
nftables forwardAllow/deny by CIDR + portPer-client, per-resource
Network namespaceKernel-level isolationPer-publisher
Policy routingfwmark → routing tablePer-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.