KubeMQ
ConnectorsRabbitMQ (AMQP 0-9-1)Reference

Management HTTP API

The RabbitMQ-compatible management HTTP subset on port 15672 — endpoints, authentication, tags, visibility, and definitions export/import.

The connector can serve an opt-in, read-mostly subset of RabbitMQ's management HTTP API/api/overview, /api/queues, /api/exchanges, /api/bindings, /api/aliveness-test, plus definitions.json export and import — so tools written against RabbitMQ (rabbitmqadmin, CI health checks, Terraform providers, ops scripts) keep working. It runs on a second, dedicated HTTP listener, never the dashboard's own /api, and shapes its replies on RabbitMQ 4.3.4, measured against a real broker.

Enabling

FieldDefaultEnv var
Connectors.Amqp.Management.EnablefalseCONNECTORS_AMQP_MANAGEMENT_ENABLE
Connectors.Amqp.Management.Port15672 (RabbitMQ's own management port)CONNECTORS_AMQP_MANAGEMENT_PORT
config.toml
[Connectors.Amqp.Management]
  Enable = true
  Port = 15672

The listener starts only beside a running AMQP 0-9-1 connector: if it is enabled but the connector did not start (disabled, or it failed open), the server logs a warning and continues without the management listener. A bind failure on the management port is a soft-fail like every other AMQP listener — logged, and the server continues with everything else running.

Port conflicts are refused at boot and on every settings save: the management port must differ from the core gRPC/REST/HTTP ports, the shared AMQP 5672/5671 ports, and the MQTT, STOMP, AWS, GCP and Kafka ports. The check runs whenever Management.Enable = true, independent of Connectors.Amqp.Enable.

TLS follows the server-wide security mode, on the same port. There is no separate TLS port: when the global Security block configures a mode other than none, the listener serves TLS or mutual TLS on the one configured port; otherwise it serves plain HTTP.

While the broker is not ready, every request — including one with no Authorization header — gets 503 with {"error":"service_unavailable","reason":"broker not ready"}.

Authentication

HTTP Basic, checked against Connectors.Amqp.Credentials — the same connector-local credential store SASL PLAIN/AMQPLAIN uses, in the same order:

  • A credential store is configured: both the username and password are checked against it.
  • No store, but Authentication.Enable = true: the Basic password must be a valid KubeMQ platform token; the username is not checked.
  • No store and Authentication.Enable = false: any credentials are accepted.

No certificate logins. SASL EXTERNAL has no equivalent here — HTTP Basic is the only mechanism this listener offers, whatever Connectors.Amqp.SslCertLogin is set to.

A wrong password, an unknown username, and an empty username all produce the byte-identical reply, so a client can never use the response to enumerate valid usernames:

{"error":"not_authorized","reason":"Not_Authorized"}

A request with no Authorization header gets an empty body and the challenge header WWW-Authenticate: Basic realm="RabbitMQ Management" with status 401.

Tags

Every endpoint requires any one of RabbitMQ's four management-class tags on the authenticated user — management, policymaker, monitoring, administrator — configured per credential via Connectors.Amqp.Credentials[].Tags. A store user with none of the four is refused on every route:

{"error":"not_authorised","reason":"Not management user"}

GET/POST /api/definitions additionally require the administrator tag; a management-class user without it gets {"error":"not_authorised","reason":"Not administrator user"}.

A platform-token login, and the no-store/no-authentication login, both count as administrator — by policy, not by a tag they carry — so they reach every endpoint, including both definitions routes.

monitoring (or administrator) widens GET /api/overview's object_totals/queue_totals to every vhost rather than just the caller's own visible set. It does not widen any object list — measured RabbitMQ behavior, not a KubeMQ choice.

Visibility

A store user's Permissions entries (see Users and permissions) also scope what the listener shows: a user holding at least one entry sees only the vhosts it has an entry for (a wildcard Vhost: "" entry sees every vhost); a user with no entries, a platform token, and the no-authentication login all see every vhost. A store user tagged administrator also sees every vhost regardless of its entries, as RabbitMQ 4.3.4 does.

When platform (Casbin) authorization is enabled, list endpoints additionally filter through the same Read check the wire runs — a queue absent from /api/queues because the caller's policy denies Read on it is the same decision basic.consume would make.

Two 404 bodies, for two different reasons:

WhenBody
The caller cannot see the vhost or object at all — whether or not it exists{"error":"not_found","reason":"Not Found"}
The caller can see the vhost, but the named object does not exist; or the path names nothing{"error":"Object Not Found","reason":"Not Found"}

RabbitMQ tells a scoped caller when a vhost does not exist; this connector never makes that distinction, so the body never discloses existence to a caller not permitted to see it.

Endpoints

Method & pathFields emitted
GET /api/overviewcluster_name, exchange_types, management_version, object_totals{channels, connections, exchanges, queues[, consumers]}, product_name, product_version, queue_totals{messages, messages_ready, messages_unacknowledged}, rabbitmq_version
GET /api/queues, /api/queues/{vhost}, /api/queues/{vhost}/{name}arguments, auto_delete, consumers, durable, exclusive, messages, messages_ready, messages_unacknowledged, name, state (always "running"), type (the declared x-queue-type, else "classic"), vhost
GET /api/exchanges, /api/exchanges/{vhost}, /api/exchanges/{vhost}/{name}arguments, auto_delete, durable, internal, name, type, vhost — includes the pre-declared exchanges
GET /api/bindings, /api/bindings/{vhost}source, vhost, destination, destination_type, routing_key, arguments, properties_key — includes one synthesized default-exchange binding per queue
GET /api/aliveness-test/{vhost}{"status":"ok"} on success; {"status":"failed","reason":"<text>"} on failure (503)
GET /api/definitionsadministrator only — see Definitions export
POST /api/definitionsadministrator only — see Definitions import

Message counts come from the same computation the dashboard uses, so they can lag the true state by up to one snapshot refresh (about 5 seconds) — the same lag RabbitMQ's own default stats emission has. Connection and channel counts in object_totals are node-local; topology and message counts are cluster-wide.

properties_key is RabbitMQ's own form encoding of the routing key: [A-Za-z0-9._-] kept, a space becomes +, every other byte becomes % plus two capital hex digits (orders.#orders.%23), and an empty key encodes to ~. A binding that carries arguments omits it.

product_name is KubeMQ, never RabbitMQ. rabbitmq_version, management_version and rabbit_version are all 4.3.4 — the API level these shapes mirror, for tools that branch on the version string, not a claim about what product answered.

Aliveness

GET /api/aliveness-test/{vhost} runs a real round-trip through the connector's own topology and message path: it declares a server-named queue (amq.gen-…, never the literal aliveness-test, so it cannot collide with a queue you own), publishes one message to it through the default exchange, receives it back and compares the body, then deletes the queue — under a 3-second deadline for the whole round-trip.

The check needs a real permission on the vhost, not just visibility: a store user with Permissions entries, none covering the vhost, is refused — 401 with {"error":"not_authorised","reason":"Access refused."} if it can still see the vhost (an administrator), the usual 404 otherwise.

Definitions export

GET /api/definitions, administrator only. Contains vhosts, queues, exchanges (excluding the pre-declared ones), bindings, users (name and tags only), and permissions (exact-vhost entries only — a wildcard Vhost: "" entry has no RabbitMQ form and is omitted). topic_permissions, policies, parameters and global_parameters are always empty arrays.

The export never contains a password, a password hash, or a hashing algorithm name.

Definitions import

POST /api/definitions, administrator only, applies each entry through the same declare/bind code path an AMQP client's own queue.declare/exchange.declare/queue.bind takes — the same argument validation, the same durable persistence, the same cluster replication. Administrator import bypasses the connector's own permission layer for every create, mirroring RabbitMQ; platform (Casbin) authorization still runs per entry.

Every entry in the request body is attempted, in order — vhosts, users, permissions, exchanges, queues, bindings — and one entry's refusal never stops the ones after it. RabbitMQ stops at the first error; this connector deliberately does not, so a migration run reports everything that needs fixing in one pass.

  • 204 No Content: every entry applied, with no caveat.
  • 400 Bad Request: every entry was still attempted — read applied, unapplied and report to find out which:
{
  "error": "bad_request",
  "reason": "<the first entry that was not applied>",
  "applied": 3,
  "unapplied": 2,
  "report": [
    {"kind": "policy", "vhost": "m3v", "name": "m3policy", "applied": false, "reason": "policies are not supported"}
  ]
}

Users and permissions are configuration, not runtime state — import never writes Connectors.Amqp.Credentials. A users[] entry counts as applied only when the configured store already holds that username with the same tag set, and — when the entry carries a password_hash — that hash verifies against the configured password (rabbit_password_hashing_sha256 and sha512 are verified; md5 and unknown algorithms are reported by name, unverified). Anything not already matching is reported, naming the config path to edit. See the migration recipe in Moving topology with definitions export/import.

Reported and not applied: policies, runtime parameters, topic permissions, operator policies, vhost limits, and an unsupported exchange type. Exchange-to-exchange bindings (destination_type: "exchange") are applied.

Reported but still applied (a warning): a queue declared with an inert argument is still created; the argument is named in report with applied: true. x-queue-type: "classic" and x-queue-mode are not reported at all.

Silently accepted as RabbitMQ export noise: an empty global_parameters cluster_tags value, internal_cluster_id, the amq.rabbitmq.log/amq.rabbitmq.trace exchanges, and a queue's x-queue-type: "classic" / x-queue-mode arguments — every fresh RabbitMQ export carries them, and reporting them would mean no real migration ever reaches 204.

Not implemented

A tool that assumes RabbitMQ parity needs to know the boundary before it hits it:

  • The management UI is not served — this listener answers JSON only.
  • Every write endpoint except POST /api/definitions: no PUT/DELETE for queues, exchanges, bindings, users, permissions, vhosts or policies.
  • /api/connections, /api/channels, /api/nodes, /api/vhosts, /api/whoami, /api/health/checks/* — not served.
  • Pagination (page, page_size) and columns= — every list always answers in full.
  • Rates, message_stats, memory and node fields are not emitted.
  • The firehose tracer and log forwarder behind amq.rabbitmq.trace and amq.rabbitmq.log: both exchanges exist and are listed, but nothing is ever published to them.
  • A known path with an unsupported HTTP method answers 405 with an empty body and the measured Allow header, never the 404 an unregistered path gets.

Every field or endpoint in this list is simply absent from a reply, never emitted as a zero or a placeholder — a tool checking for a field's presence sees it is missing rather than being misled by a confident-looking 0.

Was this page helpful?

On this page