📜 ⬆️ ⬇️

We analyze the proxying methods based on HAProxy

Recently I had to deal with proxying access to web servers using HAProxy. The main problem was encrypted access. Who is interested in this topic, welcome under cat.

There are a number of web servers in our company. To save addresses, access to them is organized through HAProxy. Like this:



At the same time, the configuration of HAProxy itself is extremely simple ( example No. 1 ):
')
frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

backend mytest1_web
mode http
cookie SERVERID insert indirect nocache
server mytestweb1 192.168.1.5:80 check cookie mytestweb1

backend mytest2_web
mode http
cookie SERVERID insert indirect nocache
server mytestweb2 192.168.1.10:80 check cookie mytestweb2

Hereinafter I will give not complete examples of the config file, but only pieces of interest to us.

Extremely simple - we listen to port 80 and parse all incoming traffic. If mytest1.loc is requested, it is placed in the access-list is_mytest1, in this case the mytest1_web backend is used, in which we redirect traffic to the internal host 192.168.1.5, where we have this site. Similarly for mytest2.loc. Everything is extremely simple and at the same time we save real IP addresses.

There was a question of resiliency, especially since we also have servers in the neighboring town where we can put up these websites. Well, there is a virtual machine with Linux in the Amazon cloud, which does the same thing, but for sites located in the cloud. Can we use 2 HAProxy in a row? Raise about this test circuit and see:



