개발/MLOps

020. [Kubeflow][KServe] 인증문제 해결하기 (Istio-Dex)

봉자씨 2022. 9. 21. 16:31
반응형

KServe on Kubeflow with Istio-Dex

Kubeflow KServe 인증문제 해결하기

Dex, Istio, Kubeflow

 

 

KServe를 Kubeflow와 함께 배포했다면, [[KServe First InferenceService 처음배포하기]]에서 예상하지 못한 인증문제를 겪으셨을 것입니다. 인증 문제가 발생한 이유는 Kubeflow내 외부로 통하는 모든 트래픽이 Istio-Dex를 통해 인증과 인가(AuthN/AuthZ)를 거치기 때문입니다. 따라서 KServe로 추론 요청을 보낼 때에도 인증정보가 필요합니다.

[[KServe First InferenceService 처음배포하기]]에 이어서 인증정보를 추가하여 추론요청을 보내는 방법을 알아보겠습니다.

인증정보 받아오기

Istio-dex는 ID / Password로 인증을 한 후 Session Cookie에 authserviece_session token 데이터를 통해 인증정보를 검증합니다.
다음 두가지 방법중 한가지 방식으로 authserviece_session token을 받아올 수 있습니다.
CLI를 이용한 방식과 web browser를 이용한 방식이 있는데, web browser를 이용한 방식이 더 쉽습니다.

Web Browser

1) kubeflow centeral dashboard에 로그인합니다.
2) 검색창 왼쪽의 자물쇠 버튼클릭 > 쿠키 > kubeflow centeral dashboard 주소에서 쿠키를 찾습니다.
3) 보여지는 쿠키중 authservice_session 쿠키의 값을 복사합니다. (아래 이미지의 Content 부분)

CLI

CLI를 이용한 방법을 사용한다면 다음 명령어를 따라서 token을 얻을 수 있습니다.

Host 정보 가져오기

[[KServe First InferenceService 처음배포하기]]와 동일하게 클러스터 외부에서 요청한다면, INGRESS_HOST와 INGRESS_PORT를 사용하고 클러스터 내부에서 요청한다면 CLUSTER_IP를 사용합니다.

  • LoadBalancer
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
  • Node Port
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}') export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
  • Cluster IP
CLUSTER_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.clusterIP}')

다음 예시는 모두 Ingress를 기준으로 설명합니다. Cluster IP를 사용하는경우 명령어중 INGRESS_HOST:INGRESS_PORT부분을 CLUSTER_IP로 변경하여 사용하세요.

인증

1) STATE 값 가져오기
response 의 마지막에 있는 STATE_VALUE를 저장합니다.

curl -v http://${INGRESS_HOST:INGRESS_PORT}

Response:
>> <a href="/dex/auth?client_id=kubeflow-oidc-authservice&amp;redirect_uri=%2Flogin%2Foidc&amp;response_type=code&amp;scope=profile+email+groups+openid&amp;state=STATE_VALUE">Found</a>.

STATE=STATE_VALUE

2) REQ_VALUE 가져오기

curl -v "http://${CLUSTER_IP}/dex/auth?client_id=kubeflow-oidc-authservice&redirect_uri=%2Flogin%2Foidc&response_type=code&scope=profile+email+groups+openid&amp;state=${STATE}"

Response:
>> <a href="/dex/auth/local?req=REQ_VALUE">Found</a>

REQ=REQ_VALUE

3) ID/PW 인증하기
ID/PW를 전송하고 승인을 요청합니다.첫번째 명령어의 --data 부분에 ID와 PW를 전달합니다.

예시에 사용된 아이디는 admin@kubeflow.org, 패스워드는 12341234 입니다.

curl -v "http://${CLUSTER_IP}/dex/auth/local?req=${REQ}" -H 'Content-Type: application/x-www-form-urlencoded' --data 'login=admin%40kubeflow.org&password=12341234'
curl -v "http://${CLUSTER_IP}/dex/approval?req=${REQ}"

Response:
>> <a href="/login/oidc?code=CODE_VALUE&amp;state=STATE_VALUE">See Other</a>.

Response에서 CODE_VALUE를 저장합니다.

4) 세션쿠키를 받아옵니다.

curl -v "http://${CLUSTER_IP}/login/oidc?code=${CODE}&amp;state=${STATE}"

Response:
>> set-cookie authservice_session=SESSION

SESSION=SESSION

인증정보와 함께 추론 요청하기

위에서 얻은 세션쿠키 정보를 추론 요청의 header에 추가합니다.

MODEL_NAME=sklearn-iris
INPUT_PATH=@./iris-input.json
SERVICE_HOSTNAME=$(kubectl get -n admin inferenceservice ${MODEL_NAME} -o jsonpath='{.status.url}' | cut -d "/" -f 3)

curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Cookie: authservice_session=${SESSION}" http://${CLUSTER_IP}/v1/models/${MODEL_NAME}:predict -d ${INPUT_PATH}

주요 부분은 curl 추론 요청시 header에 "Cookie: authservice_session=${SESSION}" 를 추가하는 부분입니다.

성공적으로 추론요청을 보냈습니다!

*   Trying 10.152.183.241...
* TCP_NODELAY set
* Connected to 10.152.183.241 (10.152.183.241) port 80 (#0)
> POST /v1/models/sklearn-iris:predict HTTP/1.1
> Host: sklearn-iris.admin.example.com
> User-Agent: curl/7.58.0
> Accept: */*
> Cookie: authservice_session=MTU4OTI5NDAzMHxOd3dBTkVveldFUlRWa3hJUVVKV1NrZE1WVWhCVmxSS05GRTFSMGhaVmtWR1JrUlhSRXRRUmtnMVRrTkpUekpOTTBOSFNGcElXRkU9fLgsofp8amFkZv4N4gnFUGjCePgaZPAU20ylfr8J-63T
> Content-Length: 76
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 76 out of 76 bytes
< HTTP/1.1 200 OK
< content-length: 23
< content-type: text/html; charset=UTF-8
< date: Tue, 12 May 2020 14:38:50 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 7307
< 
* Connection #0 to host 10.152.183.241 left intact
{"predictions": [1, 1]}
반응형