Search code examples
spring-bootmicroserviceskeycloakkong

Managing authorization at API Gateway (Kong HQ) + Keycloak + Spring boot microservices


I am working on a Microservices architecture where I am using following components:

  1. KongHQ as an API gateway
  2. Keycloak as a IAM solution
  3. Microservices written in Spring Boot.

My basic requirement is to completely decouple authentication/authorization from Spring boot microservices. Therefore, authentication as well as authorization of API should be done at API gateway layer. Most of the articles and tutorials recommend to integrate Keycloak with Spring Boot as well. I would really like to know if the requirement is feasible and if so how to do it?


Solution

  • I would not de-couple security from micro-services for two reasons:

    • access-control is a business requirement I want to unit test
    • spring-security is probably more powerful (expressive, testable, etc.) than any API gateway security filter

    You do not have to integrate Keycloak with spring-boot (actually you should not because Keycloak libs for spring are deprecated).

    Spring-security has tools for resource-servers. Sample here.

    I also wrote (very) thin layers on top of spring-boot-starter-oauth2-resource-server to ease resource-server configuration. Most config options are available from properties, which save quite some Java code in micro-services. Sample there.

    Following advanced tutorial, you can even build a security DSL as expressive as @PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')"). Good luck to achieve the same with an API getway.

    The repo linked above also contains quite a few annotations for configuring unit-tests security-context:

        @Test
        @ProxiesAuth(
                authorities = { "AUTHOR" },
                claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"))
        void whenHimselfThenCanGreetFor() throws Exception {
            mockMvc.get("/greet/on-behalf-of/Tonton Pirate").andExpect(status().isOk()).andExpect(content().string("Hi Tonton Pirate from Tonton Pirate!"));
        }