패스스루 관리형 ID

패스스루 관리형 ID (Passthrough Managed IDs)

LiteLLM의 패스스루 엔드포인트(예: /openai_passthrough/v1/files, /azure/openai/batches)를 쓰면 업스트림 공급자가 file-abc123이나 batch_xyz 같은 자체 원시 ID를 반환해요. 기본적으로 그 ID가 클라이언트에 직접 반환되는데, 이는 다음을 뜻해요:

  • 누군가 다른 사용자의 file-abc123을 추측하거나 가로채면 그걸 쓸 수 있어요.
  • 누가 무엇을 소유하는지에 대한 프록시 레벨 기록이 없어요.
  • 멀티 테넌트 격리를 전적으로 애플리케이션 코드에서 해야 해요.

Passthrough Managed IDs가 이 문제를 해결해요. 이 기능이 켜지면 프록시는:

  1. 응답에서 보는 모든 원시 provider ID에 대해 안정적이고 불투명한 관리형 ID를 발행(mint) 해요.
  2. managed_id → raw_id 매핑을 프록시 데이터베이스에 저장하고, 생성한 사용자/팀을 태그해요.
  3. 소유권/권한 검사를 실행한 뒤, 요청을 업스트림으로 전달하기 직전에 관리형 ID를 원시 provider ID로 다시 풀어(resolve) 줘요.

클라이언트는 원시 provider ID를 절대 보지 못하고, 관리형 ID 문자열을 추측하거나 위조해도 소유하지 않은 리소스에 접근할 수 없어요.

출처: 문서

본문

LiteLLM의 패스스루 엔드포인트(예: /openai_passthrough/v1/files, /azure/openai/batches)를 쓰면 업스트림 공급자가 file-abc123이나 batch_xyz 같은 자체 원시 ID를 반환해요. 기본적으로 그 ID가 클라이언트에 직접 반환되는데, 이는 다음을 뜻해요:

  • 누군가 다른 사용자의 file-abc123을 추측하거나 가로채면 그걸 쓸 수 있어요.
  • 누가 무엇을 소유하는지에 대한 프록시 레벨 기록이 없어요.
  • 멀티 테넌트 격리를 전적으로 애플리케이션 코드에서 해야 해요.

Passthrough Managed IDs가 이 문제를 해결해요. 이 기능이 켜지면 프록시는:

  1. 응답에서 보는 모든 원시 provider ID에 대해 안정적이고 불투명한 관리형 ID를 발행해요.
  2. managed_id → raw_id 매핑을 프록시 데이터베이스에 저장하고, 생성한 사용자/팀을 태그해요.
  3. 소유권/권한 검사를 실행한 뒤, 요청을 업스트림으로 전달하기 직전에 관리형 ID를 원시 provider ID로 다시 풀어 줘요.

클라이언트는 원시 provider ID를 절대 보지 못하고, 관리형 ID 문자열을 추측하거나 위조해도 소유하지 않은 리소스에 접근할 수 없어요.

활성화 방법

프록시 config의 general_settings에 한 줄을 추가하세요:

    general_settings:
      passthrough_managed_object_ids: true

이 기능은 다음이 필요해요:

  • 프록시에 구성된 데이터베이스 (Prisma / PostgreSQL).
  • managed_files enterprise 훅 사용 가능.

이 기능은 OpenAI(/openai_passthrough/...)와 Azure OpenAI(/azure/openai/...) 패스스루 라우트에서만 동작해요.

/openai/v1/files, /openai/v1/batches, /openai/v1/responses는 패스스루 라우트가 아니에요.

그 세 경로는 /v1/files, /v1/batches, /v1/responses와 정확히 같은 LiteLLM 네이티브 엔드포인트가 서빙하므로 passthrough_managed_object_ids는 그걸 보지 못해요. 거기서 테넌트를 격리하려면 파일과 배치에는 require_managed_files를, 응답에는 내장 Responses API 소유권 검사를 사용하세요. OpenAI 패스스루 접두사는 /openai_passthrough예요.

네이티브 관리 엔드포인트 vs 패스스루

네이티브 관리 엔드포인트 관리형 ID를 가진 패스스루
URL 접두사 /v1/files, /v1/batches /openai_passthrough/v1/files, /azure/openai/batches
라우팅 LiteLLM 내부 로직; 모델 기반 라우팅 업스트림 공급자로 직접 전달
자격 증명 해석 model_list 라우터를 통해 PassthroughEndpointRouter / 환경 변수를 통해
사용 시점 LiteLLM이 올바른 디플로이먼트를 자동으로 고르길 원하거나 크로스-공급자 배칭이 필요할 때 공급자 API를 직접 호출하고 싶지만(예: fine-tuning, responses, 커스텀 엔드포인트) 프록시 레벨 접근 제어는 필요할 때
ID 관리 항상 LiteLLM이 관리 passthrough_managed_object_ids: true일 때만 관리형 ID
스트리밍 ID 발행 지원 stream: truePOST /v1/responses 지원 (모든 이벤트의 response.id가 다시 쓰임)

