Skip to content

Event Broker

Edge Core can publish lifecycle events to a message broker. This is opt-in — Edge Admin connects to whatever broker you point it at via env vars, the broker itself is your responsibility.

Edge Core publishes and forgets — it has no knowledge of consumers. All messages follow the CloudEvents 1.0 spec, with type and corename promoted to broker-native message attributes / headers / partition keys / topics so subscribers can filter without parsing the body.

Adapters

Adapter Protocol family Works against
nats NATS / NATS JetStream Any NATS server. JetStream-enabled servers gain durable log + replay via EVENT_BROKER_NATS_JETSTREAM=true.
kafka Kafka wire protocol Apache Kafka, Redpanda, Confluent Cloud, Aiven, AWS MSK, Azure Event Hubs, Upstash, Redpanda Cloud, etc.
amqp091
(alias: rabbitmq)
AMQP 0-9-1 Any AMQP 0-9-1 broker — RabbitMQ, LavinMQ (single-node or clustered), AmazonMQ for RabbitMQ, CloudAMQP.
redis Redis Pub/Sub Any Redis instance. Fire-and-forget — no durability, no replay.
mqtt MQTT 3.1.1 / 5 Any MQTT 3.1.1 or 5 broker — EMQX, Mosquitto, HiveMQ, AWS IoT Core, Azure Event Grid (MQTT broker mode), VerneMQ, NanoMQ, etc. Publisher CONNECT uses proto_ver: :v4 (3.1.1), the lowest common denominator; v5 brokers downgrade our session transparently.
aws_sns AWS SNS REST API AWS SNS (managed). Publishes to four pre-provisioned domain topics; subscribers filter via subscription filter policies.
google_pubsub Google Cloud Pub/Sub REST API Google Cloud Pub/Sub (managed). Same shape as SNS — four pre-provisioned domain topics, subscription filter expressions on attributes.

Pick whichever adapter matches a broker your stack already runs. There is no recommended default.

Not currently supported, on the table if there's demand: AMQP 1.0 (different wire protocol from AMQP 0-9-1 despite the similar name — covers ActiveMQ, Azure Service Bus, IBM MQ, Solace) and Apache Pulsar. If you have a concrete use case for either, open an issue — adapters are tractable to add and we prioritise based on real user demand.

Quick Start

For self-hosted brokers, this directory ships compose files you can layer onto the cloud stack:

# Self-hosted (one of):
docker compose -f cloud.yml -f ../event_brokers/nats.yml up -d
docker compose -f cloud.yml -f ../event_brokers/redpanda.yml up -d
docker compose -f cloud.yml -f ../event_brokers/kafka.yml up -d
docker compose -f cloud.yml -f ../event_brokers/rabbitmq.yml up -d
docker compose -f cloud.yml -f ../event_brokers/redis.yml up -d
docker compose -f cloud.yml -f ../event_brokers/emqx.yml up -d
docker compose -f cloud.yml -f ../event_brokers/mosquitto.yml up -d

Managed cloud services (AWS SNS, Google Cloud Pub/Sub) have no compose file — provision the topics in your account first (see Managed Cloud Services).

Either way, then enable the adapter via env vars:

EVENT_BROKER_ENABLED=true
EVENT_BROKER_ADAPTER=<one of the adapter ids above>

# ...plus the adapter-specific endpoint / project / region — see Configuration below.
CORE_NAME=prod-us   # optional; included in every event envelope (default: "default")

Configuration

Endpoint env var name carries the shape:

  • _URLS (plural) — adapter accepts a comma-separated cluster list (NATS, Kafka).
  • _URL (singular) — adapter takes a single endpoint (RabbitMQ, Redis, MQTT).
  • Managed services have no endpoint var — region / project + auth locate the service.

NATS

EVENT_BROKER_ADAPTER=nats
EVENT_BROKER_NATS_URLS=nats://host:4222     # comma-separated for cluster; tls:// for public/external brokers
EVENT_BROKER_NATS_JETSTREAM=true            # optional — enable JetStream durable log (default: false)

# Auth — pick one (mutually exclusive, token takes precedence):
EVENT_BROKER_NATS_TOKEN=
EVENT_BROKER_NATS_USERNAME=
EVENT_BROKER_NATS_PASSWORD=
EVENT_BROKER_NATS_NKEY_SEED=                # standalone or paired with JWT
EVENT_BROKER_NATS_JWT=                      # alongside NKEY_SEED

Kafka / Redpanda

EVENT_BROKER_ADAPTER=kafka
EVENT_BROKER_KAFKA_URLS=host:9092           # comma-separated for cluster; no scheme

