HAProxy https configuration, four-tier load balancing, and access control for load balancing services

In the previous section, we talked about the configuration of haproxy's access control ACL. For a review, please refer to https://www.cnblogs.com/qiuhom-1874/p/12817773.html ; Today let's talk about the configuration of haproxy's https, tcp-based four-tier load balancing, and access control.

First let's look at the configuration of haproxy's https; what HTTPS are I won't go into much detail here. Please refer to the instructions for Certificate Application https://www.cnblogs.com/qiuhom-1874/p/12237944.html ; in the haproxy configuration file, we explicitly state that we listen on a port that requires ssl protocol access, similar to listen 443 in nginxSSL configuration; in addition to crt, we need to specify the certificate; unlike nginx, haproxy's certificate content contains private key information; so after we apply for the certificate, we need to merge the certificate file content with the private key file;

Example: Configure haproxy to listen on port 443 and support https

Tip: The contents in the red box indicate listening on port 443 and explicitly specify access using SSL protocol; the certificate file is/etc/haproxy/ssl/haproxy.pem

Create ssl directory and certificate file

[root@docker_node1 ~]# mkdir -p /etc/haproxy/ssl
[root@docker_node1 ~]# cd /etc/haproxy/ssl
[root@docker_node1 ssl]# ls
[root@docker_node1 ssl]# (umask 066;openssl genrsa -out haproxy.key 2048)
Generating RSA private key, 2048 bit long modulus
.......+++
...+++
e is 65537 (0x10001)
[root@docker_node1 ssl]# ls
haproxy.key
[root@docker_node1 ssl]# openssl req -new -x509 -key haproxy.key -out haproxy.crt -subj "/CN=www.test.com"
[root@docker_node1 ssl]# ls
haproxy.crt  haproxy.key
[root@docker_node1 ssl]# cat haproxy.crt haproxy.key > haproxy.pem
[root@docker_node1 ssl]# ls
haproxy.crt  haproxy.key  haproxy.pem
[root@docker_node1 ssl]# openssl  x509 -in haproxy.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            e6:c5:30:f9:10:e5:da:cf
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=www.test.com
        Validity
            Not Before: May  2 14:41:50 2020 GMT
            Not After : Jun  1 14:41:50 2020 GMT
        Subject: CN=www.test.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e6:bd:db:2d:37:1e:b3:26:21:45:37:c3:bc:c2:
                    f8:f0:35:31:7c:af:f4:22:be:bc:f2:01:a1:ce:31:
                    32:91:37:06:14:a8:eb:ec:99:30:ae:8f:66:6b:51:
                    03:94:bb:d1:ae:7d:15:23:ea:9a:83:74:6d:d0:be:
                    30:5d:bf:4c:dd:79:c6:8d:51:01:ea:d7:a8:e5:93:
                    f9:11:d9:75:cc:2c:65:d6:31:db:15:20:7f:5e:9f:
                    56:15:3e:17:b9:82:a8:25:ba:40:17:1c:ef:f2:fc:
                    11:cb:72:ce:07:5b:57:5d:c3:f1:f6:42:1f:02:63:
                    b0:33:de:87:a3:43:c7:a0:1b:03:c4:ab:09:f4:67:
                    ce:ec:ef:1f:88:7a:c2:aa:ca:41:ed:1d:78:60:b1:
                    41:6d:b9:46:67:1e:c9:ce:43:d8:d6:36:be:ba:ed:
                    d9:2b:01:9a:0c:8e:64:59:07:3a:c2:2c:55:2b:9b:
                    06:e5:5b:c7:ba:e2:9f:ea:be:71:9f:76:da:79:c6:
                    f0:b8:94:70:c0:4f:7b:57:53:5c:30:71:c5:82:d0:
                    7a:a8:d0:71:32:2c:f0:38:61:69:9b:9e:ac:da:45:
                    74:63:25:76:78:91:c3:be:6c:7c:72:1c:54:4a:ac:
                    10:24:45:9c:89:6a:1f:5b:00:22:3a:b6:fe:3f:b8:
                    73:7b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                B2:EC:53:AE:68:E0:65:1D:E6:DB:C8:16:E3:BA:D3:70:BC:E7:79:81
            X509v3 Authority Key Identifier: 
                keyid:B2:EC:53:AE:68:E0:65:1D:E6:DB:C8:16:E3:BA:D3:70:BC:E7:79:81

            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         91:a2:36:9b:b8:d3:fd:89:ea:6c:b4:b9:3c:b6:a1:f3:86:87:
         71:13:8b:10:a0:73:e9:96:b7:1b:dd:7e:91:64:41:a4:c3:80:
         7c:b6:f2:ce:a7:77:28:74:51:da:a6:52:98:a7:88:48:41:2f:
         ad:3d:cb:36:bd:94:f9:27:72:f1:e8:ae:f8:bd:38:2e:d6:ea:
         0b:26:2d:8b:49:3e:bc:4e:58:9e:bf:79:99:5b:88:23:da:98:
         e4:45:79:9c:d2:c9:05:05:9f:23:8a:0f:38:db:9a:c4:5c:e9:
         a0:f5:e5:aa:02:bc:df:a7:5d:11:cd:35:08:cc:41:08:40:b6:
         0b:e4:ad:79:df:9a:1d:7b:70:8b:65:e5:dc:85:34:55:5c:f2:
         94:dc:07:91:43:d0:bb:b4:fb:31:b9:74:19:7a:69:43:11:70:
         41:41:86:93:ad:83:42:62:e2:67:69:38:cd:18:c7:e9:f7:f4:
         be:78:22:ea:ee:20:db:27:1f:06:87:4c:51:67:19:0a:64:97:
         3a:e6:2c:32:bd:84:91:88:96:d2:01:e5:c3:62:59:11:c8:20:
         7d:a1:c8:5a:3d:8a:fc:f5:14:fe:41:15:97:ee:47:ec:e5:19:
         49:0b:c1:8a:c9:3f:10:4d:66:bf:d5:01:21:2d:fd:8b:a7:95:
         17:08:7e:46