The configurations of HAProxy2 and HAProxy3 have not changed, but the balancing parameter has been added to HAProxy1 ( example # 2 ):

frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

backend mytest1_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server HAProxy1 1.1.1.1:80 check cookie haproxy1_1
server HAProxy2 3.3.3.3:80 check cookie haproxy2_1

backend mytest2_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server HAProxy1 1.1.1.1:80 check cookie haproxy1_3
server HAProxy2 3.3.3.3:80 check cookie haproxy2_3

Everything worked fine. It would seem, you can rejoice, but here it was decided to redo the sites for work through SSL. And the problems started.

Let's return to the beginning and consider everything from the beginning. The first assumption is that we do not need to encrypt the traffic between the proxy server and the site itself. Secondly, we do not need to worry about linking the certificate to the site, that is, we use self-signed certificates everywhere.



What do we need to do? Generate and install a self-signed certificate on our HAProxy server, then the client, accessing the site, will go to our proxy server, take its certificate, establish a secure connection with the server and then be redirected to the website. And for all sites behind the proxy server, one certificate will be used.

So let's get started. We generate:

openssl req -new -x509 -nodes -out server.crt -keyout server.key

Write to one file:

cat server.key> /etc/ssl/mytest.loc.pem
cat server.crt >> /etc/ssl/mytest.loc.pem

And edit the configuration of HAProxy ( example number 3 ):

frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

backend mytest1_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb1 192.168.1.5:80 check cookie mytestweb1

backend mytest2_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb2 192.168.1.10:80 check cookie mytestweb2

frontend https_frontend
bind *: 443 ssl crt /etc/ssl/mytest.loc.pem
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

By the way, checking the configuration before restarting is a very good habit:

haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid

Check and see that everything works fine.

Well, now let's take the case when each site has its own certificate, and not a self-signed one, but a purchased one. And it has a strict binding to the name of the site. In this case, we can resolve the issue in two ways: place certificates for sites on the HAProxy server or proxy TCP instead of HTTP. But in both cases we will not be able to manage with one IP address for our two sites.

Consider the first case:



The difference between this case and the previous one (with self-signed certificates) is only in the fact that here we have to listen to individual interfaces and issue a certificate depending on the interface ( example No. 4 ):

frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

backend mytest1_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb1 192.168.1.5:80 check cookie mytestweb1

backend mytest2_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb2 192.168.1.10:80 check cookie mytestweb2

frontend https_frontend_site1
bind 1.1.1.1:443 ssl crt /etc/ssl/mytest.loc1.pem
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1

frontend https_frontend_site2
bind 9.9.9.9:443 ssl crt /etc/ssl/mytest.loc2.pem
mode http
option httpclose
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2

It seems everything is clear, if traffic came to the interface with the address 1.1.1.1, it means that the client requests the site mytest1.loc. So, we give him the certificate of this site and then we proxy on the backend mytest1_web .

In the second case, we forward all TCP traffic that came to us to port 443 completely. This should be done, for example, when for some reason you do not want site certificates stored on a proxy server. Or, for example, do not trust the internal network between the proxy and web servers.



The configuration of HAProxy will be approximately the following ( example No. 5 ):

frontend mytest1_frontend
bind 1.1.1.1:443
mode tcp
use_backend mytest1_webssl

backend mytest1_webssl
mode tcp
option ssl-hello-chk
server mytestweb 192.168.1.5:443

frontend mytest2_frontend
bind 9.9.9.9:443
mode tcp
use_backend mytest2_webssl

backend mytest2_webssl
mode tcp
option ssl-hello-chk
server mytestweb 192.168.1.10:443

It seems quite understandable configuration. Probably, it is worth saying that since we are sending all TCP traffic, we cannot analyze it, and therefore the presence of any access-lists in the frontend part will generate an error.

It is time to return to our task with the division of web sites for different cities. To begin, consider the simpler case:



Since we have the Internet between HAProxy1 and HAProxy2, even when using self-signed certificates, we cannot use HTTP PROXY MODE on HAProxy1, otherwise the whole point in encrypting such a connection is lost. We will use on HAProxy1 tcp mode, and on HAProxy2 http mode.

Configuration for HAProxy1 ( Example # 6 ):

frontend https_frontend
bind *: 443
mode tcp
use_backend https_web

backend https_web
mode tcp
option ssl-hello-chk
server haproxy2 1.1.1.1:443

The configuration for HAProxy2 will be identical to the configuration in example No. 3

It is time to add the second part of the servers:


Configuration for HAProxy1 ( example number 7 ):

frontend https_frontend
bind *: 443
mode tcp
use_backend https_web

backend https_web
mode tcp
balance roundrobin
option ssl-hello-chk
server haproxy2 1.1.1.1:443 check
server haproxy3 3.3.3.3:443 check

All the difference of this example from the previous one is the presence of balancing and fault tolerance between HAProxy2 and HAProxy3, which, by our condition, must be located in different cities.

Well, the last example would be if there are non-signed certificates. Suppose they are installed on HAProxy servers - as in Example 4 :



The configuration for HAProxy1 will be as in the previous example, and for HAProxy2 - as in example 4 . Same for HAProxy3 with minor changes to real addresses in the frontend part.

It is also worth saying that all 3 HAProxy servers can be configured in TCP MODE - and this will also be a workable solution.

And finally, I would like to say: if someone knows some fundamentally different solutions for this task, I would be grateful if you share them.

A small update. It seemed to me here that if we forward traffic, then there is no need for us to use a set of different IP addresses on HAProxy2 and HAProxy3, it is much easier just to use different ports.
Let's consider the following scheme:


We have two different host sites in different cities. One is for HAProxy2 and the other is for HAProxy3. And the central proxy server, on which the task of balancing rests, while the sites www.mytest1.loc and www.mytest2.loc must be balanced, and the site www.mytest3.loc exists only on one site, therefore access to it should only be forwarded through proxy server. All sites must be accessible via both HTTP and HTTPS with non-signed certificates.
Configuration HAProxy1:
frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2
acl is_mytest3 hdr_end (host) -i mytest3.loc
use_backend mytest3_web if is_mytest3

backend mytest1_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb1 1.1.1.1:80 check cookie mytestweb1
server mytestweb1 2.2.2.2:80 check cookie mytestweb1

backend mytest2_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb2 1.1.1.1:80 check cookie mytestweb2
server mytestweb2 2.2.2.2:80 check cookie mytestweb2

backend mytest3_web
mode http
balance roundrobin
cookie SERVERID insert indirect nocache
server mytestweb3 2.2.2.2:80 check cookie mytestweb3

frontend mytest1_frontend
bind 3.3.3.3:443
mode tcp
use_backend mytest_webssl1

backend mytest_webssl1
mode tcp
balance roundrobin
option ssl-hello-chk
server mytestweb1 1.1.1.1 Down5551
server mytestweb2 2.2.2.2 Down5551

frontend mytest2_frontend
bind 4.4.4.4:443
mode tcp
use_backend mytest_webssl2

backend mytest_webssl2
mode tcp
balance roundrobin
option ssl-hello-chk
server mytestweb1 1.1.1.1 Down5552
server mytestweb2 2.2.2.2 Down5552

frontend mytest3_frontend
bind 5.5.5.5:443
mode tcp
use_backend mytest_webssl3

backend mytest_webssl3
mode tcp
balance roundrobin
option ssl-hello-chk
server mytestweb2 2.2.2.2 Down5553

And the HAProxy3 configuration:

frontend http_frontend
bind *: 80
mode http
option httpclose
acl is_mytest1 hdr_end (host) -i mytest1.loc
use_backend mytest1_web if is_mytest1
acl is_mytest2 hdr_end (host) -i mytest2.loc
use_backend mytest2_web if is_mytest2
acl is_mytest3 hdr_end (host) -i mytest3.loc
use_backend mytest3_web if is_mytest3

frontend mytest1_frontend
bind 2.2.2.2 ro5551 ssl crt /etc/ssl/mytest1.loc.pem
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto: \ https
use_backend mytest1_web

frontend mytest2_frontend
bind 2.2.2.2 bn5552 ssl crt /etc/ssl/mytest2.loc.pem
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto: \ https
use_backend mytest2_web

frontend mytest3_frontend
bind 2.2.2.2 ro5553 ssl crt /etc/ssl/mytest3.loc.pem
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto: \ https
use_backend mytest3_web

backend mytest1_web
mode http
balance roundrobin
stats enable
cookie SERVERID insert indirect nocache
server mytestweb1 192.168.1.5:80 check cookie mytestweb1

backend mytest2_web
mode http
balance roundrobin
stats enable
cookie SERVERID insert indirect nocache
server mytestweb2 192.168.1.10:80 check cookie mytestweb2

backend mytest3_web
mode http
balance roundrobin
stats enable
cookie SERVERID insert indirect nocache
server mytestweb3 192.168.1.15:80 check cookie mytestweb3

Source: https://habr.com/ru/post/244027/


All Articles