lex-node
Node identity and cluster management for LegionIO. Handles heartbeat broadcasting, dynamic configuration distribution, cluster secret exchange, Vault token management, and RSA public key distribution between nodes.
Version: 0.3.2
This is a core LEX installed by default with LegionIO.
Installation
Installed automatically as a dependency of legionio. To disable:
{
"extensions": {
"node": {
"enabled": false
}
}
}
Runners
Beat
Periodic heartbeat broadcast to the cluster.
beat(status:)- Publishes a heartbeat message with the node hostname, PID, timestamp, and status. Interval is controlled by thebeat_intervalsetting.
Crypt
RSA keypair and cluster secret exchange.
push_public_key- Broadcasts this node's RSA public key to all peersupdate_public_key(name:, public_key:)- Stores a received public key in cluster settingsdelete_public_key(name:)- Removes a stored public key from cluster settingsrequest_public_keys- Broadcasts a request for all nodes to send their public keyspush_cluster_secret(public_key:, queue_name:)- Encrypts the cluster secret with a peer's RSA public key and delivers it to their queuerequest_cluster_secret- Requests the cluster secret from peersreceive_cluster_secret(message:)- Decrypts and stores the cluster secret received from a peer
Node
Dynamic configuration distribution and node management.
message(**hash)- Merges arbitrary key/value pairs intoLegion::Settingsat runtimeupdate_settings(settings:, restart: false)- Merges a settings hash intoLegion::Settings; optionally restarts Legion. Publishes anUpdateResultmessage on completion.update_gem(extension:, version: nil, reload: true)- Installs or upgrades a LEX gem viaGem.install, then reloads Legion. Publishes anUpdateResultmessage on completion.push_public_key- Broadcasts this node's RSA public key (raw string form)update_public_key(name:, public_key:)- Stores a received public key in cluster settingspush_cluster_secret(public_key:, queue_name:)- Encrypts and delivers the cluster secret to a peerreceive_cluster_secret(message:)- Decrypts and stores the received cluster secretreceive_vault_token(message:, routing_key:, public_key:)- Delegates to the Vault runner
Vault
Vault token lifecycle management.
request_token- Checks if Vault is enabled but not connected, then callsrequest_vault_tokenrequest_vault_token- Broadcasts a request for a Vault token from peersreceive_vault_token(message:)- Decrypts the received Vault token, stores it, and callsLegion::Crypt.connect_vaultpush_vault_token(public_key:, node_name:)- Encrypts the local Vault token with a peer's RSA public key and delivers it to their queue
How It Works
Each node periodically calls beat to broadcast its presence. On startup, nodes exchange RSA public keys, then use them to securely distribute the cluster shared secret (AES encryption key) and Vault tokens - all encrypted peer-to-peer so no secrets traverse the bus in plaintext.
Dynamic config changes (update_settings) and gem upgrades (update_gem) can be pushed to individual nodes or broadcast to all nodes at runtime. Both operations publish an UpdateResult message to node.<name>.update_result so the outcome can be observed cluster-wide.
Cluster Control Settings
Cluster-control broadcasts are configurable under extensions.node.cluster_control. By default, auth mode is auto: messages are signed and verified when a shared secret is configured, and unsigned messages are allowed when no secret exists for simpler local or homelab deployments.
{
"extensions": {
"node": {
"cluster_control": {
"auth": {
"mode": "auto",
"timestamp_skew_seconds": 300,
"nonce_bytes": 16
},
"queue": {
"durable": true,
"exclusive": false,
"auto_delete": false,
"queue_type": "classic",
"expires_ms": 604800000,
"message_ttl_ms": 86400000,
"max_length": 1000
}
}
}
}
}
Set auth.mode to required to force HMAC signatures, or disabled to run without cluster-control signatures even when a shared secret is present.
Transport
- Exchange:
node(topic exchange) - Queues:
node.<name>(node-specific, exclusive, auto-delete),crypt,vault,health - Messages: Beat, PublicKey, RequestPublicKeys, PushClusterSecret, RequestClusterSecret, RequestVaultToken, PushVaultToken, UpdateResult
Requirements
- Ruby >= 3.4
- LegionIO framework
License
MIT