SAML 2.0 SSO

SAML 2.0 SSO

Enterprise 기능이에요. SSO는 LiteLLM Enterprise 라이선스가 필요해요. 무료 30일 체험판 시작 또는 데모 예약을 해보세요. Enterprise에 포함된 것 보기.

SSO는 최대 5명의 사용자까지 무료예요. 그 이상은 엔터프라이즈 라이선스가 필요해요.

LiteLLM은 기존 OIDC 제공자(Google, Microsoft, Generic OAuth)와 함께 admin UI용 SAML 2.0 싱글 사인온을 지원해요. SAML은 admin UI(Admin Settings → SSO Settings) 또는 환경 변수를 통해 구성할 수 있고, config.yaml 변경은 필요 없어요. SAML이 구성되고 OIDC 제공자가 설정되지 않으면, admin UI의 기존 SSO 로그인 버튼이 자동으로 SAML Identity Provider로 리다이렉트돼요.

동작 방식

프록시가 SAML Service Provider(SP) 역할을 해요. 사용자가 로그인 버튼을 클릭하면 서명된 AuthnRequest와 함께 Identity Provider(IdP)로 리다이렉트돼요. 사용자가 IdP에서 인증을 마치면 브라우저는 서명된 SAML assertion을 프록시의 Assertion Consumer Service(ACS) 엔드포인트로 POST해요. 프록시는 assertion의 서명, audience, 타임스탬프를 검증하고, 필요하면 데이터베이스에 사용자를 프로비저닝한 뒤, admin UI에 로그인시키는 세션 JWT를 발급해요.

SP-initiated와 IdP-initiated 흐름 모두 HTTP-POST binding으로 지원돼요. SP-initiated 로그인은 HttpOnly 상태 쿠키로 시작한 브라우저에 묶이므로, 가로챈 assertion을 다른 브라우저에서 재생(replay)할 수 없어요. IdP-initiated(unsolicited) 응답은 기본적으로 거부되며 SAML_ALLOW_UNSOLICITED=true를 명시적으로 설정했을 때만 허용돼요.

admin UI에서 구성하기

가장 빠른 SAML 설정 방법은 대시보드에서 하는 거예요. Admin Settings → SSO Settings로 가서 Configure SSO를 클릭하고, 제공자 드롭다운에서 SAML SSO를 선택하세요. IdP의 메타데이터(URL 또는 인라인 XML)를 붙여 넣고, SP Entity ID와 Proxy Base URL을 설정하고, 선택적으로 IdP-initiated 응답을 활성화한 뒤 저장하면 돼요.

설정은 (암호화되어) SSO config 테이블에 저장되고 핸들러가 읽는 SAML_* 변수로 적용돼요. 그래서 env var 없이도 재시작 후에도 유지돼요. 헤드리스나 GitOps 배포에서는 환경 변수를 선호하세요. 아래 Quick start에서 그 경로를 다뤄요.

빠른 시작

1. SAML extra 설치

SAML 통합은 네이티브 xmlsec/libxml2 라이브러리를 번들하는 python3-saml 라이브러리에 의존해요. saml extra로 설치하세요:

    pip install 'litellm[saml]'  
    

공식 Docker 이미지에는 이미 이 extra가 포함돼 있어요. 자체 이미지를 만든다면 설치 단계에 litellm[saml]을 추가하세요.

2. 환경 변수 설정

최소한 IdP의 메타데이터(URL 또는 인라인 XML)와, 선택적으로 SP entity ID가 필요해요:

    # Point to your IdP's metadata (pick one)  
    SAML_IDP_METADATA_URL="https://your-idp.example.com/app/abc123/sso/saml/metadata"  
    # or  
    SAML_IDP_METADATA_XML="<EntityDescriptor ...>...</EntityDescriptor>"  
      
    # Optional: override the SP entity ID (defaults to the metadata endpoint URL)  
    SAML_SP_ENTITY_ID="https://litellm.yourcompany.com/sso/saml/metadata"  
      
    # Required for any SSO  
    PROXY_BASE_URL="https://litellm.yourcompany.com"  
    LITELLM_MASTER_KEY="sk-..."  
    DATABASE_URL="postgresql://..."  
    

