External Authorization not working

307 views
Skip to first unread message

Akshit Rawat

unread,
Jul 6, 2023, 10:31:02 AM7/6/23
to envoy-users
Hi Everyone,

I have been working on routing using envoyproxy.
I am using docker to deploy envoy and my springboot application.
The above scenario for routing without ext_auth is working perfectly

The problem i am facing is when i am using ext_authz filter and using another authorization service written in springboot.

Please find below the config and my api code.
______________________________________________________________________________________
envoy.yaml

stats_sinks:
  - name: envoy.stat_sinks.statsd
    typed_config:
      "@type": type.googleapis.com/envoy.config.metrics.v3.StatsdSink
      address:
        socket_address:
          address: 10.131.50.226
          port_value: 8092
static_resources:
  listeners:
    - address:
        socket_address:
          address: 0.0.0.0
          port_value: 10000
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                codec_type: AUTO
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains:
                        - "*"
                      routes:
                        - match:
                            prefix: "/serviceA"
                          route:
                            cluster: my_cluster                        
                        - match:
                            prefix: "/serviceB"
                          route:
                            cluster: my_cluster
                access_log:
                  - name: envoy.access_loggers.stdout
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                http_filters:
                  - name: envoy.filters.http.ext_authz
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
                      http_service:
                        server_uri:
                          uri: http://host.docker.internal:8084/auth
                          cluster: ext_authz_service
                          timeout: 0.250s
                        authorization_request:
                          allowed_headers:
                            patterns:
                              - exact: token
 
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
    - name: my_cluster
      type: STRICT_DNS
      # Comment out the following line to test on v6 networks
      dns_lookup_family: V4_ONLY
      load_assignment:
        cluster_name: my_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: host.docker.internal
                      port_value: 8085

    - name: ext_authz_service
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
          cluster_name: ext_authz_service
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address:
                        address: host.docker.internal
                        port_value: 8084

admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9910
layered_runtime:
  layers:
    - name: static_layer_0
      static_layer:
        envoy:
          resource_limits:
            listener:
              example_listener_name:
                connection_limit: 10000

______________________________________________________________________________________
service code

package com.ukg.App.DemoApp.Controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/serviceA")
public class Controller {

  @GetMapping("hello")
  ResponseEntity<String> getHelloResponse() {
    System.out.println("Test Logs printing");
    return ResponseEntity.ok()
        .body("If You are watching this message. You have successfully logged in!!!");
  }

  @GetMapping("bye")
  ResponseEntity<String> getByeResponse() {
    return ResponseEntity.ok().body("Login again!!!");
  }
}


package com.ukg.App.DemoApp.Controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/serviceB")
public class AnotherController {

  @PostMapping("write")
  ResponseEntity<String> getValue(@RequestBody String value) {
    return ResponseEntity.ok().body("You wrote: " + value);
  }

}
______________________________________________________________________________________
Authorization Service api

@RestController
@RequestMapping("/")
public class AuthorizationController {

  @GetMapping(value = "auth", produces = "application/json")
  ResponseEntity<String> validateAuthorization(
      @RequestHeader("token") String authorizationHeader) {
    final HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    try {
      String token = authorizationHeader;
      if (token.equals("validToken"))
      {
        System.out.println("Token:" + token);
        return new ResponseEntity<String>("{\"Token\": \"Valid Token\"}", httpHeaders,
            HttpStatus.OK);
      } else {
        return new ResponseEntity<String>("{\"Token\": \"InvalidToken\"}", httpHeaders,
            HttpStatus.FORBIDDEN);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

  }
}
______________________________________________________________________________________
After ext_authz configuration,
This is what i am getting as a response when i am hitting localhost:10000/serviceA/hello

also i am providing a header as {token : validToken} to authorize and route
{
    "timestamp""2023-07-06T13:00:01.797+00:00",
    "status"404,
    "error""Not Found",
    "path""/serviceA/hello"
}

I am stuck due to this issue and could not find any solution on the internet. Can someone point out the issue here and let me know what i am doing wrong here?

Yan Avlasov

unread,
Jul 10, 2023, 3:59:17 PM7/10/23
to Akshit Rawat, envoy-users
This is not enough information for anyone to help you. Please enable logs and do more debugging to understand the cause of failure. One possibility is that the DNS names that are used in clusters are not being resolved.

--
You received this message because you are subscribed to the Google Groups "envoy-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to envoy-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/envoy-users/0cfa9618-7046-455d-b519-9db29b4f226cn%40googlegroups.com.

Erik Åsén

unread,
Oct 5, 2023, 12:22:37 PM10/5/23
to envoy-users
Hi, 

So I'm joining this thread/discussion since this looks like the thing me and my colleagues found out about the http envoy filter.

What we found out and hopefully this help you is that the auth component will either need to have a catch all rest path, something like @GetMapping(value = "*", produces = "application/json"), or implement every single route you want to check in your auth component, e.g. @GetMapping(value = "auth/serviceA/hello", produces = "application/json"). This is also probably why your request results in a 404 for the /serviceA/hello and what I have gathered from my own implementation, but with Istios implementation of the standard (https://istio.io/v1.16/docs/tasks/security/authorization/authz-custom/), is that the request is forwarded to /auth/serviceA/hello.

Here is an example (not mine but a colleagues) Quarkus app https://github.com/dnulnets/oidcgk/blob/main/src/main/java/eu/stenlund/authz/Resource.java that uses @Path("{:.+}") @GET to filter on specific REST methods with Istio forwarding the request to the app.

P.S. In my opinion this should be documented in envoy.extensions.filters.http.ext_authz.v3.ExtAuthz documentation somewhere since gRPC just works with all endpoints right out of the box to my testing.

P.P.S. I probably wasted to much time testing this with my own app by trying to implement every single endpoint I could find the https://mvnrepository.com/artifact/io.envoyproxy.controlplane/server code and packages it includes. Also my knowledge of services is "What endpoint should i call and is it a GET, POST, PUSH, PATCH, DELETE or PUT and if it should have a payload with JSON, XML and so on".
Reply all
Reply to author
Forward
0 new messages