How to configure reverse proxy/loadbalancer for custom routing - apache2

Suppose I have 3 webservers behind a reverse proxy/loadbalancer. Currently I use Apache 2 but don't mind switching.
Those webservers are not equal. They have different sets of local data meaning that different kinds of requests will be handled more efficiently on specific webserver.
I want to plug some custom routing logic into my loadbalancer, that would on start of a new session select a webserver for it, then tie that session to that node until it breaks down (sticky session).
For example: a new user comes to the webapp, load balancer runs my custom code somehow, this code finds out information about that user and makes a conclusion that this user should be handled on node1. The balancer proxies that user to node1 and sticks it to it. When another user comes, custom routing logic suggests node3, to which loadbalancer then proxies this user.
Is it possible to do with Apache 2? If not, what proxy/loadbalancer would give me that ability?
Thank you.

Apache mode_proxy_balancer has stickyness if you want to stay on apache.
Otherwise, have a look at Haproxy. The first line of the abstract states: "route HTTP requests depending on statically assigned cookies ;"
You just have to set a cookie to know which backend you want the user to be stuck to.

Related

Exposing API Endpoints in Frontend Application

I am building a frontend application using react and I am wondering whether it is risky to expose API endpoint URLs (ex: https://myapi.com/v1/getitems) on GitHub, assuming that the endpoint has several security measures that are not exposed such as CORS and JWT Token Bearer Authentication. I would assume not, since, if someone were to take the endpoint and send requests, they would need a token and be allowed to do so by CORS.
Is there any security risk in doing so?
Yes. Don't add the base url of your api on github in plain view. Even though you might have CORS and Authorization, that doesn't stop a malicious actor to keep spamming your back-end.
What you do is create a .env file in your root folder. You can use a library like #beam-australia/react-env and there are others as well.
You add in the .env file the values that are important for your environment and that are usually secrets, and you want them to not be visible in your code. You do it like so:
API_URL="https://myapi.com/v1"
And then you access this variable in your code with env("API-URL") ( in the #beam-australia/react-env case, but others libraries work the same). Keep in mind that you need to add .env in .gitignore so that the .env file is not pushed to github.
Regarding requests, you can make one like so:
fetch(`${env("API_URL}/getitems`)
This way your code will be stripped of the API's base url and if someone sees your code it will see only the endpoint, not the full url.
Publishing the code of the API is risky on its own. Somebody can find a vulnerability in it and instantly hack it. If you add the address of the API to the code you help this kind of attacks. They can get the address with some investigation; OSINT and social engineering too, but better to reduce the attack surface.
As of the secrets, they must never be near to the code, because you or another developer can accidentally publish it. It happened too many times with many developers, so better to take this seriously. If you want to keep the address in secret, then you must extract it from the code and put it in the configuration of the production environment which is imported from a totally different location than your code. Using environment variables like Alex suggested is a good idea for this. Nowadays it is common to use docker, which has a way to manage secrets, so you don't need to reinvent the wheel: https://docs.docker.com/engine/swarm/secrets/ Another aspect that the configuration belongs to the actual instance. In OOP terms you want to describe the injected properties of an object in its class or in a global variable, which is an antipattern.
As of client side REST clients like javascript applications running in the browser or Android/iOS apps, you must not publish your secrets along with the REST client, otherwise it is not a secret anymore. In that case you need a server side part for the REST client and for example sign and encrypt JWT there with a secret key. It is your decision whether this server side part of the REST client sends the HTTP request to the REST API and in that case you can hide the URI of the REST API or it just manages the JWT and the client side part of the REST client sends it. If the server side part of the REST client sends the HTTP request to the REST API, then you can even use traditional sessions with session cookies between the client side and the server side parts of the REST client, but you cannot use them between the server side part of the REST client and the REST API where the communication must be stateless. Though it does not make much sense to have a separate REST API if you don't have multiple different REST clients in this scenario e.g. browser clients for JS and JSless browsers, Android and iOS clients, fully automated clients running on servers, etc. So don't confuse the REST client - REST API relationship with the browser - HTTP server relationship, because they are not necessarily the same. Most of the REST clients run on servers, not in the browser.

Request with params, processing and rendering SPA - architectural approach

I was not sure how to name the question but here is what I need to do and I'm looking for some advice how to handle it architecture-wise. I'm Java / Kotlin developer very familiar with Spring Boot and very basic knowledge of front end as a whole - just so you know my origin.
Here is the flow of my new application:
user retrieves a generated link with lots of params that he can click in his browser
when he clicks on that link I want to retrieve those params in backend, run some longish external API calls & calculations (up to 10 seconds) and then return results one by one (some websocket or server sent events) and present them in SPA application (preferably React) with results nicely presented so he can pick one of the options I calculated, fill out some form and pay for it.
Maybe I'm confused - I've worked with many front end developers but I never thought how to actually "start" a SPA when someone clicks on some URL with params and then handle all those passed params via backend.
Is what I just wrote doable with React rendered on client side and Spring Boot as the backend? Or do I have to use React server side rendered because I have this static URL with params?
Could someone clarify how I should approach this?
Generally when a SPA is hosted on a domain, the webserver will be configured to redirect all requests on all paths to the root url. So it doesn't matter what path on your domain the user is trying to access, the SPA will still get loaded.
Then in your React SPA you inspect window.location to find the path and params in the url. You then call the backend (most likely on another domain) sending it the params via a web request. It then sends back a response with a random key, and continues to start the time consuming process in the background. When results come in, they are persisted globally in a dictionary against the random key (could be to a database, could be held in memory if you only are going to need one back-end server). Then on another API endpoint, the React front end can poll with the random key and get the current status of the processing, displaying it to the user.

Need all requests from the same client to go to the same instance

I have a GWT based Java web application deployed to Google App Engine, in which the servelet reads and changes state held in memory. The client code might send requests to change this state and, subsequently, to change or read the same state. So it's important that all requests from the same instance of the client page go to the same instance of the application's version.
Since I don't expect a lot of traffic, I don't mind limiting the maximum number of instances to 1. But I'd like that one instance to exist more or less permanently. (If a user takes more than, say, an hour between requests, I don't mind if their data is lost.)
In detail, the way I'm managing state is that I have a static variable that points to a hash table, the hash table maps strings to states. On the first request from the client, a new unique string is created and a new state and a new entry is made in the hash table. The string is returned in the response. On subsequent requests, the client sends the string so that the servelet can find the state that it needs to mutate or read. I can't keep the state in a database because it is very complex and not at all serializable.
What are the ways to ensure that all requests from a given client instance go to the same server instance?
What are the ways to ensure that all requests from a given client instance go to the same server instance?
There are no ways, by design. If you want to persist state between requests reliably, use the datastore, with memcache as a cache.
Adding: You can also use cookies if your data storage is meager, obfuscating/encrypting them as needed.
App Engine assumes that applications hold no essential state between requests. That makes spinning up/shutting down instances a non-issue.
I second Dave's answer, GAE is not exactly the right fit for what you desire.
However there could be ways around it, but in only a few specific cases: if you're using the standard GAE environment with manual scaling and a subsequent request is always based on URLs embedded in the response to the previous request.
You could craft the URLs in a response to a request according to the targeted routing rules such that subsequent requests hit the same instance. From Targeted routing:
If you are still using backends or have manually-scaled services, you can target and send a request to a instance by
including the instance ID. The instance ID is an integer in the range
from 0 up to the total number of instances that are running, and can
be specified as follows:
Sends a request to a specific service and version within a specific instance:
https://INSTANCE_ID-dot-VERSION_ID-dot-SERVICE_ID-dot-MY_PROJECT_ID.appspot.com
http://INSTANCE_ID.VERSION_ID.SERVICE_ID.MY_CUSTOM_DOMAIN
Note: Targeting an instance is not supported in services that are configured for auto scaling or basic scaling. The instance ID must be
an integer in the range from 0, up to the total number of instances
running. Regardless of your scaling type or instance class, it is not
possible to send a request to a specific instance without targeting a
service or version within that instance.
To determine the instance ID you could use the modules API, for example:
// Get the instance handling the current request.
int currentInstance = modulesApi.getCurrentInstance();
Note that if the targeted instance goes down you will keep getting errors permanently (that instance will not come back), so you might want to think at a fall-back solution for going somehow to a non-instance-based based page from where you could hitch a flow on another instance.
But such solution is not available in the GAE flex environment. From Targeted routing:
Note: In the flexible environment, targeting an instance is not supported. It is not possible to send requests directly to a specific
instance.

Calling Function on a different client SIlverlight

I have one very weird question.
There are 2 Silverlight Client
1. Admin
2. User
Now, I want a scenario wherein the Admin Silverlight can initiate a function call on the User Silverlight.
Pretty much a newbie with SL so wonder if that would be possible.
I'd appreciate any help.
Thanks
I suppose the applications are not in the same browser / machine, and when you describe the usage pattern as admin and user, I take that there are probably more users than admins.
You might want to take a look at duplex bindings for WCF services - this is a web service binding that allows pushing notifications to clients from the server. When all clients establish such a channel, you can implement hub-and-spoke communication between clients.
This blog post gives a good receipt for getting started:
http://silverlightforbusiness.net/2009/06/23/pushing-data-from-the-server-to-silverlight-3-using-a-duplex-wcf-service/
If they are both in the same frame/browser, you could call JavaScript in the first using the HtmlPage API, which could interact with the second.
So:
Silverlight control -> injects JS into HtmlPage -> JS interacts with Silverlight control 2 (assuming this is possible, please correct me if wrong) -> Silverlight control responds.
If they are in separate windows or running "out of browser", I would expect it wouldn't work.
If the 2 instances are seperated (i.e., the admin is on one machine and the user is on another) there's no direct way to do it. However, you can rig it up with a publisher/subscriber style system.
Assumption: You have some sort of shared data store between the two, maybe a database or something.
Idea: You have the admin client write a request to this shared data store; an entry in a table, or a new file in a network share, or something. You have the user client app regularly scan this table/share for new entries, say every .5 seconds or so. When it sees the entry, it executes the requested operation, storing any return values back to the shared store. When the admin sees the return value, he knows the operation has been successfully executed.
There are a couple of options that I can think of.
You could implement some sort of remote procedure call via web services whereby one Silverlight app posts a request to call the method, and the other Silverlight regularly checks for method call requests.
If hosted on the same HTML page in a browser, you could use javascript to allow the two controls to interact.
However, direct communication between two Silverlight instances isn't supported, and while the suggestions may help to achieve something close to what you want, they don't provide a complete solution that will work in all scenarios.

Using a subdomain to identify a client

I'm working on building a Silverlight application whereas we want to be able to have a client hit a url like:
http://{client}.domain.com/
and login, where the {client} part is their business name. so for example, google's would be:
http://google.domain.com/
What I was wondering was if anyone has been able, in silverlight, to be able to use this subdomain model to make decisions on the call to the web server so that you can switch to a specific database to run a query? Unfortunately, it's something that is quite necessary for the project, as we are trying to make it easy for their employees to get their company specific information for our software.
Wouldn't it work to put the service on a specific subdomain itself, such as wcf.example.com, and then setup a cross domain policy file on the service to allow it to access it?
As long as this would work you could just load the silverlight in the proper subdomain and then pass that subdomain to your service and let it do its thing.
Some examples of this below:
Silverlight Cross Domain Services
Silverlight Cross Domain Policy Helpers
On the server side you can check the HTTP 1.1 Host header to see how the user came to your server and do the necessary customization based on that.
I think you cannot do this with Silverlight alone, I know you cannot do this without problems with Javascript, Ajax etc. . That is because a sub domain is - for security reasons - treated otherwise than a sub-page by the browsers.
What about the following idea: Insert a rewrite rule to your web server software. So if http://google.domain.com is called, the web server itself rewrites the URL to something like http://www.domain.com/google/ (or better: http://www.domain.com/customers/google/). Would that help?
Georgi:
That would help if it would be static, but alas, it's going to all be dynamic. My hope was to have 1x deployment for the application, and to use the http://google.domain.com/ idea to switch to the correct database for the user. I recall doing this once when we built an asp.net website, using the domain context to figure out what skin to use, etc.
Ates: Can you explain more about what you are saying... sounds like you are close to what I am trying to come up with. Have you seen such a tutorial for this?
The only other way I have come up with to make this work is to have a metabase that when the user logs in, it will switch them to the appropriate database as required... was just thinking as well that telling Client x to hit:
http://ClientX.domain.com/ would have been sweeter than saying to hit http://www.domain.com/ and login. It seemed as if they were to hit their name, and to show it personalized for them right from the login screen would have been much more appealing for the client base.
#Richard B: No, I can't think of any such tutorial that I've seen before. I'll try to be more verbose.
The server-side approach in more detail:
Direct *.example.com to the same IP in your DNS settings.
The backend app that handles login checks the Host HTTP header (e.g. the "HTTP_HOST" server variable in some platforms). That would contain the exact subdomain.example.com that the client used for reaching your server. Extract the subdomain part and continue...
There can also be a client-side-only approach. I don't know much about Silverlight but I'm assuming that you should be able to interface Silverlight with JavaScript. You could read document.location with JavaScript and pass it to your Silverlight applet, whereon further data fetching etc. logic would rely on the subdomain that was passed in by JavaScript.
#Ates:
That is what we did when we wrote the ASP.Net system... we pushed a slew of *.example.com hosts against the web server, and handled using the HTTP headers. The hold-up comes when dealing with WCF pushing the info between the client and the server... it can only exist in one domain...
So, for example, when you have {client}.example.com and {sandbox}.example.com, the WCF service can't be registered to both. It also cannot be registered to just *.example.com or example.com, so that's where the catch 22 is coming in at. everything else I have the prior knowledge of handling.
I recall a method by which an application can "spoof" another domain name in certain instances. I take it in this case, I would need to do such a configuration? Much to research yet I believe.

Resources