Skip to content

게이트웨이 공유

공유 배포를 위한 클라이언트별 토큰, 그리고 프록시와 터널을 위한 SSE keepalive ping.

Updated View as Markdown

인바운드 클라이언트 토큰

기본적으로 shunt에는 인바운드 인증이 없습니다 — 루프백 전용 개인 게이트웨이에는 괜찮지만, VPN/터널을 통해 공유하는 순간, 그것에 도달할 수 있는 누구든 매핑된 모델에서 운영자의 계정을 쓸 수 있습니다(shunt가 그런 모델에 대해 자체 api_key/chatgpt_oauth 자격 증명을 주입하기 때문). 패스스루 모델은 문제가 되지 않습니다: 각 호출자 본인의 Anthropic 자격 증명을 전달합니다.

[server.auth]는 주입된 자격 증명 라우트와 모델 디스커버리를 클라이언트별 토큰으로 게이팅합니다:

[server.auth]                        # 두 키 모두 선택; 기본값 표시됨
header = "x-shunt-token"
tokens_env = "SHUNT_CLIENT_TOKENS"
# 게이트웨이 측: name:token 쌍 (이름은 로깅용 레이블; 토큰은 비밀)
export SHUNT_CLIENT_TOKENS="minsu:$(openssl rand -hex 32),alice:$(openssl rand -hex 32)"

[server.auth]가 있는데 env 변수가 설정되지 않았거나 형식이 잘못되면 시작은 **닫힌 채로 실패(fail closed)**합니다. 유효한 토큰 없이 매핑된 모델과 GET /v1/models에 대한 요청은 401 authentication_error를 받습니다. 두 게이트 모두 표준 Anthropic 자격 증명 슬롯 어디로든 클라이언트 토큰을 받습니다 — 구성된 헤더(기본 x-shunt-token), Authorization: Bearer, x-api-key 순의 우선순위로(여러 슬롯에 유효한 토큰이 있을 때). GET /routes, GET|HEAD /, GET /health, 그리고 패스스루 모델은 열린 채로 유지됩니다. GET /routes는 라우팅 메타데이터(구성된 프로바이더/업스트림 모델 매핑)를 노출하는 shunt 네이티브 엔드포인트이기 때문에 인증되지 않습니다 — 자격 증명은 절대 노출하지 않으며, 자격 증명은 오직 프로바이더 구성에만 존재하고 그 핸들러가 읽는 일이 없습니다.

게이팅된 라우트에서는 수락되는 자격 증명 헤더가 전달 전에 항상 제거되고(shunt가 거기에 자체 프로바이더 자격 증명을 주입합니다), 매칭은 상수 시간(constant-time)이며, 토큰 값은 절대 로깅되지 않습니다(클라이언트 이름은 요청별로 로깅됩니다).

클라이언트 측은 게이트웨이가 무엇을 제공하는지에 따라 고르세요:

  • 풀/매핑 전용 게이트웨이(예: Anthropic 계정 풀이 기본 프로바이더): 클라이언트 토큰이 Claude Code가 이미 보내는 자격 증명 그 자체가 될 수 있습니다 — 추가 헤더 줄이 필요 없습니다:

    export ANTHROPIC_AUTH_TOKEN="<your client token>"   # Authorization: Bearer로 전송됨
  • 패스스루 모델이 섞여 있는 경우: Bearer 슬롯은 각 호출자의 실제 Anthropic 자격 증명을 계속 실어야 하므로, 대신 구성된 헤더로 전용 토큰을 배포하세요(ANTHROPIC_CUSTOM_HEADERS는 한 줄당 하나의 Name: Value를 받습니다):

    export ANTHROPIC_CUSTOM_HEADERS="x-shunt-token: <your token>"

옵트인 관리자 웹 화면도 활성화한다면, 별도의 관리자 토큰으로 보호하고 HTTPS 또는 신뢰할 수 있는 터널을 통해서만 노출하세요.

SSE keepalive ping

미들박스는 조용한 스트림을 끊습니다 — Cloudflare의 프록시는 한 바이트도 없이 100초가 지나면 524를 반환하며(Enterprise 미만에서는 고정), 긴 추론 구간은 그만큼 조용할 수 있습니다. 그래서 shunt는 스트리밍 응답이 유휴 상태일 때마다 Anthropic 프로토콜 자체의 ping 이벤트를 주입합니다(api.anthropic.com이 직접 방출하며 모든 클라이언트가 무시하는 것):

[server]
sse_keepalive_seconds = 30   # 기본값; 0은 비활성화

Ping은 완전한 SSE 이벤트 사이에서만(절반만 보낸 프레임 안에서는 절대 안 됨), text/event-stream 응답에서만 주입되며, 업스트림 스트림과 함께 멈춥니다. 유휴 타임아웃이 없는 터널(WireGuard/Tailscale) 뒤에서는 ping이 무해합니다; 바이트 단위로 동일한 릴레이를 원한다면 0으로 비활성화하세요.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close