JWT 인증

JWT 인증 (JWT Authentication)

ClickHouse는 JSON Web Tokens(JWTs)로 사용자를 인증할 수 있어요. LDAP이나 Kerberos 같은 다른 외부 인증기와 달리, JWT 인증은 기존 사용자의 신원을 검증하지 않습니다. 대신 각 토큰에 포함된 클레임에서 **임시 사용자(ephemeral users)**를 동적으로 만듭니다.

출처: 문서

본문

ClickHouse는 JSON Web Tokens(JWTs)를 사용해 사용자를 인증할 수 있습니다. LDAP이나 Kerberos 같은 다른 외부 인증기와 달리, JWT 인증은 기존 사용자의 신원을 검증하지 않아요. 대신 각 토큰에 포함된 클레임(claims)에서 임시 사용자를 동적으로 만듭니다. 이 사용자들은 메모리에만 존재하며, 토큰 클레임에서 파생된 접근 권한을 받고, 토큰이 만료되면 자동으로 제거됩니다.

이 때문에 JWT 인증은 비밀번호 기반이나 인증서 기반 방식과 근본적으로 다릅니다: CREATE USER ... IDENTIFIED WITH jwt 문은 존재하지 않으며, 시도하면 예외가 발생합니다. JWT 사용자는 전적으로 토큰 수명주기에 의해 관리됩니다.

개요 (Overview)

인증 흐름은 다음과 같이 동작합니다:

  1. 클라이언트가 지원되는 전송 메커니즘 중 하나(HTTP Authorization: 헤더, TCP 네이티브 프로토콜, 또는 gRPC jwt 필드)를 통해 서명된 JWT를 제시합니다.
  2. ClickHouse가 토큰 서명을 검증합니다.
  3. 필수 클레임(exp, iat, iss, sub, aud)이 확인됩니다.
  4. clickhouse:grantsclickhouse:roles 토큰 클레임에서 파생된 접근 권한을 가진 임시 사용자가 메모리에 생성되며, 권한 제한(permission limit)과 교차(intersect)됩니다.
  5. 토큰이 만료되면 백그라운드 가비지 컬렉션 작업이 사용자를 제거합니다.

토큰 클레임 (Token claims)

필수 클레임 (Required claims)

ClickHouse에 제시되는 모든 JWT는 다음 클레임을 포함해야 합니다:

클레임 설명
alg 서명 알고리즘(헤더 클레임). 지원 값: RS256. 26.8 버전부터 EC 알고리즘 ES256, ES384, ES512도 지원됩니다.
exp 만료 시간. 임시 사용자의 valid_until을 설정합니다.
iat 발행 시간(issued-at). 같은 신원에 대해 오래된 토큰의 재생(replay)을 방지하는 데 사용됩니다.
iss 발급자(issuer). 제공업체의 기대 발급자와 매칭됩니다.
sub 주체(subject). 생성된 사용자 이름의 일부가 됩니다.
aud 대상(audience). 제공업체의 기대 대상과 매칭됩니다.

JWKS 기반 키 해석을 사용할 때는 kid(키 ID) 헤더 클레임도 필요합니다.

기타 인식되는 클레임 (Other recognized claims)

클레임 설명
nbf not-before 시간. 필수는 아니지만, 존재하면 이 시간 이전의 토큰은 거부됩니다.
jti 예약됨. 토큰에서 허용되지만 현재는 검증되거나 사용되지 않습니다.

선택적 클레임 (Optional claims)

클레임 기본 이름 설명
Grants clickhouse:grants SQL GRANT 조각들의 JSON 배열, 예: ["SELECT ON db.*", "INSERT ON db.table1"]. 각 요소는 GRANT 문의 본문으로 파싱됩니다.
Roles clickhouse:roles 할당할 역할 이름의 JSON 배열, 예: ["analyst", "reader"].
기본 클레임 이름은 identity provider가 다른 명명 규칙을 사용하는 경우 커스텀 클레임 이름으로 다시 매핑할 수 있습니다.

예시 토큰 헤더와 페이로드 (Example token header and payload)

