From 994250c189e490bd375a622ca0834f6aaafa7e0a Mon Sep 17 00:00:00 2001 From: Ruoyu Ying Date: Wed, 11 Sep 2024 13:01:35 +0800 Subject: [PATCH] authn-authz: fix CORS issue and refine doc (#419) * authn-authz: fix CORS issue and refine doc * add cors policy in the configuration * reflect helm chart related changes * clearify the three options for authentication and authorization in readme Signed-off-by: Ruoyu Ying * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: Ruoyu Ying Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- authN-authZ/auth-istio/README.md | 54 ++++++++++++------- .../{ => gmc-based}/chatQnA_authZ_oauth.yaml | 2 + .../chatQnA_router_gateway_oauth.yaml | 15 +++++- .../{ => gmc-based}/chatQnA_ui_gateway.yaml | 0 .../helm-chart-based/chatQnA_authZ_oauth.yaml | 22 ++++++++ .../chatQnA_router_gateway_oauth.yaml | 16 ++++-- authN-authZ/auth-istio/oauth2_install.yaml | 11 ++-- 7 files changed, 89 insertions(+), 31 deletions(-) rename authN-authZ/auth-istio/{ => gmc-based}/chatQnA_authZ_oauth.yaml (87%) rename authN-authZ/auth-istio/{ => gmc-based}/chatQnA_ui_gateway.yaml (100%) create mode 100644 authN-authZ/auth-istio/helm-chart-based/chatQnA_authZ_oauth.yaml diff --git a/authN-authZ/auth-istio/README.md b/authN-authZ/auth-istio/README.md index b3c14dc1..96220ae0 100644 --- a/authN-authZ/auth-istio/README.md +++ b/authN-authZ/auth-istio/README.md @@ -2,7 +2,13 @@ In enterprise settings not only do we want to identify who is using a service but also what they are entitled to use. This is where authentication and authorization comes in. In contrast, API tokens provide full access by virtue of possession as long as they are valid/not expired. With that aside, we first provide the solution on AuthN and AuthZ in OPEA using Istio and JWT tokens. Another option is to leverage the oauth2-proxy with various OIDC providers for authentication and authorization. Using oauth2-proxy with Istio ensures secure, scalable access control, centralizes user management, and provides seamless single sign-on capabilities, improving overall security and user experience in complex microservices environments. -Currently we provide three kinds of setups for authentication and authorization: via fake JWT token, via JWT token generated by OIDC providers and via oauth2-proxy and OIDC providers. And here we use the chatQnA pipeline as an example. +Currently we provide three kinds of setups for authentication and authorization. Note: Please complete the steps in the [prerequisite](#prerequisite) before proceeding with these tasks. : + +- [via fake JWT token with curl](#perform-authentication-and-authorization-via-fake-jwt-tokens) +- [via JWT token generated by OIDC providers with curl](#perform-authentication-and-authorization-via-jwt-tokens-generated-by-oidc-provider) +- [via oauth2-proxy and OIDC providers with UI](#perform-authentication-and-authorization-via-oauth2-proxy-and-oidc-provider-and-ui) + +Here we use the chatQnA pipeline as an example. ## Prerequisite @@ -15,7 +21,7 @@ Before composing an OPEA pipeline with authN & authZ, user need to install Istio # deploy ChatQnA pipeline. You can either leverage GMC or the ChatQnA helm chart. kubectl create ns chatqa # here's the command to leverage GMC custom resource for ChatQnA deployment. -kubectl apply -f $(pwd)/../../microservices-connector/config/samples/ChatQnA/chatQnA_xeon.yaml +kubectl apply -f $(pwd)/../../microservices-connector/config/samples/ChatQnA/chatQnA_dataprep_xeon.yaml # please refer the doc https://github.com/opea-project/GenAIInfra/tree/main/helm-charts/chatqna for deployment with helm chart. # and install under `chatqa` namespace @@ -211,6 +217,13 @@ kubectl apply -f $(pwd)/keycloak_install.yaml export HOST_IP=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' | cut -d '/' -f3 | cut -d ':' -f1) export KEYCLOAK_PORT=$(kubectl get svc keycloak -o jsonpath='{.spec.ports[0].nodePort}') export KEYCLOAK_ADDR=${HOST_IP}:${KEYCLOAK_PORT} + +# set the url to access the backend services +if [ "${DEPLOY_METHOD}" = "gmc-based" ]; then + export URL="http://chatqna-ui.com:${INGRESS_PORT}" +else + export URL="http://chatqna-service.com:${INGRESS_PORT}" +fi ``` **Note:** Double check if the host ip captured is the correct ip. @@ -223,7 +236,7 @@ The user management is done via Keycloak and the configuration steps look like t ![create realm](./docs/create_realm.png) -2. Create a new client called `chatqna` and set `Client authentication` to 'On'. Set "http://chatqna-ui.com:${INGRESS_PORT}/*" in the `Valid redirect URIs` part. Note that `INGRESS_PORT` and `INGRESS_HOST` shall be exported following the guide [here](https://istio.io/latest/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports). Under the Credentials tab you will now be able to locate ``, which will be used in the oauth2-proxy configs. +2. Create a new client called `chatqna` and set `Client authentication` to 'On'. Set the value of `$URL` with "/\* " (e.g. "http://chatqna-ui.com:${INGRESS_PORT}/*") in the `Valid redirect URIs` part. Note that `INGRESS_PORT` and `INGRESS_HOST` shall be exported following the guide [here](https://istio.io/latest/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports). Under the Credentials tab you will now be able to locate ``, which will be used in the oauth2-proxy configs. ![create client 1](./docs/create_client_1.png) @@ -265,29 +278,28 @@ kubectl create ns oauth2-proxy envsubst < $(pwd)/oauth2_install.yaml | kubectl apply -f - ``` -**Expose the pipeline endpoint through Istio Ingressgateway and install chatQnA UI** +**Expose the pipeline endpoint and UI through Istio Ingressgateway** Here we expose the chatQnA endpoint through the ingress gateway and then install the chatQnA conversation UI. +Notice that the instructions differs between helm chart based deployment and GMC based deployment. Please the instructions accordingly. + +With GMC based deployment, export chatqna endpoint and install UI services: ```bash # expose chatqna endpoint kubectl apply -f $(pwd)/$DEPLOY_METHOD/chatQnA_router_gateway_oauth.yaml -# build chatqna UI image if not exist on your machine -git clone https://github.com/opea-project/GenAIExamples.git -cd GenAIExamples/ChatQnA/docker/ui/ -docker build --no-cache -t opea/chatqna-conversation-ui:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f ./docker/Dockerfile.react . -# inject image to containerd repo -docker save -o ui.tar opea/chatqna-conversation-ui:latest -sudo ctr -n k8s.io image import ui.tar # install chatqna conversation UI -cd && cd GenAIInfra -if [ "${DEPLOY_METHOD}" = "gmc-based" ]; then - helm install chatqna-ui $(pwd)/helm-charts/common/chatqna-ui --set BACKEND_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/",DATAPREP_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/dataprep" -else - helm install chatqna-ui $(pwd)/helm-charts/common/chatqna-ui --set BACKEND_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/v1/chatqna",DATAPREP_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/v1/dataprep" -fi +cd ../../ +helm install chatqna-ui $(pwd)/helm-charts/common/ui --set BACKEND_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/",DATAPREP_SERVICE_ENDPOINT="http://chatqna-service.com:${INGRESS_PORT}/dataprep" # expose ui service outside -kubectl apply -f $(pwd)/chatQnA_ui_gateway.yaml +cd authN-authZ/auth-istio +kubectl apply -f $(pwd)/$DEPLOY_METHOD/chatQnA_ui_gateway.yaml +``` + +With helm chart based deployment, the UI already deployed as part of the pipeline. So expose endpoints like this: + +```bash +kubectl apply -f $(pwd)/$DEPLOY_METHOD/chatQnA_router_gateway_oauth.yaml ``` **Add authentication and authorization rules to the pipeline through Istio Ingress Gateway** @@ -303,7 +315,7 @@ kubectl rollout restart deployment/istiod -n istio-system # apply the authentication and authorization rule # these files will restrict user access with valid token (with valid group and role) envsubst < $(pwd)/chatQnA_authN_oauth.yaml | kubectl apply -f - -envsubst < $(pwd)/chatQnA_authZ_oauth.yaml | kubectl apply -f - +envsubst < $(pwd)/$DEPLOY_METHOD/chatQnA_authZ_oauth.yaml | kubectl apply -f - ``` **Validate authentication and authorization with UI service** @@ -315,4 +327,6 @@ sudo sed -i '1i\127.0.0.1 chatqna-service.com' /etc/hosts sudo sed -i '1i\127.0.0.1 chatqna-ui.com' /etc/hosts ``` -Open browser with address "chatqna-ui.com:${INGRESS_PORT}". Login with user `bob` and its credentials shall return a 403 error. Login with user `mary` and its credentials shall able to access the ChatQnA service. +Open browser with address `"chatqna-ui.com:${INGRESS_PORT}"` if using GMC based deployment. Otherwise, open the browser with address `"chatqna-service.com:${INGRESS_PORT}"`. + +Login with user `bob` and its credentials shall return a 403 error. Login with user `mary` and its credentials shall able to access the ChatQnA service. diff --git a/authN-authZ/auth-istio/chatQnA_authZ_oauth.yaml b/authN-authZ/auth-istio/gmc-based/chatQnA_authZ_oauth.yaml similarity index 87% rename from authN-authZ/auth-istio/chatQnA_authZ_oauth.yaml rename to authN-authZ/auth-istio/gmc-based/chatQnA_authZ_oauth.yaml index ad0a9fd7..1ccbaac9 100644 --- a/authN-authZ/auth-istio/chatQnA_authZ_oauth.yaml +++ b/authN-authZ/auth-istio/gmc-based/chatQnA_authZ_oauth.yaml @@ -13,6 +13,8 @@ spec: rules: - to: - operation: + hosts: + - chatqna-ui.com:${INGRESS_PORT} notPaths: - /realms/* selector: diff --git a/authN-authZ/auth-istio/gmc-based/chatQnA_router_gateway_oauth.yaml b/authN-authZ/auth-istio/gmc-based/chatQnA_router_gateway_oauth.yaml index 84288f78..5760739f 100644 --- a/authN-authZ/auth-istio/gmc-based/chatQnA_router_gateway_oauth.yaml +++ b/authN-authZ/auth-istio/gmc-based/chatQnA_router_gateway_oauth.yaml @@ -29,7 +29,20 @@ spec: hosts: - chatqna-service.com http: - - match: + - corsPolicy: + allowCredentials: true + allowHeaders: + - content-type + - authorization + allowMethods: + - POST + - GET + - OPTIONS + - PUT + - DELETE + allowOrigins: + - regex: http://chatqna-ui.com:.* + match: - uri: prefix: / route: diff --git a/authN-authZ/auth-istio/chatQnA_ui_gateway.yaml b/authN-authZ/auth-istio/gmc-based/chatQnA_ui_gateway.yaml similarity index 100% rename from authN-authZ/auth-istio/chatQnA_ui_gateway.yaml rename to authN-authZ/auth-istio/gmc-based/chatQnA_ui_gateway.yaml diff --git a/authN-authZ/auth-istio/helm-chart-based/chatQnA_authZ_oauth.yaml b/authN-authZ/auth-istio/helm-chart-based/chatQnA_authZ_oauth.yaml new file mode 100644 index 00000000..a1f669f9 --- /dev/null +++ b/authN-authZ/auth-istio/helm-chart-based/chatQnA_authZ_oauth.yaml @@ -0,0 +1,22 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: security.istio.io/v1 +kind: AuthorizationPolicy +metadata: + name: chatqna-ext-authz + namespace: istio-system +spec: + action: CUSTOM + provider: + name: oauth2-proxy + rules: + - to: + - operation: + hosts: + - chatqna-service.com:${INGRESS_PORT} + notPaths: + - /realms/* + selector: + matchLabels: + istio: ingressgateway diff --git a/authN-authZ/auth-istio/helm-chart-based/chatQnA_router_gateway_oauth.yaml b/authN-authZ/auth-istio/helm-chart-based/chatQnA_router_gateway_oauth.yaml index e8a11404..2eb2e8bc 100644 --- a/authN-authZ/auth-istio/helm-chart-based/chatQnA_router_gateway_oauth.yaml +++ b/authN-authZ/auth-istio/helm-chart-based/chatQnA_router_gateway_oauth.yaml @@ -34,14 +34,22 @@ spec: prefix: /v1/chatqna route: - destination: - host: chatqna.chatqa.svc.cluster.local + host: chatqna-nginx.chatqa.svc.cluster.local port: - number: 8888 + number: 80 - match: - uri: prefix: /v1/dataprep route: - destination: - host: chatqna-data-prep.chatqa.svc.cluster.local + host: chatqna-nginx.chatqa.svc.cluster.local port: - number: 6007 + number: 80 + - match: + - uri: + prefix: / + route: + - destination: + host: chatqna-nginx.chatqa.svc.cluster.local + port: + number: 80 diff --git a/authN-authZ/auth-istio/oauth2_install.yaml b/authN-authZ/auth-istio/oauth2_install.yaml index 14418cce..6ae69188 100644 --- a/authN-authZ/auth-istio/oauth2_install.yaml +++ b/authN-authZ/auth-istio/oauth2_install.yaml @@ -31,10 +31,13 @@ data: session_store_type="redis" redis_connection_url="redis://redis-service:6379" # Redirect url - redirect_url="http://chatqna-ui.com:${INGRESS_PORT}/oauth2/callback" + redirect_url="${URL}/oauth2/callback" #extra attributes reverse_proxy = true auth_logging = true + request_logging = true + silence_ping_logging = true + standard_logging = true cookie_httponly = true cookie_refresh = "2m" cookie_expire = "3m" @@ -43,15 +46,11 @@ data: pass_authorization_header = true pass_basic_auth = true pass_user_headers = true - request_logging = true set_authorization_header = true set_xauthrequest = true - silence_ping_logging = true skip_provider_button = true - skip_auth_strip_headers = false + skip_auth_preflight = true skip_jwt_bearer_tokens = true - ssl_insecure_skip_verify = true - standard_logging = true kind: ConfigMap metadata: name: oauth2-proxy-config