Using EntraID JWT to verify external calls with Istio add-on on AKS

December 28, 2024

Problem Statement

Istio PeerAuthentication CRD helps to authenticate the calls between services in the mesh. However, if you want to authenticate the calls from external services, Istio requires a different CRD which is called RequestAuthentication. How can you configure RequestAuthentication CRD to verify EntraID JWT and allow/deny calls?

This CRD helps to authenticate the calls from external services using JWT tokens. This guide will show you how to use RequestAuthentication CRD to authenticate the calls from external services using JWT tokens.

Solution

Few basics:

RequestAuthentication resource configures the Istio proxy with data extracted from a JWT token. The JWT token is extracted from the request header and the data is extracted from the token and stored as filter metadata. The data can be used in the authorization policy to allow or deny the request.

RequestAuthentication and AuthenticationPolicy CRDs:

AuthenticationPolicy CRD is similar to what is used for PeerAuthentication CRD. Since PeerAuthentication CRD is used to authenticate the calls between services in the mesh, the correspoonding AuthenticationPolicy CRD uses source: principals to specify the source of the call. However, RequestAuthentication CRD is used to authenticate the calls from external services, the corresponding AuthenticationPolicy CRD uses source: requestPrincipals to specify the source of the call.

Steps to implement RequestAuthentication CRD to verify EntraID JWT and allow/deny calls are as follows:

  • Define 'RequestAuthentication' CRD to specify the JWT token issuer, jwksUri, and the JWT token audience. Change 'x' to your tenant id.
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: reqauth-product-jwt
  namespace: aks-istio-ingress
spec:
  jwtRules:
    - issuer: "https://sts.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/"
      jwksUri: "https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/discovery/v2.0/keys"
EOF
  • Define 'AuthorizationPolicy' CRD to verify JWT claims and allow/deny calls. The 'requestPrincipals' field is used to specify the source of the call. The 'principals' field is used to specify the source of the call in PeerAuthentication CRD. Change 'mytenant' to your tenant name and also change the 'upn' claim to the claim that you want to verify.

You can use the following command to get the upn claim.

az account show --query user.name
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: authz-product
  namespace: aks-istio-ingress
spec:
  action: ALLOW
  rules:
    - from:
        - source:
            requestPrincipals: ["*"]
      when:
        - key: request.auth.claims[upn]
          values: ["admin@mytenant.onmicrosoft.com"]
EOF

For testing this, you can use the following command to get the access token and use it in the curl command to test the call.

export ACCESSTOKEN=$(az account get-access-token --query accessToken --output tsv)  
curl http://ingressgateway-ip-address -H "Authorization: Bearer $ACCESSTOKEN"

Replace ingressgateway-ip-address with the IP address of the ingress gateway. You can get the IP address of the ingress gateway using kubectl get svc -n aks-istio-ingress

If you change access token, the call will be denied.

You can optionally enable access logging to see the logs in the ingress gateway pod. The following command will enable access logging.

cat <<EOF | kubectl apply -f -
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
  name: ns-logging-aks-istio-ingress
  namespace: aks-istio-ingress
spec:
  accessLogging:
  - providers:
    - name: envoy
EOF

Check logs in the ingress gateway pod.

k logs -n aks-istio-ingress -l app=aks-istio-ingressgateway-external

You should be able to see the logs with failed messages if the access token is not valid.

"GET / HTTP/1.1" 403 - rbac_access_denied_matched_policy[none]"

For successful calls, you should see the logs with success messages.

"GET / HTTP/1.1" 404 NR route_not_found -

or if the call is made to a valid endpoint, you should see the logs with success messages.

"GET /productpage HTTP/1.1" 200 - via_upstream 

For detailed examples and steps, please refer to the following links:

https://github.com/srinman/aksworkshop/blob/main/lab-istio/istio-security.md

https://istio.io/latest/docs/tasks/security/authorization/authz-jwt/


Profile picture

Written by Sridher Manivel Based out of Charlotte, NC. Linkedin