Admin UI용 SSO

Admin UI용 SSO

LiteLLM Admin UI에 SSO(Single Sign-On)를 설정하는 방법을 알아봐요. Okta, Google, Microsoft, 일반 OAuth 제공사를 지원해요.

출처: 문서

본문

Enterprise 기능: SSO는 LiteLLM Enterprise 라이선스가 필요해요. 무료 30일 체험판이나 데모 예약이 가능해요. v1.76.0부터 SSO는 최대 5명까지 무료예요. 그 이상은 엔터프라이즈 라이선스가 필요해요.

Okta SSO

1단계: Okta에서 OIDC 애플리케이션 만들기

Okta Admin Console에서 새 OIDC Web Application을 만들어요. 애플리케이션 구성 시:

  • Sign-in redirect URI: https://<litellm>/sso/callback
  • Sign-out redirect URI (선택): https://<litellm>

앱 생성 후 General 탭에서 Client ID와 Client Secret을 복사해요.

2단계: 애플리케이션에 사용자 할당

Assignments 탭에서 사용자를 앱에 할당해요. Federation Broker Mode가 활성화되어 있으면 수동 할당을 위해 비활성화해야 할 수 있어요.

3단계: 환경 변수 설정

두 Okta 인가 서버의 유일한 차이는 엔드포인트 URL이에요.

Org Authorization Server (모든 Okta 플랜에서 사용 가능, 추가 SKU 불필요):

GENERIC_CLIENT_ID=""
GENERIC_CLIENT_SECRET=""
GENERIC_AUTHORIZATION_ENDPOINT="https://<org>/oauth2/v1/authorize"
GENERIC_TOKEN_ENDPOINT="https://<org>/oauth2/v1/token"
GENERIC_USERINFO_ENDPOINT="https://<org>/oauth2/v1/userinfo"
PROXY_BASE_URL="https://<litellm>"

Custom Authorization Server (Okta API Access Management SKU 필요):

GENERIC_CLIENT_ID=""
GENERIC_CLIENT_SECRET=""
GENERIC_AUTHORIZATION_ENDPOINT="https://<org>/oauth2/default/v1/authorize"
GENERIC_TOKEN_ENDPOINT="https://<org>/oauth2/default/v1/token"
GENERIC_USERINFO_ENDPOINT="https://<org>/oauth2/default/v1/userinfo"
PROXY_BASE_URL="https://<litellm>"

: 모든 OAuth 엔드포인트는 https://<org>/.well-known/openid-configuration에서 찾을 수 있어요.

3a단계: Access Policy 구성 (Custom Authorization Server 전용)

사용자가 no_matching_policy 오류를 받게 되므로 Access Policy를 구성해야 해요. Org Authorization Server를 쓰면 이 단계를 건너뛰어요.

  • Security → API로 이동
  • 기본 인가 서버(또는 사용자 정의 서버) 선택
  • Access Policies 탭에서 LiteLLM 앱에 할당된 새 정책 생성
  • Authorization Code grant type을 허용하는 규칙 추가

4단계: Okta 보안 설정 구성

CSRF 공격 방지를 위해 GENERIC_CLIENT_STATE가 권장돼요:

GENERIC_CLIENT_STATE="random-string"

Okta 앱이 PKCE를 요구하도록 구성되어 있으면:

GENERIC_CLIENT_USE_PKCE="true"

LiteLLM이 OAuth 흐름 중 PKCE 파라미터 생성·검증을 자동 처리해요.

5단계: SSO 흐름 테스트

  • LiteLLM proxy 시작
  • https://<litellm>/ui로 이동
  • SSO 로그인 버튼 클릭
  • Okta로 인증하고 LiteLLM으로 리다이렉트되는지 확인

문제 해결

오류 원인 해결책
redirect_uri 오류 Redirect URI 미구성 Okta의 Sign-in redirect URIs에 /sso/callback 추가
access_denied 사용자가 앱에 할당되지 않음 Assignments 탭에서 사용자 할당
no_matching_policy Access Policy 누락 (Custom Authorization Server 전용) Authorization Server에 Access Policy 생성 (3a단계 참고)

Google SSO

https://console.cloud.google.com/ 에서 새 Oauth 2.0 Client를 만들어요.

Proxy에 필요한 .env 변수:

# for Google SSO Login
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

Redirect URL 설정 = /sso/callback:

https://litellm-production-7002.up.railway.app/sso/callback

Microsoft SSO

https://portal.azure.com/ 에서 새 App Registration을 만들어요. App Registration용 client Secret을 만들어요.

Proxy에 필요한 .env 변수:

