跳到正文
cccskills
免费在 GitHub 公开

auth:mlflow-oidc-auth

Configure MLflow with mlflow-oidc-auth plugin for Keycloak OIDC authentication

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl星标 303(GitHub 303 + cccskills 0)

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md7.1 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

MLflow OIDC Authentication

Configure MLflow Tracking Server with Keycloak OIDC authentication using the mlflow-oidc-auth plugin.

Overview

mlflow-oidc-auth is a FastAPI wrapper around MLflow that provides:

  • OIDC authentication via Keycloak
  • Group-based authorization (READ/EDIT/MANAGE permissions)
  • Session management for browser access
  • Basic/Bearer auth for programmatic access

Architecture

Browser → Keycloak OIDC → mlflow-oidc-auth → MLflow Flask → PostgreSQL
OTEL    → mTLS (Istio) → /v1/traces       → MLflow      → PostgreSQL

Required Environment Variables

env:
  # Database for MLflow
  - name: MLFLOW_BACKEND_STORE_URI
    value: "postgresql://user:pass@postgres:5432/mlflow"
  - name: MLFLOW_TRACKING_URI
    value: "postgresql://user:pass@postgres:5432/mlflow"  # Needed for otel_router

  # OIDC Configuration
  - name: OIDC_DISCOVERY_URL
    value: "http://keycloak-service.keycloak:8080/realms/master/.well-known/openid-configuration"
  - name: OIDC_CLIENT_ID
    value: "mlflow"
  - name: OIDC_CLIENT_SECRET
    valueFrom:
      secretKeyRef:
        name: mlflow-oauth-secret
        key: OIDC_CLIENT_SECRET

  # OIDC Groups for Authorization
  - name: OIDC_GROUP_NAME
    value: "mlflow"  # Users must be in this group
  - name: OIDC_ADMIN_GROUP_NAME
    value: "mlflow-admin"  # Admin users group

  # Database for OIDC plugin
  - name: OIDC_USERS_DB_URI
    value: "postgresql://user:pass@postgres:5432/mlflow"

OTEL Trace Ingestion Setup

Problem

mlflow-oidc-auth doesn't include MLflow's otel_router which provides the /v1/traces OTLP endpoint.

Solution: Runtime Patches

Apply two patches before starting the app:

# Patch 1: Add otel_router to get_all_routers()
from mlflow.server.otel_api import otel_router
import mlflow_oidc_auth.routers as routers_module

original_get_all_routers = routers_module.get_all_routers
def patched_get_all_routers():
    return original_get_all_routers() + [otel_router]
routers_module.get_all_routers = patched_get_all_routers

# Patch 2: Exclude /v1/traces from OIDC auth
from mlflow_oidc_auth.middleware.auth_middleware import AuthMiddleware

original_is_unprotected = AuthMiddleware._is_unprotected_route
def patched_is_unprotected(self, path: str) -> bool:
    if path.startswith("/v1/traces"):
        return True
    return original_is_unprotected(self, path)
AuthMiddleware._is_unprotected_route = patched_is_unprotected

# NOW import app (uses patched functions)
from mlflow_oidc_auth.app import app
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5000)

Security

The /v1/traces endpoint is secured via Istio instead of OIDC:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: mlflow-traces-from-otel
spec:
  targetRefs:
    - kind: Service
      name: mlflow
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/rossoctl-system/sa/otel-collector"
      to:
        - operation:
            methods: ["POST"]
            paths: ["/v1/traces", "/v1/traces/*"]
    - to:
        - operation:
            notPaths: ["/v1/traces", "/v1/traces/*"]

Waypoint Proxy for L7 Auth

The AuthorizationPolicy needs L7 (path-based) evaluation, which requires a waypoint proxy:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mlflow-waypoint
  labels:
    istio.io/waypoint-for: service
spec:
  gatewayClassName: istio-waypoint
  listeners:
    - name: mesh
      port: 15008
      protocol: HBONE

Add the waypoint label to the MLflow service:

apiVersion: v1
kind: Service
metadata:
  name: mlflow
  labels:
    istio.io/use-waypoint: mlflow-waypoint

Helm Chart Integration

See charts/rossoctl-deps/templates/mlflow.yaml for the full implementation.