{
  "alg": "RS256",
  "kid": "my-key-id"
}
{
  "iss": "https://idp.example.com",
  "sub": "jane.doe",
  "aud": "my-clickhouse-cluster",
  "exp": 1719504000,
  "iat": 1719500400,
  "clickhouse:grants": ["SELECT ON analytics.*", "INSERT ON analytics.events"],
  "clickhouse:roles": ["analyst"]
}

임시 사용자 동작 (Ephemeral user behavior)

JWT 사용자는 일반 ClickHouse 사용자와 여러 중요한 점에서 다릅니다.

신원과 명명 (Identity and naming)

각 JWT 사용자는 iss, sub, aud 클레임에서 계산된 결정적 UUID를 받습니다. 이 UUID는 로그인 간에 안정적입니다. (같은 발급자, 주체, 대상을 가진) 다른 토큰으로 여러 번 로그인하는 사용자는 항상 같은 UUID를 받습니다.

하지만 사용자 이름은 **휘발성(volatile)**입니다. 다음과 같이 구성됩니다:

JWT::<subject>::<claims_hash>

<claims_hash>iss, sub, aud 클레임과 clickhouse:roles, clickhouse:grants 클레임을 함께 사용해 파생된 해시입니다. issaud 클레임은 이 해시를 통해서만 참여합니다. 더 이상 보이는 사용자 이름 접두사에 인라인되지 않습니다. 이는 iss/aud가 긴 불투명한 IDP URL(예: Microsoft Entra나 Okta)일 때 이름을 간결하고 읽기 쉽게 유지하면서도, 서로 다른 (iss, sub, aud) 튜플과 서로 다른 clickhouse:roles / clickhouse:grants 집합이 서로 다른 안정적인 이름에 매핑됨을 보장합니다. 해시에 들어가지 않는 클레임(예: iat, exp, nbf, 또는 무관한 커스텀 클레임)은 사용자 이름을 바꾸지 않습니다.

<claims_hash> 부분은 clickhouse:roles 또는 clickhouse:grants 클레임이 바뀔 때마다 바뀝니다. 즉, 역할이나 권한 집합이 다른 토큰은 같은 신원이라도 서로 다른 사용자 이름을 만들어 냅니다.

접근 권한 (Access rights)

유효 접근 권한은 다음과 같이 계산됩니다:

effective_rights = permission_limit ∩ (token_grants ∪ token_roles)

여기서 permission_limit은 상한(upper bound)으로 구성된 참조 역할 또는 사용자가 가진 접근 권한 집합입니다. 토큰이 요청한 권한 중 한도를 초과하는 것은 조용히 버려집니다.

토큰 신선도 (Token freshness)

ClickHouse는 각 안정적 신원에 대해 가장 최근에 인증된 토큰의 iat(발행 시간) 클레임을 추적합니다. 저장된 값과 같거나 더 오래된 iat를 가진 토큰이 제시되면, 서버는 클레임을 다시 평가하지 않고 기존 임시 사용자를 재사용합니다. 이는 오래된 토큰이 사용자의 권한을 낮추는 것을 방지합니다.

수명과 가비지 컬렉션 (Lifetime and garbage collection)

임시 사용자는 토큰이 처음 인증될 때 생성되고, valid_until(exp에서 파생)이 지나면 백그라운드 가비지 컬렉션 작업에 의해 제거됩니다. GC 간격은 gc_interval 파라미터(기본값: 5분)로 제어됩니다.

GC 실행 사이에 만료된 사용자는 여전히 system.users에 보일 수 있지만 더 이상 인증할 수 없습니다.

영구 접근 할당 (Persistent access assignments)

UUID가 안정적이므로 SQL 문을 사용해 설정 프로필, 할당량, 행 정책, 컬럼 마스킹 정책을 JWT 사용자에게 할당할 수 있습니다. 이러한 할당은 접근 제어 저장소(디스크 또는 ZooKeeper)에 유지되며 토큰 만료와 재인증에도 살아남습니다.

현재 사용자 이름으로 사용자를 참조하세요:

ALTER SETTINGS PROFILE my_profile ADD TO 'JWT::jane.doe::<claims_hash>';

