Linking an Edge Node to a Remote Router
Link an edge node to a remote Bondy router with a bridge relay: accept bridges on the remote router, configure the bridge on the edge, verify the link, and take it down again.
In this guide the remote router is the Bondy deployment the edge connects to, and the edge is the node that runs the bridge.
Prerequisites:
- A remote router and an edge node, each with admin access to its master realm (
com.leapsight.bondy). - The realm to share, already provisioned on the remote router. The edge does not need it: the bridge copies the realm's security model from the remote router when it connects.
- OpenSSL 3, to generate the edge's key pair.
- A server certificate for the remote router's bridge listener, and the CA certificate that signed it.
For what a bridge carries and why it is a separate mechanism from clustering, read Bondy Edge (Bridge Relay) first.
1. Create the edge's identity
The edge authenticates to the remote router with WAMP cryptosign, so it needs an Ed25519 key pair. Generate one, and print the private seed and the public key as hexadecimal:
openssl genpkey -algorithm ed25519 -out edge-key.pem
openssl pkey -in edge-key.pem -outform DER | tail -c 32 | xxd -p -c 32
openssl pkey -in edge-key.pem -pubout -outform DER | tail -c 32 | xxd -p -c 32The first printed line is the private seed, the second the public key. Each is 64 hexadecimal characters. Keep the seed secret; the edge reads it at runtime (step 4).
2. Provision the identity on the remote router
In the realm to share, on the remote router:
- Make sure the realm's
authmethodsincludecryptosign. - Create a user for the edge, with the public key from step 1 in its
authorized_keys. - Add a source that allows
cryptosignfor that user from the edge's address.
Authenticating Clients walks through all three for a key-based user.
The bridge session needs no grants of its own to register proxies for the edge's procedures or to republish the edge's events. The local clients on each side still need theirs, and the edge enforces them with the users, groups and grants it copies from the remote router.
The copy does not include group membership: on the edge, every copied user belongs to no group. A client on the edge therefore has only the grants made to its user directly. Grant the permissions that edge clients need to their users, not to a group they belong to.
The copy does not include passwords either. A copied user cannot log in to the edge with a password-based method. On the remote router, add a public key to the authorized_keys of each user that connects to the edge. That user then authenticates on the edge with cryptosign.
3. Accept bridges on the remote router
Declare a listener whose protocol is bridge_relay in the remote router's bondy.conf:
listeners.bridge_relay_tls.transport = tls
listeners.bridge_relay_tls.protocol = bridge_relay
listeners.bridge_relay_tls.port = 18093
listeners.bridge_relay_tls.tls.certfile = /etc/bondy/ssl/bridge/keycert.pem
listeners.bridge_relay_tls.tls.keyfile = /etc/bondy/ssl/bridge/key.pem
listeners.bridge_relay_tls.tls.cacertfile = /etc/bondy/ssl/bridge/cacert.pemRestart the remote router. Its log shows description="Started listener" … listener=bridge_relay_tls.
Variations:
Require a client certificate from the edge (mTLS). Add these two keys, and give the edge a certificate signed by the CA in
tls.cacertfile(step 4):listeners.bridge_relay_tls.tls.verify = verify_peer listeners.bridge_relay_tls.tls.fail_if_no_peer_cert = onAn edge without a certificate then fails the TLS handshake with
certificate_requiredand retries.Plain TCP. Use
transport = tcpand drop thetls.*keys only when the edge reaches the remote router over a network you already trust. The challenge-response authentication does not send the private key, but everything after it, including the realm sync, travels unencrypted.Authentication deadline.
listeners.$name.auth_timeout(default5s) is how long a connected edge has to authenticate before the remote router drops the connection.
A bridge_relay listener cannot use the uds transport and takes no services key.
4. Configure the bridge on the edge
Add the bridge to the edge's bondy.conf. The name after bridge. (here core) is your choice; it is the name you pass to the bondy.router.bridge.* procedures later.
bridge.core = on
bridge.core.endpoint = 203.0.113.10:18093
bridge.core.transport = tls
bridge.core.tls.verify = verify_peer
bridge.core.tls.cacertfile = /etc/bondy/ssl/bridge/cacert.pem
bridge.core.tls.versions = 1.3
bridge.core.realm.1.uri = com.example.factory
bridge.core.realm.1.authid = edge-plant-7
bridge.core.realm.1.cryptosign.pubkey = <public key from step 1>
bridge.core.realm.1.cryptosign.privkey_env_var = BONDY_EDGE_PRIVKEY
bridge.core.realm.1.topic.1 = com.example.factory.telemetry. prefix outThen start the edge with the private seed from step 1 in the variable named by privkey_env_var:
BONDY_EDGE_PRIVKEY=<private seed from step 1> bin/bondy-connect foregroundHow you set that variable depends on how you run Bondy: a systemd EnvironmentFile, a Kubernetes Secret mapped to an environment variable, or your secrets manager's injector.
The settings that need a decision:
Endpoint and certificate. Bondy resolves the host in
bridge.$name.endpointto an IP address once, when it loadsbondy.conf. A name that does not resolve stops the node from starting, and a DNS change takes effect only after a restart. Withtls.verify = verify_peerthe edge then checks the remote router's certificate against that IP address, not the host name, so the certificate has to list the address as an IPsubjectAltName. A certificate that names only the host fails withhostname_check_failed, andbridge.$name.tls.hostname_verification = nonedoes not change that.Client certificate. If the listener requires one (step 3), add
bridge.$name.tls.certfileandbridge.$name.tls.keyfile. The bridge sends no client certificate unless both are set.Private key.
cryptosign.privkey_env_varhas to name a variable holding the 32-byte Ed25519 seed as 64 hexadecimal characters. A 64-byte value (seed and public key together, 128 characters) fails withCouldn't get EDDSA private key. Of the other signing keys,cryptosign.procedureis not implemented and the bridge fails withnot_implemented, andcryptosign.privkeyputs the key inbondy.conf, which is for testing only.One realm per bridge. A bridge opens a session for one realm mapping only, even when several
realm.$identries are configured. To share several realms, configure one bridge per realm.Network timeout.
bridge.$name.network_timeoutdefaults to30s. The bridge decides the network is down when the host has no non-loopback IPv4 interface; on a host that has none, set it toinfinity.One node. Every node that loads this
bondy.confstarts its own copy of the bridge. In a clustered edge, declare the bridge on one node only. See Running a bridge in a cluster.
What crosses the bridge
| Traffic | Crosses? |
|---|---|
Events published on the edge to a topic matched by a topic.$tid … out entry | Yes, to subscribers on the remote router |
| Calls on the remote router to procedures registered on the edge | Yes, for registrations that exist when the bridge connects and for registrations added later |
| Events published on the remote router, to subscribers on the edge | No |
| Calls made on the edge to procedures registered on the remote router | No |
The procedure.$pid entries are not applied: the bridge proxies every registration on the realm, whether or not one matches. A topic.$tid entry with direction in logs a warning and does nothing.
These keys are accepted but have no effect in this release:
bridge.$name.max_frame_size: the bridge does not limit frame size.bridge.$name.parallelism: the bridge opens one connection.bridge.forward.ackandbridge.forward.retransmission: no part of Bondy reads them.
5. Verify the link
The edge logs three lines as the bridge comes up:
… description="Starting bridge-relay client" … endpoint={{203,0,113,10},18093} …
… description="Established connection with remote router." id=core …
… description="AAE sync finished" id=core …AAE sync finished means the edge authenticated and copied the realm's security model. A bridge that connects but never logs it did not authenticate: check the key pair, the user's authorized_keys, and the source on the remote router.
Then ask the edge for its bridges' status, from a session on its master realm as a member of bondy.administrators. With the Wampy command-line client:
npx wampy call bondy.router.bridge.status \
--url ws://localhost:18080/ws --realm com.leapsight.bondy \
--authid admin --secret <admin password>The result maps each bridge name to its status:
{ "core": { "status": "running" } }bondy.router.bridge.status is the procedure to use for a bridge declared in bondy.conf. For such a bridge, bondy.router.bridge.get and bondy.router.bridge.list fail in this release with wamp.error.invalid_argument.
6. Stop or remove the bridge
To stop the bridge without forgetting it, call bondy.router.bridge.stop with its name. The remote router drops the routes it held for the edge's procedures, and calls to them return wamp.error.no_such_procedure. bondy.router.bridge.start with the same name brings it back.
To remove it:
- Call
bondy.router.bridge.removewith the name. Bondy stops a running bridge before it removes it. The call returns an empty result on success, and also for a name the edge does not know, so a typo is not reported. - Delete the bridge's keys from the edge's
bondy.conf, or setbridge.<name> = off. Bondy reloads the bridges declared inbondy.confevery time the node starts, so a bridge removed only at runtime comes back on the next restart.
Result
The edge holds one TLS connection to the remote router, authenticated with its own key. Events it publishes under the shared topics reach the remote router's subscribers, and the remote router routes calls to the procedures the edge serves.
See also
- Bridge Relay Configuration Reference — every
bridge.*key. - Bridge Relay WAMP API Reference — the
bondy.router.bridge.*procedures. - Configuring Network Listeners — TLS material and mTLS on any listener.
- Connecting an Edge Node — the same link on one machine.