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.
Related
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
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.
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)
i have a requirement, i want to call list of REST services which have different security mechanisms, like, some may have HTTPS and others may have naked HTTP, few others may have basic authentication and remaining may require a "Authorization header" . i want to call all these REST services with different service mechanism from a single HTTP OUT BOUND END POINT . how can i configure the HTTP endpoint to accomplish this ? or should i use different end points to accomplish my requirement .
You can't do that. Some of the attributes of the Http connector/endpoints can be configured as an expression but not all of them.
You'll have to leverage a choice-router and a number of http and https endpoints.
Different service mechanism requires different configuration...
If you want to do it in a single flow, as Victor said you need to use choice router and based on certain condition it will call the rest service it required...
and in each Choice block, you have to configure the calling of each type of rest service with it's security mechanism
I have a REST API which allows the developer to fetch a certain resource:
/api/projects
/api/project/4
...
The API requires authentication. The authentication token is added to the HTTP headers.
Is it RESTful to return a different output based on which user is authenticated?
Thanks!
REST doesn't define anything in that respect.
You should keep authentication logic and authorization logic independent of your RESTful architecture.
There are indeed requirements whereby you want to change what is returned based on different attributes / parameters e.g.:
authentication type
time of day
user location
device type...
You would achieve that by using a filter in front of your REST service. Filters / interceptors are explained here.
You would then send an authorization request to a decision point that determines what can be returned based on the identity (or other attributes) of the user.
For instance you could have a logic to return projects to a user if and only if they belong to the same region. The REST endpoint would still be /api/projects but the content returned would differ based on the authZ logic. Have a look at XACML and ALFA to implement that layer.
HTH