Blink
Blink

Reputation: 1546

Istio EnvoyFilter that checks header for a valid token

I need to verify that a custom header is provided with a correct value. If not, I want deny access to the service and produce a 401 with a message.

I've been able to create an Istio AuthorizationPolicy for that but it gives me 403 which isn't totally wrong but I want to be correct and give 401.

This is what I've tried so far and unfortunately it doesn't have any impact on the requests that I'm sending (I'm no envoy nor lua expert so bare with me please):

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: custom-filter
  namespace: dev
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
    patch:
      operation: MERGE
      value: # lua filter specification
        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
          inlineCode: |
            function envoy_on_request(request_handle)
              if request_handle:headers():get("auth_token") != "xxx" then
                request_handle:respond({[":status"] = "401"}, "nope")                        
              end
            end

Working AuthorizationPolicy that produces 403 and which I would like to replace with above:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-method-get
  namespace: dev
spec:
  selector:
    matchLabels:
      app: myapp
  action: DENY
  rules:
  - when:
    - key: request.headers[auth_token]
      notValues: ["xxx"]

Upvotes: 3

Views: 2507

Answers (1)

Chris
Chris

Reputation: 5623

From my understanding, the response from istio is correct:

From RFC Standards:

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource...The user agent MAY repeat the request with a new or replaced Authorization header field.

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it...If authentication credentials were provided in the request, the server considers them insufficient to grant access.

So your request with token is understood but forbidden (403) but a request without token doesn't provide credentials at all, so it's unauthorized.

Regarding your filter:

Apply the Filter to HTTP_FILTER instead of the NETWORK_FILTER. And it should be applied before any other filter, so set opteration to INSERT_BEFORE.

Update

To apply the filter to a single pod instead of all pods, change context from GATEWAY to SIDECAR_INBOUND and set a workloadSelector :

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: custom-filter
  namespace: dev
spec:
  workloadSelector:
    labels:
      app: my-app
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch:
      operation: INSERT_BEFORE
      value: # lua filter specification
        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
          inlineCode: |
            function envoy_on_request(request_handle)
              if request_handle:headers():get("auth_token") ~= "my_secret_token" then
                request_handle:respond({[":status"] = "401"}, "nope")                        
              end
            end

Upvotes: 3

Related Questions