I have a kubernetes cluster and i have more than 15 microservices running in it, Each REST API send me a custom header lets say "version":"1.2.0", i need to check this version from each REST api and throw a custom error if it doesn't match with the value i have.
Suppose i have a mobile app and i have released a new version of the app and redeployed the microservices to match the new app, i want to throw a custom error to users using the old application to download the new app to continue using the application.
Is there a way to achieve this using ingress-nginx or in the kubernetes level instead of repeating logic in each microservice.
With Nginx ingress, you will be able to inject the secret into the request if it's coming outside and forward request to service
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header My-Custom-Header $http_my_custom_header;
since as your all microservices talking internally and routing based on custom header you can use the service mesh istio
for example : https://istio.io/latest/docs/tasks/traffic-management/request-routing/#route-based-on-user-identity
https://dwdraju.medium.com/simplified-header-based-routing-with-istio-for-http-grpc-traffic-ff9be55f83ca
ingress-nginx supports configuration snippets as an annotation.
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_version != "1.2.0") {
return 418;
}
You can configure the ingress to capture certain error codes so the default backend app receives these requests and can build a custom error response. Be aware that this captures all listed error codes. So don't use a status code that the rest of your application might or you might hide a real error response.
Related
I have a single ASP.NET MVC app - website and API controllers. I'd like to use Azure API Management to manage these APIs but retain the same URL so that it is seamless for our consumers. We have a custom domain setup on the app service for this web app that is currently used to serve up both the site and APIs(e.g. Website: xyz.com, APIs: xyz.com/api1, xyz.com/api2, etc.). Also we use AAD for auth. and have the redirect URI setup to the custom domain(xyz.com). Everything works great at present.
The issue arises after we configure API Management to expose our APIs and potentially use it as a passthrough. In order to ensure that the URLs remain the same after API Management is introduced we set the custom domain to be on the API Management instance itself and removed it from the app. service. This is how our current setup looks -->
User hits xyz.com and the request proceeds as follows -> Traffic Manager -> APIM(xyz.com) -> App Service(xxx.azurewebsites.net)
After that last point above, AAD auth. should kick in and once it has the access token after successful auth. it should redirect the user and the page should load. But it doesn't. Instead we get a blank page and if we refresh it, then and only then does it proceed to auth. and load the page.
We have tried setting our redirect URI to both the custom domain(xyz.com) as well as the base app service name that Azure generated(xxx.azurewebsites.net).
Directly hitting the API urls specifically(e.g. xyz.com/api1) works fine. It goes through APIM and responds as expected. The only problem is that the website doesn't load as outlined above.
The moment we take APIM out of the equation, and set the custom domain back on the app service again, everything works as expected.
I'm trying to figure out if we've misconfigured our assets for this scenario somehow or if APIM doesn't support pass through for the website in this manner. Any thoughts/suggestions here would be much appreciated!
Wow, that was a lot of text.
Ok, let's see:
Visitors -> Traffic manager -> APIM -> backend (your website) - ok got it.
this is like a common way of using APIM, and it should work. However, maybe your policies are not set up correctly?
Have you built your product/API/Operations? Do you see requests coming from APIM hitting your site? What responses are you getting?
Now, of course, you will need to define and set up APIM (products, APIs, and every operation) to pass it throw to your backend. This means if you (as a visitor) need to list all products, you would need to go through the APIM operation (sed GetProducts ). Your request will be passed through the Inbound policy(adjust and build the request if needed), pass it to the backend( to your website with custom APIs), and the response will be sent back from the backend back to the visitor.
Now to this: to protect your Web API Backend in APIM, you could use OAuth 2.0 authorization with Azure AD:
big picture overview:
Register an application (for your backend) in Azure AD to represent the API
Register another Application (the client) in Azure AD to represent a client app that will call your API
And I guess this is the one for you grant permissions to allow the client app to call the backend app
And, of course, add the validate-jwt policy to validate the OAuth token for every incoming request
Read om on this here https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-protect-backend-with-aad
I'm new to url rewriting process in Marklogic and need help to resolve the below issue.
I have written Xquery implementation to redirect my API endpoints to the respective Xquery modules as /rewriter-ex/rewriter.xqy.
xquery version "1.0-ml";
let $url := xdmp:get-request-url()
return if(fn:matches($url,"/fetchRecord")) then
fn:replace($url,"/fetchRecord","/lib/fetch-record.xqy$1")
else if(fn:matches($url,"/saveRecord")) then
fn:replace($url,"/saveRecord$","/lib/save-record.xqy")
else (xdmp:set-response-code(404, "Not found"),"/no/such/resource")
And the url-rewriter path in the App server configuration is set to /rewriter-ex/rewriter.xqy and rewrite resolves globally parameter is set to true in App server.
I'm able to redirect my API urls to the respective endpoints.But I'm not able to use predefined ML Res-API endpoints like /v1/documents,it is showing 404 error as returned in the rewriter.xqy.
Is there a way I can implement rewriter to support both rest api endpoints as well as custom API endpoints?
If you'd like to create your own RESTful API on top of MarkLogic, with your own custom end-points. Please check out XQuery API for RESTful Services (XQRS).
declare
%rest:path("/fetchRecord/{$record-id}")
%rest:GET
function fetch-record($record-id as xs:string) {
fn:doc($record-id)
};
declare
%rest:path("/saveRecord/{$record-id}")
%rest:PUT("{$doc}")
%xdmp:update
function put-record($record-id as xs:string, $doc as document-node(element())) {
xdmp:document-insert($record-id, $doc)
};
Your RESTXQ Modules can sit on their own separate HTTP App Server (on their own port) and live side by side with another HTTP App Server which has the default MarkLogic REST API on it.
XQRS is totally compatible with the rest of MarkLogic's software, including Data Hub Framework, they can party together.
The REST API doesn't support customization or replacement of the default declarative rewriter configured during initialization of a REST API server. In addition, the REST API doesn't provide an XQuery API interface to the functionality of the REST API endpoints.
Instead, the recommended approach is to extend the REST API through one of the following alternatives:
Providing an endpoint module in the modules database and specifying the actual path of the module in the modules database on a request to the REST API server to invoke the endpoint without rewriting as in http://myhost:8010/the/directory/path/to/my/module.xqy
Such endpoints can be Data Service endpoints. See https://docs.marklogic.com/guide/java/DataServices
Using the /v1/invoke endpoint to invoke a main module. See https://docs.marklogic.com/guide/rest-dev/extensions#id_72813
Using a Resource Service Extension. See https://docs.marklogic.com/guide/rest-dev/extensions#id_41710
Hoping that helps,
Thanks for your answers.I'm planning to use two app servers one for rest calls and other for API calls.These two app servers will point to the same DB.Please let me know if this is a right approach.
I have a simple Spring Gateway project that uses 3 microservices - 1 service for doing authentication and 2 "secured" microservices (i.e. all requests to these services must be authenticated).
The authentication service which is responsible for authentication (generate JWT tokens) works fine via the Gateway.
As in I can access it via the Gateway to create tokens and via the Gateway to confirm if a token is valid.
In my scenario when the user attempts to access a “secure” microservice I want
Call the auth service to verify the user has the correct JWT token
If the use does not have the required permission confirmed in (a) return some Http status 404 code with a specific message
If the user is authenticated confirmed by (a) allow the call to proceed to request route
Reading around seems to suggest I would need to apply some filter on the Spring Gateway routes to do this.
The examples on https://cloud.spring.io/spring-cloud-gateway/multi/multi__developer_guide.html#_writing_custom_gatewayfilter_factories aren’t too clear on how to achieve this. Wondering is this the reccomended approach?
If so can someone point me in the direction of what this would look like in terms of the routing code in Spring Gateway
builder.routes()
.route(route -> route.path("/auth/**")
.uri(LOAD_BALANCED_AUTHENTICATION_SERVICE)
.id("authentication-service"))
.route(route -> route.path("/images/**")
.filters(SOME_AUTHENTICATION_FILTER)
.uri(LOAD_BALANCED_IMAGES_SERVICE)
.id("images-service"))
.route(route -> route.path("/inbox/**")
.filters(SOME_AUTHENTICATION_FILTER)
.uri(LOAD_BALANCED_INBOX_SERVICE)
.id("inbox-service"))
.build();
Note I haven't implemented the filter (SOME_AUTHENTICATION_FILTER) shown above yet as I'm not clear from the examples how to call the authentication service from the filter. Also unclear from the examples how the filters would terminate a request or allow the request to proceed.
As I understand, you have two questions, first one the routing recommended flow; and as you defined exactly will be good, if the filter worked correctly move route to Service X.
For the other part, How to define the custom filter? you need to do the authorization check inside it using your secure service; there is a good example which can tell you how to handle this, and how to terminate the request also with descriptive messages.
You can find it here Spring Cloud Gateway Custom Filter
I have a SpringBoot Micro-Service based backend API that uses Zuul as a gateway proxy between a JavaFX Desktop Application. Right now there is no security in place, but I am looking to secure the backend with Spring Security, however, every tutorial I seem to run across seems to be based on web-apps and I haven't seen anything for my particular use case. I don't know much about spring security but would like to know if I can accomplish my goals with it, and if so, what modules or examples should I be looking for.
Goals:
Provide a way for my API to know that requests are coming from the desktop app itself, I think the technical term for this is assigning the desktop app a client id and then having the Zuul Server validate that the client id is that off the desktop app before accepting the request. This should be the case for all requests
Only allow API traffic through the Zuul Proxy, all of the downstream requests to the micro-services behind the Zuul gateway should only be accepted if they are coming from the Zuul Server itself.
Allow requests for logging in and registering as a new user without any type of security other than the desktop client id discussed in 1.
When a user provides a successful username/password on login, they are returned a JWT which is then stored in the JavaFX application and used for all of the other requests to the backend.
Configure the token to expire after a specific time frame, say like 90 minutes and provide a method for automatically refreshing an expired token as long as the users account is still valid. For this, I don't want the user to have to re-login, I just want it to check behind the scenes to make sure their account is still valid and then issue a new token if needed.
Have user based roles so certain features, methods, endpoints, etc. are only accessible to users with the valid role. Within the GUI these features will be hidden or disabled, but I would still like a layer of security on the server side to protect against unwanted access in case someone was able to modify the app.
I am just writing down answers to each of your goals :
Passing the client Id in every request from desktop application doesnt make sense, instead you client Id and secret can be passed during authenticaiton call, Like we have in Oauth 2.0 framework. Rest https calls should be made from client, So to avoid tampering of request, You can also go for mutual SSL between your client application and Zuul API gateway, It assures that call is coming from Desktop client only.
Yes, Zuul api gateway should be single entry point to your application, Your internal microservices should not be exposed to public.
For user registeration, Client authentication can be achieved using client Id and secret
Correct, You can also create http only cookie at backend, which will include your jwt token only.
Token refresh can be achieved at zuul api gateway, if session is active, make call to refresh token endpoint to get new access token.
On server side, At zuul proxy you can validate the incoming bearer token expiry along with signature validation, with generic claims too. Now at microservices level spring security can be used for role based access control for particular methods.
I am using Spring-Boot-Admin in order to monitor a SpringBoot app whose actuator endpoints are secured using basic auth. The required credentials are transferred to Spring-Boot-Admin (SBA) like described in the documentation. SBA itself is also secured using spring-boot-admin-server-ui-login and the provided SecurityConfiguration (based on the documentation & sample apps, see Github Repo for code).
Both the app to be monitored and SBA are deployed via docker.
Logging in to SBA works fine and I can see the application state as well as the health results. For some content I see a nested login mask though. When I click on "Logging" or "JMX" I am redirected to the login mask:
In the browsers network tab I can see that a 401 is returned for the /jolokia endpoint. All requests after that seem to be forwarded to the login page.
I have the following questions:
Why am I logged out if one request to the application fails? Is that a bug?
What is the source of the 401? SBA or my app? I know that SBA proxies requests to the app. According to the access logs from my app no request to /jolokia is done when I login to SBA. Does this mean that the 401 is returned by SBA directly? Its logs contain nothing of relevance though.
Accessing the /jolokia endpoint directly works fine. It even works when I use the same (proxied) URL that SBA uses (e.g. http://XXX:8090/api/applications/XXX/jolokia/). What is different when this is executed from within SBA?
I've tried to find more error details in SBA but so far failed to find the proper logging options. They either contain nothing relevant or way too much information (e.g. Spring Security) that doesn't seem to be relevant. Logging the full response would probably help...
Edit: I just realized, that the request to the /jolokia endpoint actually contains a different cookie (Cookie:JSESSIONID=4E51B84AE15A6890500F967B23EB92AC) than the requests to the working endpoints (e.g. /metrics). Thats weird, but probably explains why the /jolokia endpoint returns a 401. Now the question is: Why does it send a different cookie`?
I tried various things, but in the end couldn't solve this.
I instead ended up with a different configuration: No security at all for the endpoints (management.security.enabled=false), but exposing them on a different port (management.port=8081). This management endpoint is blocked for external access to the system completely.
With that, SBA behaves nicely and the application is still secure. In the end, its a much simpler setup which is good, too.
I had a similar problem.
I could access all actuator endpoints, but everything with /jolokia would not be authorized. Although my security setup is a different to yours, i assume the problem is the same.
When i digged into this I found out that jolokia runs in its own servlet separately from the spring boot application. Maybe therefore you have different sessions!?
My Security Config tries to match this expression
.mvcMatchers("/actuator/**").access("hasAnyRole('ADMIN','SBA')"),
but the SBA user role was not able to access Jolokia. It always matched the last fallback-rule where only Admin was allowed.
In my case the context- and servlet-path of the jolokia servlet would be stripped away from the request path before trying to match it to my security config. Then it would only match "/list" against my MVC matchers instead of "/actuator/jolokia/list" which would then not fit as expected.
Unfortunately I do not have a fix for your problem. For my case i added a requestMatchers rule which is a little bit less opinionated and would still match:
.requestMatchers(request -> request.getRequestURI().contains("/actuator/jolokia/")).access("hasAnyRole('ADMIN','SBA')")
instead of
.mvcMatchers("/actuator/**").access("hasAnyRole('ADMIN','SBA')")