주어진 신원의 사용자 이름과 UUID는 사용자가 활성 상태인 동안 system.usersnameid 컬럼에서 찾을 수 있습니다.

ALTER USER는 JWT 사용자에게 직접 동작하지 않는다는 점을 기억하세요. 그들은 읽기 전용이기 때문입니다. 설정 프로필, 할당량, 정책을 할당하려면 위에 표시된 것처럼 ALTER SETTINGS PROFILE, ALTER QUOTA, ALTER ROW POLICY 문을 사용하세요.

일반 사용자와의 차이 (Differences from regular users)

기능 JWT 사용자 일반 사용자
생성 토큰 클레임에서 자동 CREATE USER
저장 메모리 전용(임시) 디스크, ZooKeeper, 또는 설정 파일
CREATE USER ... IDENTIFIED WITH jwt 지원 안 함(예외 발생) 다른 모든 인증 유형 지원
ALTER USER / DROP USER 지원 안 함 지원
백업과 복원 포함 안 됨 포함
사용자 이름 자동 생성, 휘발성 관리자 선택, 고정
UUID iss+sub+aud에서 결정적 생성 시 무작위
수명 토큰 exp에 의해 제한 명시적으로 제거될 때까지
접근 권한 토큰 클레임에서 파생, 권한 제한으로 상한 GRANT로 명시적으로 부여
호스트 제한 제공업체별 네트워크 구성 사용자별 HOST
설정 프로필 UUID로 할당 가능(영구) 직접 구성 가능
할당량과 행 정책 UUID로 할당 가능(영구) 직접 구성 가능
기본 역할 구성 불가 구성 가능

SQL SECURITY DEFINER 뷰 (SQL SECURITY DEFINER views)

임시 JWT 사용자가 SQL SECURITY DEFINER로 뷰를 만들면, 서버는 뷰의 정의자(definer) 역할을 하도록 사용자의 지속적인 섀도우 사본을 자동으로 만듭니다. 이 섀도우 사용자는:

  • <original_jwt_username>:definer라는 이름을 가짐
  • NO_AUTHENTICATION임(로그인에 사용할 수 없음)
  • 뷰가 생성된 시점의 원래 JWT 사용자와 같은 접근 권한을 유지

이는 임시 사용자의 토큰이 만료되고 원래 사용자가 가비지 컬렉션된 후에도 뷰가 계속 동작하도록 보장합니다.

클라이언트 사용법 (Client usage)

토큰을 직접 전달하기 (Passing a token directly)

clickhouse-client에서 --jwt 플래그를 사용해 미리 얻은 토큰으로 인증합니다:

clickhouse-client --host your-instance.clickhouse.cloud --secure --jwt '<your_jwt_token>'

--jwt 플래그는 --user와 상호 배타적입니다. --jwt가 지정되면 사용자 이름은 토큰에서 파생됩니다.

HTTP 인터페이스 (HTTP interface)

Authorization 헤더에 Bearer 토큰으로 토큰을 보냅니다:

curl -H 'Authorization: Bearer ***' \
    'https://your-instance.clickhouse.cloud:8443/?query=SELECT+currentUser()'

항상 HTTPS로 JWT를 보내세요. 일반 HTTP로 보내진 Bearer 토큰은 네트워크 경로상의 누구에게나 노출되며 자격 증명 유출과 같습니다.

OAuth2 디바이스 코드 로그인 (OAuth2 device code login)

clickhouse-client--login 플래그를 통해 대화형 OAuth2 디바이스 코드 흐름을 지원합니다. ClickHouse Cloud 엔드포인트의 경우 클라이언트가 자동으로 토큰 교환을 수행해 ClickHouse 전용 JWT를 얻습니다. 토큰은 세션 동안 투명하게 갱신됩니다. 새 토큰을 얻으면 클라이언트가 자동으로 재연결합니다.

clickhouse-client --host your-instance.clickhouse.cloud --login

ClickHouse Cloud 내장 JWT 인증기 (ClickHouse Cloud built-in JWT authenticator)

모든 ClickHouse Cloud 서비스에는 SQL Console과 clickhouse-client --login 흐름이 사용하는 사전 정의된 JWT 인증기가 제공됩니다. 이 인증기는 다음과 같이 구성됩니다:

