Cookie prefix with dynamic server template - haproxy

I am trying to implement sticky sessions. I have found out that I can add a prefix to the exiting cookies servers to identify them. See here for more
backend bk_web
balance roundrobin
cookie JSESSIONID prefix nocache
server s1 192.168.10.11:80 check cookie s1
server s2 192.168.10.21:80 check cookie s2
My problem is that I do not have distinct servers which I could hard code the cookie names for. Such as s1 and s2.
backend java_container
balance roundrobin
cookie JSESSIONID prefix nocache
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none
I know the server will be named later worker-1, worker-2 etc but I can't figure out how to give this dynamic info as cookie name. Ideally it would be something like
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none cookie worker

I tried munging the snippets together and it actually worked.
backend java_container
balance leastconn
dynamic-cookie-key MYKEY
cookie JSESSIONID prefix dynamic nocache
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none
Cookie looks like this now where the first part the hashed server IP.
JSESSIONID: 8a90ee411f256174~602EE52C3C605D45070366D4009EED56
https://www.haproxy.com/blog/whats-new-haproxy-1-8/#dynamic-cookies

You are looking for the dynamic option as part of the cookie directive. You will also want to look into dynamic-cookie-key.

Related

How to Create sticky session in haproxy

My Configurations are:-
frontend http-8081
bind *:8081
mode http
acl is_keycloak hdr(X-TARGET) keycloak
use_backend keycloak if is_keycloak
backend keycloak
mode http
balance roundrobin
option forwardfor
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server 192.168.99.100:32768 192.168.99.101:32766 check inter 5000
I am new to this and I need a Sticky session. Can anyone tell me using this configuration that how to create a Sticky session?
I believe using cookies will help you here.
I would also say have your servers on seperate lines for each one
cookie SERVERID insert
server s1 192.168.99.100:32768 check inter 5000 check cookie s1
server s2 192.168.99.101:32766 check inter 5000 check cookie s2

JWT Validation in HAProxy

I have an HAProxy configured to accept requests to *.mysubdomain.com. The HAProxy will parse the subdomain (prod or dev from prod.mysubdomain.com or dev.mysubdomain.com) and forward to the correct backend. Two backends exist, one for prod and one for dev. Each backend contains two server entries pointing towards Marathon LB instances on each subdomain.
The subdomains require a JWT cookie for authentication on the backend. I have the public key to check the validity of the JWT, but would like to do so in the HAProxy. Is there a way to add my own code to perform the JWT validity check within the HAProxy configuration?
The HAProxy configuration file is as follows:
global
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
mode http
# Returns true when one of the headers contains one of the strings either isolated or delimited by dots. This is used to perform domain name matching.
acl host_dev hdr_dom(host) -i dev
acl host_prod hdr_dom(host) -i prod
acl jwtPresent req.cook(JWT) -m found
use_backend prod_domain if jwtPresent host_prod
use_backend dev_domain if jwtPresent host_dev
default_backend prod_domain
backend prod_domain
balance roundrobin
server prodDomain1 "${MARATHON_LB_PROD_1}" maxconn 32 check
server prodDomain2 "${MARATHON_LB_PROD_2}" maxconn 32 check
backend dev_domain
balance roundrobin
server devDomain1 "${MARATHON_LB_DEV_1}" maxconn 32 check
server devDomain2 "${MARATHON_LB_DEV_2}" maxconn 32 check
HAProxy can act as an API gateway and validate JWT tokens against a public key. They have written a blog post and provided sample code to show you how.
The post is here: https://www.haproxy.com/blog/using-haproxy-as-an-api-gateway-part-2-authentication/
The sample lua code is here: https://github.com/haproxytech/haproxy-lua-jwt
As the other answer pointed out, you have to use Lua script. You can use existing implementations from lua-resty-jwt or Kong.
Notes:
Those code-bases are not concise. A simple copy & paste won't work. So you have to extract the bare minimum you need.
You can't have dependencies in your Lua script. Only plain vanilla Lua. So you have to get rid of all require statements.
The tricky part is the HMAC implementation.
Avoid any I/O operation in your Lua script, e.g. file, database, network operations.
It's not an easy undertaking. Good luck! It's something worth sharing.
As far as I could tell, HAProxy does not have the functionality to perform the logic for validating the JWT. Instead, I implemented a script in Lua for haproxy.cfg to call to perform the validation:
global
maxconn 256
lua-load /choose_backend.lua
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
http-request set-header X-SSL-Client-DN %{+Q}[ssl_c_s_dn]
http-request set-var(txn.backend_name) lua.backend_select()
use_backend %[var(txn.backend_name)]
backend prod_domain
balance roundrobin
server prodDomain1 "${MARATHON_LB_PROD_1}" maxconn 32 check
server prodDomain2 "${MARATHON_LB_PROD_2}" maxconn 32 check
backend dev_domain
balance roundrobin
server devDomain1 "${MARATHON_LB_DEV_1}" maxconn 32 check
server devDomain2 "${MARATHON_LB_DEV_2}" maxconn 32 check

