fix(nats): security review — secure-by-default + per-tenant inbox isolation
Two HIGH findings from automated review on the generator, both fixed:
1. Cross-tenant inbox access: per-license users were granted _INBOX.>,
letting license A subscribe to license B's request-reply responses.
Now scoped to corrosion.{license}.> ONLY; replies must ride the
license namespace (corrosion.{license}.reply.<id>) — documented in
PROTOCOL.md. Agent unchanged (responds to msg.reply); constraint is
on the requester (internal user has full >).
2. Default-open auth bypass: generator defaulted to stage=open with a
full-access anonymous user — a stale regen left the broker wide open.
Now defaults to enforce (secure by default); the explicit 'open'
migration stage maps anonymous to a harmless corrosion.unclaimed.>
namespace, never real tenant subjects. Committed bootstrap default
hardened the same way.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -179,6 +179,23 @@ service that attempts connections to the customer's public IP/ports on
|
||||
request; that is specified as a Phase 1+ feature and will reuse this report
|
||||
format with `direction: "inbound"`.
|
||||
|
||||
## Authentication & tenant isolation
|
||||
|
||||
The broker enforces per-license auth: an agent connects with `user = license_id`,
|
||||
`password = HMAC-SHA256(license_id, NATS_TOKEN_SECRET)` (shown on the panel
|
||||
Server page), and is scoped to `corrosion.{license_id}.>` only. The backend uses
|
||||
a privileged internal user. This makes cross-tenant access impossible at the
|
||||
broker, not just by convention.
|
||||
|
||||
**Reply-subject rule:** per-license users have NO `_INBOX` permission (granting
|
||||
it would let one license read another's request-reply traffic). Therefore any
|
||||
backend→agent request-reply MUST use a reply subject inside the license
|
||||
namespace — e.g. `corrosion.{license_id}.reply.<id>` — never the client's
|
||||
default global `_INBOX`. The agent is unaffected: it responds to whatever
|
||||
`msg.reply` it receives. The constraint is on the requester (the internal user
|
||||
has full access). The contract/CI tests run against an unauthenticated broker
|
||||
and use the default inbox; production request-reply must follow this rule.
|
||||
|
||||
## Versioning
|
||||
|
||||
- The agent embeds semver + git hash + build timestamp (`--version`,
|
||||
|
||||
Reference in New Issue
Block a user