Authentication
How a RabbitMQ (AMQP 0-9-1) client authenticates to KubeMQ — SASL PLAIN with the password as a KubeMQ JWT, the accept-any dev default, and Casbin authorization.
The KubeMQ RabbitMQ connector authenticates over SASL PLAIN only. The non-obvious part: the
password carries a KubeMQ JWT, and the username is cosmetic. When authentication is
disabled (the dev default), any credentials are accepted, so the examples clone-and-run with
guest:guest.
On a stock dev broker, authentication is off and any credentials are accepted — guest:guest
completes a full round-trip. SASL PLAIN with a KubeMQ JWT in the password is the one
credentialed form that also runs on a stock broker. To encrypt the JWT on the wire, use the TLS
listener (amqps://:5671) — see TLS and mTLS.
SASL PLAIN is the only mechanism
The connector advertises and accepts only the PLAIN mechanism. A connection.start-ok
carrying any other mechanism (AMQPLAIN, EXTERNAL, …) is rejected with 503 command-invalid
("unsupported SASL mechanism … only PLAIN is supported").
The PLAIN response is parsed as the standard triple authzid \x00 authcid \x00 passwd.
Password = KubeMQ JWT, username = cosmetic
The username slot is informational; the password slot carries the credential. Most AMQP 0-9-1
clients accept a (username, password) pair in the connection URL — put the JWT in the
password:
amqp://<username-ignored>:<KubeMQ-JWT>@host:5672/<vhost>
└─ cosmetic ─┘ └─ authenticated ─┘| Field | Role |
|---|---|
| Username | Cosmetic. Recorded for audit and user-id checks; ignored for authorization. |
| Password | The KubeMQ JWT — passed to the auth service. |
| Identity | ClientID from the JWT's claims. This single ClientID covers both connector-level and channel-level (Casbin) authorization. |
The JWT is validated at connect time only — there is no mid-connection expiry enforcement.
On auth failure the connector sends connection.close(403) and emits an auth.failure audit
event.
The JWT travels in the SASL PLAIN password in cleartext at the AMQP layer. Production
deployments that use authentication MUST use the TLS listener (amqps://:5671), otherwise the
JWT is exposed on the wire. See TLS and mTLS and
Auth & security.
Put the JWT in the password slot regardless of client library:
// amqp091-go — username is cosmetic, password is the KubeMQ JWT.
conn, err := amqp.Dial(fmt.Sprintf(
"amqp://audit-user:%s@broker:5672/", os.Getenv("KUBEMQ_AMQP_JWT")))
if err != nil {
log.Fatalf("dial (bad/expired JWT? auth-disabled broker?): %v", err)
}
defer conn.Close()# pika — credentials: username audit-only, password is the KubeMQ JWT.
creds = pika.PlainCredentials("audit-user", os.environ["KUBEMQ_AMQP_JWT"])
params = pika.ConnectionParameters(host="broker", port=5672, credentials=creds)
conn = pika.BlockingConnection(params)// amqp-client — setUsername is cosmetic; setPassword carries the KubeMQ JWT.
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("broker");
factory.setPort(5672);
factory.setUsername("audit-user");
factory.setPassword(System.getenv("KUBEMQ_AMQP_JWT"));
Connection connection = factory.newConnection();// amqplib — username audit-only, password is the KubeMQ JWT.
const connection = await amqp.connect(
`amqp://audit-user:${process.env.KUBEMQ_AMQP_JWT}@broker:5672/`);// RabbitMQ.Client — UserName is cosmetic; Password carries the KubeMQ JWT.
var factory = new ConnectionFactory
{
HostName = "broker",
Port = 5672,
UserName = "audit-user",
Password = Environment.GetEnvironmentVariable("KUBEMQ_AMQP_JWT"),
};
using var connection = factory.CreateConnection();# bunny — username audit-only, password is the KubeMQ JWT.
conn = Bunny.new(
host: "broker", port: 5672,
user: "audit-user", password: ENV.fetch("KUBEMQ_AMQP_JWT"))
conn.start// lapin — username audit-only, password is the KubeMQ JWT.
let uri = format!("amqp://audit-user:{}@broker:5672/",
std::env::var("KUBEMQ_AMQP_JWT")?);
let conn = Connection::connect(&uri, ConnectionProperties::default()).await?;Auth disabled — the dev default
When authentication is disabled (the default on a dev broker), any credentials are accepted —
guest:guest completes a full round-trip. The ClientID is then derived from the client's
sanitized connection_name:
amqp-{connection_name}if a connection name was provided, otherwiseamqp-{uuid8}.
The user-id property
When authentication is enabled and the user-id property is set on basic.publish, it MUST
equal the JWT's ClientID; a mismatch is rejected with 406 precondition-failed. When auth is
disabled, user-id passes through unvalidated.
Authorization (Casbin)
When auth is enabled, every channel operation is checked per-channel against a Casbin policy
using the connection's ClientID:
| Operation | Casbin permission | On denial |
|---|---|---|
| Publish | Write, per routed queue | The denied queue is silently removed from the routed set + an amqp.publish.denied audit. The publish does not error. |
| Consume | Read | 403 access-refused. |
queue.declare / queue.delete / bind | Write | 403 access-refused. |
When authorization is disabled, all operations are allowed.
Publish denial is silent. Because a denied queue is removed from the routed set rather than
rejected, a publish to a partially-denied fanout still succeeds for the allowed queues. Use
mandatory=true if you need a 312 NO_ROUTE when nothing routed — see
Reliability.
Example policy
{"ClientID":"amqp-authz-allowed","Channel":"amqp.default.*","Read":true,"Write":true}A client with this policy can declare, publish, and consume under amqp.default.*. A client
without Read on a channel gets 403 on consume; a client without Write has its publishes
silently dropped for that queue.
Quick decision guide
| You want… | Do this |
|---|---|
| Clone-and-run on a stock dev broker | Connect with any credentials (guest:guest) |
| Authenticate with a KubeMQ identity | SASL PLAIN, JWT in the password slot; username is audit-only |
| Encrypt the JWT on the wire | Use amqps://:5671 — see TLS and mTLS |
| Diagnose a permission failure | A 403 access-refused on consume means no Read; silently-dropped publishes mean no Write |
Related
TLS and mTLS
amqps:// on port 5671 and mutual TLS — encrypt the JWT that travels in the SASL PLAIN password.
Auth & security
The shared JWT model, TLS/mTLS, and security concepts across KubeMQ connectors.
Error codes
The 403, 406, and 503 AMQP codes the connector returns on authentication and authorization failures.
Was this page helpful?
Getting Started
Connect a stock RabbitMQ client to KubeMQ and run a declare-publish-consume round-trip over a KubeMQ Queue in minutes — no KubeMQ SDK required.
Pub/Sub (Fanout)
Broadcast every message to all subscribers over AMQP 0-9-1 — a fanout exchange copies to exclusive queues, each backed by its own KubeMQ Queue channel.