Skip to content

Security: authentication, TLS and encryption

Keep strangers out of a Queen cluster: private ports, JWT on the broker, TLS and API keys through the built-in proxy, the cluster token, and encryption at rest.

Updated View as Markdown

Out of the box a node authenticates nobody: its port is plain HTTP, and every route answers any caller that can reach it. That keeps the first run to one command, and it is the first thing to change. Put one of two front doors on it (the broker’s own JWT for services, or the built-in proxy for API keys and people), keep the raft port private, and encrypt the queues whose payloads must not sit on disk in clear.

Why
a broker on a laptop should start with one command, and a broker in production should trust nobody. The defaults serve the first; this page is the list for the second.

What listens where

Port Serves Protected by
6632 (PORT) The HTTP API, the dashboard, /health, the metrics Broker JWT, off by default. Plain HTTP.
7400 (the raft address) Votes, log entries, snapshots, membership; a standby’s reads QUEEN_RAFT_TOKEN, and QUEEN_LINK_TOKEN for a standby. Plain HTTP.
raft port + N Raft group N The same token.
QUEEN_PROXY_PORT, e.g. 6711 The proxy: API keys, sessions, the console, /api/cp/* Keys and sessions; TLS with QUEEN_TLS_CERT and QUEEN_TLS_KEY.
9092 The Kafka port QUEEN_KAFKA_SASL=plain, off by default. No TLS in 2.6.

Port 6632 never faces the internet without one of the front doors below. QUEEN_BIND_ADDR=127.0.0.1 keeps it on the host, which is wrong in Kubernetes, where probes arrive on the pod’s IP.

Broker JWT

JWT_ENABLED=true
JWT_ALGORITHM=RS256                 # HS256 (default), HS384, HS512, RS256, RS384, RS512, EdDSA, auto
JWT_JWKS_URL=https://idp.example.com/.well-known/jwks.json   # or JWT_PUBLIC_KEY, or JWT_SECRET for HS*
JWT_ISSUER=https://idp.example.com/
JWT_AUDIENCE=queen

A token’s roles come from its role or roles claim. Each route has an access level, and the roles decide which levels a token passes:

Level Routes Passes with role
public /health, the metrics, the dashboard’s files, /auth/* none
read-only listings, status, messages, groups, the DLQ, traces, KV and timer reads, reads by offset read-only, read-write, admin
write-only push, timer schedules, the ephemeral push write-only, read-write, admin
read-write everything else: pop, ack, transactions, KV writes, locks, configure read-write, admin
admin /api/v1/system/*, deletes of queues, groups and dead letters admin

JWKS keys are cached and refreshed every hour, and exp, nbf and iat are checked with 30 seconds of skew. A token without exp is accepted, so issue tokens that expire. The HTTP reference has every route’s level.

Why
write-only exists for services that must push and read nothing: a producer that leaks its token leaks no data.

API keys and people

The proxy built into the binary (QUEEN_PROXY_EMBEDDED=true) is the second front door: API keys bound to one tenant, sessions for people with a role per cluster, quotas, and TLS on a port of its own, which is the port to expose. See Tenants and API keys.

TLS

The broker port does not terminate TLS. The proxy’s port does (QUEEN_TLS_CERT, QUEEN_TLS_KEY). The Kafka port has none in 2.6, so with SASL its passwords cross the network in clear: keep it private, or terminate TLS in front of it. For anything else, terminate TLS at your ingress, with the hop to the node on a private network.

The raft token

QUEEN_RAFT_TOKEN="$(openssl rand -hex 32)"    # the same value on every node

Every raft call carries the token, checked before the body is read. Unset, anything that reaches the raft port can vote, append entries and install snapshots. Set, it still travels in clear, so allow the raft port only from the other nodes. Rotating it is a rolling restart. With the broker’s JWT on, set it in any case: the nodes’ ephemeral hand-overs prove themselves with it, and without it ephemeral partitions that move lose their contents.

A standby reads on the same port with its own token, QUEEN_LINK_TOKEN. It opens only the log and the snapshot, but those are everything the cluster holds: guard it as you guard the data.

Encryption at rest

QUEEN_ENCRYPTION_KEY="$(openssl rand -hex 32)"    # 64 hex characters, the same on every node

Then turn encryptionEnabled on for the queues that need it. Their payloads are stored AES-256-GCM encrypted, including what transactions and timers push into them. Names, KV keys and KV values stay in clear.

Check the boot line encryption service initialized (AES-256-GCM): a missing or malformed key is silent, and the node stores flagged queues in plain text. A changed key makes the old payloads unreadable, and consumers get the ciphertext as data, with no error.

The data directory

QUEEN_RAFT_DIR holds everything a node knows: payloads (in clear unless encrypted), KV, timers, positions and, with the proxy, its users and key hashes. Treat the volume, and every snapshot of it, like a credential.

Limits

  • Everything is open by default. With no JWT and no proxy, anyone who reaches port 6632 can read, delete queues and change the membership.
  • /metrics/prometheus is public on port 6632 and names every tenant’s queues. On the proxy’s port it needs the control-plane token.
  • There is no TLS between nodes, nor between a standby and its source.
  • The messages a stream’s sink pushes are stored in clear, even in an encrypted queue.

To report a vulnerability, see About.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close