Is there any possibility to:
Connect Spring, Feign, any Load Balancer with working SSL together?
See any working example?
Read explanation about how features?
Spring Feign with SSL and Load Balancer
I couldn't find out comprehensive source of knowledge about creating modern Spring Client based on interfaces, without writing much boilerplate code. Now, I have learned a lot and I want to share with my little project about creating such a thing, without cracking Your head against the wall, but let's start from the beggining.
Prerequisite
We need some features like:
Java 11 or higher.
Maven (3.6.3 is enough).
Spring (2.6.5 is my starter version).
Minimal knowledge about SSL.
TL;DR Gimme some code
You can download whole project from this repository. All dependencies, files, configuration is included and is ready to start as it is. You just need to specify client, two instances of one kind and two of another API to see the proof of working load balancing. Just follow instruction.
Introduction
Nowadays, we expect high avaliable, very efficient and complex infrastructure on many instances. Furthermore, everything should be encrypted over HTTPS protocol, increasing the level of security. From hundreds of different libraries I decided to do something with Feign Client and check the posibilities.
Why Feign?
It is oficially part of a Spring Cloud components.
Multiple implementations like OkHttpClient or ApacheHttpClient.
Configuration over implementation in out of a box style, like Retryer or ErrorDecoder.
It can be easly bound with Spring Load Balancer.
In my example I have used both implementation of Client to show differences in configuration, e.g. the way we can add truststore to our API client. Probably the biggest pros is fact, that we can configure our clients totally dependant from themselves. In inner traffic, between our own components, we have possibility to turn of SSL and set less timeouts, quite the opposite to outer traffic with TLS and longer timeouts.
Configuration over Implementation
As I said, we have many implementations as out of a box, ready to use with a little dose of magic. Default configuration provide us possibility to attempt max 5 times any endpoint, when it fail to response with any reason. In a simply way we can change it by creating #Bean in EndpointConfiguration.class. The most important thing is to bind our configuration with appropriate #LoadBalancerClient and #FeignClient, because It's not bean, thus we manually point at configuration.
SSL
It is important to provide truststore and build SSLContext/SSLFactory with TrustManager to work with SSL. We must override default client with our proposition of Bean, of course we can inject any other bean by constructor. Alternatively we can use default client and install certificate in JDK truststore or override javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword. Very usefull is to use JVM argument -Djavax.net.debug=all during connection tests to check if our certificates are properly loaded and connection ends up with success. Of course You should not keep password in clear text format in Your production environment. It is a way better to keep encrypted format of our secret and decrypt it during application start.
Load Balancer
The most important thing that I have done is load balancer configuration with pointers to the service and configuration. We can decide current load balancing strategy defining ReactorLoadBalancer<ServiceInstance> #Bean, default one is round robin, also we can choose random way. Another challange is to provide our instances of nodes to load balancer. Every client should implement it own ServiceInstanceListSupplier with serviceId bound to the service name and list of actual instances, that specify host, port or protocol (HTTP/HTTPS).
All that glitters is not gold
Patience is the key to success. Spring, Feign and Load Balancer specification is really good, but at this moment I have not seen good working example with all those things linked up together. A lot of beans are marked as #ConditionalOnMissingBean even with combined property. It is a bit messy to see currently bean, especially client, so you have to work with debugger.
Related
I'm developing an API which will connect with several endpoints. The uri for each endpoint is something like this:
rest/services/General/directory1/MapServer/export
rest/services/General/directory2/MapServer/export
rest/services/General/directory3/MapServer/export
rest/services/General/directory4/MapServer/export
and so on...
I don't know if it's possible, but would like to have something like this instead:
rest/services/General/${value}/MapServer/export
and then on my code just call the endpoint above injecting the specific directory that I want on ${value}
Is it possible? Don't know what I'm missing as I googled but couldn't find anything related.
Cheers
You can do so by means of Spring Cloud Config.
Spring Cloud Config provides server and client-side support for
externalized configuration in a distributed system. With the Config
Server you have a central place to manage external properties for
applications across all environments. The concepts on both client and
server map identically to the Spring Environment and PropertySource
abstractions, so they fit very well with Spring applications, but can
be used with any application running in any language. As an
application moves through the deployment pipeline from dev to test and
into production you can manage the configuration between those
environments and be certain that applications have everything they
need to run when they migrate. The default implementation of the
server storage backend uses git so it easily supports labelled
versions of configuration environments, as well as being accessible to
a wide range of tooling for managing the content. It is easy to add
alternative implementations and plug them in with Spring
configuration.
For more details, kindly go through spring documentation here.
I solve the problem using the simplest approach possible. In my code I used the string.replace() method. Was looking for something more robust, but as it was taking lots of time to sort it out how to do it, I decided to go with the string.replace method.
We're maintaining a Java application with a JAX-WS SOAP API for external systems running on WildFly 14 application server. The external systems currently connect using common one-way SSL. Our goal is to switch communication to mutual authentication, so two-way SSL.
Not all of the external systems can make the switch at the same time though, so simply enforcing two-way SSL is not an option. We need to migrate them step-by-step during a transition phase. That why I've been wondering: Is there a possibility to enable two-way SSL on a WildFly HTTPS interface for specific caller IPs only?
I have based my tests on the official documentation on setting up regular two-way SSL. Following these steps, every caller needs to provide a client certificate. Modifying that example configuration to use want-client-auth instead of need-client-auth softens the checks to support two-way SSL but not require it. Unfortunately that is not enough in our case, because it does not imply guarantees about whether a particular external system is consistently using two-way SSL or not. A system could send some of its requests providing a client certificate, and some without. In other words, business requires a way to say "From this day on, external system Foo may only use the API with a client certificate. All the other external systems are unaffected, for now."
To implement this - preferably without application code changes -
I've been reading the documentation of the new WildFly security module Elytron. It seems quite extensible, but details on custom components are sparse and I haven't found an extension point that sounds like it would help in my case.
The only solution approach I have right now is configuring a separate set of socket-binding and https-listener for Wildfly, similar to what is described here. That means we would have two HTTPS ports: One with one-way SSL, and another one with mandatory two-way SSL. As external systems are completing their migration steps, they switch the port used for invoking our API. Forcing them to only use the two-way SSL port from then on would require specific firewall rules, but should be possible.
So, this solution is rather simple in technical implementation but leads to overhead for re-configuring the external systems and adapting firewall rules. That's why I'd be happy about any suggestions for a solution that is more elegant, or hints how to use Elytron for that.
Thanks in advance!
I think you came to best conclusion. Elytron does not have possibility to choose SSL Context based on client parameters (What would that be? Client IP address? That can change when behind the load balancer.)
So I think only way is to have different SSLContext configured on different ports (or hostnames).
Regarding extending server. I guess SSL handshake is very early step and after that different customisation points take part. I thought about some Undertow custom handler, something similar to [1], but as I said that would be too late.
[1] http://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#redirect-handler
Our application currently uses Spring's HttpInvokerProxyFactoryBean to expose a Java service interface, with POJO requests and responses handled by our single Tomcat server. This solution allows us to have a pure Java client and server, sharing the same Java interface. Due to increased load, we are now looking into the possibility of load balancing across multiple Tomcat instances.
It would be nice if we could make this transition while retaining the same Java interface, as this would minimise the additional development required. Googling seems to suggest that the most common solution for Tomcat load balancing is to use Apache http server together with mod_jk, but I presume this would mean using some communication mechanism other than Spring's HTTP invoker? Is there a better solution which would allow us to retain more of our current code? If not, what would be involved in transitioning between what we have now and Apache/mod_jk?
Any help would be greatly appreciated as I don't have any experience in this matter.
I'm working on a project which involves writing web services on mainframe enviroment.We are going to be provided a test enviroment on which we can do development and see the inital results. That process is taking a lot of time and I wanted to see if I can simulate some of the parts that I've to do.
Finally I've to get web services talking with mainframes which would have webservice talking with DB2 and IMS segments. I've never worked with mainframes before and I wanted to know how can I create mocks for IMS segment which then my webservice can read and update to. I would appreciate any insights into this
I've done the mainframe side of POX and SOAP web services in CICS. (CICS can access both DB2 and IMS) The thing that seems to surprise the distributed folks is the tag names. They tend to be generated from language structures, so they look like (in our case) COBOL variable names.
Other than that, the SOAP looks like what the WSDL says it should, the POX looks like POX.
If you've got a schema, work from that. Don't worry about the fact that it's a mainframe or that the data is stored in IMS or DB2, write to the specification.
You might want to ask about authentication mechanisms, as this is another stumbling block regardless of platform. Generally people are nervous about unauthenticated access to their business systems, even if that access is coming from another part of the same organization. No one wants to have created an exploitable hole in their security.
In our case, using CICS, we required a logon ID and password for each transaction - http basic authentication as per RFC 2617. Depending on your policies and procedures, that password may be required to expire on a regular basis. Some organizations allow non-expiring IDs, some don't.
An option we looked at but did not implement was SSL certificates. CICS allows one to send a certificate along with a request and then CICS matches the certificate to a logon ID under whose auspices the rest of the transaction runs. The ID is authenticated by virtue of the certificate. This is done in the TCPIPSERVICE definition in CICS.
I realize I'm going on about CICS and you didn't even mention it in your question, but I have to believe you're going to run into similar concepts/issues. IMS also does web services, and I seem to remember there being a mechanism to expose a DB2 stored procedure as a web service. IMS, DB2, and CICS all use the same external security manager behind the scenes.
I have a problem. I need to host many (tens, hundreds) of small identical JAVA web applications that have different loads during one time. I want to use Glassfish V3. Do I need to use a load balancer and clusters or something else? Advise where can I find information about similar problems and their solutions...
I need to host many (tens, hundreds) of small identical JAVA web applications that have different loads during one time.
For hundreds of webapps, you will very likely need more than one app server instance. But this sounds odd to be honest.
I want to use Glassfish V3. Do I need to use a load balancer and clusters or something else?
Right now, GlassFish v3 offers only basic clustering support using mod_jk (i.e. no load balancer plugin, no centralized admin, no high availibility). If you are interested, have a look at this note that describes the configuration steps of GFv3 and mod_jk.
For centralized admin and clustering, you'll have to wait for GlassFish 3.1 (see the GlassFish Roadmap Community Update slides).
You could check out Gigaspaces. I have seen it used in conjunction with Mule for a somewhat similar project. ESBs tend to be overkill in my opinion, but it sounds like you have quite the task to conquer.
Based on your requirements, you cannot do load balancing since the load is predetermined by which client the request is for. Each request has to go to the app handling that client, so it cannot be distributed outside the set of apps dedicated to that client.
You can use multi-threading. you could set up the configuration so that different threads handle different clients. However, it might be better to simply have a server that can handle requests from different clients. Based on the client sent with the request, it would be dispatched to a different database etc.