MICROSOFT_CLIENT_ID="84583a4d-"
MICROSOFT_CLIENT_SECRET="nbk8Q~"
MICROSOFT_TENANT="5a39737"

선택: 사용자 정의 Microsoft SSO 엔드포인트. 사용자 정의 엔드포인트(예: 사용자 정의 IdP, sovereign cloud, proxy)가 필요하면 기본 엔드포인트를 오버라이드할 수 있어요. 설정하지 않으면 테넌트 기반 기본 Microsoft 엔드포인트가 사용돼요.

Red:irect URI = /sso/callback:

http://localhost:4000/sso/callback

사용자 권한에 App Roles 사용

Entra ID의 App Roles로 사용자 역할을 직접 할당할 수 있어요. LiteLLM이 JWT 토큰에서 app roles를 자동으로 읽고 해당 역할을 사용자에게 할당해요. 지원 역할:

  • proxy_admin - 플랫폼 관리자
  • proxy_admin_viewer - 로그인, 모든 키 보기, 모든 스펜드 보기 (읽기 전용)
  • internal_user - 일반 사용자. 로그인, 스펜드 보기, 팀 멤버 권한에 따라 자신의 키 보기/생성/삭제

App roles 설정: App Registration → "App roles" → 새 app role 생성 → 위 지원 역할 이름 중 하나 사용 (예: proxy_admin) → Enterprise Application에서 사용자를 역할에 할당 → SSO로 로그인하면 LiteLLM이 자동으로 해당 역할 부여.

사용자 정의 사용자 속성 매핑

일부 Microsoft Entra ID 구성에서는 기본 사용자 속성 필드 이름을 오버라이드해야 할 수 있어요. SSO Debug Route로 JWT 필드를 먼저 검사한 뒤 다음 환경 변수를 설정해요:

환경 변수 설명 기본값
MICROSOFT_USER_EMAIL_ATTRIBUTE 사용자 이메일 필드 이름 userPrincipalName
MICROSOFT_USER_DISPLAY_NAME_ATTRIBUTE 표시 이름 필드 이름 displayName
MICROSOFT_USER_ID_ATTRIBUTE 사용자 ID 필드 이름 id
MICROSOFT_USER_FIRST_NAME_ATTRIBUTE 이름 필드 이름 givenName
MICROSOFT_USER_LAST_NAME_ATTRIBUTE 성 필드 이름 surname

일반 SSO 제공사

거의 코드 없이 어떤 OAuth 제공사든 지원을 빠르게 만들 수 있는 일반 OAuth 클라이언트예요.

Proxy에 필요한 .env 변수:

GENERIC_CLIENT_ID = "******"
GENERIC_CLIENT_SECRET = "G*******"
GENERIC_AUTHORIZATION_ENDPOINT = "http://localhost:9090/auth"
GENERIC_TOKEN_ENDPOINT = "http://localhost:9090/token"
GENERIC_USERINFO_ENDPOINT = "http://localhost:9090/me"

선택 .env 변수 (일반 OAuth 제공사와 상호작용 시 속성 이름을 커스터마이즈):

GENERIC_USER_ID_ATTRIBUTE = "sub"
GENERIC_USER_EMAIL_ATTRIBUTE = "email"
GENERIC_USER_DISPLAY_NAME_ATTRIBUTE = "display_name"
GENERIC_USER_FIRST_NAME_ATTRIBUTE = "first_name"
GENERIC_USER_LAST_NAME_ATTRIBUTE = "last_name"
GENERIC_USER_ROLE_ATTRIBUTE = "given_role"
GENERIC_USER_PROVIDER_ATTRIBUTE = "provider"
GENERIC_USER_EXTRA_ATTRIBUTES = "department,employee_id,manager" # comma-separated list of additional fields to extract from SSO response
GENERIC_CLIENT_STATE = "some-state" # if the provider needs a state parameter
GENERIC_INCLUDE_CLIENT_ID = "false" # some providers enforce that the client_id is not in the body
GENERIC_SCOPE = "openid profile email" # default scope openid is sometimes not enough to retrieve basic user info like first_name and last_name located in profile scope

GENERIC_INCLUDE_TOKEN_CLAIMS = "true"로 설정하면 UserInfo 응답이 불완전할 때 ID 토큰·액세스 토큰에서도 사용자 클레임을 읽어요. UserInfo 클레임이 우선해요.