Key values:

mlflow:
  auth:
    enabled: true
    secretName: mlflow-oauth-secret

Programmatic API Access

Using Client Credentials Flow

For E2E tests and CI/CD pipelines, use the MLflow client's OAuth credentials:

import base64
import requests
from kubernetes import client, config

# Get credentials from K8s secret
config.load_kube_config()
k8s = client.CoreV1Api()
secret = k8s.read_namespaced_secret("mlflow-oauth-secret", "rossoctl-system")

client_id = base64.b64decode(secret.data["OIDC_CLIENT_ID"]).decode()
client_secret = base64.b64decode(secret.data["OIDC_CLIENT_SECRET"]).decode()
token_url = base64.b64decode(secret.data["OIDC_TOKEN_URL"]).decode()

# Get token using client credentials flow
response = requests.post(token_url, data={
    "grant_type": "client_credentials",
    "client_id": client_id,
    "client_secret": client_secret,
}, verify=False)

access_token = response.json()["access_token"]

# Set for MLflow Python client
import os
os.environ["MLFLOW_TRACKING_TOKEN"] = access_token

Important: Use the mlflow client credentials, NOT admin-cli. The mlflow-oidc-auth validates the token audience and will reject tokens from other clients.

Troubleshooting

"Authentication required" for /v1/traces

Verify patches are applied:

kubectl logs -n rossoctl-system deploy/mlflow -c mlflow | grep "otel_router"
# Should see: "Patched get_all_routers() to include otel_router"
# Should see: "Excluded /v1/traces from OIDC auth (mTLS via Istio)"

Bearer token rejected with "Invalid token"

Check MLflow logs for SSL errors:

kubectl logs -n rossoctl-system deploy/mlflow -c mlflow | grep -i "ssl\|cert\|jwks"

If you see CERTIFICATE_VERIFY_FAILED, the CA bundle is incomplete. On OpenShift/HyperShift:

  • Set SSL_CERT_FILE (for httpx/authlib) in addition to REQUESTS_CA_BUNDLE
  • Include both ingress CA and root CA in the bundle (HyperShift uses a CA chain)
# In mlflow.yaml startup script:
export SSL_CERT_FILE=/etc/pki/ingress-ca/ingress-ca.pem && \
export REQUESTS_CA_BUNDLE=/etc/pki/ingress-ca/ingress-ca.pem && \

SQLite errors for trace storage

Ensure both MLFLOW_BACKEND_STORE_URI AND MLFLOW_TRACKING_URI are set to PostgreSQL.

Traces not appearing

  1. Check OTEL collector logs:
kubectl logs -n rossoctl-system deploy/otel-collector | grep mlflow
  1. Verify trace count in database:
kubectl exec -n rossoctl-system postgres-otel-0 -- \
  psql -U postgres -d mlflow -c "SELECT COUNT(*) FROM trace_info;"
  1. Check AuthorizationPolicy:
kubectl get authorizationpolicy -n rossoctl-system mlflow-traces-from-otel -o yaml

Known Limitations

  1. No path exclusion config: mlflow-oidc-auth hardcodes unprotected paths
  2. Missing otel_router: Not included in get_all_routers()
  3. Direct Access Grants disabled: MLflow client uses client_credentials flow only, not password grant

Future Improvements

  • Upstream PR for OIDC_EXCLUDE_PATHS environment variable
  • Upstream PR to include otel_router in standard routers
  • Consider Istio-level auth as alternative to application auth

Related Skills

  • auth:otel-oauth2-exporter
  • auth:keycloak-confidential-client
  • istio:ambient-waypoint

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

auth

免费

Authentication and authorization patterns for Rossoctl services

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

Create confidential OAuth2 clients in Keycloak for server-to-service authentication

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

Configure OpenTelemetry Collector with OAuth2 authentication for trace export

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

ci

免费

CI pipeline monitoring, status checks, and PR validation workflows

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

Monitor running CI jobs, wait for completion, create tasks for results

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

ci:status

免费

Check PR CI status - all checks, failures, test results, and artifacts

中文简介正在准备中。当前显示原文说明。

rossoctl/rossoctl3032026年10月25日 更新

查看 rossoctl 的全部技能

报告此技能的问题