[root@docker_node1 ssl]# 

Tip: I will use -subj directly to specify certificate/CN to generate self-signed certificate; haproxy's certificate requires that certificate information and private key information be combined together, so we need to merge certificate file information with new private key information by redirection;

Testing: Restart haproxy for browser access

Tip: You can see that our access with https is normal, but the certificate browser does not trust it, so we will be prompted that it is not safe;

* Redirect request for port 80 to fixed 443

Tip: The configuration in the red box indicates that the http request is redirected to https, which is similar to the rewritten url in nginx;

Testing: Visit http://192.168.0.22 in your browser to see if you want to rewrite HTTP as https?

Tip: You can see that our access is accessed using http, and in the response message the browser is told to access https://192.168.0.22 using location; this enables the full site of https;

Pass user-requested protocols and ports (frontend or backend) to back-end

Tip: The content in the red box means setting the value of the dst_port variable in the X-Forwarded-port header in the request message to the back end; adding the X-Forwarded-Proto header with the value of HTTPS when the request protocol is https; these two settings are usually required for the front end HTTPS requests to be passed to the back end through X-Forwarded-Proto when the back end application server requires HTTPS access;

Testing: Configure the log format on the back-end server, log these two headers separately, and then access to see if the values recorded in the log for these two headers are the 443 port and https protocol we visited?

