<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>MLflow | Erich Heil</title><link>https://reboting.com/tag/mlflow/</link><atom:link href="https://reboting.com/tag/mlflow/index.xml" rel="self" type="application/rss+xml"/><description>MLflow</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><copyright>© {2021} hedata</copyright><lastBuildDate>Wed, 21 Oct 2026 07:00:00 +0000</lastBuildDate><image><url>https://reboting.com/media/icon_hua2ec155b4296a9c9791d015323e16eb5_11927_512x512_fill_lanczos_center_2.png</url><title>MLflow</title><link>https://reboting.com/tag/mlflow/</link></image><item><title>The default permission of your experiment tracker is a design decision</title><link>https://reboting.com/post/2026-10-21-tracker-default-permission/</link><pubDate>Wed, 21 Oct 2026 07:00:00 +0000</pubDate><guid>https://reboting.com/post/2026-10-21-tracker-default-permission/</guid><description>&lt;p>MLflow is an open-source tool for tracking machine learning work: every training run, its parameters and metrics, the models that come out of it and, increasingly, the traces of LLM applications. Teams usually run one MLflow server for several people and projects, so that results sit in one place and can be compared. I run one for that reason. A shared server also raises a question that a personal laptop never does, namely who is allowed to see what.&lt;/p>
&lt;h2 id="the-default-grant-is-the-answer-to-every-question-nobody-asked">The default grant is the answer to every question nobody asked&lt;/h2>
&lt;p>MLflow&amp;rsquo;s access control is opt-in: you switch on its auth feature at startup, or use a plugin that signs users in through an OIDC identity provider (&lt;a href="https://mlflow.org/docs/latest/ml/auth/" target="_blank" rel="noopener">MLflow&amp;rsquo;s auth docs&lt;/a>, &lt;a href="https://github.com/mlflow-oidc/mlflow-oidc-auth" target="_blank" rel="noopener">the plugin&lt;/a>). Either way, a request is answered by walking a list of sources, the last being the default grant. I think it is the most important line in the configuration, because it governs everything that does not exist yet: every experiment, model and trace created next month, until somebody writes a more specific rule.&lt;/p>
&lt;p>In the plugin the first source holding a grant wins, by default in the order user, group, regex, group-regex (an operator can reorder it), and the default applies when none does (&lt;a href="https://github.com/mlflow-oidc/mlflow-oidc-auth/blob/main/mlflow_oidc_auth/utils/grant_context.py" target="_blank" rel="noopener">the resolution code&lt;/a>). Since version 7.6.0 that default is no permissions. The docstring of a function in &lt;a href="https://github.com/mlflow-oidc/mlflow-oidc-auth/blob/main/mlflow_oidc_auth/utils/permissions.py" target="_blank" rel="noopener">another file of the plugin&lt;/a> explains why that matters: with a default which grants, access &amp;ldquo;is being handed out by configuration rather than by an explicit permission record&amp;rdquo;. I agree. A good default is no permissions, so that every access is a record somebody made on purpose.&lt;/p>
&lt;h2 id="what-a-good-setup-keeps-and-for-whom">What a good setup keeps, and for whom&lt;/h2>
&lt;p>With the default at nothing, each kind of user lands somewhere predictable. The chain below follows one request down to the default.&lt;/p>
&lt;pre>&lt;code class="language-mermaid">%%{init: {&amp;quot;theme&amp;quot;: &amp;quot;base&amp;quot;, &amp;quot;themeVariables&amp;quot;: {&amp;quot;fontFamily&amp;quot;: &amp;quot;Roboto, Helvetica, Arial, sans-serif&amp;quot;, &amp;quot;primaryColor&amp;quot;: &amp;quot;#e8f1fb&amp;quot;, &amp;quot;primaryTextColor&amp;quot;: &amp;quot;#313131&amp;quot;, &amp;quot;primaryBorderColor&amp;quot;: &amp;quot;#1565c0&amp;quot;, &amp;quot;secondaryColor&amp;quot;: &amp;quot;#f7f7f7&amp;quot;, &amp;quot;tertiaryColor&amp;quot;: &amp;quot;#ffffff&amp;quot;, &amp;quot;lineColor&amp;quot;: &amp;quot;#34495e&amp;quot;, &amp;quot;textColor&amp;quot;: &amp;quot;#313131&amp;quot;, &amp;quot;clusterBkg&amp;quot;: &amp;quot;#f7f7f7&amp;quot;, &amp;quot;clusterBorder&amp;quot;: &amp;quot;#e6e6e6&amp;quot;, &amp;quot;edgeLabelBackground&amp;quot;: &amp;quot;#ffffff&amp;quot;}}}%%
flowchart TD
R[&amp;quot;Request&amp;quot;] --&amp;gt; A{&amp;quot;Admin group?&amp;quot;}
A -- yes --&amp;gt; K0[&amp;quot;Keeps everything&amp;quot;]
A -- no --&amp;gt; U{&amp;quot;User grant?&amp;quot;}
U -- &amp;quot;yes: creators hold MANAGE&amp;quot; --&amp;gt; K1[&amp;quot;Keeps own work&amp;quot;]
U -- no --&amp;gt; G{&amp;quot;Group grant?&amp;quot;}
G -- yes --&amp;gt; K2[&amp;quot;Keeps group grants&amp;quot;]
G -- no --&amp;gt; X{&amp;quot;Regex grant?&amp;quot;}
X -- yes --&amp;gt; K3[&amp;quot;Keeps matches&amp;quot;]
X -- no --&amp;gt; D[&amp;quot;Default decides&amp;quot;]
D --&amp;gt; L[&amp;quot;Default is nothing: no access to others' work or to gateway endpoints&amp;quot;]
&lt;/code>&lt;/pre>
&lt;p>Admins keep everything; the plugin&amp;rsquo;s docs say they bypass all permission checks. Regular users keep everything they created themselves, since MLflow&amp;rsquo;s docs say the creator of an experiment, a registered model or a gateway resource automatically receives full control (the MANAGE permission) on it. What they do not see is what colleagues created. Everything else is opened deliberately: per user, per group for what everybody may see, or by regex for a family of experiments.&lt;/p>
&lt;p>The part that is easy to overlook is the model gateway, MLflow&amp;rsquo;s front door for calling language models through managed endpoints. Endpoints an admin set up resolve through the same chain, so a script or application that calls the gateway with a non-admin account needs a grant too, and without one it gets a permission error far from anywhere a human would look. That is what the source says; I have not watched it happen. Traces make this matter most: they hold whatever users typed, and a default that reads everything shows all of it to the whole group.&lt;/p>
&lt;h2 id="choose-the-default-first-then-grant-on-purpose">Choose the default first, then grant on purpose&lt;/h2>
&lt;p>Reading everything is a decision about every person who will ever join the group, so I would make it explicitly or not at all. Granting a few things deliberately is cheaper than finding out later who read what.&lt;/p>
&lt;p>So before the next person joins your tracker, read what its default grants and set it to nothing unless you can name why not. Then walk the resolution order once for each kind of user you have, and write down what each keeps: own work, group grants, regex matches, gateway endpoints. That list is your access policy, and it takes less time than the first incident without it.&lt;/p></description></item></channel></rss>