JWT/OIDC 인바운드 인증¶
이 문서는 인바운드 bearer 토큰에 대한 선택적 JWT 검증(이슈 #2375)의 설계와 실제 구현된 동작을 기록합니다. 설정과 운영 방법은 보안 & 관리 문서에 있습니다.
구현된 동작¶
- 설정:
api_keys.jwt에서 issuer, audience, 키 원본 하나(jwks_uri또는static_jwks), 허용할 비대칭 알고리즘, 클레임 매핑을 지정합니다. 이 섹션은 기본적으로 꺼져 있습니다. 섹션이 없거나 비활성이면 정적 키 인증은 그대로 동작합니다. - 해석 순서: 인증 미들웨어는 제시된 자격 증명을 먼저 키 저장소와 대조합니다. 일치하는 키가 없을 때만 JWT로 해석하므로, 정적 키가 항상 먼저입니다. 검증 전
iss가 설정된 issuer와 다른 토큰은 기존 키 불일치 경로로 넘어갑니다. - 검증기: JWT 분기는 JWKS로 서명을 검증하고, 제한된 시계 오차 안에서
iss,aud,exp,nbf를 확인합니다. 설정된 비대칭 알고리즘만 허용합니다. - 같은
AuthContext: 유효한 토큰은 정적 키와 같은AuthContext를 만들고, 키 id는 issuer와 subject에서 파생합니다. 키별 속도 제한,allowed_models,allowed_backends, 예산, 요청 귀속은 그대로 동작합니다. - 클레임 매핑:
subject_claim,user_claim,team_claim은 신원을,scopes_claim,allowed_models_claim,allowed_backends_claim은 권한을 매핑합니다. JWT의 scope 목록은 빈 목록까지 포함해 최종 기준이므로, 매핑하지 않은 scope 클레임은 아무 권한도 주지 않습니다. - 키 캐싱: JWKS는 TTL과 함께 캐시합니다. 알 수 없는
kid는 설정된 간격마다 최대 한 번 갱신을 유발하며, 교체된 서명 키를 반영합니다. 각 가져오기에는 고정 제한 시간과 본문 크기 상한이 있습니다. - 실패 동작: 만료되었거나, audience가 다르거나, 서명자가 다른 토큰은 blocking과 permissive 모드 모두에서 표준 잘못된 키 본문의
401을 받습니다. JWKS 가져오기 실패는 fail-closed로 동작합니다. 거부와 가져오기 결과는 Prometheus로 집계합니다. - 빌드 그래프: 검증기에는
jsonwebtoken이 필요하고,embed부정 의존성 계약은 이 크레이트를 금지합니다. 따라서 런타임은default와full밖에 있는jwt-authCargo 기능 뒤에 둡니다. 설정 타입은 모든 빌드에서 컴파일합니다. 기능이 없는 바이너리는 설정을 읽을 때 섹션이 비활성이라고 경고합니다.
설계 결정¶
- 비대칭만 허용:
none, HMAC 알고리즘, 허용 목록 밖의 알고리즘은 키 선택 전에 거부하며,kty: octJWK는 절대 선택하지 않습니다. - 토큰이 키 자료를 고르지 못함:
jku,jwk,x5u헤더는 거부합니다. 토큰이 검증에 쓰일 키나 엔드포인트를 선택할 수 없습니다. - 작업량 상한: 토큰 크기, 알고리즘 개수,
kid길이, JWKS 본문 크기, 키 개수, 클레임 길이, 목록 개수, scope 개수에 고정 상한을 둡니다. - 네트워크 동작 상한: JWKS 클라이언트는 리디렉션을 따르지 않으며, URI는
https이거나 루프백 호스트의http여야 합니다. 스트리밍 본문은 설정된 바이트 상한에서 중단합니다. - 단일 실행 갱신: 동시에 들어온 알 수 없는
kid요청은 하나의 가져오기를 공유하고, 실패한 가져오기는 갱신 간격 안에서 재시도하지 않습니다. TTL이 지난 캐시는 사용하지 않습니다. - 명시적 scope 거부: 최종 기준이지만 빈 scope 목록을 가진 principal은 scope가 필요 없는 경로만 통과합니다. 이렇게 하면 매핑되지 않은 JWT가 정적 키의 "빈 목록은 무제한" 해석을 물려받지 않습니다.
- 설정된 issuer에 대해서만 fail-closed: 설정된 issuer를 가리키는 토큰은 이후 어떤 실패에서도 거부합니다. 다른 issuer의 토큰은 형식이 잘못된 정적 키와 구분하지 않고 기존 동작을 유지합니다.
다루지 않는 범위¶
- 토큰 introspection, refresh-token 교환, provider 검색(
/.well-known/openid-configuration). - provider별 클레임 매핑: 하나의
jwt섹션은 하나의 issuer를 매핑합니다. - JWKS 푸시 또는 예약 사전 갱신: 캐시는 TTL 또는 알 수 없는
kid에서 갱신합니다. - 자체 인증을 가진 엔드포인트(Admin, Files, Metrics)의 토큰 검증: 해당 엔드포인트는 영향을 받지 않습니다.
이력¶
이 이슈는 설계 기록으로 시작했습니다. 최초 문서는 설정 표면, 검증 분기, AuthContext 재사용, 클레임 매핑, 키 캐싱, 실패 동작, 빌드 그래프 제약을 제안했습니다. 두 가지 질문은 열어 두었습니다. 정확한 클레임 이름, 그리고 런타임에 별도 Cargo 기능을 둘지 full에 포함할지입니다. 구현에서 둘 다 정했습니다. 클레임 이름은 일반적인 기본값과 함께 설정 가능하고, 런타임은 별도의 opt-in 기능입니다.