I have a spring boot app with zuul and ribbon (no eureka) and I need to forward all traffic over https with mutual tls. The keystore and password are all automatically generated by an internal framework. At the end I end up with an SSLContext spring bean which I would like ribbon to use when forwarding zuul requests. Now my question is how do I force ribbon to use my SSLContext?
Thanks in advance!
I figured it out. You need to register your own SSLSocketFactory and initialize it with your own SSLContext. Then set the ribbon property ribbon.CustomSSLSocketFactoryClassName: full-path-to-your-CustomSslSocketFactory
public class CustomSslSocketFactory extends SSLSocketFactory {
public CustomSslSocketFactory() throws Exception {
super(SSLContextConfig.createSSLContext());
}
}
Related
I am trying to leverage Spring Cloud Feign client for declaring rest endpoints(third-party-endpoints) which will be called based on the request that my controller receives.
I have declared a feign client interface like:
#FeignClient(name = "my-client", url = "https://abc.xyz.com", configuration = MyClientConfiguration.class)
public interface MyFeignClient{
}
MyClientConfiguration is an unannotated feign configuration class just exposing BasicAuthRequestInterceptor bean preconfigured with some credential.
public class MyClientConfiguration {
#Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
return new BasicAuthRequestInterceptor("USERID","PWD");
}
}
So, what I have right now is a preconfigured feign client.
I am not sure how do I deal with the requirement that asks for being able to define/override the feign configuration with the url and credentials received in the body of different POST request.
So its not about overriding the feign configuration via properties file(like other somewhat similar SO questions), but instead being able to configure the feign client on the fly based on the url and credentials received in the body of the incoming requests.
I am aware of ways to do it with WebClient and looking for something similar to what WebClient provides via its uri and headers methods. Webclient allows us to override the webClient bean configuration with different uri and different auth credentials,
webClient
.put()
.uri("base-uri", uriBuilder -> uriBuilder.path("/rest").path("/api").path("/2").path("/issue").path("/" + id).build())
.headers(httpHeaders -> {
httpHeaders.setBasicAuth("decrypted-username", "decrypted-pwd");
})
Does Spring Cloud Feign provide any such facility where it is possible to have a generic configuration yet allowing to override those configurations at runtime?
EDIT 1 : START
The closest I got to is implementing via the feign's builder pattern :
MyFeignClient myFeignClient = Feign.builder()
.contract(new SpringMvcContract())
.requestInterceptor(new BasicAuthRequestInterceptor("decrypted-username", "decrypted-pwd")
.target(MyFeignClient.class, myRequestDTO.getBaseUrl());
I was challenged with an exception because I didn't specify which Contract to use. It was using the Default Contract.I then changed to SpringMvcContract as the annotation that I am using are the Spring MVC ones and not feign's default.
Getting DecodeException as of now. Trying to fix it. Will post update when done.
EDIT 1 : END
EDIT 2 : START
I was finally able to get this working. I figured out that the feign-gson does a great job at deserialization with minimal configuration.
My final feign configuration with the Decoder in place looks like :
MyFeignClient myFeignClient = Feign.builder()
.contract(new SpringMvcContract())
.decoder(new GsonDecoder())
.requestInterceptor(new BasicAuthRequestInterceptor("decrypted-username", "decrypted-pwd")
.target(MyFeignClient.class, myRequestDTO.getBaseUrl());
EDIT 2 : END
I have Spring beans configured in a microservice as follows that I'm using to connect to Kinesis:
#Bean
// ClientConfiguration has proxy protocol, proxy host, and proxy port set
public AmazonKinesisAsync amazonKinesisAsync(ClientConfiguration clientConfiguration, AppProperties properties) {
return AmazonKinesisAsyncClientBuilder.standard().
withClientConfiguration(clientConfiguration).withRegion(properties.getRegion()).build();
}
#Bean
public KinesisProducerConfiguration kinesisProducerConfiguration(AppProperties properties) {
return new KinesisProducerConfiguration()
.setRegion(properties.getRegion());
}
This GH issue states that the KPL doesn't support proxy configuration, but I'm hoping there is a way to utilize KPL behind a firewall. So, my main question is whether or not KPL supports proxy configuration, and if not, how can I use KPL/KCL behind a corporate firewall? I've read about AWS Kinesis VPC Endpoints here, so would this be the only alternative we would have if we can't use KPL with a proxy configuration?
In our project we use Spring cloud + Eureka as service registry.
When we use the ribbon client to call internal micro-services, all URL are resolved via Eureka ... that's a problem to call external URLs.
As external API are old fashioned usage of Feign doesn't seem to be good choice.
What's the best way to call an external URL from such a service ?
Thanks in advance
Patrice
One way working:
Use two configurations.
Declare your RestTemplate Bean to call external services like this:
#Primary
#Qualifier("withoutEureka")
#Bean
public RestTemplate restTemplate(){
...
}
Inject this reference in your client this way
#Bean
public MyClientForExtCall myClientForExtCall(#Qualifier("withoutEureka")RestTemplate restTemplate)
In the other configuration use the restTemplate as usual, but don't forget to use another qualifier
#LoadBalanced
#Bean
#Qualifier("withEureka")
public RestTemplate loadBalancedEureka(){
...
}
#Bean
public MyClientForInternal myClientForInternal(#Qualifier("withoutEureka")RestTemplate restTemplate)
Patrice
You can use Ribbon without Eureka. For external APIs where you cannot configure in Eureka to abstract the discover. You can hard code their URLs in client and configure server list. The Ribbon client defaults to a configured server list, and you can supply the configuration like this:
stores:
ribbon:
listOfServers: example.com, google.com
I understand #LoadBalanced indicates the Rest template should be based on Client Side Load Balancing using Ribbon and checks Eureka server for resolving the service name to host/port.
What is the use of #RibbonClient. Is it to support native Ribbon Client LB without Eureka and also support Eureka Discover when configured with DiscoveryEnabledNIWSServerList?
TL;DR: #LoadBalanced is a marker annotation & #RibbonClient is used for configuration purposes.
#LoadBalanced
Used as a marker annotation indicating that the annotated RestTemplate should use a RibbonLoadBalancerClient for interacting with your service(s).
In turn, this allows you to use "logical identifiers" for the URLs you pass to the RestTemplate. These logical identifiers are typically the name of a service. For example:
restTemplate.getForObject("http://some-service-name/user/{id}", String.class, 1);
where some-service-name is the logical identifier.
#RibbonClient
Used for configuring your Ribbon client(s).
Is #RibbonClient required?
No! If you're using Service Discovery and you're ok with all of the default Ribbon settings, you don't even need to use the #RibbonClient annotation.
When should I use #RibbonClient?
There are at least two cases where you need to use #RibbonClient
You need to customize your Ribbon settings for a particular Ribbon client
You're not using any service discovery
Customizing your Ribbon settings:
Define a #RibbonClient
#RibbonClient(name = "some-service", configuration = SomeServiceConfig.class)
name - set it to the same name of the service you're calling with Ribbon but need additional customizations for how Ribbon interacts with that service.
configuration - set it to an #Configuration class with all of your customizations defined as #Beans. Make sure this class is not picked up by #ComponentScan otherwise it will override the defaults for ALL Ribbon clients.
See the section "Customizing the RibbonClient` in the Spring Cloud Netflix documentation (link)
Using Ribbon without Service Discovery
If you're not using Service Discovery, the name field of the #RibbonClient annotation will be used to prefix your configuration in the application.properties as well as "logical identifier" in the URL you pass to RestTemplate.
Define a #RibbonClient
#RibbonClient(name = "myservice")
then in your application.properties
myservice.ribbon.eureka.enabled=false
myservice.ribbon.listOfServers=http://localhost:5000, http://localhost:5001
RestTemplate supports load balancing, using #LoadBalanced tells Spring Cloud that we want to take advantage of its load balancing support(If you are using Ribbon then the effect of using #LoadBalanced will be that RestTemplate will use RibbionClient to get the server address).
You can also check how LoadBalancerAutoConfiguration works here
Using #RibbonClients you can provide declarative configuration for a ribbon client.
E.g.
#SpringBootApplication
#RestController
#RibbonClient(name = "app", configuration = RibbonConfig.class)
public class App {
#LoadBalanced
#Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
//...
}
Then you create RibbonConfig.class to override any Ribbon related bean.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.AvailabilityFilteringRule;
public class RibbonConfig {
#Autowired
IClientConfig ribbonClientConfig;
#Bean
public IPing ribbonPing (IClientConfig config) {
return new PingUrl();//we override default Iping which is a NoOpPing
}
#Bean
public IRule ribbonRule(IClientConfig config) {
return new AvailabilityFilteringRule(); // we override the default ZoneAvoidanceRule
}
}
I am trying to get familiar with Spring's Project Reactor (https://projectreactor.io/) and have built a small application to make REST calls to another service over SSL. I cannot find any way to configure the org.springframework.web.client.reactive.WebClient to make requests over SSL. There seems to be no documentation about this. I am using reactor-core 3.0.0.RC1 and reactor-netty 0.5.0.M3, and Spring Framework 5.0.0.M1. Does anyone know how to configure reactor-netty with SSL support?
Update 2017-01-04:
This was corrected in the 5.0.0.M4 release of Spring Framework with this patch.
Original Answer:
I discovered that the solution is to create a new ClientHttpConnector implementation that respects SSL.
public class ReactorClientHttpsAwareConnector implements ClientHttpConnector {
#Override
public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {
return reactor.ipc.netty.http.HttpClient.create()
.request(io.netty.handler.codec.http.HttpMethod.valueOf(method.name()),
uri.toString(),
httpClientRequest -> requestCallback
.apply(new ReactorClientHttpRequest(method, uri, httpClientRequest)))
.cast(HttpInbound.class)
.otherwise(HttpException.class, exc -> Mono.just(exc.getChannel()))
.map(ReactorClientHttpResponse::new);
}
}
HttpClient.create() is required to make the client SSL-aware.