GENERIC_USER_ID_ATTRIBUTE 선택: LiteLLM은 이 속성 값을 사용자 신원으로 저장하고 이후 로그인마다 그걸로 사용자를 찾아요. 제공사가 계정 수명 동안 고유하고 절대 변하지 않는 클레임을 가리켜야 해요. sub가 표준 OIDC 클레임이에요. preferred_username, email, name처럼 사용자가 프로필에서 편집할 수 있는 클레임은 LiteLLM 밑에서 바뀌므로, 다음 로그인이 별도 키·팀·스펜드를 가진 다른 사람으로 취급돼요. GENERIC_USER_ID_ATTRIBUTE가 설정되지 않으면 LiteLLM은 preferred_username을 읽으므로, 제공사가 사용자가 그 값을 바꿀 수 있게 한다면 명시적으로 설정하세요.

SSO로 사용자 역할 할당: GENERIC_USER_ROLE_ATTRIBUTE로 SSO 토큰에서 사용자 역할이 들어 있는 속성을 지정해요. 역할 값은 다음 지원 LiteLLM 역할 중 하나여야 해요: proxy_admin, proxy_admin_viewer, internal_user, internal_user_viewer. 중첩 속성 경로 지원 (claims.role, attributes.litellm_role).

추가 SSO 필드 캡처: 표준 사용자 속성(id, email, name 등) 너머의 필드도 GENERIC_USER_EXTRA_ATTRIBUTES로 추출할 수 있어요. 커스텀 SSO 핸들러에서 접근:

from litellm.proxy.management_endpoints.types import CustomOpenID

async def custom_sso_handler(userIDPInfo: CustomOpenID):
    # Access the extra fields
    extra_fields = getattr(userIDPInfo, 'extra_fields', None) or {}

    user_department = extra_fields.get("department")
    employee_id = extra_fields.get("employee_id")
    user_groups = extra_fields.get("groups", [])
    # ...

중첩 경로는 점 표기법 지원:

GENERIC_USER_EXTRA_ATTRIBUTES="org_info.department,org_info.cost_center,metadata.employee_type"

Redirect URI (제공사가 요구하면) = /sso/callback:

http://localhost:4000/sso/callback

기본 로그인, 로그아웃 URL

일부 SSO 제공사는 로그인·로그아웃에 특정 redirect url을 요구해요.

  • Login: /sso/key/generate
  • Logout: empty

proxy에서 로그아웃 url 설정:

PROXY_LOGOUT_URL="https://www.google.com"

.envPROXY_BASE_URL 설정

PROXY_BASE_URL=https://litellm-api.up.railway.app

SSO로 이메일 서브도메인 제한

특정 서브도메인(예: @berri.ai 이메일 계정) 사용자만 UI에 접근하게 하려면:

export ALLOWED_EMAIL_DOMAINS="berri.ai"

SSO에서 받은 사용자 이메일에 이 도메인이 포함되는지 접근 허용 전에 확인해요.

Proxy Admin 설정

SSO가 활성화되면 사용자의 user_id를 SSO 제공사에서 가져와요. Proxy Admin을 설정하려면 UI에서 user_id를 복사해 .envPROXY_ADMIN_ID로 설정해야 해요.

export PROXY_ADMIN_ID="116544810872468347480"

이렇게 하면 LiteLLM_UserTable의 사용자 역할이 proxy_admin으로 업데이트돼요. ID를 변경할 계획이라면 /user/update API나 UI(Internal Users 페이지)로 사용자 역할을 업데이트하세요.

OIDC로 SSO 사용자를 팀에 자동 추가

OIDC 제공사(Okta, Google, Generic SSO)에서 IdP가 반환한 토큰의 클레임을 사용자의 team_ids로 가져올 수 있어요. 매 SSO 로그인마다 LiteLLM이 해당 클레임을 읽고 사용자를 각 일치 팀의 멤버로 추가해요.

1단계: 팀 id가 들어 있는 클레임을 LiteLLM에 지정:

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  litellm_jwtauth:
    team_ids_jwt_field: "groups" # any claim; dot notation works for nested claims, e.g. "resource_access.myapp.groups"

제공사 토큰이 이렇게 생겼다고 가정:

{
  ...,
  "groups": ["team_id_1", "team_id_2"]
}

2단계: LiteLLM에 팀 생성: 클레임 값은 LiteLLM에 이미 존재하는 팀의 team_id와 일치해야 해요. 팀은 OIDC 클레임에서 자동 생성되지 않으며, 일치하는 팀이 없는 클레임 값은 건너뛰어요.

curl -X POST '/team/new' \
-H 'Authorization: *** ' \
-H 'Content-Type: application/json' \
-d '{
    "team_alias": "team_1",
    "team_id": "team_id_1"
}'

3단계: SSO 흐름 테스트.