3. IdP에 프록시 등록

IdP에는 프록시에서 두 가지 값이 필요해요:

필드
ACS URL (Assertion Consumer Service) https://<proxy_base_url>/sso/saml/callback
SP Entity ID / Audience https://<proxy_base_url>/sso/saml/metadata (또는 SAML_SP_ENTITY_ID에 설정한 값)

GET /sso/saml/metadata에서 SP 메타데이터 XML을 직접 다운로드할 수 있고, IdP가 메타데이터 업로드를 지원한다면 그걸 가져올 수 있어요.

저장 후 SSO Settings 페이지에는 IdP에 등록하는 SP Entity ID를 포함해 구성된 제공자가 표시돼요.

4. 프록시 시작 및 테스트

프록시를 시작(또는 재시작)하세요. https://<proxy_base_url>/ui로 이동해 SSO 로그인 버튼을 클릭하면 IdP로 리다이렉트되고, 인증 후 admin UI로 돌아와요.

IdP 설정 가이드

  • Okta
  • Microsoft Entra ID (Azure AD)
  • 기타 SAML IdP

1단계: Okta에서 SAML 애플리케이션 생성

Okta Admin Console에서 Applications > Create App Integration으로 가서 SAML 2.0을 선택하세요.

General Settings 페이지에서 앱 이름(예: "LiteLLM Proxy")을 지정하세요.

Configure SAML 페이지에서 다음을 입력하세요:

필드
Single sign-on URL https://<proxy_base_url>/sso/saml/callback
Audience URI (SP Entity ID) https://<proxy_base_url>/sso/saml/metadata
Name ID format EmailAddress

Attribute Statements 아래에서 프록시가 읽을 속성을 추가하세요. 기본값은 흔한 claim 이름으로 바로 동작하지만, 명시적인 매핑을 추가할 수도 있어요:

이름
email user.email
firstName user.firstName
lastName user.lastName

Okta에서 사용자 역할을 제어하려면 Group Attribute Statementproxy_admin, proxy_admin_viewer, internal_user, internal_user_viewer 값의 role이라는 맞춤 속성을 추가하세요.

2단계: IdP 메타데이터 URL 복사