How to implement the code which redirect clients request to another node

I'm very curious about how to implement redirect code in a back server node.
For example: Client A request web server C, there is a load balance node B between A and C. So the graph is A=>B=>C=>A (not A=>B=>C=>B=>A). Actually C get requests from B, so I'm wondering how does C create a socket to connect to A and send data to A. I highly appreciate if you would share me some code snippet about this, Thanks!
I think this is the question you are asking:
"I have multiple web servers behind a load balancer, so how can I create a persistent http socket connection to a back end server from a client without it being redirected to another server and therefore breaking connection?"
The answer to that question is through cookie injection. For example, with HAProxy you can set a cookie depending on the server that the request is routed to first, then the load balancer will know to stick that request in future to the specified server.
An example in HAProxy backend configuration:
backend socket-servers
timeout server 120s
balance leastconn
# based on cookie set in header
# haproxy will add the cookies for us
cookie SRVNAME insert
server node-1 127.0.0.1:5000 cookie S1 check
server node-2 127.0.0.1:5001 cookie S2 check
This example was taken from http://toon.io/configuring-haproxy-multiple-engine-io-servers/.
Upon a new request it will see no cookie, and route to the best server based on the server with the least number of connections. As it does so, it sets a cookie SRVNAME=node-1 or SRVNAME=node-2 depending on the server it goes to. Every subsequent request from the client goes to the node specified in the cookie.

haproxy configuration for RESTful loadbalancing - creating resurces

I am trying to come up with a haproxy configuration
for a cluster of rest servers where the creation of a resource
should be sent in round-robin to the servers
POST /somecollection
responds with the created resource uri (eg /collection/instance01 )
but then any further use of the created resources
GET /collection/instance01/blah
PUT /collection/instance01/foo
DELETE /collection/instance01/
must be sticky to the server instance that handled the POST
(where the resource has been created).
And I would like to do that without cookies :-)
Any ideas ?
One way to achieve this is via cookie:
Example:
backend rest_backend
...
cookie __sticky_rest insert indirect nocache
server rest1 x.x.x.1:xxxx cookie 1
server rest2 x.x.x.2:xxxx cookie 2
...

Route by using existing cookie

How can I route requests in haproxy using a cookie that was set on the app servers?
Example: SESS=<hash-of-username>
haproxy should not insert cookies by itself in any case.
For testing a specific server behind haproxy I can recommend this approach:
frontend http
acl is_cookie_hack_1 hdr_sub(cookie) server_test_hack=server1
acl is_cookie_hack_2 hdr_sub(cookie) server_test_hack=server2
... insert your normal acl rules here
use_backend bk_server_1 if is_cookie_hack_1
use_backend bk_server_2 if is_cookie_hack_2
... insert your normal use_backend expressions here
backend bk_server_1
...
backend bk_server_2
...
I insert the server_test_hack cookie by javascript in my browser's js console by this script:
document.cookie="server_test_hack=server1";
You can't use your existing cookie for balancing, the way you could use the URI parameter. You can't just take the md5() or build the hash table of the cookie, at least that is not documented. You could use prefix parameter for the cookie to achieve a different result. It might be what you are looking for (if you want to avoid creation of yet another cookie).
So in your case the config would look like this:
backend bk_web
balance roundrobin
cookie SESS prefix indirect nocache
server s1 192.168.10.11:80 check cookie s1
server s2 192.168.10.21:80 check cookie s2
When the request arrives without a cookie, any server is chosen by round-robin and request is redirected to it. When response arrives from the backend, HAProxy checks for the SESS cookie and if it's set, it prepends the server name (sX) to the cookie and sends it to the client. In the browser, the cookie looks like sX~, but when the next request is sent with that cookie, the backend server only sees in the cookie, as HAProxy strips the sX~ part
Source: load balancing, affinity, persistence, sticky sessions: what you need to know
If you just want to read cookies in the request and route accordingly, you can do something like this in your configuration:
frontend http
acl cookie_found hdr_sub(cookie) COOKIENAME
use_backend app_server if cookie_found
backend app_server
balance roundrobin
server channel1 X.X.X.X:PORT #Host1
server channel2 Y.Y.Y.Y:PORT #Host2