일부 제공사는 groups 클레임을 userinfo 응답이 아닌 access token에만 포함해요. 그 경우 ui_access_mode로 클레임을 구성하세요. 이 형태는 access token도 디코딩하며, UI 로그인을 특정 그룹 멤버로 제한해요:

general_settings:
  ui_access_mode:
    type: "restricted_sso_group"
    restricted_sso_group: ""
    sso_group_jwt_field: "groups"

Microsoft Entra ID는 그룹 멤버십을 Microsoft Graph API에서 읽으며, SAML은 팀 id를 assertion 속성에서 가져와요.

개인 키 생성 제한

팀이 없는 개인 키(keys with no team) 생성을 막으려면 key_generation_settings를 설정하세요. /key/generate에서 강제되므로 Admin UI와 직접 API 호출 모두에 적용돼요.

litellm_settings:
  key_generation_settings:
    personal_key_generation:
      allowed_user_roles: ["proxy_admin"]

SSO가 켜져 있을 때 사용자 이름/암호 사용

SSO가 켜진 상태에서 사용자 이름/암호로 UI에 접근해야 한다면 /fallback/login으로 이동해요.

UI 접근 제한

UI 접근을 관리자만으로 제한할 수 있어요. 지금 사용 중인 사용자(proxy_admin)와 전역 스펜드를 보는 뷰 전용(proxy_admin_viewer) 사람을 포함해요.

general_settings:
    ui_access_mode: "admin_only"

Admin UI 사용자 지정 브랜딩

회사의 사용자 지정 브랜딩을 LiteLLM Admin UI에 적용할 수 있어요. UI 로고와 UI 색상 구성표를 커스터마이즈할 수 있어요.

로고 설정: 로컬 이미지 또는 http/https URL을 전달할 수 있어요. UI_LOGO_PATH를 env에 설정하세요. 호스팅 이미지 사용을 권장해요.

UI_LOGO_PATH="https://litellm-logo-aws-marketplace.s3.us-west-2.amazonaws.com/berriai-logo-github.png"

또는 로컬 이미지:

UI_LOGO_PATH="ui_images/logo.jpg"

색상 테마 설정: /enterprise/enterprise_ui로 이동해 _enterprise_colors.jsonenterprise_colors.json으로 이름 변경하고 회사 색상 구성표를 설정하세요.

{
    "brand": {
      "DEFAULT": "teal",
      "faint": "teal",
      "muted": "teal",
      "subtle": "teal",
      "emphasis": "teal",
      "inverted": "teal"
    }
}

문제 해결

"The 'redirect_uri' parameter must be a Login redirect URI in the client app settings" 오류

이 오류는 보통 Okta와 다른 SSO 제공사에서 redirect URI 구성이 잘못됐을 때 발생해요.

  1. .envPROXY_BASE_URL을 프로토콜 포함으로 설정했는지 확인:
# ✅ Correct - includes https://
PROXY_BASE_URL=https://litellm.platform.com

# ❌ Incorrect - missing protocol
PROXY_BASE_URL=litellm.platform.com
  1. Okta는 GENERIC_CLIENT_STATE를 설정하고 필요 시 PKCE를 구성해야 해요.

SSO JWT 필드 디버깅

LiteLLM이 SSO 제공사에서 받은 JWT 필드를 검사하려면 디버그 콜백을 설정할 수 있어요.

  • SSO 제공사에 /sso/debug/callback을 redirect URL로 추가
  • 브라우저에서 https://<litellm>/sso/debug/login으로 이동
  • 표준 SSO 흐름을 완료하면 "SSO Debug Information" 페이지에서 JWT 필드를 볼 수 있어요

고급

Azure App Roles로 사용자 역할 관리

사용자 권한을 Azure Entra ID에서 정의해 역할 관리를 중앙화해요. 사용자가 로그인하면 LiteLLM이 Azure 구성에 따라 역할을 자동 할당해요.

App Roles 생성: App Registration → App roles → Create app role. 지원 역할 값: proxy_admin, proxy_admin_viewer, internal_user, internal_user_viewer. 사용자를 Enterprise Applications에서 역할에 할당하면 SSO 로그인 시 LiteLLM이 JWT에서 app role을 추출해 해당 역할을 할당해요. Entra ID의 역할은 LiteLLM 데이터베이스의 기존 역할보다 우선하므로, SSO 제공사가 사용자 역할의 권위 있는 출처이에요.

더 알아보기 (Learn more)

  • Okta OIDC 앱 설정 가이드
  • LiteLLM SAML SSO
  • LiteLLM 역할 문서