Can I replace a microservice inside of AKS k8s with smarter nginx config? - kubernetes

Question
Can I get nginx to call another microservice inside of AKS k8s prior to it routing to the requested api? - the goal being to speed up requests (fewer hops) and simplify build and deployment (fewer services).
Explanation
In our currently deployed Azure AKS (Kubernetes) cluster, we have an additional service I was hoping to replace with nginx. It's a routing microservice that calls out to a identity API prior to doing the routing.
The reason is a common one I'd imagine, we recieve some kind of authentication token via some pre-defined header(s) (the standard Authorization header, or sometimes some bespoke ones used for debug tokens, and impersonation), we call from the routing API into the identity API with those pre-defined headers and get a user identity object in return.
We then pass on this basic user identity object into the microservices so they have quick and easy access to the user and roles.
A brief explanation would be:
Nginx receives a request, off-loads SSL and route to the requested service.
Routing API takes the authorization headers and makes a call to the Identity API.
Identity API validations the authorization information and returns either an authorization error (when auth fails), or a serialized user identity object.
Router API either returns there and then, for failure, or routes to the requested microservice (by cracking the request path), and attaches the user identity object as a header.
Requested microservice can then turn that user identity object into a Claims Principal in the case of .NET Core for example.
There are obviously options for merging the Router.API and the UserIdentity.API, but keeping the separation of concerns seems like a better move. I'd just to remove the Route.API, in-order to maintain that separation, but get nginx to do that work for me.