Tip: Define the httpd log format above to record the values at the beginning of {X-Forwarded-Port and X-Forwared-Proto, respectively

Use a browser to access the test and see the information recorded in the log

Tip: You can see that the corresponding access port and protocol are passed to the back-end server in the log.

haproxy does tcp load balancing based on 4-tier proxy

Example: Load balancing mysql based on tcp

Tip: The above configuration indicates that tcp protocol is used to proxy back-end server;

Backend server environment preparation

[root@docker_node1 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
wordpress           latest              c3fa1c8546fb        44 hours ago        540MB
mysql               5.7                 f965319e89de        4 days ago          448MB
httpd               2.4.37-alpine       dfd436f9a5d8        16 months ago       91.8MB
[root@docker_node1 ~]# docker run --name db1 -d --net bridge -e MYSQL_ROOT_PASSWORD=admin mysql:5.7
8cade03e4f28f40e7d7e970355735c8b881892754b18a637fef0d956f3f88877
[root@docker_node1 ~]# docker run --name db2 -d --net bridge -e MYSQL_ROOT_PASSWORD=admin mysql:5.7 
1bff841c226abe88441103764655dc86257d5b99079eaa113384fd04b62cf0f8
[root@docker_node1 ~]# docker ps 
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                 NAMES
1bff841c226a        mysql:5.7             "docker-entrypoint.s..."   7 seconds ago       Up 6 seconds        3306/tcp, 33060/tcp   db2
8cade03e4f28        mysql:5.7             "docker-entrypoint.s..."   12 seconds ago      Up 12 seconds       3306/tcp, 33060/tcp   db1
3572c621f827        wordpress             "docker-entrypoint.s..."   9 hours ago         Up 9 hours          80/tcp                wordpress
f07288d607e5        httpd:2.4.37-alpine   "httpd-foreground"       7 days ago          Up 13 hours         80/tcp                web3
971595b7f409        httpd:2.4.37-alpine   "httpd-foreground"       7 days ago          Up 13 hours         80/tcp                web2
5c74f3be1868        httpd:2.4.37-alpine   "httpd-foreground"       7 days ago          Up 13 hours         80/tcp                web1
[root@docker_node1 ~]# docker exec -it db1 /bin/sh
# mysql -padmin
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.30 MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> grant all on *.* to "myuser"@'172.17.0.%' identified by 'admin';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> \q
Bye
# exit
[root@docker_node1 ~]# docker exec -it db2 /bin/sh
# mysql -padmin
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.30 MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> grant all on *.* to "myuser"@'172.17.0.%' identified by 'admin';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> \q
Bye
# exit
[root@docker_node1 ~]# 

Tip: When starting the mysql container, we need to set a password for the root; when creating a new user, the host IP address we specify should be the address of the docker0 bridge, although it is based on a 4-tier tcp proxy, it still needs to change the source ip;

Testing: Restart haproxy and use the mysql client to access port 3306 that haproxy listens on to see if it can properly connect to the back-end mysql container?

Tip: You can see that mysql clients on other hosts can normally access port 3306 that haproxy listens on;

haproxy does access control based on 4-tier tcp

Tip: tcp-request connection indicates that incoming connections are operated upon according to Layer 4 conditions; the above configuration denies connections with source address 192.168.0.21

Testing: Restart haproxy and connect 192.168.0.22:3306 using the mysql client on 192.168.0.21 to see if it works?

Tip: You can see that mysql on 192.168.0.21 cannot be connected with the mysql tool on 192.168.0.22;

Example: only host access with open source address 192.168.0.21, deny access to other hosts

Tip: tcp-request connection allows access to be identified by accept and rejects by reject; if it is used in combination, all entries except ACL entries matched above can be represented without writing conditions; unlike http-request, HTTP-request allows access to be identified by allow and deny is rejected;

Testing: Connect mysql client on host with source address 192.168.0.21 to mysql client on 192.168.0.22 and mysql client on source address other than 192.168.0.21 to see if they can connect?

Tip: You can see that using the mysql client at the source address other than 192.168.0.21 cannot connect to the backend mysql container; this is because it is not matched by the ACL we defined, so it will be matched by tcp-request connect reject; thus, the connection will be rejected;

Last topic, we talked about the configuration of the status page of haproxy in the previous blog; in which we demonstrated how to manage the back-end server by clicking on the mouse through the page; this is a challenge for us to monitor haproxy itself and the back-end server; smart you must have noticed that there is an s in the global configuration section of haproxyConfigurations such as Tat socket/var/lib/haproxy/stats; let's move on to what this configuration is for;

Tip: The above configuration means binding monitoring page information to a socket file; we can achieve the purpose of haproxy by sending specific instructions to the socket file

Example: Pass help information to/var/lib/haproxy/stats via socat and have them print help pages

[root@docker_node1 ~]# echo "help"|socat stdio /var/lib/haproxy/stats 
Unknown command. Please enter one of the following commands only :
  clear counters : clear max statistics counters (add 'all' for all counters)
  clear table    : remove an entry from a table
  help           : this message
  prompt         : toggle interactive mode with prompt
  quit           : disconnect
  show info      : report information about the running process
  show pools     : report information about the memory pools usage
  show stat      : report counters for each proxy and server
  show errors    : report last request and response errors for each proxy
  show sess [id] : report the list of current sessions or dump this session
  show table [id]: report table usage stats or dump this table's contents
  get weight     : report a server's current weight
  set weight     : change a server's weight
  set server     : change a server's state or weight
  set table [id] : update or create a table entry's data
  set timeout    : change a timeout setting
  set maxconn    : change a maxconn setting
  set rate-limit : change a rate limiting value
  disable        : put a server or frontend in maintenance mode
  enable         : re-enable a server or frontend which is in maintenance mode
  shutdown       : kill a session or a frontend (eg:to release listening ports)
  show acl [id]  : report available acls or dump an acl's contents
  get acl        : reports the patterns matching a sample for an ACL
  add acl        : add acl entry
  del acl        : delete acl entry
  clear acl <id> : clear the content of this acl
  show map [id]  : report available maps or dump a map's contents
  get map        : reports the keys and values matching a sample for a map
  set map        : modify map entry
  add map        : add map entry
  del map        : delete map entry
  clear map <id> : clear the content of this map
  set ssl <stmt> : set statement for ssl

[root@docker_node1 ~]# 

Tip: From the help information above, we can see that we can manage the backend server by piping the corresponding instructions to the / var/lib/haproxy/stats file.

Example: Mark web1 disable d with the socat command

Tip: We executed marking web1 disable, which prompted us that we do not have permissions; let's configure the permissions next

Tip: The above configuration indicates that the socket file has admin privileges. Next, mark web1 disable (modifying the haproxy configuration file requires restarting haproxy)

Tip: After we modified the permissions, there are no permissions reported and other errors when we execute the above command. Next, we open the status page to see what the status of web1 is.

Tip: You can see that web1 has become a maintenance mode;

Example: List information for monitoring page indicator data

[root@docker_node1 ~]# echo "show info " |socat stdio /var/lib/haproxy/stats
Name: HAProxy
Version: 1.5.18
Release_date: 2016/05/10
Nbproc: 4
Process_num: 3
Pid: 6374
Uptime: 0d 0h05m04s
Uptime_sec: 304
Memmax_MB: 0
Ulimit-n: 8039
Maxsock: 8039
Maxconn: 4000
Hard_maxconn: 4000
CurrConns: 0
CumConns: 3
CumReq: 10
MaxSslConns: 0
CurrSslConns: 0
CumSslConns: 0
Maxpipes: 0
PipesUsed: 0
PipesFree: 0
ConnRate: 0
ConnRateLimit: 0
MaxConnRate: 1
SessRate: 0
SessRateLimit: 0
MaxSessRate: 1
SslRate: 0
SslRateLimit: 0
MaxSslRate: 0
SslFrontendKeyRate: 0
SslFrontendMaxKeyRate: 0
SslFrontendSessionReuse_pct: 0
SslBackendKeyRate: 0
SslBackendMaxKeyRate: 0
SslCacheLookups: 0
SslCacheMisses: 0
CompressBpsIn: 0
CompressBpsOut: 0
CompressBpsRateLim: 0
ZlibMemUsage: 0
MaxZlibMemUsage: 0
Tasks: 14
Run_queue: 1
Idle_pct: 100
node: docker_node1
description: 

[root@docker_node1 ~]# 

Tip: The above information is the indicator data in the monitoring page;

Example: online web1

View the status of web1 on the Monitor page

Tip: You can see that web1 is online normally; smart enough, you must have thought of dynamically managing the back-end server in this way; so you can achieve many functions, such as monitoring status indicators in haproxy through zabbix; dynamically uploading and downloading servers through scripts; dynamically modifying the weight of back-end servers (this needs to be done according to the algorithm, ifScheduling algorithms are supported dynamically but not statically;

Keywords: Linux MySQL SSL Docker Oracle

Added by amandas on Sun, 03 May 2020 09:12:33 +0300