Kerberos + HTTPS 환경에서 Hue 의 REST API 를 쓰는 두 가지 경로를 정리한다. Base 클러스터의 Hue 는 SPNEGO 로 세션 쿠키를 받아 CSRF 토큰과 함께 호출하는 방식이 정석이고, CDW 의 Hue 는 Knox 가 발급한 JWT 를 Bearer 로 넘기는 방식이다. /api/v1/token/auth 토큰 엔드포인트는 username/password 를 요구해 Kerberos 단독 환경에서는 쓸 수 없다.
서버 쪽 hue.ini 설정을 먼저 확인한다.
[desktop]
[[auth]]
backend=desktop.auth.backend.SpnegoDjangoBackend
api_auth=rest_framework.authentication.SessionAuthentication
[[kerberos]]
hue_keytab=/etc/security/keytabs/hue.service.keytab
hue_principal=hue/<hue-fqdn>@<REALM>
keytab 에 HTTP/<hue-fqdn>@<REALM> SPN 이 있어야 하고, 클라이언트는 반드시 그 FQDN 으로 접속해야 한다. IP 로 접속하면 SPNEGO 가 실패한다.
curl 로 확인한다. curl -V 출력에 GSS-API 와 SPNEGO 가 있어야 동작한다.
kinit -kt <app.keytab> <appuser>@<REALM>
curl -s --negotiate -u : \
--cacert <ca-bundle.pem> \
-c cookie.txt -b cookie.txt \
"https://<hue-fqdn>:8889/hue/accounts/login/" -o /dev/null
CSRF=$(awk '/csrftoken/{print $7}' cookie.txt)
curl -s --negotiate -u : \
--cacert <ca-bundle.pem> \
-b cookie.txt -c cookie.txt \
-H "X-CSRFToken: $CSRF" \
-H "Referer: https://<hue-fqdn>:8889/" \
-X POST "https://<hue-fqdn>:8889/api/v1/editor/execute/hive" \
--data 'statement=SHOW TABLES'
파이썬에서는 requests-gssapi 를 쓴다.
import os
import requests
from requests_gssapi import HTTPSPNEGOAuth, OPTIONAL
HUE = os.environ["HUE_BASE_URL"]
CA = os.environ["HUE_CA_BUNDLE"]
session = requests.Session()
session.verify = CA
session.auth = HTTPSPNEGOAuth(mutual_authentication=OPTIONAL)
session.get(f"{HUE}/hue/accounts/login/", timeout=10).raise_for_status()
csrf = session.cookies.get("csrftoken")
headers = {
"X-CSRFToken": csrf,
"Referer": HUE + "/",
"Content-Type": "application/x-www-form-urlencoded",
}
r = session.post(f"{HUE}/api/v1/editor/execute/hive",
headers=headers, data={"statement": "SHOW TABLES"}, timeout=30)
r.raise_for_status()
op_id = r.json()["history_uuid"]
session.post(f"{HUE}/api/v1/editor/check_status",
headers=headers, data={"operationId": op_id}, timeout=30)
res = session.post(f"{HUE}/api/v1/editor/fetch_result_data",
headers=headers, data={"operationId": op_id}, timeout=60)
print(res.json()["result"]["data"])
프로세스 안에서 keytab 을 직접 쓰려면 자격 증명을 명시한다.
import gssapi
name = gssapi.Name(os.environ["KRB_PRINCIPAL"], gssapi.NameType.kerberos_principal)
creds = gssapi.Credentials(name=name, usage="initiate",
store={"client_keytab": os.environ["KRB_KEYTAB_PATH"]})
session.auth = HTTPSPNEGOAuth(creds=creds, mutual_authentication=OPTIONAL)
CDW 의 Hue 는 Knox 가 발급한 JWT 를 검증한다. 토큰을 파일로 두고 헤더로 넘긴다. 명령줄에 직접 넣으면 ps 목록에 노출되므로 파일을 경유한다.
umask 077; printf '%s' "$KNOX_JWT" > /tmp/jwt.txt
curl -sS --cacert "$CA_BUNDLE" \
-H "Authorization: Bearer $(cat /tmp/jwt.txt)" \
-o /tmp/resp.txt -w 'CODE=%{http_code}\n' \
-X POST "$HUE_URL/api/v1/get_config/"
shred -u /tmp/jwt.txt /tmp/resp.txt 2>/dev/null
어떤 토큰을 쥐고 있는지 먼저 확인해야 한다. 헤더에 jku 가 있으면 Knox UI 에서 발급한 토큰이고, 없으면 API 로 발급한 토큰이다.
echo "$KNOX_JWT" | cut -d. -f1 | tr '_-' '/+' \
| awk '{l=length($0)%4; if(l==2)print $0"=="; else if(l==3)print $0"="; else print $0}' \
| base64 -d 2>/dev/null; echo
echo "$KNOX_JWT" | cut -d. -f2 | tr '_-' '/+' \
| awk '{l=length($0)%4; if(l==2)print $0"=="; else if(l==3)print $0"="; else print $0}' \
| base64 -d 2>/dev/null | python3 -m json.tool
Base Hue 와 CDW Hue 를 같은 토큰으로 각각 호출해 보면 원인이 좁혀진다.
| Base | CDW | 의미 |
|---|---|---|
| 200 | 200 | 토큰을 잘못 쓰고 있었던 것 |
| 200 | 401 | 설정은 맞고 CDW 쪽 환경 문제 |
| 401 | 401 | 설정 문제. key_server_url 경로 누락이 유력 |
| 403 | — | JWT 백엔드 미인식 |
Hue 쪽 로그도 함께 본다.
tail -300 /var/log/hue/runcpserver.log \
| grep -iE 'jwt|jwks|key_server|audience|issuer|certificate|SSL'
Hue 가 공개키를 어떻게 조회하는지는 소스에서 확인할 수 있다.
find /opt/cloudera/parcels/CDH/lib/hue -name 'api_authentications.py' 2>/dev/null
grep -n "key_server_url\|jku\|jwks\|audience" <위 경로>
코드가 key_server_url 을 그대로 GET 하면 그 값에 JWKS 경로가 빠져 있는 것이 공개키 조회 실패의 직접 원인이 된다.
Referer 헤더를 빠뜨리면 Django 가 CSRF 403 을 낸다. 가장 흔한 실패 원인이다.--negotiate 후 리다이렉트가 일어나므로 쿠키를 반드시 재사용한다. 매 요청마다 재협상하면 세션이 꼬인다.verify=False 를 쓰지 않고 사내 CA 번들 경로를 환경변수로 주입한다. 티켓·쿠키·CSRF 값과 JWT 는 로그에 남기지 않는다.https://<knox>:8443/gateway/<topology>/hue/... 로 바뀌고 SPNEGO 협상 대상도 Knox 가 된다./api/v1/* 이 없을 수 있다. 그때는 /notebook/api/execute/hive, /filebrowser/view=... 같은 내부 엔드포인트를 같은 인증 흐름으로 호출한다.CDW Hue 의 JWT 검증은 대화에서 성공하지 못했고, 다음 세 가지가 벤더 확인 대상으로 남았다.
key_server_url 에 JWKS 경로가 빠져 호스트와 포트만 설정돼 있었다. 또 JWKS 경로의 버전이 어긋나, knoxtoken/api/v1/jwks.json 은 200 을 주는데 knoxtoken/api/v2/jwks.json 은 404 이며 발급 토큰의 jku 클레임은 v2 를 가리킨다. 마지막으로 토큰 발급 경로에 따라 aud 클레임이 달라, Knox UI 발급 토큰은 aud=cdp-proxy-token 이고 knoxtoken/api/v1/token 발급 토큰에는 aud 가 없다. Hue 는 audience=cdp-proxy-token 으로 설정돼 있어 API 발급 토큰은 검증에 실패한다.