1. 개요
- Dex ? (https://github.com/dexidp/dex)
Dex is an identity service that uses OpenID Connect to drive authentication for other apps.
- Dex 구성
'kfctl_istio_dex.v1.2.0.yaml'를 이용하여 Kubeflow(v1.2)를 구성할 경우 dex(v2.22)가 포함되어 설치 된다.
- Dex 인증 범위
다음과 같은 유형의 자원에 호출할 경우 Dex 인증을 요구 한다.
✓ Kubeflow dashboard login
✓ KFServing (Knative 기반에서 동작)
✓ Knative serving (Istio 기반에서 동작)
✓ Istio Virtual service
- 적용된 auth filter
$ k get envoyfilters.networking.istio.io authn-filter -n istio-system
NAME AGE
authn-filter 135d
$
2. Dex 인증 요구
- KFServing, Knative serving, Istio Virtual service 등를 호출할 경우 '/dex/auth'로 리다이텍트 되면서 인증을 요구 한다.
✓ 요청할 URL에 대하여 Dex 인증을 우회하거나,
✓ 사전에 인증 과정을 거쳐서 authservice_session 값을 얻은 후, 요청시 Token을 전달하면 된다.
- KFServing 호출
$ curl -v http://flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80/v1/models/flowers-sample:predict -d @./input.json
* About to connect() to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr port 80 (#0)
* Trying 14.52.244.137...
* Connected to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr (14.52.244.137) port 80 (#0)
> POST /v1/models/flowers-sample:predict HTTP/1.1
> User-Agent: curl/7.29.0
> Host: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr
> Accept: */*
> Content-Length: 16201
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 302 Found
< location: /dex/auth?client_id=kubeflow-oidc-authservice&redirect_uri=%2Flogin%2Foidc&response_type=code&scope=profile+email+groups+openid&state=MTYzMjg5NjI1NHxFd3dBRUV0eFFYUjRhbEF5V20xRU1XcDBkRE09fEz3NQUn3zDR9uI_xrfHiAyt6JuqvrCR8bp4hIzFzdX9
< date: Wed, 29 Sep 2021 06:17:33 GMT
< content-length: 0
< x-envoy-upstream-service-time: 3
< server: istio-envoy
* HTTP error before end of send, stop sending
<
* Closing connection 0
$
3. Dex 인증 우회
- Dex 인증을 제외할 URL(flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80)를 아래와 같이 EnvoyFilter에 적용한다.
spec.configPatches[].match.routeConfiguration.vhost.name: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80
spec.configPatches[].patch.value.per_filter_config.envoy.ext_authz.disabled: true
- 추가할 EnvoyFilter는 istio-system namespace로 반듯이 지정해야 한다.
- https://stackoverflow.com/questions/62270590/apply-envoyfilter-ext-authz-per-virtual-hosts
$ cat bypass-auth-flowers-sample.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: bypass-auth-flowers-sample
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: VIRTUAL_HOST
match:
routeConfiguration:
vhost:
name: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80
patch:
operation: MERGE
value:
per_filter_config:
envoy.ext_authz:
disabled: true
$ k apply -f bypass-auth-flowers-sample.yaml
envoyfilter.networking.istio.io/bypass-auth-flowers-sample created
[iap@iap01 tensorflow]$ k get envoyfilters.networking.istio.io -n istio-system
NAME AGE
authn-filter 135d
bypass-auth-filter 49d
bypass-auth-flowers-sample 9s
$
- KFServing 호출
$ curl -v http://flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80/v1/models/flowers-sample:predict -d @./input.json
* About to connect() to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr port 80 (#0)
* Trying 14.52.244.137...
* Connected to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr (14.52.244.137) port 80 (#0)
> POST /v1/models/flowers-sample:predict HTTP/1.1
> User-Agent: curl/7.29.0
> Host: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr
> Accept: */*
> Content-Length: 16201
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< content-length: 221
< content-type: application/json
< date: Wed, 29 Sep 2021 06:31:13 GMT
< x-envoy-upstream-service-time: 2018
< server: istio-envoy
<
{
"predictions": [
{
"prediction": 0,
"key": " 1",
"scores": [0.999114931, 9.2098875e-05, 0.000136786344, 0.000337258534, 0.000300534302, 1.84814126e-05]
}
]
* Connection #0 to host flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr left intact
}
$
- Trouble-shooting
▷ Problem: curl 명령어로 요청시 응답지연 또는 타임아웃 에러가 발생
외부 네트워크에서 요청 시에만 발생되며, 외부 네트워크에서 브라우저로 요청시 정상 동작 됨
yoosungjeon@ysjeon-Dev ~ % curl -v http://flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80/v1/models/flowers-sample:predict -d @./input.json
* Trying 14.52.244.137:80...
* Connected to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr (14.52.244.137) port 80 (#0)
> POST /v1/models/flowers-sample:predict HTTP/1.1
> Host: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr
> User-Agent: curl/7.71.1
> Accept: */*
> Content-Length: 16192
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 16192 out of 16192 bytes
* Recv failure: Operation timed out
* Closing connection 0
curl: (56) Recv failure: Operation timed out
yoosungjeon@ysjeon-Dev ~ %
▷ Solution: curl 명령어로 요청시 User-Agent를 명시적으로 "curl/7.71.1" 대신 null 또는 Chrome으로 지정
curl -v http://{URL} -d @./input.json -A ""
curl -v http://{URL} -d @./input.json -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"
본 현상은 외부 네트워크에서 요청할 경우만 발생되며 Kubernetes, Kubeflow, Dex 설정과는 무관함
테스트 서버 앞단에 있는 IPS (침입방지시스템)와 관련이 있을 것으로 예상 됨
yoosungjeon@ysjeon-Dev ~ % curl -v http://flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80/v1/models/flowers-sample:predict -d @./input.json -A ""
* Trying 14.52.244.137:80...
* Connected to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr (14.52.244.137) port 80 (#0)
> POST /v1/models/flowers-sample:predict HTTP/1.1
> Host: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr
> Accept: */*
> Content-Length: 16192
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 16192 out of 16192 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-length: 221
< content-type: application/json
< date: Wed, 29 Sep 2021 06:41:42 GMT
< x-envoy-upstream-service-time: 1957
< server: istio-envoy
<
{
"predictions": [
{
"prediction": 0,
"key": " 1",
"scores": [0.999114931, 9.2098875e-05, 0.000136786344, 0.000337258534, 0.000300534302, 1.84814126e-05]
}
]
* Connection #0 to host flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr left intact
}%
yoosungjeon@ysjeon-Dev ~ %
4. ID token 발급 using kfp
- kfp is KubeFlow Pipelines SDK
- kfp package를 이용하여 아래와 같이 token을 얻는 다.
✓ 발급 받은 token은 24시간 유효하다.
yoosungjeon@ysjeon-Dev ~ % pip install kfp
Looking in indexes: http://mirror.kakao.com/pypi/simple
Collecting kfp
...
Successfully installed Deprecated-1.2.13 absl-py-0.11.0 docstring-parser-0.10 fire-0.4.0 google-api-python-client-1.12.8 kfp-1.8.3 kfp-pipeline-spec-0.1.11 kfp-server-api-1.7.0 pydantic-1.8.2 requests-toolbelt-0.9.1 strip-hints-0.1.10 tabulate-0.8.9 typing-extensions-3.10.0.2
yoosungjeon@ysjeon-Dev ~ % vi get_token.py
import requests
import kfp
HOST = "http://kf.acp.kt.co.kr/"
USERNAME = "admin@kubeflow.org"
PASSWORD = "12341234"
session = requests.Session()
response = session.get(HOST)
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
data = {"login": USERNAME, "password": PASSWORD}
session.post(response.url, headers=headers, data=data)
session_cookie = session.cookies.get_dict()["authservice_session"]
print(session_cookie)
yoosungjeon@ysjeon-Dev ~ % python get_token.py
MTYzMjk2NTA5NHxOd3dBTkVoTU1rcFhVVTlRUmt4Q1dqYzFWMWxQTWtkWlZGQk1XRkZQTlVsSFVWUkdSak5WVEU1SFdsQkJRMWRPV2tJMU5saElVVUU9fOFpbeudhGgoPGfXouHc-s3rcwVjAEKS7hmouSmjsh4o
yoosungjeon@ysjeon-Dev ~ %
- Dex log
$ k logs dex-7b5b7f4fb6-qq8qp -n auth
...
time="2021-09-30T01:19:48Z" level=info msg="login successful: connector \"local\", username=\"admin\", preferred_username=\"\", email=\"admin@kubeflow.org\", groups=[]"
- KFserving 호출하기
해더에 token을 추가 후 호출 한다.
-H "Cookie: authservice_session=${TOKEN}"
$ TOKEN=MTYzMjk2NTA5NHxOd3dBTkVoTU1rcFhVVTlRUmt4Q1dqYzFWMWxQTWtkWlZGQk1XRkZQTlVsSFVWUkdSak5WVEU1SFdsQkJRMWRPV2tJMU5saElVVUU9fOFpbeudhGgoPGfXouHc
$ curl -v http://flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr:80/v1/models/flowers-sample:predict -d @./input.json -H "Cookie: authservice_session=${TOKEN}"
* About to connect() to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr port 80 (#0)
* Trying 14.52.244.137...
* Connected to flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr (14.52.244.137) port 80 (#0)
> POST /v1/models/flowers-sample:predict HTTP/1.1
> User-Agent: curl/7.29.0
> Host: flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr
> Accept: */*
> Cookie: authservice_session=MTYzMjk2NTA5NHxOd3dBTkVoTU1rcFhVVTlRUmt4Q1dqYzFWMWxQTWtkWlZGQk1XRkZQTlVsSFVWUkdSak5WVEU1SFdsQkJRMWRPV2tJMU5saElVVUU9fOFpbeudhGgoPGfXouHc
> Content-Length: 16201
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< content-length: 221
< content-type: application/json
< date: Wed, 29 Sep 2021 09:16:55 GMT
< x-envoy-upstream-service-time: 2034
< server: istio-envoy
<
{
"predictions": [
{
"scores": [0.999114931, 9.2098875e-05, 0.000136786344, 0.000337258534, 0.000300534302, 1.84814126e-05],
"prediction": 0,
"key": " 1"
}
]
* Connection #0 to host flowers-sample.yoosung-jeon.kf-serv.acp.kt.co.kr left intact
$
5. ID token 발급 using rest api
- ID token 발급 빋기
## istio 주소 설정
$ k get svc -n istio-system istio-ingressgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.110.60.217 14.52.244.137 15020:30943/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:31449/TCP,15030:31395/TCP,15031:31117/TCP,15032:30569/TCP,15443:31974/TCP 135d
$ ISTIO_URL=14.52.244.137
$
## 임의의 URI 호출
$ curl http://${ISTIO_URL}/v1/models/flowers-sample:predict
<a href="/dex/auth?client_id=kubeflow-oidc-authservice&redirect_uri=%2Flogin%2Foidc&response_type=code&scope=profile+email+groups+openid&state=MTYzMjkwNTYyOHxFd3dBRUhKUmJqUkhjV0pCVEVGNFUwSllkMjA9fJKaeQAdBimGkiqF1Bw6UV6Q0dQL2WlXBLdwZoGbMHCC">Found</a>.
$
## Req 얻기
$ curl "http://${ISTIO_URL}/dex/auth?client_id=kubeflow-oidc-authservice&redirect_uri=%2Flogin%2Foidc&response_type=code&scope=profile+email+groups+openid&state=MTYzMjkwNTYyOHxFd3dBRUhKUmJqUkhjV0pCVEVGNFUwSllkMjA9fJKaeQAdBimGkiqF1Bw6UV6Q0dQL2WlXBLdwZoGbMHCC"
<a href="/dex/auth/local?req=fmpegyloe6jeh6gjfxlbarwnd">Found</a>.
$ REQ=fmpegyloe6jeh6gjfxlbarwnd
## 인증하기
$ LOGIN=admin%40kubeflow.org
$ PASSWORD=12341234
$ curl "http://${ISTIO_URL}/dex/auth/local?req=${REQ}" -H 'Content-Type: application/x-www-form-urlencoded' --data "login=${LOGIN}&password=${PASSWORD}"
$
## approval 얻기
$ curl "http://${ISTIO_URL}/dex/approval?req=${REQ}"
<a href="/login/oidc?code=rsytn2zptxhmq56gcj65wz2co&state=MTYzMjkwNTYyOHxFd3dBRUhKUmJqUkhjV0pCVEVGNFUwSllkMjA9fJKaeQAdBimGkiqF1Bw6UV6Q0dQL2WlXBLdwZoGbMHCC">See Other</a>.
## ID token 얻기
$ curl -v "http://${ISTIO_URL}/login/oidc?code=j4j2lheobduu4i2xe7r446pzf&state=MTYzMjkwNjE3NHxFd3dBRURsbVNHcDRSMVY2VW0xRE9UaG5RWG89fDRNILnTBS2qLrQdhh_qT3v6Ol-Yyjr57ouquKg-sCX8" | grep set-cookie
* About to connect() to 14.52.244.137 port 80 (#0)
* Trying 14.52.244.137...
* Connected to 14.52.244.137 (14.52.244.137) port 80 (#0)
> GET /login/oidc?code=j4j2lheobduu4i2xe7r446pzf&state=MTYzMjkwNjE3NHxFd3dBRURsbVNHcDRSMVY2VW0xRE9UaG5RWG89fDRNILnTBS2qLrQdhh_qT3v6Ol-Yyjr57ouquKg-sCX8 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 14.52.244.137
> Accept: */*
>
< HTTP/1.1 302 Found
< content-type: text/html; charset=utf-8
< location: /hello
< set-cookie: authservice_session=MTYzMjkwNjIzN3xOd3dBTkZoQlUwMVRRa3hTVGt0WVRscFFNa1ZHUTB4RlFrOVRWMDlPV1ZaS1IxcEhTRU5UUjFaWFVrTlJRazVPVVVOQlNqSkZRMEU9fM9NitxyMMnG6ye3CSjyQr4J4ntKc_RnJW4DqWQ181QV; Path=/; Expires=Thu, 30 Sep 2021 09:03:57 GMT; Max-Age=86400
< date: Wed, 29 Sep 2021 09:03:57 GMT
< content-length: 29
< x-envoy-upstream-service-time: 27
< server: istio-envoy
<
<a href="/hello">Found</a>.
* Connection #0 to host 14.52.244.137 left intact
$
✓ 위 과정을 거쳐 최종적으로 ID token(authservice_session)을 얻을 수 있다.
set-cookie:
authservice_session=MTYzMjkwNjIzN3xOd3dBTkZoQlUw...;
Path=/;
Expires=Thu, 30 Sep 2021 09:03:57 GMT;
Max-Age=86400
✓ ID Token은 한번만 조회가 가능한다. 두번째 호출 부터는 "504 Gateway Timeout" 에러가 발생된다.
6. Dex 사용자 추가
- Add static users for basic auth
Kubeflow 1.2 in On-prem 구성 : "2. Kubeflow Install / e. Add static users for basic auth"
- LDAP / Active Directory
Kubeflow 1.0 in On-prem 구성 : "2. Kubeflow Install / g. Log in with LDAP / Active Directory"
'Kubeflow > Management' 카테고리의 다른 글
KFServing - Canary rollout 테스트 (0) | 2021.10.17 |
---|---|
KFServing - Deep dive (0) | 2021.10.14 |
Kubeflow Jupyter Custom Image 추가 (0) | 2021.09.24 |
댓글