chore(mq): per-service broker credentials + least-privilege permissions

What / why

Every service and every test shares ONE RabbitMQ credential: the craig user in devstack/rabbitmq/definitions.json carries the administrator tag and .*/.*/.* configure/write/read on /. Compromise of any single service is total broker control (declare, consume, purge, ack any queue). The #1181 (closed) trust-boundary bound (wrapper-token forgery by a write-only-credentialed publisher) is currently vacuous because no write-only credential exists — the ADR-022 #1181 (closed) amendment routing note now points here (repointed from #1198 (closed) by the C4 scope decision, 2026-07-29).

Acceptance criteria

  • Per-service RabbitMQ users in devstack definitions.json (devstack test creds stay public in-tree per the security baseline; production provisioning documented, never hardcoded).
  • Scoped configure/write/read regexes per service: own queues + craig.events publish; craig.dlx write where the app dead-letter path needs it; only craig-security reads dlq.*. No service keeps administrator.
  • Compose service URLs switched to the per-service credentials; the test URL (.ports.env) uses a dedicated test user, not a service identity.
  • Deployment guide: least-privilege section (credential provisioning, the regex table, rotation note).
  • ADR amendment (ADR-003 or ADR-022) recording the credential model; the #1181 (closed) trust-boundary bound updated to reference the real write-only posture.
  • Full battery green — services boot, consume, and dead-letter under the scoped permissions (the regexes are proven by the battery, not by inspection).

Context / references

Epic &75 (closed) addendum (C4/#1198 (closed) scope decision: separate deliverable, distinct mechanism). Relates to #1198 (closed), #1181 (closed).

Amendment (2026-07-29, epic &75 (closed) C3 / ADR-059)

The C3 topology adds two per-DLQ-queue durable queues the scoped permissions must cover: the DLQ-consuming service (craig-security) needs configure/write/read on {queue}.parking and {queue}.quarantine (declared at boot through the craig-mq choke-point), plus DEFAULT-exchange publish rights to both queue names and craig.dlx publish rights for the replayer's confirmed republishes.

Edited by CRAIG-Bot-CA