Expose and Secure a Workload with OAuth2 Proxy External Authorizer (Client Credentials Flow) ​
Learn how to expose and secure a workload using OAuth2 Proxy external authorizer and the OAuth 2.0 Client Credentials flow. SAP Cloud Identity Services acts as the OAuth2/OIDC Identity Provider (IdP) that issues JSON Web Tokens (JWTs).
Prerequisites ​
- You have an SAP BTP, Kyma runtime instance with the Istio and API Gateway modules added. The Istio and API Gateway modules are added to your Kyma cluster by default.
- You have an SAP Cloud Identity Services tenant. See Initial Setup.
- You have installed helm.
Context ​
This procedure shows how to implement external authorization for your Kyma workloads using the OAuth2 Client Credentials flow. In this context, your application exchanges its credentials directly with SAP Cloud Identity Services to obtain an access token.
When the URL of your exposed workload is requested, the following steps take place:
- The client sends its client ID and client secret to SAP Cloud Identity Services.
- SAP Cloud Identity Services validates these credentials and responds with a JWT that contains specific scopes defining what resources the client can access.
- The client includes this JWT in the Authorization header when making requests to your secured Kyma workload.
- OAuth2 Proxy validates the JWT against SAP Cloud Identity Services and either allows the request to proceed to your workload or returns
401 Unauthorizedin response.
Unlike the Authorization Code flow which requires browser redirects and user consent, the Client Credentials flow enables direct server-to-server communication using only the application's own credentials.
For more information, see OAuth 2.0 RFC 6749 and Client Credentials Flow.
Procedure ​
Create and Configure OpenID Connect Application ​
You need an identity provider to issue JWTs. Creating an OpenID Connect application allows SAP Cloud Identity Services to act as your issuer and manage authentication for your workloads.
Sign in to the administration console for SAP Cloud Identity Services. See Access Admin Console.
Create an OpenID Connect Application.
- Go to Application Resources > Application.
- Choose Create, provide the application name, and select the OpenID Connect radio button. For more configuration options, see Create OpenID Connect Application.
- Choose +Create.
Configure OpenID Connect Application for the Client Credentials flow.
- In the Trust > Single Sign-On section of your created application, choose OpenID Connect Configuration.
- Provide the name.
- In the Grant types section, check Client Credentials. For more configuration options, see Configure OpenID Connect Application for Client Credentials Flow.
- Choose Save.
Configure a secret for API authentication.
- In the Application API section of your created application, choose Client Authentication.
- In the Secrets section, choose Add.
- Choose the OpenID API access and provide other configuration as needed. For more configuration options, see Configure Secrets for API Authentication.
- Choose Save. Your client ID and secret appear in a pop-up window. Save the secret, as you will not be able to retrieve it from the system later.
Get a JWT ​
Export the following values as environment variables:
bashTENANT_URL="https://my-example-tenant.accounts.ondemand.com" CLIENT_ID="${YOUR-CLIENT-ID}" CLIENT_SECRET="${YOUR-CLIENT-SECRET}"Export base 64 encoded client ID and client secret.
bashexport ENCODED_CREDENTIALS=$(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)Get token_endpoint, jwks_uri, and issuer from your OpenID application, and save these values as environment variables:
bashTOKEN_ENDPOINT=$(curl -s ${TENANT_URL}/.well-known/openid-configuration | jq -r '.token_endpoint') echo token_endpoint: ${TOKEN_ENDPOINT} JWKS_URI=$(curl -s ${TENANT_URL}/.well-known/openid-configuration | jq -r '.jwks_uri') echo jwks_uri: ${JWKS_URI} ISSUER=$(curl -s ${TENANT_URL}/.well-known/openid-configuration | jq -r '.issuer') echo issuer: ${ISSUER}Get the JWT access token:
bashACCESS_TOKEN=$(curl -s -X POST "${TOKEN_ENDPOINT}" \ -d "grant_type=client_credentials" \ -d "client_id=${CLIENT_ID}" \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Authorization: Basic ${ENCODED_CREDENTIALS}" | jq -r '.access_token') echo ${ACCESS_TOKEN}
Deploy OAuth2 Proxy as an External Authorizer ​
Export the domain name:
bashEXPOSE_DOMAIN=$(kubectl get gateway -n kyma-system kyma-gateway -o jsonpath='{.spec.servers[0].hosts[0]}') EXPOSE_DOMAIN=${EXPOSE_DOMAIN#*.} GATEWAY=kyma-system/kyma-gatewayThis procedure uses the default domain of your Kyma cluster and the default Gateway. Alternatively, you can replace these values and use your custom domain and Gateway instead.
Create a namespace for deploying the OAuth2 Proxy.
bashkubectl create ns oauth2-proxy kubectl label namespace oauth2-proxy istio-injection=enabled --overwriteAdd the oauth2-proxy helm chart to your local Helm registry.
bashhelm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests helm repo update oauth2-proxyReplace the placeholders and define the
oauth2-proxyconfiguration for your authorization server. You can adjust this configuration as needed. See the additional configuration parameters.bashhelm upgrade --install oauth2-proxy --namespace oauth2-proxy oauth2-proxy/oauth2-proxy \ --set config.clientID="${CLIENT_ID}" \ --set config.clientSecret="${CLIENT_SECRET}" \ --set config.cookieName="" \ --set config.cookieSecret="$(openssl rand -base64 32 | head -c 32 | base64)" \ --set extraArgs.provider=oidc \ --set extraArgs.auth-logging="true" \ --set extraArgs.cookie-domain="${EXPOSE_DOMAIN}" \ --set extraArgs.cookie-samesite="lax" \ --set extraArgs.cookie-secure="false" \ --set extraArgs.force-json-errors="true" \ --set extraArgs.login-url="static://401" \ --set extraArgs.oidc-issuer-url="${TENANT_URL}" \ --set extraArgs.pass-access-token="true" \ --set extraArgs.pass-authorization-header="true" \ --set extraArgs.pass-host-header="true" \ --set extraArgs.pass-user-headers="true" \ --set extraArgs.request-logging="true" \ --set extraArgs.reverse-proxy="true" \ --set extraArgs.scope="openid email" \ --set extraArgs.set-authorization-header="true" \ --set extraArgs.set-xauthrequest="true" \ --set extraArgs.skip-jwt-bearer-tokens="true" \ --set extraArgs.skip-oidc-discovery="false" \ --set extraArgs.skip-provider-button="true" \ --set extraArgs.standard-logging="true" \ --set extraArgs.upstream="static://200" \ --set extraArgs.whitelist-domain="*.${EXPOSE_DOMAIN}:*" \ --waitCheck if the Oauth2 Proxy Pods are running:
bashkubectl --namespace=oauth2-proxy get pods -l "app=oauth2-proxy"Register
oauth2-proxyas an authorization provider in the Istio module:bashkubectl patch istio -n kyma-system default --type merge --patch '{"spec":{"config":{"authorizers":[{"name":"oauth2-proxy","port":80,"service":"oauth2-proxy.oauth2-proxy.svc.cluster.local","headers":{"inCheck":{"include":["x-forwarded-for", "cookie", "authorization"]}}}]}}}'
For more information about the fields set above, see the Istio Custom Resource documentation.
Expose Your Workload Using extAuth APIRule ​
To configure OAuth2 Proxy, expose your workload using APIRule custom resource (CR). Configure extAuth as the access strategy.
NOTE
To expose a workload using APIRule in version v2, the workload must be a part of the Istio service mesh. See Enable Istio Sidecar Proxy Injection.
See the following example APIRule with extAuth authorizer that exposes the sample HTTPBin Deployment:
Create the
httpbin-systemnamespace and deploy a sample HTTPBin Deployment.bashkubectl create ns httpbin-system kubectl label namespace httpbin-system istio-injection=enabled kubectl apply -f \ https://raw.githubusercontent.com/istio/istio/master/samples/httpbin/httpbin.yaml \ -n httpbin-systemExpose the workload with an APIRule using the extAuth access strategy.
bashcat <<EOF | kubectl apply -f - apiVersion: gateway.kyma-project.io/v2 kind: APIRule metadata: name: httpbin namespace: httpbin-system spec: gateway: ${GATEWAY} hosts: - httpbin.${EXPOSE_DOMAIN} service: name: httpbin port: 8000 rules: - path: /* methods: ["GET"] extAuth: authorizers: - oauth2-proxy EOFCheck if the APIRule's status is ready:
bashkubectl --namespace=oauth2-proxy get apirules httpbin -n httpbin-system
Results ​
To access your HTTPBin Service use curl.
To test the connection, first, do not provide the JWT.
bashcurl -ik -X GET https://httpbin.${EXPOSE_DOMAIN}/headersYou get the error
401 Unauthorized.Now, access the secured workload using the correct JWT.
bashcurl -ik -X GET https://httpbin.${EXPOSE_DOMAIN}/headers --header "Authorization:Bearer ${ACCESS_TOKEN}"You get code
200 OKin response.