Spring cloud: Ribbon and HTTPS

17,735

We solved the zuul proxy problem now by setting

ribbon.IsSecure=true
eureka.instance.secureVirtualHostName=${spring.application.name}

so that all services are also in the secure virtual hosts pool in com.netflix.discovery.shared.Applications. That helps the discovery process to find the instances in eureka.

However, the Hystrix dashboard has still a similar problem

Share:
17,735

Related videos on Youtube

Daniel Sass
Author by

Daniel Sass

developer, software architect, addicted quadcopter pilot

Updated on September 14, 2022

Comments

  • Daniel Sass
    Daniel Sass over 1 year

    We want to use HTTPS for our microservices communication based on Feign and Ribbon. The services are based on spring boot and tomcat is correctly setup. The instances are registered with the HTTPS URL and securePort enabled on Eureka. However, when we call another microservice via Feign then the underlying Ribbon doesn't recognizes the protocol and falls back to HTTP. I could solve that problem by adding the protocol to the FeignClient annotation like this:

        @FeignClient("https://users")
    

    But it seem that the Zuul proxy and the Hystrix/Turbine which are also using Ribbon internally have the same HTTP fallback problem. Is there any way to configure Ribbon centrally to use HTTPS as default or use the securePort setting of the registred eureka instance?

    Eureka instance configuration:

    eureka.instance.hostname=localhost
    eureka.instance.securePort = ${server.port}
    eureka.instance.securePortEnabled = true  
    eureka.instance.nonSecurePortEnabled = false 
    eureka.instance.metadataMap.hostname = ${eureka.instance.hostname}
    eureka.instance.metadataMap.securePort = ${server.port}
    eureka.instance.homePageUrl = https://${eureka.instance.hostname}:${server.port}/
    eureka.instance.statusPageUrl = https://${eureka.instance.hostname}:${server.port}/admin/info
    

    With these settings it looks in Eureka like the service runs on HTTPS. The Zuul proxy runs fine, but uses the HTTP URL to call the service. You have to enable SSL in Spring Boots embedded Tomcat by providing a server certificate in a keystore:

    server.ssl.key-store=server.jks
    server.ssl.key-store-password=<pw>
    server.ssl.keyStoreType=jks
    server.ssl.keyAlias=tomcat
    server.ssl.key-password=<pw> 
    

    Tomcat than only runs on HTTPS and the HTTP port is blocked, but than I get: localhost:8081 failed to respond because a HTTP URL is used to call the service. By setting ribbon.IsSecure=true the users service url is correctly generated, but the Ribbon loadbalancer fails to lookup the users service in Eureka: Load balancer does not have available server for client: users. I aslo tried to set users.ribbon.IsSecure=true in the zuul proxy only, but still get the same error.

    Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: user
    at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:468)
    at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184)
    at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180)
    at rx.Observable$1.call(Observable.java:145)
    at rx.Observable$1.call(Observable.java:137)
    at rx.Observable$1.call(Observable.java:145)
    at rx.Observable$1.call(Observable.java:137)
    at rx.Observable.unsafeSubscribe(Observable.java:7304)
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:112)
    at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:81)
    at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:59)
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:77)
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45)
    at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:41)
    at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:30)
    at rx.Observable$1.call(Observable.java:145)
    at rx.Observable$1.call(Observable.java:137)
    at rx.Observable$1.call(Observable.java:145)
    at rx.Observable$1.call(Observable.java:137)
    at rx.Observable$1.call(Observable.java:145)
    at rx.Observable$1.call(Observable.java:137)
    at rx.Observable.subscribe(Observable.java:7393)
    at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:441)
    at rx.observables.BlockingObservable.single(BlockingObservable.java:340)
    at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:102)
    at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:81)
    at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.forward(RibbonCommand.java:129)
    at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:103)
    at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:1)
    at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:298)
    
  • yathirigan
    yathirigan over 8 years
    where should these 2 properties be added ? i added these 2 properties to the Spring Boot App which is HTTPS enabled and registered to Eureka. When Zuul tries to route the request to it, looks like Zuul is still trying to use the HTTP url for it. Caused by: org.apache.http.ProtocolException: The server failed to respond with a valid HTTP response at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHea‌​d(DefaultHttpRespons‌​eParser.java:151) ~[httpclient-4.3.6.jar:4.3.6]
  • yathirigan
    yathirigan over 8 years
    I have added these 2 properties to my Zuul Route application's yaml file as well but, still facing the same issue. org.apache.http.ProtocolException: The server failed to respond with a valid HTTP response
  • blindstack
    blindstack almost 8 years
    yes, this got resolved by specifying ribbon isSecure and implement a custom socketfactory to accept the cert you want. ` instance: securePort: ${server.port} secureVirtualHostName: ${spring.application.name} metadatamap: instanceId: "${spring.application.name}:${spring.application.instance_id‌​:${server.port}}" preferIpAddress: true securePortEnabled: true nonSecurePortEnabled: false ribbon: IsSecure: true CustomSSLSocketFactoryClassName: YourCustomSocketFactory `