how to set private endpoint in zuul - spring

how to set private endpoint in zuul?
env: spring, zuul
i'm using
zuul:
routes:
abc:
path: /abc/**
sensitive-headers:
url: http://abc.api.develop.com
in abc service, i want to make private /abc/xyz/1/test.
only it has to be work, when i request directly to http://abc.api.develop.com/xyz/1/test in server. not https://develop.com/abc/xyz/1/test by gateway.
/abc/1, /abc/1/public, /abc/xyz/2/good etc have to be public.
so only one path(/abc/xyz/1/test) is private endpoint.
how to set this?
can anyone help me please?
or any hint?
is zuul setting or is spring security setting?
how to block this specific path?

I used ignoredPatterns: /abc/xyz/*/good.

Related

Expose public and private endpoint through Spring Cloud Gateway

I'm using Spring Cloud Gateway like entrypoint for my infrastructure. The gateway is configured with keycloak to validate Authentication header with following configuration
spring:
security:
oauth2:
resource-server:
jwt:
jwk-set-uri: https://httpd.keycloak.local:443/keycloak/realms/myRealm/protocol/openid-connect/certs
An example Route is the following
spring:
cloud:
gateway:
routes:
- id: my-route
uri: http://service.local:8020
predicates:
- Path=/myPath/api/myRoute/test
filters:
- name: StripPrefix
args:
parts: 2
How can I define, into yml file, this route public and another one authenticated through jwk-uri directed to keycloak?
I see nothing about security rules in spring-cloud-gateway configuration doc.
I believe you'll have to either:
let all traffic go through gateway and handle security on each service
write a web-security configuration class and define a SecurityWebFilterChain bean.
use spring-addons-webflux-jwt-resource-server to define permitAll() routes from properties (other routes requirering user to be authenticated)
Only last solution would work with yaml file configuration only:
in pom, replace spring-boot-starter-oauth2-resource-server with
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-webflux-jwt-resource-server</artifactId>
<version>${com.c4-soft.springaddons.version}</version>
</dependency>
in yaml, replace spring.security.oauth2.resource-server with
com.c4-soft.springaddons.security:
jwt-issuers:
- location: https://httpd.keycloak.local:443/keycloak/realms/myRealm
permit-all:
- /myPath/api/myRoute/test
- /public/**
Note that trying to access "non-public" routes without valid authorization would result in 401 (unauthorized) and not in 302 (redirect to login). In my opinion, client should unsure requests to protected routes are issued with Authorization header or handle unauthorized with a redirection to authorization-server and a retry.
Also note that spring-security-oauth2-webflux-addons will auto-configure more than just permit-all routes (CORS, CSRF and authorities mapping for instance).
Last, I haven't tried it yet with spring-cloud-gateway. please let me know how it goes ;-)

How to redirect to https with Spring cloud gateway & ribbon

I have 2 microservices working with https, I added spring cloud gateway api to centralize the routes but I faced a problem where it says: This combination of host and port requires TLS I'm pretty sure that's because of the routes configuration on my gateway, I dont have much experience on this side but if someone could help me.
this is my spring gateway routes configuration :
#Bean
public RouteLocator gatewayRouter(RouteLocatorBuilder builder){
return builder.routes()
.route(p -> p.path("/api/v1/**")
.uri("lb://statement"))
.route( p -> p.path("/api/v3/**")
.uri("lb://activiti-workflow"))
.build();
}
Please I just want to know if this configuration will redirects to https or not, because while sending http requests directly to the microservices it works but with gateway is doesn't.
If your backend services in eureka provide https, your can set route uri like this:
uri: lb:https://your-service-name
Or
.uri("lb:https://your-service-name")
It just like websocket configuration. The key class is org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter
More info see at: https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-routetorequesturl-filter
If your backend services use insecure HTTPS cert, your may need config this:
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
See at: https://cloud.spring.io/spring-cloud-gateway/reference/html/#tls-and-ssl

Zuul request headers not forwarded

I have an application that uses Zuul and is hosted in a Kubernetes Cluster on AWS. It would appear that Zuul is not forwarding headers from the request to the destination, so I m having to do this:
private void copyRequestHeaders() {
RequestContext context = RequestContext.getCurrentContext();
Enumeration<String> headerNames = context.getRequest().getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
context.addZuulRequestHeader(headerName, context.getRequest().getHeader(headerName));
}
}
I'm guessing that I shouldn't have to do this and that I'm missing a configuration option somewhere or something like that. Can anyone shed any light on this. Interestingly the application works fine in my local development environment.
I'd also like to know the purpose of the ZuulRequestHeader and ZuulResponseHeadera and how they differ from standard request and response headers. Are they wrappers perhaps?
Thanks
Try adding the sensitiveHeaders in your configuration.
zuul:
routes:
sample:
sensitiveHeaders:
path: /sample
Removing any values on sensitiveHeaders means that all headers passed on your Zuul Gateway will be passed deep within the microservices.
For more information, refer to this documentation.
By default, Zuul API Gateway will not let sensitive information to be forwarded to downstream Microservices.
The default value for this property is
zuul.sensitiveHeaders: Cookie,Set-Cookie,Authorization
we can override this value to allow certain headers by
zuul.sensitiveHeaders: Cookie,Set-Cookie
And to allow all the headers we can keep it blank
zuul.sensitiveHeaders:

Feign Client Prioritizing URL's in yaml over Eureka

I have a Spring Boot application which serves as a Eureka client. The application has the need to call another micro-service through REST, and I wish to make this call using Feign. The issue I am having is, my application is trying to lookup the service name in Eureka, when it is only defined in my applications yaml file.
I apologize for the hard to follow explanation, hopefully the following code snippets will help clarify.
Feign client:
#FeignClient("foo")
#Component
public interface FooServiceProxy{
#RequestMapping(value = "/balance", method = RequestMethod.POST, produces = "application/json")
ServiceResponse execute(ServiceRequest serviceRequest);
}
In my controller who calls this Feign client, the FooServiceProxy is defined using #AutoWired:
#Autowired
private FooServiceProxy fooServiceProxy;
My yaml file is as follows:
spring:
application:
name: app-name
server:
port: 8080
foo:
ribbon:
listOfServers: http://hostname:8081/balance
eureka:
client:
fetchRegistry: false
serviceUrl:
defaultZone: http://eurekasrver:8761/eureka/
My issue is, during run-time, the following error is thrown:
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: foo
Interestingly, if I remove the #EnableEurekaClient annotation from the application, everything works. I believe I understand the problem which is that instead of looking up the server for foo in my yaml file, because the application is a Eureka client, Feign is going straight to Eureka to lookup a server ip, then failing as none can be found. Despite seeming to understand the problem, I have been unable to find a solution online or to think of one myself.
Any help will be appreciated.
Thank you!
Concerning this question, you should take in account that when eureka is on your classpath, all ribbon configuration are charged by eureka, so it'll use eureka server's list.
Spring Cloud uses #RibbonClient to configure the types used by ribbon, like server list. If you have eureka on the classpath, by default it uses the eureka server list (hence your need for the flag to disable eureka).
Commented by spencergibb https://github.com/spring-cloud/spring-cloud-netflix/issues/564
You can try either by adding the NIWSServerListClassName configuration:
`someservice.ribbon:
NIWSServerListClassName:com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: server1:80`
Or try the solution proposed in this issue https://github.com/spring-cloud/spring-cloud-netflix/issues/564

Zuul url mapping with spring boot,Eureka

I am building Rest api using microservice architecture. I have multiple apis for user that we have made into multiple projects. I have everything else ready except I am not able to map the user facing url to the application url in zuul.
The user facing url is : user/v1/accountholders/{id}/cards and the actual url for my application is /user-cards/v1/accountholders/{id}/cards.
Here id is the path variable. Below are other similar api url so if there is a way to configure them generically in zuul. Also the context root of the application url is also the project name in Eureka.
Other similar urls are:
client side:- /user/v1/accountholders/{id}/cards/{cardid}
application:- /user-cards/v1/accountholders/{id}/cards/{cardid}
client side:- /user/v1/accountholders
application:- /user-cardholder/v1/accountholder
client side:- /user/v1/accountholders
application:- /user-cardholder/v1/accountholder
client side:- /user/v1/accountholders/{id}
application:- /user-cardholder/v1/accountholders/{id}
client side:- /user/v1/accountholders/{id}/accounts
application:- /user-accounts/v1/accountholders/{id}/accounts
client side:- /user/v1/accountholders/{id}/accounts/{accid}
application:- /user-accounts/v1/accountholders/{id}/accounts/{accid}
Need some help to set this up in the properties or yml file for zuul. I havent been able to make any progress with the mapping stuff yet. Any inputs will be helpful.
SOLVED:-
After getting the input from #Daniel (which is the accepted answer)This is what i used in zuul config:-
zuul:
routes:
User-Cards:
path: /user/v1/accountholders/*/cards/**
url: http://desktop-uvkv1ed:9999/user-cards/v1/accountholders
User-Transactions1:
path: /user/v1/accountholders/*/transactions
url: http://desktop-uvkv1ed:5555/user-transactions/v1/accountholders
service-id: User-Transactions
User-Transactions2:
path: /user/v1/accountholders/*/accounts/*/transactions
url: http://desktop-uvkv1ed:5555/user-transactions/v1/accountholders
service-id: User-Transactions
User-Accounts:
path: /user/v1/accountholders/*/accounts/**
url: http://desktop-uvkv1ed:7777/user-accounts/v1/accountholders
User-Cardholders:
path: /user/v1/accountholders/**
url: http://desktop-uvkv1ed:8888/user-cardholders/v1/accountholders
It is possible to achieve what you are trying to do by giving the correct Zuul config. Lets assume you have the user-cardholder service running on port 8081 and the user-account service on 8082 so that you can successfully answer requests going against:
http://localhost:8081/user-cardholder/accountholders/{id}
http://localhost:8082/user-account/accountholders/{id}/accounts/{accid}
If this is working then you can achive what you are trying for these two services by using the following zuul config:
zuul:
routes:
cardholder:
path: /user/accountholders/*
url: http://localhost:8081/user-cardholder/accountholders/
account:
path: /user/accountholders/*/accounts/**
url: http://localhost:8082/user-accounts/accountholders/
Unfortunately you will also have to add more configs – even when they go against the same backend service – due to the fact that internal and external urls are differing. Otherwise you could just add the option stripPrefix: false and use the same internally as externally.

Resources