Platform integrations
Whisper sits beside the OT stack you already run and anchors exactly one thing: a routable, verifiable identity at the asset/IP boundary. That's the layer where a reachable socket on a flat network looks identical to the real controller.
Everything below is a proposed integration pattern: our design, not a vendor endorsement. Every one is written the same way: Whisper complements the mechanism you have; it never replaces it. We do not touch Modbus, DNP3 or PROFINET on the wire, we do not sit in a PLC's command path, and we never join your OPC UA TrustList or terminate a SecureChannel. Those live on the fieldbus and inside the session, and they are already someone's job. Whisper's job is the network identity of whatever speaks across a conduit: a PLC, an RTU, an IED, an HMI, an engineering workstation, a historian, or a vendor's remote-access endpoint. It's expressed as an IPv6 /128 that DNSSEC, DANE and RDAP can prove and one call can revoke. No operator is named here as a breach victim; every pattern is described at the class level.
One spine under all six. Each integration below reuses the same shipped primitive: a deterministic /128 derived from a device's public key plus its native identifier (an OPC UA ApplicationUri, an 802.1AR IDevID serial, or a bare nameplate serial), passed as device_id (Asset & PLC identity), published with a DANE pin and an RDAP record, verifiable by anyone with no account. The integrations differ only in where in your stack that identity is bound and checked.
Anchor the boundary, not the bus
An OT environment carries several trust mechanisms, each correct for its own layer. The mistake is to imagine a new identity system has to displace one of them. It doesn't. Whisper is deliberately confined to the one place none of them cover: the moment a network endpoint claims to be a particular asset (a controller, a workstation, a sanctioned data consumer) and the receiver has only a reachable IP, a VLAN membership, or a private-CA certificate to go on.
| Layer | Owner / mechanism | Whisper's role |
|---|---|---|
| In-plant fieldbus (Modbus / DNP3 / PROFINET) | link trust; DNP3-SA pre-shared keys where present | none: never on the wire or in the command path |
| OPC UA session security | app-instance cert + local TrustList (GDS / CertificateManager) | complements: publishes the ApplicationUri↔cert binding; TrustList stays |
| Device onboarding | 802.1AR IDevID + BRSKI voucher | complements: derives the /128 from the IDevID key; private half sealed |
| Asset ↔ network (IP) | VLAN + firewall: trust = IP + topology | anchors here: a publicly verifiable /128 the asset is, provable without your CA |
SecureChannel, or the PLC's command path.Read the last row as the whole thesis: at the IP boundary, identity today is a claim, a source address on a segment. Whisper turns it into a network fact: the address itself, forward-confirmed in DNS, pinned in DANE, registered in RDAP, and revocable in one call.
OPC UA: publish the ApplicationUri↔certificate binding
OPC UA already does key-derived naming. Every application instance carries a globally-unique ApplicationUri, and OPC UA Part 6 §6.2.2 requires the application-instance certificate SAN to hold exactly one uniformResourceIdentifier equal to it. The stack enforces that binding at OpenSecureChannel / CreateSession: present a certificate whose URI ≠ the ApplicationUri and the session fails with BadCertificateUriInvalid. So the identity↔key binding is already cryptographic; it is just trapped in a local, per-site TrustList. OPC UA Part 2 §8.1.2 explicitly discourages public CAs so that no external party decides which applications are trusted, which is precisely why a peer operator, an integrator, or a regulator cannot verify your asset without being enrolled in your TrustList; revocation is a local CRL edit no one outside can see.
The integration is to publish that same binding under the public DNSSEC chain, adding nothing to OPC UA: pin the app-instance certificate's leaf key as a DANE-EE TLSA 3 1 1 under a DNSSEC-signed name for the asset. Now the ApplicationUri↔certificate binding OPC UA enforces privately becomes publicly, cross-org verifiable: no commercial CA, no change to your endpoints. The GDS / CertificateManager keeps doing onboarding, renewal, TrustList and CRL exactly as today.
# Pin the OPC UA endpoint's leaf key in DNSSEC-signed DNS. The binary port is 4840.
# No shared CA: a peer verifies the exact leaf, not a bundle you both have to trust.
dig +dnssec TLSA _4840._tcp.opcua-plc7.asset.<tenant>.agents.whisper.online
;; flags: qr rd ra ad ← ad = DNSSEC-authenticated
;; _4840._tcp....agents.whisper.online. 300 IN TLSA 3 1 1 b653a4ef…fcb82d1d
# …and the whole binding (DNSSEC + DANE + RDAP) checked with no account, no TrustList.
whisper verify --trustless opcua-plc7.asset.<tenant>.agents.whisper.online
✓ DANE-EE (TLSA 3 1 1) leaf matches the asset's OPC UA application-instance cert key
✓ DNSSEC chain valid to the IANA root · RDAP: AS219419 · 2a04:2a01::/32
Complements the GDS / local TrustList, does not replace it. Whisper never joins your TrustList, never terminates a SecureChannel, and issues no application-instance certificate. It publishes the ApplicationUri↔key binding you already enforce, so anyone can confirm it from the DNSSEC root. See DANE & TLSA for the byte-for-byte record.
MUD (RFC 8520): the device's declaration, made enforceable
This is the sharpest OT fit. Under MUD (RFC 8520) a device already declares what it should talk to: a manufacturer-signed manifest of from-device-policy and to-device-policy ACLs, emitted over DHCP (options 161/112), an LLDP vendor TLV (type 127), or the id-pe-mud-url X.509 extension co-located with an 802.1AR IDevID. MUD's structural weakness: the manifest is only a hint, fetched from the manufacturer's domain and enforced by a local MUD manager at the nearest switch. A compromised device still reaches anything the local admin didn't block, and the binding is a spoofable URL, not a verifiable identity.
The integration binds that declaration to the asset's verifiable /128 and enforces it as default-deny egress governance where traffic actually leaves: cross-org, and checkable by anyone. Egress is source-bound to the asset's /128, so the manufacturer's declaration of intent becomes a cryptographic, enforced default rather than a suggestion at the nearest hop.
# The device declares its egress in MUD; Whisper enforces it as default-deny at the /128.
# This PLC may reach ONLY its historian, its controller, and the vendor OTA endpoint.
whisper policy set --agent 2a04:2a01:7a2::4840 \
--default deny --allow historian.example-plant.example:4840,controller.line2.local,ota.vendor.example
# Per-asset firewall + a traffic budget + kill-switch: keyed to a verifiable identity, not a VLAN tag.
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:7a2::4840', deny:['0.0.0.0/0','::/0'], allow:['historian.example-plant.example:4840']}})
CALL whisper.agents({op:'budget', args:{agent:'2a04:2a01:7a2::4840', max_mb_per_day:50}})
The honest edge. Egress governance changes who may reach and speak to an asset, and constrains what a governed asset may reach. It contains C2, exfil and lateral movement across the convergence bridge and the remote-access surface. It does not add authentication to Modbus, DNP3 or PROFINET on the wire, and it does not stop a purely-internal write by an attacker who already holds an OT-segment foothold: closing that last inch needs identity enforced in the command path, at the PLC, a protocol-aware broker-gateway, or the EWS. We say so before your assessor does.
Complements MUD, does not replace it. The manufacturer keeps authoring the manifest; Whisper pins it to a globally-verifiable identity and enforces it where traffic egresses. The full policy surface is on Egress governance; a runnable enforce-a-manifest recipe is on MUD egress · verify · attribute.
IEC 62443 zones & conduits: a conduit at the asset, not the VLAN
IEC 62443-3-3 makes segmentation mandatory (SR 5.1) and organises the plant into zones joined by conduits (the cross-trust channels between them, exactly where a portable, verifiable identity matters); 62443-4-2 CR 1.2 mandates unique device identification & authentication for every component. A per-/128 egress allow-list is a conduit at asset granularity (a micro-segment at the asset, not the VLAN), keyed to a cryptographically verifiable identity rather than an IP or a VLAN tag. Compromise one asset and the blast radius is that asset, not the flat segment.
/128 conduit is a micro-segment at each asset, keyed to a verifiable identity and enforced with op:firewall, additive to your 62443 zones, not a replacement for them.# A conduit at the asset: this IED reaches ONLY its historian (OPC UA :4840) and controller (DNP3 :20000).
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:7a2::4840',
deny:['0.0.0.0/0','::/0'],
allow:['historian.example-plant.example:4840','controller.line2.local:20000']}})
And nothing is issued in the dark: every mint and every revoke lands in a public, append-only Merkle transparency log (Ed25519-signed and anchored to Bitcoin via OpenTimestamps) that you and your assessor can replay as a non-repudiable issuance/revocation trail. (Honest status: tamper-evident and Bitcoin-anchored today; independent third-party witnessing is the next step, and the log already speaks the witness protocol.)
Complements your 62443 zones & conduits, does not replace them. Whisper supplies the unique network identifier (the CR 1.2 identity half) and the identity-keyed conduit (SR 5.1), additive to your SL program. The asset still does its own mutual-auth handshake; we make identity globally verifiable and revocable, we do not claim end-to-end CR 1.2 authentication. The full mapping is on IEC 62443 · EU CRA · TSA.
IEEE 802.1AR IDevID & BRSKI: the birth certificate, onto the network
This is the shipped spine the other five build on. An 802.1AR IDevID (or a TPM or in-vehicle-grade secure element) is a device's hardware birth certificate: a key generated on the silicon whose private half never leaves it. BRSKI (RFC 8995) turns that IDevID into an operator-issued LDevID through a pledge → registrar → MASA voucher (RFC 8366) exchange. Whisper derives the asset's /128 from that device's public SubjectPublicKeyInfo plus its serial (or ApplicationUri), bridging the identity plane onto the network plane at the same onboarding moment. The private key stays sealed; only the public SPKI is ever an input.
The derivation is deterministic and tenant-bound: the same key and identifier always yield the same /128, the mapping is unlinkable to outsiders so a fleet can't be enumerated from its addresses, and the result is DNSSEC-anchored, DANE-EE 3 1 1 pinned, and RDAP-registered the instant it's minted.
# Provision the /128 for an asset from the key it already holds at onboarding + its native id.
# identity_public_key is the device's PUBLIC SPKI (base64): the IDevID / TPM key.
CALL whisper.agents({op:'connect', args:{
tier:'wireguard',
identity_public_key:'<base64 SPKI of the IDevID / TPM key>',
device_id:'urn:example-plant:line2:PLC7:server' // ApplicationUri, IDevID serial or nameplate serial
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error
Send it with stock tools. The control plane is one HTTP endpoint, and the heredoc keeps the single-quoted Cypher literals intact so it runs as-is:
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H 'content-type: application/json' \
--data @- <<'JSON'
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard', identity_public_key:'<base64 SPKI>', device_id:'urn:example-plant:line2:PLC7:server'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
{ "ok": true, "status": "created",
"result": { "address": "2a04:2a01:7a2::4840",
"fqdn": "opcua-plc7.asset.<tenant>.agents.whisper.online",
"wireguard": { /* peer, keys, allowed-ips */ } } }
The behaviour is honest and predictable, which is the point:
| Re-provision with… | Result |
|---|---|
the same key + device_id | 200: the same /128 returns (idempotent) |
a different device_id on the same tenant's key | 409: the identity is already bound; no silent rebind |
a non-string device_id | 400: a clear input error, never an opaque 500 |
Tear it down worldwide at DNS-TTL speed with one call. The /128, its PTR, and its DANE pin all go together:
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:7a2::4840'}})
Complements the IDevID / BRSKI, does not replace it. The birth certificate stays exactly where it was born: the private key never leaves the secure element, because Whisper only ever consumes the public SPKI. The full derivation, tenant-unlinkability property and DANE mechanics are on Asset & PLC identity.
OT visibility platforms: consume the inventory, feed the SOC
The OT-visibility platform class (passive discovery, deep OT-protocol inventory, and process-aware anomaly detection) is excellent at exactly what Whisper deliberately does not do. These platforms are allies, not rivals. There are two clean handoffs, and neither asks you to move a single sensor.
- Consume their asset inventory as the
device_idinput. Take an asset a visibility platform has already discovered (itsApplicationUri, IDevID serial, or nameplate serial) and provision its/128. An inferred, appliance-scoped inventory entry becomes a publicly verifiable, DNSSEC/DANE-anchored, RDAP-registered identity anyone outside your SOC can check. - Feed attribution back to the SOC. Behavioral OT monitoring is superb inside the plant, but it stops at the Purdue boundary and the firewall. The attribution graph names the operator behind a rotating remote-access or cloud egress. It's a reproducible, replayable evidence chain your SOC, your PSIRT, and a regulator can replay.
And op:lookups is a reconnaissance tripwire the platforms can't give you: because every asset's name resolves through Whisper's own authoritative DNS and RDAP, you can ask who resolved or RDAP-queried an asset's identity (someone enumerating your plant) before the write lands, not in the post-mortem afterward.
# Consume an asset from your visibility platform's inventory → give it a verifiable /128.
# device_id = whatever native id the inventory already carries (ApplicationUri / IDevID serial / nameplate).
# Feed attribution back to the SOC: name the operator behind a rotating remote-access egress.
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" -H 'content-type: application/json' \
-d '{"query":"CALL whisper.identify(\"45.83.x.x\")"}' | jq .
# → operator clustered across clouds by shared ASN / hosting / cert lineage; remote-access pool collapsed by JA4
# Who has been enumerating this asset's identity: resolving its PTR/AAAA/TLSA or hitting its RDAP object?
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:7a2::4840', window:'24h'}})
Complements OT-visibility platforms, does not replace them. Whisper does no OT-protocol visibility, no asset discovery, and no anomaly detection. That ground stays theirs. We consume their inventory as an identity input and feed cross-org attribution back to their SOC. More on the attribution verbs is in Graph & cognition.
The SIEM feed: Splunk, Sentinel & OpenCTI today; STIX/TAXII next
Identity, egress and attribution evidence should land where your OT SOC already looks. The Splunk connector is shipped & live: a signed, replayable JSON evidence line mapped to CEF / ECS fields, so an asset's own outbound activity (op:logs) and who queried its identity (op:lookups) both stream into your existing dashboards and correlation searches.
The Microsoft Sentinel connector and OpenCTI integration ship today. STIX 2.1 over TAXII is on the roadmap, together with sector-ISAC (E-ISAC / WaterISAC) machine-readable export. We label these honestly so you can plan against them, not around them.
# Shipped & live: the Splunk connector maps a signed, replayable evidence line → CEF / ECS.
# The evidence is the same whether it feeds a dashboard, a correlation search, or an audit.
{ "identity": "2a04:2a01:7a2::4840", "event": "egress.deny",
"dst": "scan.example:502", "policy": "default-deny", "sig": "ed25519:…" }
# → cef: CEF:0|Whisper|OT|1|egress.deny|Egress denied|5|src=2a04:2a01:7a2::4840 dst=scan.example dpt=502
Shipped today vs proposed
Honesty about what runs matters more here than anywhere. The identity primitive and its control plane under every integration are live and provable right now; the integration guides themselves are proposed patterns for wiring that primitive into each platform.
| Building block | Status |
|---|---|
Deterministic /128 from a device's public key + device_id (ApplicationUri / IDevID serial / nameplate) | shipped, live |
Provision via the control plane (op:'connect', WireGuard tier) | shipped, live |
Keyless verify: whisper verify --trustless, /verify-identity, dig -x, RDAP | shipped, live |
MUD-style egress governance: op:policy / op:firewall / op:budget | shipped, live |
Revoke: /128 + PTR + DANE torn down at DNS-TTL speed | shipped, live |
op:lookups (who queried this identity) + the Merkle transparency log | shipped: log is tamper-evident + Bitcoin-anchored, not yet independently witnessed |
Attribution graph over the public API (CALL whisper.identify(…)) | shipped, live |
| The Splunk connector (signed JSON → CEF / ECS) | shipped, live |
A first-class typed --application-uri / --mud CLI flag | proposed: provision via the control-plane call today |
| STIX 2.1 / TAXII · sector-ISAC export | proposed / roadmap |
| The six integration guides on this page (OPC UA, MUD, 62443, 802.1AR/BRSKI, OT-visibility, SIEM) | proposed: our design, not a vendor endorsement |
The --application-uri / --mud CLI flags are not shipped yet. Asset provisioning today goes through the control-plane call in the 802.1AR section above, which is live. The shipped CLI verbs are whisper verify --trustless, whisper create --register, whisper kill --revoke, whisper policy, and whisper logs. See CLI & one-command.
Next
- Asset & PLC identity: the shipped derivation these integrations all build on
- OT-exposure cure: why a reachable socket on a flat network is the whole exploit
- IEC 62443 · EU CRA · TSA: where the identity, egress and attribution evidence lands
- MUD egress · verify · attribute: runnable recipes end to end