파라미터
iss (발급자) ClickHouse
aud (대상) 서비스 UUID (Cloud 콘솔 URL에서 볼 수 있음)
sub (주체) 사용자의 ClickHouse Cloud 계정 이메일 주소

내장 인증기의 권한 제한은 default_role 역할과 default 사용자로 설정됩니다. 즉, 어떤 JWT 사용자의 유효 권한이라도 그 두 엔터티가 가진 권한과 교차되므로, 토큰은 default_roledefault가 허용하는 것 이상으로 권한을 상승시킬 수 없습니다.

이 인증기를 사용하기 위해 별도로 구성할 것은 없습니다. 서비스가 생성될 때 자동으로 프로비저닝됩니다.

서비스에서 JWT 인증 활성화하기 (Enabling JWT authentication for your service)

내장 인증기에 더해, 자신의 identity provider(예: Microsoft Entra나 Okta)가 발급한 JWT를 수락하도록 ClickHouse Cloud 서비스를 구성할 수 있습니다. 이 기능은 ClickHouse 버전 26.4 이상을 실행하는 서비스의 Enterprise 플랜에서 사용할 수 있습니다. Cloud 콘솔의 Settings → Security → JWT authentication에서 직접 구성할 수 있습니다 — 단계별 지침은 JWT 인증 설정을 참고하세요. 각 제공업체는 다음으로 정의됩니다:

파라미터 설명
이름 서비스에서 제공업체의 고유 이름.
Issuer identity provider가 발급한 토큰의 iss 클레임 값, 보통 제공업체의 URL(예: https://your-tenant.okta.com). ClickHouse는 발급자가 이 값과 일치하지 않는 토큰을 거부합니다.
Audience identity provider가 이 서비스용으로 만든 토큰에 넣는 aud 클레임 값. ClickHouse는 다른 대상으로 발급된 토큰을 거부합니다.
JWKS URL identity provider가 JSON Web Key Set을 게시하는 HTTPS 엔드포인트(예: https://idp.example.com/.well-known/jwks.json). ClickHouse는 이 엔드포인트에서 공개 키를 가져와 토큰 서명을 검증합니다. JWKS 검증은 RSA 키(RS256)와, 26.8 버전부터 P-256, P-384, P-521 곡선의 EC 키(ES256, ES384, ES512)로 동작합니다(필수 클레임 참고).
Roles claim (선택) 임시 사용자의 ClickHouse 역할이 들어 있는 토큰 클레임의 이름. 비워 두면 기본 클레임 이름 clickhouse:roles를 사용합니다. 클레임은 역할 이름의 JSON 배열을 포함해야 합니다, 예: ["analyst", "reader"].

서버 간 통신 (Interserver communication)

쿼리가 다른 샤드나 복제본으로 전달되면 JWT 토큰이 interserver 프로토콜에 포함됩니다. 원격 노드는 토큰을 독립적으로 재인증하여 자체 임시 사용자를 만듭니다.

문제 해결 (Troubleshooting)

  • 부여된 접근 권한이 없음: 참조된 역할이나 사용자에 필요한 권한이 없을 수 있습니다. clickhouse:roles에 참조된 역할이 존재하고 적절한 권한을 포함하는지 확인하세요.
  • 토큰 거부됨: 토큰의 iss, aud, 서명 알고리즘이 JWT 제공업체가 기대하는 것과 일치하는지 확인하세요. JWKS를 사용한다면 토큰의 kid가 제공업체의 키 집합에 있는 키와 일치하는지 확인하세요.
  • 쿼리 사이에 사용자가 사라짐: 임시 사용자는 토큰 만료 후 제거됩니다. 긴 세션에는 토큰 갱신을 지원하는 클라이언트(예: --login 모드)를 사용하세요.
  • CREATE USER ... IDENTIFIED WITH jwt 실패: 이는 예상된 동작입니다. JWT 사용자는 DDL로 만들 수 없습니다. 그들은 전적으로 토큰 수명주기에 의해 관리됩니다.

더 알아보기 (Learn more)