지원 엔드포인트

응답 ID 발행 (OUTPUT)

다음은 LiteLLM이 응답 본문에서 보는 원시 provider ID에 대해 관리형 ID를 발행하고, 클라이언트에 반환하기 전에 바꿔치기하는 특정 라우트들이에요.

공급자 메서드 경로 다시 쓰는 필드
OpenAI POST /v1/files id (file-)
OpenAI GET /v1/files/{file_id} id (file-)
OpenAI DELETE /v1/files/{file_id} id (file-)
OpenAI POST /v1/batches id (batch_), input_file_id, output_file_id, error_file_id
OpenAI GET /v1/batches/{batch_id} id (batch_), input_file_id, output_file_id, error_file_id
OpenAI POST /v1/batches/{batch_id}/cancel id (batch_), input_file_id, output_file_id, error_file_id
OpenAI POST /v1/responses id (resp_)
OpenAI GET /v1/responses/{response_id} id (resp_)
OpenAI DELETE /v1/responses/{response_id} id (resp_)
Azure POST /v1/files id (file-)
Azure GET /v1/files/{file_id} id (file-)
Azure DELETE /v1/files/{file_id} id (file-)
Azure POST /v1/batches id (batch_), input_file_id, output_file_id, error_file_id
Azure GET /v1/batches/{batch_id} id (batch_), input_file_id, output_file_id, error_file_id
Azure POST /v1/batches/{batch_id}/cancel id (batch_), input_file_id, output_file_id, error_file_id
Azure POST /v1/responses id (resp_)
Azure GET /v1/responses/{response_id} id (resp_)
Azure DELETE /v1/responses/{response_id} id (resp_)

stream: truePOST /v1/responses도 포함돼요. 프록시는 첫 번째 response.created 이벤트부터 응답을 호출자 소유로 기록하고, 스트림이 중계되는 동안 모든 이벤트 안의 response.id를 다시 써요. 그래서 스트리밍 응답도 비-스트리밍 응답과 정확히 똑같이 소유되고 보호돼요.

관리형 ID 해석 (INPUT)

이건 라우트별이 아니에요. 모든 OpenAI 또는 Azure 패스스루 요청에 대해 LiteLLM은 업스트림으로 전달하기 전에 요청 전체를 스캔해요:

위치 무엇을 스캔
URL 경로 각 경로 세그먼트
쿼리 파라미터 모든 문자열 값 파라미터
요청 본문 모든 문자열 값, 재귀적으로 (중첩 객체·배열에서도 동작)

즉 경로·쿼리·본문에서 file ID, batch ID, response ID를 받는 어떤 엔드포인트든 자동으로 관리형 ID를 풀어요. 여기에는 위 출력 표에 없는 엔드포인트(fine-tuning 잡 /v1/fine_tuning/jobs, assistants, 커스텀 엔드포인트)도 포함돼요.

예시, fine-tuning 잡:

    # Client sends managed IDs for training_file and validation_file
    response = client.post("/azure/openai/v1/fine_tuning/jobs", json={
        "model": "gpt-4o-mini",
        "training_file": "bGl0ZWxsbV9wcm94eTpwYXNzdGhyb3VnaDtwcm92...",  # managed ID
        "validation_file": "bGl0ZWxsbV9wcm94eTpwYXNzdGhyb3VnaDtwcm92...",  # managed ID
    })

    # Proxy resolves both to raw file IDs and forwards:
    # POST .../fine_tuning/jobs
    # { "model": "gpt-4o-mini", "training_file": "file-2dbc75...", "validation_file": "file-2dbc75..." }

요청 흐름 - 모든 엔드포인트

이것은 fine-tuning뿐 아니라 모든 OpenAI 또는 Azure 패스스루 엔드포인트에 적용돼요. 같은 경로/쿼리/본문 스캔이 모든 요청에서 실행돼요. 아래 예제는 본문에 관리형 file ID가 있는 fine-tuning 잡을 사용해요.

응답 경로에서는 rewrite_response_ids()가 원시 provider ID에 대한 관리형 ID를 발행하지만, 출력 맵에 나열된 라우트(파일, 배치, 응답)에서만 그래요. 다른 엔드포인트(예: fine-tuning)는 그 맵에 없으면 업스트림 ID를 그대로 반환해요.

권한 검사 (Permission checks)

모든 관리형 ID 해석은 순서대로 네 가지 검사를 실행해요. 모두 통과해야 하며 그렇지 않으면 요청이 거부돼요.

1. 공급자 일치

관리형 ID는 발행된 공급자(예: azure)를 인코딩해요. Azure에서 발행한 ID를 OpenAI 패스스루 라우트에 보내면(또는 그 반대) 프록시는 404를 반환하고 그 ID를 업스트림으로 전달하지 않아요.

