MLflow 배포 (OIDC Auth)
MLflow 3.11.1 + mlflow-oidc-auth v7.0.3를 Keycloak과 연동하여 배포하는 가이드이다.
커스텀 이미지 wbsong111/mlflow:v3.11.1-oidc에 OIDC 플러그인이 포함되어 있다.
1. 사전 준비
1.1 Keycloak 설정
Client 생성
- Realm:
paasup, Client ID:mlflow, Protocol:openid-connect - Access Type:
confidential - Valid Redirect URIs:
https://mlflow.example.org/* - Web Origins:
https://mlflow.example.org
Groups Mapper 추가 (userinfo 포함 필수)
Client → Mappers → Create:
| 항목 | 값 |
|---|---|
| Mapper type | Group Membership |
| Token Claim Name | groups |
| Full group path | false |
| Add to ID token | true |
| Add to access token | true |
| Add to userinfo | true ← 반드시 true |
Groups 생성
mlflow— 일반 사용자 접근 허용 그룹mlflow-admin— 관리자 그룹
사용자를 해당 그룹에 할당한다.
1.2 Keycloak CA 인증서 ConfigMap 생성
Keycloak이 사설 CA 인증서를 사용하는 경우 필수이다.
# Keycloak TLS secret에서 CA 인증서 추출
kubectl get secret keycloak.example.org-tls -n platform \
-o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/keycloak-ca.crt
# ConfigMap 생성
kubectl create configmap keycloak-ca-cert -n mlflow \
--from-file=ca.crt=/tmp/keycloak-ca.crt
1.3 OIDC Secret 생성
SECRET_KEY는 uvicorn 멀티워커 환경에서 세션 공유를 위해 반드시 포함해야 한다.
# Fernet key 생성 (webhook secret 암호화용)
FERNET_KEY=$(python3 -c "import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())")
# Session key 생성 (멀티워커 세션 공유용)
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
kubectl create secret generic mlflow-oidc-secret -n mlflow \
--from-literal=OIDC_CLIENT_SECRET="<keycloak-client-secret>" \
--from-literal=MLFLOW_WEBHOOK_SECRET_ENCRYPTION_KEY="$FERNET_KEY" \
--from-literal=SECRET_KEY="$SECRET_KEY"
Keycloak Client Secret은 Keycloak Admin Console → Client → Credentials 탭에서 확인한다.
2. 배포 방법
git clone https://github.com/paasup/dip-catalog.git
cd dip-catalog
# 신규 설치
helm install mlflow manifests/helm/mlflow/1.8.1/ \
-f manifests/helm/mlflow/1.8.1/custom-values.yaml \
-n mlflow --create-namespace
# 업그레이드
helm upgrade mlflow manifests/helm/mlflow/1.8.1/ \
-f manifests/helm/mlflow/1.8.1/custom-values.yaml \
-n mlflow
3. custom-values.yaml 설명
3.1 이미지 설정
OIDC 플러그인이 포함된 커스텀 이미지를 사용한다.
image:
repository: wbsong111/mlflow
tag: "v3.11.1-oidc"
initImages:
mlflowDbMigration:
repository: wbsong111/mlflow
tag: "v3.11.1-oidc"
3.2 OIDC 환경변수 설정
extraEnvVars:
SSL_CERT_FILE: "/etc/ssl/certs/custom-ca.crt"
OIDC_CLIENT_ID: "mlflow"
OIDC_DISCOVERY_URL: "https://keycloak.example.org/realms/paasup/.well-known/openid-configuration"
OIDC_REDIRECT_URI: "https://mlflow.example.org/callback"
OIDC_SCOPE: "openid email profile"
OIDC_GROUPS_ATTRIBUTE: "groups"
OIDC_GROUP_NAME: "mlflow"
OIDC_ADMIN_GROUP_NAME: "mlflow-admin"
OIDC_USERS_DB_URI: "postgresql://mlflow:mlflow1234@mlflow-postgresql:5432/mlflow"
DEFAULT_MLFLOW_PERMISSION: "READ"
MLFLOW_ENABLE_WORKSPACES: "false"
AUTOMATIC_LOGIN_REDIRECT: "true"
OIDC_ALEMBIC_VERSION_TABLE: "mlflow_oidc_alembic_version"
주의사항
| 항목 | 올바른 값 | 잘못된 값 | 이유 |
|---|---|---|---|
SSL_CERT_FILE |
SSL_CERT_FILE |
REQUESTS_CA_BUNDLE |
mlflow-oidc-auth는 httpx를 사용하며 httpx는 SSL_CERT_FILE 환경변수를 인식 |
OIDC_SCOPE |
"openid email profile" |
"openid,email,profile" |
OAuth2 RFC 6749 표준: 스코프는 공백으로 구분 |
OIDC_REDIRECT_URI |
.../callback |
.../oidc/callback |
mlflow-oidc-auth auth_router에 prefix가 없어 실제 경로는 /callback |
OIDC_ALEMBIC_VERSION_TABLE |
"mlflow_oidc_alembic_version" |
기본값(alembic_version) |
MLflow와 mlflow-oidc-auth가 동일한 alembic_version 테이블을 사용하면 마이그레이션 충돌 발생 |
3.3 OIDC App 활성화
extraArgs:
appName: "oidc-auth" # OIDC 플러그인 활성화
uvicornOpts: "--timeout-keep-alive 600"
allowedHosts: "mlflow.example.org"
log:
enabled: false # uvicornOpts 사용 시 반드시 false (gunicorn/uvicorn 충돌 방지)
auth:
enabled: false # mlflow-oidc-auth가 자체 인증 처리
3.4 Secret 참조
extraSecretNamesForEnvFrom:
- mlflow-oidc-secret # OIDC_CLIENT_SECRET, SECRET_KEY, MLFLOW_WEBHOOK_SECRET_ENCRYPTION_KEY 포함
3.5 CA 인증서 볼륨 마운트
extraVolumes:
- name: keycloak-ca-cert
configMap:
name: keycloak-ca-cert
extraVolumeMounts:
- name: keycloak-ca-cert
mountPath: /etc/ssl/certs/custom-ca.crt
subPath: ca.crt
readOnly: true
3.6 Ingress 설정
ingress:
enabled: true
className: "kong"
annotations:
cert-manager.io/cluster-issuer: "selfsigned-issuer"
cert-manager.io/duration: 8760h
cert-manager.io/renew-before: 720h
hosts:
- host: mlflow.example.org
paths:
- path: /
pathType: ImplementationSpecific
tls:
- secretName: mlflow-tls-secret
hosts:
- mlflow.example.org
mlflow.example.org를 실제 도메인으로 변경한다.
3.7 PostgreSQL 설정
내장 PostgreSQL을 사용한다.
postgresql:
enabled: true
auth:
username: mlflow
password: mlflow1234 # 변경 권장
database: mlflow
image:
repository: bitnamilegacy/postgresql
primary:
persistence:
enabled: true
OIDC_USERS_DB_URI도 동일한 접속 정보를 사용한다.
extraEnvVars:
OIDC_USERS_DB_URI: "postgresql://mlflow:mlflow1234@mlflow-postgresql:5432/mlflow"
3.8 S3 (MinIO) 설정
artifactRoot:
proxiedArtifactStorage: true
defaultArtifactsDestination: "s3://mlflow/artifacts"
s3:
enabled: true
bucket: mlflow
path: artifacts
awsAccessKeyId: "adminuser" # MinIO access key
awsSecretAccessKey: "adminuser" # MinIO secret key
extraEnvVars:
MLFLOW_S3_ENDPOINT_URL: "http://minio.minio.svc.cluster.local:9000"
MLFLOW_S3_IGNORE_TLS: "true"
외부 MinIO 사용 시 MLFLOW_S3_ENDPOINT_URL을 해당 엔드포인트로 변경한다.
4. 배포 검증
https://mlflow.example.org접속 → Keycloak 로그인 페이지로 자동 리다이렉트mlflow그룹 사용자로 로그인 → MLflow UI 정상 진입 확인mlflow-admin그룹 사용자로 로그인 → 관리자 메뉴 접근 확인- 미가입 사용자 로그인 → 접근 거부 확인