Mesh security Packetman saysPacketman here. The mesh is how every DataStun agent measures the path to every other agent in your tenant. For those measurements to mean anything, the probe an agent receives has to actually be from another agent in your tenant — not from a scanner, not from an attacker, not from someone else's fleet. This page is how we make that true. Per-tenant key, derived pair keys, HMAC on every packet, monotonic nonces, five-second window. Anything that fails the check gets dropped silently — no error message for an attacker to learn from.

How DataStun agents authenticate every probe they send each other on the measurement fabric — in five steps, with diagrams.

Audience: network engineers and security architects who want to understand the mechanism before deploying. If you just want to use the mesh, the /mesh-diagnostics page is the right starting point.

Contents

1. Why authenticate at all 2. The five-step flow 3. Pair-key derivation 4. The probe wire format 5. Four checks — or silent drop 6. Limits & caveats

1. Why authenticate at all

Two things go wrong if you don’t. Spoofed responses skew measurements — if anyone on the internet can answer an agent’s probe, the throughput and latency numbers you see aren’t for the path you think you’re measuring. Unauthenticated punch-hints are a reflection vector — an attacker who can send to the agent’s mesh port can cause it to send a burst at a target of the attacker’s choice. Neither is acceptable in a measurement fabric.

The fix is to bind every probe to a key only the two endpoints share, and to drop anything that doesn’t prove possession of that key. The rest of this page is how that works.

2. The five-step flow

From key issuance through to a verified round-trip:

ten (tenant platform) postgres: control.tenants mesh_root_key bytea — 32 bytes, per tenant 1 heartbeat (TLS, cf-tunnel) response carries mesh_root_key (base64) 2 Agent A stores key 0600 on disk <StateDir>/mesh-root-key (never in tenant.json — 0644) Agent B stores key 0600 on disk same tenant ⇒ same root different tenant ⇒ different root pair_key = HKDF-SHA256(root, info) info = "dt-mesh-v1" | tenant_id | min(A,B) | max(A,B) 3 v1 probe — payload + sender_id + nonce + HMAC-SHA256[:16] 4 verified — same shape echoed back with fresh nonce + fresh HMAC 5
End-to-end flow. The key never leaves the TLS-encrypted heartbeat channel until it lands on the agent’s disk at mode 0600. The two agents independently derive the same pair key — no key exchange between them — and from then on every probe and every reply carries an HMAC that proves the sender knows that pair key.
Step 1

Key issuance. A 32-byte random key is generated per tenant at signup. Different tenants get different keys, always.

Step 2

Key delivery. ten returns the key in every heartbeat response. TLS in flight; 0600 file at rest on the agent.

Step 3

Pair-key derivation. Each agent pair derives a unique key from the tenant root plus both agent IDs. No key exchange needed.

Step 4

Probe sent. Probe payload travels with an 8-byte nonce, a sender_id, and a 16-byte HMAC-SHA256 trailer.

Step 5

Verify & reply. The receiver runs four checks (next section). Pass → reply same shape. Fail → silent drop.

3. Pair-key derivation — why no key exchange

Two agents in the same tenant need a shared secret to authenticate probes between them — but having them negotiate one over the wire would be both fragile and a new attack surface. So we use a key derivation function: given the same inputs, both sides compute the same answer without ever talking to each other about it.

Agent A knows: root, tenant_id, A, B Agent B knows: root, tenant_id, A, B HKDF-SHA256 ikm = root · salt = ∅ info = "dt-mesh-v1" | tenant_id | min(A,B) | max(A,B) pair_key same on both sides, never transmitted
Same inputs, same output, no exchange. The agent IDs are sorted lexically — min(A,B) | max(A,B) — so A→B and B→A produce the same key. The tenant ID is in the formula, so the same root key in two different tenants — which can’t happen today, but defense in depth — would still produce different pair keys per tenant. Rotation: change the root, every pair key changes on the next derivation.

4. The probe wire format

Every authenticated probe is the same byte layout. The HMAC covers everything except the HMAC itself, so an attacker can’t flip a field after the fact without invalidating the trailer.

magic 4 ver 1 type 1 sender_id 8 nonce 8 probeID 4 sendTS_us 8 payload N HMAC-SHA256[:16] 16 covered by the HMAC — type swap, version downgrade, nonce rewrite, payload tamper all caught header version + type who freshness probe identity + timestamp measurement bytes authenticator network constant v0 / v1 sha256(agent_id)[:8] monotonic ±5s window e.g. punch-hint target truncated to 16 bytes
Annotated byte layout. The HMAC is computed over a canonical input — not over a copy of the wire bytes — so an attacker who flips the version byte and recomputes everything except the trailer still won’t produce a valid MAC. Every field that could be abused is covered: type so a request can’t be served as a response, version so v1 can’t be downgraded to v0, payload so a punch-hint target can’t be rewritten in flight.

5. Four checks — or silent drop

Every inbound v1 probe runs the same four checks. All four must pass; any failure drops the packet with no response and no log line above debug. Off-path attackers, port scanners, and stale binaries from other tenants all hit the same wall — no error message for them to learn from.

1. Pair key exists

The receiver looks up sender_id in its derived pair-key cache. No key for this sender — same tenant or otherwise — means no shared secret to verify against. Drop.

2. HMAC verifies

HMAC-SHA256 over the canonical input must match the trailer using the pair key. Wrong key, flipped bit, truncated packet — all fail here. Drop.

3. Timestamp within ±5s

The sendTS_us field must be within five seconds of the receiver’s clock. A captured probe replayed an hour later fails this. Drop.

4. Nonce strictly increases

Per-sender high-water mark. A replayed nonce inside the five-second window — the only window where check 3 still passes — fails here. Drop.

Three categories of probe also drop unconditionally, even before the four checks:

6. Limits & caveats

Honest accounting of what this design does and doesn’t cover. We’d rather you know.

Threat model in one sentence

An off-path attacker who can send UDP to an agent’s mesh port should be unable to skew its measurements or weaponize it as a reflector. That’s what the mechanism on this page is for. It is not a defense against a compromised endpoint, and not a substitute for endpoint security.

See also: /mesh-diagnostics for the buyer-facing overview · /diagnostics for the mesh testing fabric and Advanced Packet Diagnostics · /security lane hub.