ProxyKit (https://github.com/damianh/ProxyKit) could be a good alternative to nginx - it allows you to easily add custom logic to certain requests (for example I lookup API keys based on a tenant in URL) and you can cache the responses using CacheCow (see a recipe in ProxyKit source)

Related

Spring boot oauth2 integration with keycloak using Spring webflux along with multi-tenancy

I need to implement Authentication & Authorization using spring boot oauth2 with keycloak as a provider.
I also need to support muti-tenancy. I tried example with authentication using spring-boot-starter-auth2-client to authenticate, but not able to add multi-tenancy.
When I used spring-boot-starter-auth2-client, I need to configure hardcode keycloak urls(specific to one tenant) in properties and not able to support multi-tenancy.
I also analyze spring-boot-starter-auth2-resouce-server, but not clear. I understand that resouce server use for validation of token and expiry.
Note: I don't want to use keycloak adapter library which is provided by keycloak.
Could you please help me -
Where need to use spring-boot-starter-oauth2-client and spring-boot-starter-oauth2-resouce-server?
Is spring-boot-starter-oauth2-resouce-server also use to authentication?
How to authenticat user using spring-boot-starter-oauth2-client and pass to spring-boot-starter-oauth2-resouce-server for authorization.
How to implement multi-tenacy e.g. take tenant id from url and redirect user to tenant specific keycloak login page.
I tried some example but won't succeed, working example will be helpful with -
Spring Webflux + spring-boot-starter-oauth2-client+ spring-boot-starter-oauth2-resouce-server + multi-tenancy + keycloak as a provider.
Thanks & Regards,
Pravin Nawale
tried some example found on internet, but didn't work.
This question should not be answered because:
it is actually a container for many questions
quite a few are way too wide or lack precision.
But as it seems to be a first question... (break it down next time, give more details and edit your question when you get comments asking precisions)
1. Where need to use spring-boot-starter-oauth2-client and spring-boot-starter-oauth2-resouce-server?
This one is important to start with as I suspect you lack OAuth2 background, specifically regarding involved parties and how it is implemented with spring-security:
spring-boot-starter-oauth2-client is to be used with OAuth2 clients:
apps serving UI with oauth2Login (#Controllers with methods returning template names)
apps consuming REST APIs with auto-configured Spring client: WebClient, #FeignClient, RestTemplate
spring-boot-starter-oauth2-resouce-server is to be used with resource-servers: apps serving REST APIs (#RestController or #Controller with #ResponseBody)
Now, if your app has controllers for both the resources and the UI to manipulate it (with Thymeleaf or any other server-side rendering engine), then define two different security filter-chains: one for each, ordered, and with securityMatcher in the first in order to limit the routes it applies to (the second being used as fallback for unmatched routes). Sample in this answer (the sample is for servlet, but it's the exact same principles): Use Keycloak Spring Adapter with Spring Boot 3
2. Is spring-boot-starter-oauth2-resouce-server also use to authentication?
OAuth2 requests should be authorized with an Authorization header containing a Bearer access-token.
The client is responsible for acquiring such an access-token from the authorization-server before sending requests to resource-server.
Your question is not quite clear but here are a few statements which could answer:
resource-server should return 401 (unauthorized) and not 302 (redirect to login) when authorization is missing or invalid => do not configure oauth2Login in resource-server filter-chain. Again, this is client business
resource-server is responsible for resources access-control: check that access-token is valid, that the user has required authorities, etc.
3. How to authenticat user using spring-boot-starter-oauth2-client and pass to spring-boot-starter-oauth2-resouce-server for authorization.
This question is not focused enough to get a single answer: what kind of client? what kind of request? context?
I see three main cases here:
the UI is rendered on Spring server with Thymeleaf, JSF, and alike => use spring's oauth2Login and refer to its documentation to overrides defaults and implement your authorization-server selection logic
the UI is rendered in the browser (Angular, React, Vue, ...) and you are ok to make it an OAuth2 client => find a certified client lib for your framework and implement the logic in the client (angular-auth-oidc-client, for instance, supports multi-tenancy)
the UI is rendered in the browser, but you prefer to implement the Backend For Frontend pattern to hide tokens from browser, then choose a BFF (like spring-cloud-gateway with tokenRelay filter) and refer to its doc for implementing your logic in it
If that can be of any help, I have:
here a tutorial for configuring an app with a Thymeleaf UI client and REST API
there a sample repo with an Angular workspace (app configured as OIDC client + API client lib generated from OpenAPI spec) and spring-boot resource-server (using servlet, but this makes no difference to the client).
4. How to implement multi-tenacy e.g. take tenant id from url and redirect user to tenant specific keycloak login page
Note
One of key principles of OAuth2 is that identities (tokens) are emitted (issued) by trusted 3rd parties (authorization-servers) => you must configure the list of issuers your resource-servers can trust (and clients can fetch tokens from). This list is static (loaded with conf at startup).
Accept identities from various issuers on the resource-server
This is done by overriding the default ReactiveAuthenticationManagerResolver<ServerWebExchange> in your SecurityWebFilterChain configuration: http.oauth2ResourceServer().authenticationManagerResolver(authenticationManagerResolver)
I provide with thin wrappers around spring-boot-starter-oauth2-resource-server which support multi-tenancy just by defining properties. Complete sample there:
Instead of spring-boot-starter-oauth2-resource-server (which is a transient dependency):
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-webflux-jwt-resource-server</artifactId>
</dependency>
Instead of all your resource-server Java conf (unless you want access control from configuration and not with method-security, in which case, you'd have to define an AuthorizeExchangeSpecPostProcessor bean here). Of course, you'll have to add here a client filter-chain with a restrictive securityMatcher if you also serve UI client with oauth2Login:
#EnableReactiveMethodSecurity
#Configuration
public class SecurityConfig {
}
Instead of spring.security.oauth2.resourceserver properties:
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/realm-1
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,resource_access.client-1.roles,resource_access.client-2.roles
com.c4-soft.springaddons.security.issuers[1].location=https://localhost:8443/realms/realm-2
com.c4-soft.springaddons.security.issuers[1].authorities.claims=realm_access.roles,resource_access.client-1.roles,resource_access.client-2.roles
# Comma separated list of routes accessible to anonymous
com.c4-soft.springaddons.security.permit-all=/api/v1/public/**,/actuator/health/readiness,/actuator/health/liveness
# Fine-grained CORS configuration can be set per path as follow:
com.c4-soft.springaddons.security.cors[0].path=/api/**
com.c4-soft.springaddons.security.cors[0].allowed-origins=https://localhost,https://localhost:8100,https://localhost:4200
# this are defaults and can be omitted
com.c4-soft.springaddons.security.cors[0].allowedOrigins=*
com.c4-soft.springaddons.security.cors[0].allowedMethods=*
com.c4-soft.springaddons.security.cors[0].allowedHeaders=*
com.c4-soft.springaddons.security.cors[0].exposedHeaders=*
If you don't want to use "my" wrappers, just copy from the source, it is open.
Redirect the user to the right authorization-server from client UI
As explained at point 3., this depends on the kind of client, used framework and if BFF pattern is applied or not
5. I tried some example but won't succeed, working example will be helpful with - Spring Webflux + spring-boot-starter-oauth2-client + spring-boot-starter-oauth2-resouce-server + multi-tenancy + keycloak as a provider
With all the elements above and linked resources, you should have enough to find your own path

How do I challenge Yarp proxy routes by reading header requests?

I am using Yarp to reverse Proxy into internal apps. The authentication is handled by another service and I want to challenge certain request by using api keys assertion. Having gone through the documentation and the sample project here,I have trouble implementing it. I went the route of middleware but it is applying to all sets of routes and I do not need that.

Istio Programmable Routes at Ingress

I was looking a lot about the capability for Istio to have programmable routes at the ingress controller as a solid replacement for Kong API Gateway plugins. A simple example would be to have a rule in the Istio Virtual Service that rejects API calls when the user has a license expired in the application that is behind.
That means, the Ingress Controller to be capable enough to query something inside the app to determine the license status, and based on that response, block/allow traffic that is coming from a particular customer (which are being identified by a header)
This is something I do with Kong plugins, but I didnĀ“t find anything similar on Istio.
The simplest solution to rejecting requests of a user is to attach that information in the authentication process (to the cookie or the jwt token), and then use Virtual Services to reject requests with those.
Another solution (more complex) would be to use Envoy Filters with Lua scripting, in which you can add custom logic and decide if you want to proceed with the request or not.

Istio: HTTP Authorization: verify user is the resource owner

Looking into using Istio to handle Authorization for an application built on a microservices architecture in Kubernetes.
One thing we're looking to accomplish is to decouple the authorization of a service by utilizing Istio Authorization.
Our API Gateway (Kong) will handle the verification/parsing of the JWT tokens and pass along any required attributes (usernames, groups, roles etc) as headers e.g. x-username: homer#somewhere.com (abstracts that from the services)
What we want to accomplish is along with verifying based on roles etc we also want to ensure that the x-username is also the owner of the resource e.g. if they are accessing:
/user/{userID}/resource
That would mean if userId matches the value of the x-username header we can continue serving the request, otherwise we'll send a 401 etc
Is there a way to configure this as part of Istio Authorization?
Thanks in advance for your time
What you're looking for is attribute based access control (abac). Look into authorization engines e.g. Axiomatics that plug straight into Kong and provides that level of access control (ownership check).
Kong authorization handler on GitHub
Technical webcast on the integration
You could also choose to call Axiomatics from Isitio using an adapter based on Istio's authorization template.
Policies in Axiomatics are written using either XACML or ALFA which are the 2 OASIS standards for ABAC / fine-grained authorization.
You could easily write a condition along the lines of:
rule checkOwner{
deny
condition not(owner==user.uid)
}
BTW you probably want to send back a 403 rather than 401. The latter refers to failed authentication.

Passing Shibboleth credentials after successful authentication

I have a high-level/conceptual question about Shibboleth.
I'm working on the front-end (running Drupal) of a data-driven web app. End-users interact with the front-end to construct data queries, which makes background requests to a caching/archiving data proxy (the "data retrieval service"), which in turn either delivers data from its cache or goes out and queries still more services ("out there") which have desired data. So far so good... it is ornate, but only as ornate as the problem we're trying to solve.
Here's the wrinkle: Some of services queried by the data retrieval service want to implement user-level authentication, so that some users may access their data, but others cannot. For organizational reasons, our identity and authentication mechanism is likely to be Shibboleth.
So, here's my scenario: a user logs in to the frontend using Shibboleth. Now, can my frontend, and in turn, the data retrieval service, authenticate against against external services as the user? And if so, how does that work in practice (what authentication data gets passed from server to server)?
Yes it can - you service has to exist in the identity provider (how it is set up is up to you)