I have a Spring Boot application (recently enabled it for HTTPS + self signed certificate) which is registered in Eureka and visible in the Eureka dashboard.
We have a Zuul Filter layer which gets the user request and then passes it on to the Spring Boot application. This was working fine until the app was accessible via HTTP. But, once i enabled HTTPS, the zuul routing is failing.
Here is the Zuul route configuration in my yaml file. Should my Zuul Route configuration have any special configuration for HTTPS enabled URL/App ?
zuul:
routes:
ms:
path: /app/**
stripPrefix: true
ms:
ribbon:
ServerListRefreshInterval: 1000
ConnectTimeout: 20000
ReadTimeout: 20000
Here is the exception stack trace (showing that Zuul is trying to route to the HTTP URL , instead of the HTTPS url)
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: msRibbonCommand failed and no fallback available.
at com.netflix.hystrix.AbstractCommand$20.call(AbstractCommand.java:816) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.AbstractCommand$20.call(AbstractCommand.java:798) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$1.onError(OperatorOnErrorResumeNextViaFunction.java:76) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$ThrowObservable$1.call(Observable.java:10493) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$ThrowObservable$1.call(Observable.java:10483) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$1.onError(OperatorOnErrorResumeNextViaFunction.java:77) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:318) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:310) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$1.onError(OperatorOnErrorResumeNextViaFunction.java:77) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$3.onError(AbstractCommand.java:995) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$ThrowObservable$1.call(Observable.java:10493) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$ThrowObservable$1.call(Observable.java:10483) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$1.onError(OperatorOnErrorResumeNextViaFunction.java:77) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:301) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:293) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.AbstractCommand$1.call(AbstractCommand.java:388) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.AbstractCommand$1.call(AbstractCommand.java:368) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.AbstractCommand$ObservableCommand$1.call(AbstractCommand.java:1097) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.AbstractCommand$ObservableCommand$1.call(AbstractCommand.java:1093) ~[hystrix-core-1.4.0-RC6.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.subscribe(Observable.java:8680) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.BlockingOperatorToFuture.toFuture(BlockingOperatorToFuture.java:55) ~[rxjava-core-0.20.7.jar:na]
at rx.observables.BlockingObservable.toFuture(BlockingObservable.java:420) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.hystrix.HystrixCommand.queue(HystrixCommand.java:385) ~[hystrix-core-1.4.0-RC6.jar:na]
at com.netflix.hystrix.HystrixCommand.execute(HystrixCommand.java:339) ~[hystrix-core-1.4.0-RC6.jar:na]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:130) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
... 82 common frames omitted
Caused by: com.netflix.client.ClientException: null
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:123) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:81) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.forward(RibbonCommand.java:129) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:103) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:1) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:298) ~[hystrix-core-1.4.0-RC6.jar:na]
... 125 common frames omitted
Caused by: org.apache.http.client.ClientProtocolException: null
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:867) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:115) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57) ~[httpclient-4.3.6.jar:4.3.6]
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:170) ~[jersey-apache-client4-1.11.jar:1.11]
at com.sun.jersey.api.client.Client.handle(Client.java:648) ~[jersey-client-1.13.jar:1.13]
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680) ~[jersey-client-1.13.jar:1.13]
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.13.jar:1.13]
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:568) ~[jersey-client-1.13.jar:1.13]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:621) ~[ribbon-httpclient-2.0-RC13.jar:na]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:527) ~[ribbon-httpclient-2.0-RC13.jar:na]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:92) ~[ribbon-httpclient-2.0-RC13.jar:na]
at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:109) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:41) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:30) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorConcat$ConcatSubscriber.subscribeNext(OperatorConcat.java:163) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorConcat$ConcatSubscriber.onNext(OperatorConcat.java:128) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorConcat$ConcatSubscriber.onNext(OperatorConcat.java:65) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.unsafeSubscribe(Observable.java:8591) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:112) ~[rxjava-core-0.20.7.jar:na]
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:85) ~[rxjava-core-0.20.7.jar:na]
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:65) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:77) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:41) ~[rxjava-core-0.20.7.jar:na]
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:30) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:173) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable$2.call(Observable.java:166) ~[rxjava-core-0.20.7.jar:na]
at rx.Observable.subscribe(Observable.java:8680) ~[rxjava-core-0.20.7.jar:na]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:452) ~[rxjava-core-0.20.7.jar:na]
at rx.observables.BlockingObservable.single(BlockingObservable.java:348) ~[rxjava-core-0.20.7.jar:na]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:102) ~[ribbon-loadbalancer-2.0-RC13.jar:na]
... 130 common frames omitted
Caused by: org.apache.http.ProtocolException: The server failed to respond with a valid HTTP response
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:151) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:261) ~[httpcore-4.4.jar:4.4]
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283) ~[httpcore-4.4.jar:4.4]
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:251) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:223) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272) ~[httpcore-4.4.jar:4.4]
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124) ~[httpcore-4.4.jar:4.4]
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:685) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:487) ~[httpclient-4.3.6.jar:4.3.6]
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863) ~[httpclient-4.3.6.jar:4.3.6]
Update: After adding the isRibbon secure property, this error was gone and now i have a new error.
It has been a little while since I have played with this because we ended up not being able to use it due to the limitation of not being able to pass the users certificate through the proxy. However, you asked for my help, so I'll try to share what I did have working.
I was able to get 2-way SSL working between both the ZUUL, acting as an Edge Server, and the Services on the backend while running in their own VMs (i.e. doing a mvn spring-boot:run on each service).
Here is my Zuul Conifg:
info:
component: Zuul Server
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
zuul:
routes:
ui: /**
api: /api/**
logging:
level:
ROOT: INFO
org.springframework.web: DEBUG
server:
port: 8443
ssl:
key-store: classpath:dev/localhost.jks
key-store-password: yourpassword
keyStoreType: JKS
keyAlias: localhost
clientAuth: want
trust-store: classpath:dev/localhost.jks
ribbon:
IsSecure: true
The Edge Server itself is nothing interesting:
@SpringBootApplication
@Controller
@EnableAutoConfiguration
@EnableZuulProxy
public class ZuulEdgeServer {
public static void main(String[] args) {
new SpringApplicationBuilder(ZuulEdgeServer.class).web(true).run(args);
}
}
Now in my other services I had the following in their application.yml files:
server:
port: 8444
ssl:
key-store: classpath:dev/localhost.jks
key-store-password: yourpassword
keyStoreType: JKS
keyAlias: localhost
clientAuth: want
trust-store: classpath:dev/localhost.jks
eureka:
instance:
nonSecurePortEnabled: false
securePortEnabled: true
securePort: ${server.port}
homePageUrl: https://${eureka.instance.hostname}:${server.port}/
secureVirtualHostName: ${spring.application.name}
My Eureka Config doesn't have much too it, but just in case:
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
waitTimeInMsWhenSyncEmpty: 0
My bootstrap.yml's in most the applications look like this:
spring:
application:
name: eureka
cloud:
config:
uri: ${vcap.services.${PREFIX:}configserver.credentials.uri:http://user:password@localhost:8888}
I mainly found I needed the spring.application.name
in there to resolve conflicts when running the applications within the same container.
If I remember right, the important parts from above were:
ribbon.isSecure = true
in the zuul configeureka.instance.securePortEnabled = true
and the securePort
in the backend services. I can't remember if the secureVirtualHostName
was important or not.
Hopefully this info can help you out though!