EVENT_BROKER_KAFKA_USERNAME=                # optional
EVENT_BROKER_KAFKA_PASSWORD=
EVENT_BROKER_KAFKA_SASL_MECHANISM=plain     # plain (default) | scram_sha_256 | scram_sha_512
EVENT_BROKER_KAFKA_SSL=true                 # required for public/external brokers

AMQP 0-9-1 (RabbitMQ-compatible)

EVENT_BROKER_ADAPTER=amqp091                            # alias `rabbitmq` also accepted
EVENT_BROKER_RABBITMQ_URL=amqp://user:pass@host:5672    # embed credentials in URL
EVENT_BROKER_RABBITMQ_SSL=true                          # required for external brokers (CloudAMQP, etc.)

Events publish to a durable topic exchange edge.events with routing key = event type. Works against RabbitMQ, LavinMQ, AmazonMQ for RabbitMQ, CloudAMQP — anything speaking AMQP 0-9-1.

Redis

EVENT_BROKER_ADAPTER=redis
EVENT_BROKER_REDIS_URL=redis://:password@host:6379      # embed credentials in URL; rediss:// for TLS
EVENT_BROKER_REDIS_SSL=true                             # required for external brokers (Redis Cloud, Upstash, etc.)

Channel = event type. Use SUBSCRIBE edge.node.registered for exact match, PSUBSCRIBE edge.* for wildcards. No durability — if no subscriber is connected, the message is gone.

MQTT

EVENT_BROKER_ADAPTER=mqtt
EVENT_BROKER_MQTT_URL=host:1883                         # single host:port; no scheme
EVENT_BROKER_MQTT_QOS=1                                 # 0|1|2 (default 1, at-least-once with broker ACK)

# Auth — pick one mode (mutually exclusive, JWT precedence over username/password):
EVENT_BROKER_MQTT_JWT=                                  # JWT bearer in CONNECT password slot
EVENT_BROKER_MQTT_USERNAME=
EVENT_BROKER_MQTT_PASSWORD=

# TLS:
EVENT_BROKER_MQTT_SSL=true                              # required for external brokers
EVENT_BROKER_MQTT_CACERT_FILE=                          # custom CA bundle / pinning
EVENT_BROKER_MQTT_CLIENT_CERT_FILE=                     # mTLS — requires SSL=true
EVENT_BROKER_MQTT_CLIENT_KEY_FILE=                      # mTLS — requires SSL=true

Topic = event type with . rewritten to / (e.g. edge.node.registerededge/node/registered) so MQTT segment wildcards (+, #) work as expected.

AWS SNS

EVENT_BROKER_ADAPTER=aws_sns
EVENT_BROKER_AWS_SNS_REGION=us-east-1
EVENT_BROKER_AWS_SNS_TOPIC_ARN_PREFIX=arn:aws:sns:us-east-1:123456789012:    # account-scoped ARN prefix

# Auth — standard AWS credential chain (env vars / shared credentials file / instance profile / IRSA):
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_SESSION_TOKEN=                          # optional, when assuming an IAM role via STS

Google Cloud Pub/Sub

EVENT_BROKER_ADAPTER=google_pubsub
EVENT_BROKER_GOOGLE_PUBSUB_PROJECT=my-project-123
EVENT_BROKER_GOOGLE_PUBSUB_TOPIC_ID_PREFIX=                                  # optional, e.g. "edge-prod-"

# Auth — standard GCP credential chain via goth:
GOOGLE_APPLICATION_CREDENTIALS=/etc/gcp/sa.json    # service-account JSON path; unset on GKE/GCE for Workload Identity / metadata server

Self-Hosted Brokers

event_brokers/
├── nats.yml            — NATS (JetStream enabled) + NUI web UI
├── redpanda.yml        — Redpanda + Redpanda Console
├── kafka.yml           — Apache Kafka (KRaft) + Kafka UI
├── rabbitmq.yml        — RabbitMQ + Management UI
├── redis.yml           — Redis (no UI)
├── emqx.yml            — EMQX (MQTT) + built-in dashboard
├── mosquitto.yml       — Mosquitto (MQTT, minimal, no UI)
└── config/             — server configs (TLS / cluster blocks commented out by default)

These files are convenience scaffolding for new deployments. If you already run a broker matching one of the protocol families above, skip the compose file and point the relevant EVENT_BROKER_*_URL(S) directly at it.

Reusing the bundled Netmaker broker

Edge Core ships an MQTT broker (EMQX or Mosquitto) inside the Netmaker stack — it's used by Netmaker for VPN control-plane traffic. Pointing the event broker at this same instance is not recommended: lifecycle, auth, capacity tuning, and operational dashboards all become entangled with VPN internals. Run a dedicated event broker.

Managed Cloud Services

For managed services there's no compose file — the service exists in your cloud account and Edge Admin connects to it. Both supported services follow the same pattern: pre-provision the domain topics, grant publish access to the principal Edge Admin runs as, point the adapter at it.

The topic names are fixed:

edge-nodes-events           ← all node lifecycle events
edge-commands-events        ← all command execution events
edge-self-updates-events    ← all self-update events

Edge Admin promotes type and corename from each event envelope into broker-native message attributes. Subscribers filter on those attributes server-side using the cloud's own filter syntax — see the cloud's docs for the syntax (filter policies for SNS, filter expressions for Pub/Sub).

AWS SNS

Adapter aws_sns
Topics to create edge-nodes-events, edge-commands-events, edge-self-updates-events, edge-ssh-events
IAM action sns:Publish on the four topic ARNs
Auth Standard AWS credential chain via ex_aws. Prefer IRSA on EKS / instance profile on EC2; static keys via env vars are an escape hatch.
Subscriptions SQS queue, Lambda, HTTPS endpoint — your choice. SNS itself stores nothing.
Filter syntax SNS subscription filter policies — JSON, matched against message attributes.
for t in edge-nodes-events edge-commands-events edge-self-updates-events; do
  aws sns create-topic --name "$t" --region us-east-1
done

Minimal IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": [
        "arn:aws:sns:us-east-1:123456789012:edge-nodes-events",
        "arn:aws:sns:us-east-1:123456789012:edge-commands-events",
        "arn:aws:sns:us-east-1:123456789012:edge-self-updates-events"
      ]
    }
  ]
}