앱 생성 후 Sign On 탭으로 가서 Metadata URL을 복사하세요(https://your-org.okta.com/app/abc123/sso/saml/metadata 형태).

3단계: 환경 변수 설정

    SAML_IDP_METADATA_URL="https://your-org.okta.com/app/abc123/sso/saml/metadata"  
    PROXY_BASE_URL="https://litellm.yourcompany.com"  
    

4단계: 사용자 할당

Okta 앱의 Assignments 탭에서 LiteLLM admin UI에 접근해야 하는 사용자나 그룹을 할당하세요.

1단계: Enterprise Application 생성

Azure 포털에서 Microsoft Entra ID > Enterprise applications > New application > Create your own application으로 가세요. 이름(예: "LiteLLM Proxy")을 지정하고 "Integrate any other application you don't find in the gallery (Non-gallery)"를 선택하세요.

2단계: SAML SSO 설정

Single sign-on > SAML로 가서 다음을 구성하세요:

필드
Identifier (Entity ID) https://<proxy_base_url>/sso/saml/metadata
Reply URL (ACS URL) https://<proxy_base_url>/sso/saml/callback

Attributes & Claims 아래에서 기본 claim에 사용자의 이메일이 포함되는지 확인하세요. 기본 Entra ID claim(emailaddress, givenname, surname)은 LiteLLM이 자동 감지해요.

LiteLLM 역할을 매핑하려면 App Role이나 디렉터리 속성에서 값을 가져오는 role이라는 맞춤 claim을 추가하세요.

3단계: 메타데이터 URL 복사

SAML Certificates 아래에서 App Federation Metadata Url을 복사하세요.

4단계: 환경 변수 설정

    SAML_IDP_METADATA_URL="https://login.microsoftonline.com/<tenant-id>/federationmetadata/2007-06/federationmetadata.xml?appid=<app-id>"  
    PROXY_BASE_URL="https://litellm.yourcompany.com"  
    

5단계: 사용자 할당

Users and groups에서 접근해야 하는 사용자나 그룹을 할당하세요.

SAML 2.0을 준수하는 모든 IdP가 동작해요. 필요한 것:

  1. IdP의 메타데이터 XML(URL 또는 인라인으로 붙여넣기).
  2. IdP에 프록시의 ACS URL(/sso/saml/callback)과 Entity ID(/sso/saml/metadata)를 등록.
  3. IdP가 최소한 사용자 이메일을 포함한 서명된 assertion(NameID 또는 속성으로)을 보내야 함.
    # URL-based metadata  
    SAML_IDP_METADATA_URL="https://idp.example.com/metadata"  
      
    # Or paste the full metadata XML inline  
    SAML_IDP_METADATA_XML='<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://idp.example.com">...</EntityDescriptor>'  
      
    PROXY_BASE_URL="https://litellm.yourcompany.com"  
    

속성 매핑

LiteLLM은 이메일, 이름, 성, 역할, 팀에 대한 흔한 SAML 속성 이름(URN/OID 및 friendly name)을 자동 감지해요. IdP가 비표준 속성 이름을 사용한다면 환경 변수로 오버라이드하세요:

환경 변수 기본 후보 설명
SAML_ATTRIBUTE_EMAIL urn:oid:0.9.2342.19200300.100.1.3, emailaddress claim URI, email, mail 사용자 이메일을 담은 속성
SAML_ATTRIBUTE_USER_ID NameID 안정적인 사용자 식별자 속성
SAML_ATTRIBUTE_FIRST_NAME urn:oid:2.5.4.42, givenname claim URI, givenName 이름 속성
SAML_ATTRIBUTE_LAST_NAME urn:oid:2.5.4.4, surname claim URI, sn 성 속성
SAML_ATTRIBUTE_ROLE role, roles, litellm_role LiteLLM 사용자 역할에 매핑되는 속성
SAML_ATTRIBUTE_TEAM_IDS teams, team_ids, groups LiteLLM 팀 ID에 매핑되는 속성

역할 속성의 값은 반드시 proxy_admin, proxy_admin_viewer, internal_user, internal_user_viewer 중 하나여야 해요.

구성 참조

모든 구성은 환경 변수로 해요. SAML_IDP_METADATA_URL 또는 SAML_IDP_METADATA_XML 중 하나가 설정되면 SAML이 활성화돼요.

변수 기본값 용도
SAML_IDP_METADATA_URL 설정 안 됨 가져와 파싱할 IdP 메타데이터의 URL
SAML_IDP_METADATA_XML 설정 안 됨 인라인 IdP 메타데이터 XML (URL의 대안)
SAML_IDP_METADATA_VALIDATE_CERT true HTTPS로 메타데이터를 가져올 때 TLS 인증서 검증
SAML_SP_ENTITY_ID <proxy_base_url>/sso/saml/metadata Service Provider entity ID
SAML_SP_NAME_ID_FORMAT emailAddress 요청된 NameID 형식
SAML_STRICT true 엄격한 SAML 검증 시행 (audience, timestamps, destination)
SAML_WANT_ASSERTIONS_SIGNED true 서명되지 않은 assertion 거부
SAML_WANT_MESSAGES_SIGNED false SAML 응답 메시지 자체가 서명되도록 요구
SAML_AUTHN_REQUESTS_SIGNED false 나가는 AuthnRequests 서명
SAML_ALLOW_UNSOLICITED false IdP-initiated (unsolicited) 응답 허용
SAML_ATTRIBUTE_EMAIL 자동 감지 이메일용 assertion 속성 이름 오버라이드
SAML_ATTRIBUTE_USER_ID NameID 사용자 ID용 assertion 속성 오버라이드
SAML_ATTRIBUTE_FIRST_NAME 자동 감지 이름용 assertion 속성 오버라이드
SAML_ATTRIBUTE_LAST_NAME 자동 감지 성용 assertion 속성 오버라이드
SAML_ATTRIBUTE_ROLE role LiteLLM 역할용 assertion 속성 오버라이드
SAML_ATTRIBUTE_TEAM_IDS teams/groups 팀 ID용 assertion 속성 오버라이드

SP 엔드포인트

프록시는 세 개의 SAML 엔드포인트를 노출해요:

메서드 경로 용도
GET /sso/saml/login SP-initiated 로그인; 브라우저를 IdP로 리다이렉트
GET /sso/saml/metadata IdP에 프록시를 등록하기 위한 SP 메타데이터 XML
POST /sso/saml/callback Assertion Consumer Service; IdP의 서명된 응답 검증

기존 GET /sso/key/generate 엔드포인트(admin UI의 로그인 버튼)는 SAML이 유일한 구성된 SSO 제공자일 때 자동으로 SAML IdP로 리다이렉트돼요.

보안

SP-initiated 로그인은 HttpOnly 상태 쿠키(litellm_saml_authn)를 사용해 SAML 응답을 로그인을 시작한 브라우저에 묶어요. 이는 서명된 응답을 가로채 다른 브라우저 세션에 재생하는 로그인 CSRF 공격을 막아요. 쿠키는 HTTPS에서는 Secure; SameSite=None(IdP의 크로스사이트 POST를 견디도록)이고, 로컬 개발용 일반 HTTP에서는 SameSite=Lax예요.

Assertion은 assertion ID 키 기반의 consumed-assertion 가드로 재생 여부를 검사해요. 각 assertion은 유효 기간 내에서 한 번만 사용될 수 있어요.

IdP-initiated(unsolicited) 응답은 브라우저에 묶을 수 없기 때문에 기본적으로 거부돼요. IdP-initiated 로그인이 필요한 배포라서 그 트레이드오프를 이해한다면에만 SAML_ALLOW_UNSOLICITED=true를 설정하세요.

문제 해결

"SAML SSO requires the optional 'python3-saml' dependency" (501 에러). SAML extra를 설치하세요: pip install 'litellm[saml]'. 공식 Docker 이미지에는 포함돼 있어요.

"Could not parse an IdP entityID/SSO URL/certificate from the SAML metadata" (502 에러). 메타데이터 URL이 IdP 디스크립터를 추출할 수 없는 것을 반환했어요. URL이 정확하고 프록시에서 접근 가능한지 확인하고, SAML_IDP_METADATA_XML을 쓴다면 셸 따옴표 때문에 잘리지 않았는지 전체 XML이 설정됐는지 확인하세요.

"SAML response references an unknown or already-used login request" (401 에러). assertion의 InResponseTo가 대기 중인 로그인과 일치하지 않아요. 로그인 상태가 만료됐거나(10분 창), 사용자가 IdP 리다이렉트를 북마크했거나, assertion이 재생됐을 수 있어요. /sso/saml/login에서 새 로그인을 시작하게 하세요.

"Unsolicited (IdP-initiated) SAML responses are disabled" (401 에러). 프록시가 InResponseTo 속성 없는 SAML 응답을 받았어요. 즉 IdP-initiated 로그인이었던 거죠. 이 흐름을 허용하고 싶다면 SAML_ALLOW_UNSOLICITED=true를 설정하세요.

IdP 크로스사이트 POST 후 assertion 검증 실패. PROXY_BASE_URL이 프록시의 공개 URL(https:// 포함)로 설정됐는지 확인하세요. SP 메타데이터의 ACS URL과 audience가 여기서 파생되므로, 불일치하면 검증이 실패해요.

출처: 문서

더 알아보기 (Learn more)

  • OIDC 제공자(Google, Microsoft, Generic OAuth) 설정 살펴보기
  • Self-serve 라우트와 역할 기반 접근 제어 이해하기