2. DB 존재

관리형 ID는 프록시 데이터베이스의 실제 행에 매핑돼야 해요. 실제 행에 대응하지 않는 추측·위조·base64로 만든 문자열은 404를 반환해요. DB 검사가 실패하면 원시 provider ID는 절대 업스트림으로 전달되지 않아요.

3. 접근 검사 - 요청별

can_access_resource()가 호출자가 특정 리소스를 쓸 수 있는지 결정해요:

호출자 신원 접근 허용 시점
프록시 admin / master key 항상
user_id 있음 created_by == user_id
team_id 있음 (서비스 계정) team_id == resource.team_id
user_idteam_id 둘 다 있음 위 조건 중 하나라도 충족
둘 다 없음 절대 허용 없음 (403)

4. 접근 검사 - 목록 엔드포인트

build_owner_filter()가 목록 연산의 데이터베이스 쿼리를 범위 지정해요 (아래 참고). 같은 규칙을 Prisma WHERE 절로 표현한 거예요:

호출자 WHERE 절
프록시 admin / master key {} (필터 없음 — 모든 행을 봄)
user_id created_by = user_id
team_id team_id = team_id
user_idteam_id 둘 다 created_by = user_id OR team_id = team_id
둘 다 없음 즉시 빈 목록 반환 — DB 쿼리 없음

목록 엔드포인트 동작 방식

GET /openai_passthrough/v1/filesGET /openai_passthrough/v1/batches(그리고 Azure 상당)는 완전히 가로채져요. 요청은 업스트림 공급자로 전달되지 않아요. 대신 프록시가 자체 데이터베이스를 조회해 호출자가 소유한 행만 반환해요:

    GET /openai_passthrough/v1/files
                                         ┌─────────────────────────────┐
                             admin key?  │  WHERE {}                   │
                                         │  (all rows)                 │
                                         └─────────────────────────────┘
                             user key?   ┌─────────────────────────────┐
                                         │  WHERE created_by = user_id │
                                         │  OR team_id = team_id       │
                                         └─────────────────────────────┘
                                                   │
                                                   ▼
                                  OpenAI-style paginated response
                                  { "object": "list", "data": [...] }
                                  All IDs in data[] are managed IDs

페이징 파라미터 limit, after, before는 지원되며 created_at의 커서에 직접 매핑돼요.

user_idteam_id도 없는 호출자는 항상 빈 목록을 받아요. 프록시는 범위 없는 쿼리로 폴백하지 않아요.

프록시가 본 적 없는 객체

소유권은 기능을 켠 채로 패스스루 라우트를 통해 객체를 만들 때 기록돼요. 활성화 전에 만들었거나 같은 API 키로 공급자에 직접 만든 파일·배치·응답은 프록시 쪽에 소유자가 없으므로, 패스스루 라우트에서 허용된 아무 키나 그 원시 provider ID로 여전히 접근할 수 있어요(아래 제한 참고). LiteLLM은 의도적으로 그 객체들을 누구에게도 주장하지 않아요.

그런 기존 객체까지도 격리해야 한다면, 엄격한 옵션은 테넌트 간 provider 키 공유를 멈추는 거예요: 팀마다 커스텀 패스스루 엔드포인트를 하나씩 정의하고, 각각 headers에 그 팀 자체의 provider API 키를 넣고, 팀 메타데이터의 allowed_passthrough_routes로 각 팀을 자기 엔드포인트로 제한하세요. 그러면 공급자가 가시성을 스스로 범위 지정하고, 관리형 ID가 그 위에서 계속 동작해요.

제한사항 (Limitations)

스트리밍은 응답에서만 다시 쓰임

POST /v1/responses 스트림은 발행 가능한 ID를 지닌 유일한 SSE 응답이므로, 프록시가 다시 쓰는 유일한 스트림이에요. 다른 모든 스트리밍 패스스루 응답은 그대로 중계돼요.

원시 ID는 소유자에게만 동작

관리형 ID 대신 원시 provider ID(예: file-abc123)를 보내면, 프록시는 전달하기 전에 그것이 관리 리소스에 속하는지 확인해요. 다른 호출자의 리소스에 매핑되는 원시 ID는 404로 거부돼요 (알 수 없는 관리형 ID와 같은 답이라 호출자가 어떤 ID가 존재하는지 탐색할 수 없어요). 소유자 자신의 원시 ID는 전달돼요. 프록시가 기록한 적 없는 원시 ID는 소유권 검사 없이 전달되는데, 이게 위의 객체들에 접근 가능하게 만드는 이유예요.

ID는 공급자별로 범위 지정됨

azure용으로 발행된 관리형 ID는 openai 패스스루 라우트에서 쓸 수 없고 그 반대도 마찬가지예요. 시도하면 404가 반환돼요.

더 알아보기 (Learn more)