Filter policy examples:

{"type": [{"prefix": "edge.node."}]}                       // all node events
{"type": ["edge.command_execution.completed"]}             // specific event type
{"corename": ["prod-us"]}                                  // events from one core

Google Cloud Pub/Sub

Adapter google_pubsub
Topics to create edge-nodes-events, edge-commands-events, edge-self-updates-events, edge-ssh-events (prefix optional via EVENT_BROKER_GOOGLE_PUBSUB_TOPIC_ID_PREFIX)
IAM role roles/pubsub.publisher on the four topics
Auth Standard GCP credential chain via goth. Prefer Workload Identity on GKE / metadata server on GCE; service-account JSON via GOOGLE_APPLICATION_CREDENTIALS is an escape hatch.
Subscriptions Pull, push (HTTPS / Cloud Run), BigQuery, Cloud Storage. Pub/Sub buffers per subscription (default 7-day retention, max 31).
Filter syntax Pub/Sub subscription filters — query language, matched against message attributes. Set on subscription creation; cannot be changed later.
for t in edge-nodes-events edge-commands-events edge-self-updates-events; do
  gcloud pubsub topics create "$t" --project=my-project-123
done

Minimal per-topic role binding:

for t in edge-nodes-events edge-commands-events edge-self-updates-events; do
  gcloud pubsub topics add-iam-policy-binding "$t" \
    --member=serviceAccount:edge-admin@my-project-123.iam.gserviceaccount.com \
    --role=roles/pubsub.publisher --project=my-project-123
done

Filter expression examples:

attributes.type = "edge.node.status_changed"
hasPrefix(attributes.type, "edge.node.")
attributes.corename = "prod-us" AND hasPrefix(attributes.type, "edge.command_execution.")

Events Published

See the AsyncAPI spec at GET /api/asyncapi (or browse /asyncdoc) for the full event schema. Edge Admin publishes events across:

  • Node lifecycle — registration, version changes, health/status transitions, cluster moves, self-update triggers, deletion.
  • Command execution lifecycle — execution created, delivered to agent, completed/cancelled/expired.
  • Self-update lifecycle — request created and batch completed.

All events follow the CloudEvents 1.0 spec.

Files in this directory

Browse the actual files on GitHub:

File Broker
nats.yml + config/nats.conf + config/nui-context.json NATS (with NUI web UI)
redpanda.yml Redpanda (Kafka-wire compatible)
kafka.yml Apache Kafka (KRaft mode)
rabbitmq.yml + config/rabbitmq.conf + config/rabbitmq_enabled_plugins RabbitMQ (AMQP 0.9.1)
redis.yml Redis (pub/sub)
mosquitto.yml + config/mosquitto.conf MQTT (Mosquitto)
emqx.yml + config/emqx.conf MQTT (EMQX, with dashboard)

AWS SNS and Google Cloud Pub/Sub are managed services. No compose file needed; see "Managed cloud services" above for provisioning notes.

Or browse the whole directory: examples/event_brokers/.