plugin authn/authz rfc - #19
Conversation
Signed-off-by: Patrick Koss <pati.koss@gmx.de>
|
Hi! I've updated #10 to renumber the RFCs 5 and 6 that were in there to RFCs 8 and 9 to avoid conflicts with the now merged RFC 5, this PR, and #13 which proposes an RFC 7. In the future, I'd recommend the following to avoid more numbering conflicts:
Of course that only works if everybody does it, but I think it's worth trying. In my opinion, a better solution would be to stop numbering the RFC's, but presumably that's a broader community discussion. |
|
@B-Step62 what are your thoughts on refactoring how search authorization works? Right now, we do post response filtering and then backfill the pages. If a user has permission to one experiment, it could lead all experiments for the workspace being queried just looking for experiments to the fill the page. I think a better approach is to ask the authorization system, does the user have permission to all experiments? If not, which experiments do they have access to? Then modify the request to filter by only those experiment IDs. Then pagination just works and it's more efficient. |
|
@mprahl Yeah I agree with the approach, the current backfill logic is pretty dirty and suboptimal. |
Signed-off-by: Patrick Koss <pati.koss@gmx.de>
mprahl
left a comment
There was a problem hiding this comment.
This looks good! Once my small comment is addressed and @rrrkharse 's comments are addressed, I'll approve the RFC.
|
@mprahl shall we merge the pr? |
|
Hey @PatrickKoss thanks for all the hard work on the RFC! Just wanted to let you know that I'd be happy to pick up the RFC implementation work unless you were looking to own that too. |
Hey @rrrkharse, if we're all aligned on the design, please feel free to pick up the implementation! Happy for you to take it from here. |
|
@PatrickKoss @mprahl @rrrkharse The design overall looks good, thank you for pushing this forward! The only question I want to align before proceeding is integration with RFC #32. The RFC introduces fine-grained access control, for example, run-level. The main impact seems to be the inheritance design proposed in the other RFC. Basically, acl on the child resource first check its own permission and then fallback to its parent container. To achieve this, we need to extend the design of "Core" part in this RFC. One option is to produce more flexible expressions like this, instead of AND only. Then MLflow deligates the evaluation of each child expression to the backend, which continue authorizing only normalized leaf requirements. Is this approach reasonable? |
Since RFC #32 is still under review, perhaps we can merge this one and RFC #32 can account for this requirement? |
RFC 0008: Pluggable Authentication and Authorization
Tracking issue: mlflow/mlflow#21240
Summary
Adds a new RFC proposing two small plugin contracts —
AuthenticationProviderand
AuthorizationBackend— to replace MLflow's singleauthorization_functionhook. The split separates who you are from what you may do, and keeps the
load-bearing
route → requirementmapping in core so plugins never need totrack MLflow's routing surface.
This is the extension point that RFC 0005 ("Role-Based Access Control for
MLflow OSS") flagged as future work. It builds on 0005's role model and
resolver surface, and the default plugins reproduce today's behavior
byte-for-byte — operators who upgrade and change nothing see no difference.
What's in this PR
rfcs/0006-pluggable-auth/0006-pluggable-auth.md(823 lines, onecommit on top of
main).No code changes, no implementation — this is the design document. Reference
adapters described in the RFC (OIDC, Kubernetes
TokenReview/SubjectAccessReview, OPA, upstream proxy headers) are sketched in enoughdetail to validate the interface shape but are not built here.
Why now
The existing surface has three structural problems:
authorization_functionreturns awerkzeug.datastructures.Authorizationcarrying only a username — too thinfor bearer tokens, OIDC claims, group membership, or JIT provisioning.
non-default function (
mlflow/server/auth/__init__.py:4141), so the hookis effectively Flask-only.
dispatch structures. Any external authorization system (Kubernetes SAR,
OPA, a corporate policy engine) has to rediscover and re-sync that mapping
every time MLflow adds a route.
Design rule worth calling out
Core retains sole ownership of the
route → requirementmapping via a singleauthoritative
OPERATION_REGISTRY. Plugins only ever see the normalized tuple(resource_type, resource_id, action, workspace)— never a route, a protobufclass, or a GraphQL field. A CI guard fails the build if any route ships
without a declared requirement.
Out of scope (intentionally)
READ / USE / EDIT / MANAGE.Reviewer guide
Suggested reading order if you're short on time:
rest of the design hangs off this.
of truth as routes evolve.
like pushback.
Open questions I'd like input on
These are spelled out at the bottom of the RFC; flagging them here so they
don't get lost:
authn_providersshould be an ordered chain or a single providerwith explicit fallback rules.
workspaceshould be for the Kubernetes SAR adapter(namespace? label selector? both?).
Checklist
0000-template.mdstructurestart_dateset,mlflow_issuelinked,rfc_prleft empty pertemplate instructions
mlflow/server/auth/