Update broker auth proto - #61
Open
dborovcanin wants to merge 4 commits into
Open
Conversation
Atom implements FluxMQ's fluxmq.auth.v1.AuthService, so a broker can
authenticate clients and authorize topics against Atom with no adapter
service in between.
The proto is vendored verbatim from FluxMQ. Its package line is part of
the wire contract — the path a broker dials is derived from it — so it
must not be renamed. How a topic names an object is configuration
(ATOM_BROKER_TOPIC_TEMPLATE), which keeps any particular deployment's
topic vocabulary out of Atom; an adapter service is still the right
answer where the mapping needs more than a grammar.
Two invariants the implementation rests on:
- Denials are answers, not errors. Every rejection returns a successful
RPC carrying a false verdict; only infrastructure failure returns a
gRPC error. A broker wraps this callout in a circuit breaker, and a
tripped breaker rejects every client connection, so one device
retrying a stale password must not be able to take the broker's whole
auth path down. Rate limiting is on that list because it is the
failure a bad client can trigger at will.
- Tenant comes from the subject, not from config or the topic.
Authenticate resolves the identifier across tenants and the entity's
own tenant comes back with it, so the zero-configuration case needs
no tenant in the topic and no username grammar. A {tenant} template
segment only scopes alias resolution; it is deliberately not checked
against the subject's tenant, because cross-tenant grants are
legitimate and that call belongs to the PDP.
Off by default. It is the only gRPC service here with no bearer token to
check, so it authenticates its caller at the transport via the
listener's mTLS client CA; mounted on a plaintext listener, anything
that can reach the port could authenticate and authorize as any
principal. A startup warning fires if it is enabled without a client CA.
A broker carries topics that address no object — a health probe such as hc/<tenant> names nothing Atom can resolve — so no policy could describe them and every request for one was denied. ATOM_BROKER_TOPIC_ALLOW lists topics authorized without consulting the PDP. This is the only authorization bypass in the callout, so it defaults to empty and its patterns are ordinary MQTT filters: an operator writes the narrowest shape that covers the operational topic rather than reaching for a prefix. A broker '#' covers its position and everything below it, so only a pattern that is itself '#' there is broad enough to admit it. Letting '+' match it would silently widen the bypass past what the operator wrote — hc/+ would admit a subscription to the whole hc subtree.
The wire path a broker dials is derived from the proto package, so serving `fluxmq.auth.v1` put one implementation's name in the public surface of every peer that speaks the contract — including Atom's. Nothing in the messages is FluxMQ-specific; the same shape covers MQTT, AMQP, CoAP and HTTP, and other brokers and providers implement it. Renaming costs nothing structurally. The Go import path upstream is derived from the file's location rather than the package, so consumers keep the same imports and symbols, and only the dialled path changes. It is still a breaking wire change: a broker dialling the new path against a service serving the old one gets UNIMPLEMENTED. Atom, the brokers, and any adapter service have to move together.
Atom implements a proto it does not own, and nothing rebuilds the copy. An upstream change was therefore discovered at runtime — as an UNIMPLEMENTED from a renamed service, or worse, as a field that still decodes but no longer means what Atom thinks it means. scripts/check-vendored-proto.sh diffs the vendored file against the ref pinned in proto/broker/v1/REF, and CI runs it. For that diff to stay trustworthy the copy has to be byte-identical, so Atom's own notes moved out of the proto and into VENDOR.md beside it: a check that has to forgive expected differences stops catching the one that matters. Vendoring a second proto into the buf module had also broken two things that nothing here runs, so neither had surfaced: - buf lint failed on twenty-odd violations in the vendored file. Its style is upstream's, and Atom cannot fix it without breaking the byte-for-byte match, so it is excluded from lint and breaking. - buf generate silently replaced apidocs/grpc-reference.md with the broker contract, dropping Atom's own gRPC surface from the docs. protoc-gen-doc writes one file per invocation, so a second package does not extend that file. Generation is now scoped to Atom's protos. make proto regenerates both outputs. The asymmetry is worth knowing: the Rust bindings are not checked in — build.rs runs tonic-build into OUT_DIR on every compile — but grpc-reference.md is, and goes stale silently.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What type of PR is this?
What does this do?
Which issue(s) does this PR fix/relate to?
Have you included tests for your changes?
Did you document any new/modified features?
Notes