Search code examples
kubernetesistio

Enforcing JWT authentication on GKE using Istio


We are developing web-app which is backed by a bunch of BFF services deployed on GKE with Istio configured to be injected as a sidecar on every pod in the BFF services.

The requirement here is to

  • Enforce a JWT based authentication for all workloads except for the spring actuator endpoints.
  • Extract the member_id from the JWT claim and pass it as a header to the service.
  • I want to bypass this for "internal" endpoints (from within the network) and when the BFF's are talking internally (This is where I am stuck)

Here's what I have working so far.

  • Setup a RequestAuthentication as below
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: req-auth-jwt-required
  namespace: istio-testing-ns
spec:
  selector:
    matchLabels:
      app: istio-testing-service
  jwtRules:
    - issuer: "https://abc.us.com/"
      jwksUri: https://abc.us.com/.well-known/jwks.json
      outputClaimToHeaders:
        - header: X-MemberId
          claim: x-member-id
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: req-auth-policy-authenticated-only
  namespace: istio-testing-ns
spec:
  selector:
    matchLabels:
      app: istio-testing-service
  action: DENY
  rules:
    - from:
        - source:
            notRequestPrincipals: ["*"]
      to:
        - operation:
            notPaths: ["/istio-test/service/v1/actuator*"]
            notHosts: ["internal-*"]
            methods:
              - "GET"
    - to:
        - operation:
            paths:
              - "/istio-test/service/v1/categories*"
            notHosts: ["internal-*"]
            methods:
              - "GET"
              - "POST"
      when:
        - key: request.auth.claims[x-permissions]
          notValues:
            - "categories-lookup"

So, Using these two manifests I am trying to meet the above requirement, it is, by and far working, however, the problem, I am running into is below

  • When calling the service using the "internal" host, with no JWT and header X-MemberId, the outputClaimToHeaders seems to be over-writing the header because of which the service fails.

Any recommendations on how should I go about meeting this or any other general suggestions?


Solution

  • I am led to believe this could be a probable bug where the headers are wiped out in case if the JWT is not passed.

    Hence, I used the following approach to get around my problem.

    In Istio, I used the outputPayloadToHeader to pass the verified JWT's payload as a header to the service.

    apiVersion: security.istio.io/v1beta1
    kind: RequestAuthentication
    metadata:
      name: req-auth-jwt-required
      namespace: istio-testing-ns
    spec:
      selector:
        matchLabels:
          app: istio-testing-service
      jwtRules:
        - issuer: "https://abc.us.com/"
          jwksUri: https://abc.us.com/.well-known/jwks.json
          outputPayloadToHeader: "X-JWT-Payload"
    

    Once the above was done, I wrote a filter in ClaimExtractingFilter that basically, extracts the passed in header (X-JWT-Payload) and extract the claims and pass them as headers to the actual service.

    Let me know if anyone needs more details about the filter and I'll be happy to provide.