Details
-
New Feature
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
2.3.7
-
None
Description
I was told by the MaxScale team that MaxScale should skip authenticating clients locally when proxy_protocol=on is set for the backend servers.
The documentation doesn't seem to imply that this should be supported. The documentation seems to say that the proxy protocol is mostly intended to make user account management easier. Since the proxy protocol passes the original client IP address to the backend server in the proxy protocol header, the backend server isn't required to have user accounts for the specific user that resolve to both the client IP and the MaxScale IP. The user account just needs to resolve to the original client IP address.
https://mariadb.com/kb/en/library/proxy-protocol-support/
To confirm whether MaxScale skips authenticating clients locally when proxy_protocol=on is set for the backend servers, I ran a test.
I ran the test with the following:
1 MaxScale server running MaxScale 2.3.7
3 backend Galera nodes running a mixture of MariaDB 10.3.14 and 10.3.15
On the backend Galera nodes, I set proxy_protocol_networks to the IP address of the MaxScale server:
MariaDB [(none)]> SET GLOBAL proxy_protocol_networks='172.30.0.106';
|
Query OK, 0 rows affected (0.000 sec)
|
On the MaxScale server, I used the following configuration:
[maxscale]
|
threads=4
|
syslog=1
|
maxlog=1
|
log_warning=1
|
log_notice=1
|
log_info=1
|
admin_host=127.0.0.1
|
admin_port=8989
|
admin_auth=1
|
admin_enabled=1
|
connector_plugindir=/usr/lib64/mysql/plugin/
|
|
[C1N1]
|
type=server
|
address=172.30.0.105
|
port=3306
|
protocol=MariaDBBackend
|
authenticator=PAMBackendAuth
|
proxy_protocol=on
|
|
[C1N2]
|
type=server
|
address=172.30.0.96
|
port=3306
|
protocol=MariaDBBackend
|
authenticator=PAMBackendAuth
|
proxy_protocol=on
|
|
[C1N3]
|
type=server
|
address=172.30.0.126
|
port=3306
|
protocol=MariaDBBackend
|
authenticator=PAMBackendAuth
|
proxy_protocol=on
|
|
[Galera-Monitor]
|
type=monitor
|
module=galeramon
|
servers=C1N1,
|
C1N2,
|
C1N3
|
user=maxscale
|
password=password
|
monitor_interval=10000
|
|
[Read-Listener]
|
type=listener
|
service=Splitter-Service
|
port=3306
|
protocol=MariaDBClient
|
authenticator=PAMAuth
|
|
[Splitter-Service]
|
type=service
|
router=readwritesplit
|
servers=C1N1,
|
C1N2,
|
C1N3
|
user=maxscale
|
password=password
|
max_slave_connections=100%
|
The specific user account involved uses PAM authentication, so I also needed to create the Unix user on the MaxScale instance, and all 3 backend nodes:
sudo adduser alice
|
sudo passwd alice
|
I also wanted to make sure that PAM authentication attempts are very thoroughly logged, so I followed these steps:
https://mariadb.com/kb/en/library/authentication-plugin-pam/#custom-logging-with-pam_exec
i.e. I created the following script:
tee /tmp/pam_log_script.sh <<EOF
|
#!/bin/bash
|
echo "\${PAM_SERVICE}:\${PAM_TYPE} - \${PAM_RUSER}@\${PAM_RHOST} is authenticating as \${PAM_USER}"
|
EOF
|
chmod 0775 /tmp/pam_log_script.sh
|
And then used the following PAM service configuration in /etc/pam.d/mariadb:
auth optional pam_exec.so log=/tmp/pam_output.txt /tmp/pam_log_script.sh
|
auth required pam_unix.so audit
|
account optional pam_exec.so log=/tmp/pam_output.txt /tmp/pam_log_script.sh
|
account required pam_unix.so audit
|
And I created the following user on the backend nodes:
CREATE USER 'alice'@'%' IDENTIFIED VIA pam USING 'mariadb';
|
GRANT SELECT ON *.* TO 'alice'@'%';
|
Then I logged in through MaxScale:
$ mysql -u alice -h 127.0.0.1
|
[mariadb] Password:
|
Welcome to the MariaDB monitor. Commands end with ; or \g.
|
Your MariaDB connection id is 3
|
Server version: 10.3.14-MariaDB-log MariaDB Server
|
|
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
|
|
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
|
MariaDB [(none)]> SELECT USER(), CURRENT_USER();
|
+-----------------+----------------+
|
| USER() | CURRENT_USER() |
|
+-----------------+----------------+
|
| alice@localhost | alice@% |
|
+-----------------+----------------+
|
1 row in set (0.001 sec)
|
|
MariaDB [(none)]> \q
|
Bye
|
The MaxScale log shows that the MaxScale server is properly sending the proxy protocol headers to the backend servers:
2019-05-21 21:55:56 info : Found 1 valid PAM user entry for 'alice'@'::ffff:127.0.0.1'.
|
2019-05-21 21:55:56 info : Servers and router connection counts:
|
2019-05-21 21:55:56 info : current operations : 0 in [172.30.0.105]:3306 RUNNING SLAVE
|
2019-05-21 21:55:56 info : current operations : 0 in [172.30.0.96]:3306 RUNNING MASTER
|
2019-05-21 21:55:56 info : current operations : 0 in [172.30.0.126]:3306 RUNNING SLAVE
|
2019-05-21 21:55:56 info : Selected Master: C1N2
|
2019-05-21 21:55:56 info : Selected Slave: C1N1
|
2019-05-21 21:55:56 info : Selected Slave: C1N3
|
2019-05-21 21:55:56 info : Started Splitter-Service client session [3] for 'alice' from ::ffff:127.0.0.1
|
2019-05-21 21:55:56 info : (3) Sending proxy-protocol header 'PROXY TCP6 ::ffff:127.0.0.1 ::ffff:127.0.0.1 34473 3306^M
|
' to backend C1N3.
|
2019-05-21 21:55:56 info : (3) Connected to 'C1N3' with thread id 21
|
2019-05-21 21:55:56 info : (3) Sending proxy-protocol header 'PROXY TCP6 ::ffff:127.0.0.1 ::ffff:127.0.0.1 34473 3306^M
|
' to backend C1N1.
|
2019-05-21 21:55:56 info : (3) Connected to 'C1N1' with thread id 28
|
2019-05-21 21:55:56 info : (3) > Autocommit: [enabled], trx is [not open], cmd: (0x03) COM_QUERY, plen: 37, type: QUERY_TYPE_READ|QUERY_TYPE_SYSVAR_READ, stmt: select @@version_comment limit 1
|
2019-05-21 21:55:56 info : (3) Route query to slave: C1N1 [172.30.0.105]:3306 <
|
2019-05-21 21:55:56 info : (3) Sending proxy-protocol header 'PROXY TCP6 ::ffff:127.0.0.1 ::ffff:127.0.0.1 34473 3306^M
|
' to backend C1N2.
|
2019-05-21 21:55:56 info : (3) Connected to 'C1N2' with thread id 21
|
2019-05-21 21:55:56 info : (3) Reply complete, last reply from C1N1
|
2019-05-21 21:55:59 info : (3) > Autocommit: [enabled], trx is [not open], cmd: (0x03) COM_QUERY, plen: 34, type: QUERY_TYPE_READ, stmt: SELECT USER(), CURRENT_USER()
|
2019-05-21 21:55:59 info : (3) Route query to slave: C1N1 [172.30.0.105]:3306 <
|
2019-05-21 21:55:59 info : (3) Reply complete, last reply from C1N1
|
2019-05-21 21:56:00 info : (3) > Autocommit: [enabled], trx is [not open], cmd: (0x01) COM_QUIT, plen: 5, type: QUERY_TYPE_SESSION_WRITE, stmt:
|
2019-05-21 21:56:00 info : (3) Session write, routing to all servers.
|
2019-05-21 21:56:00 info : (3) Route query to slave: C1N1 [172.30.0.105]:3306
|
2019-05-21 21:56:00 info : (3) Route query to master: C1N2 [172.30.0.96]:3306
|
2019-05-21 21:56:00 info : (3) Route query to slave: C1N3 [172.30.0.126]:3306
|
2019-05-21 21:56:00 info : Stopped Splitter-Service client session [3]
|
However, when I check /tmp/pam_output.txt on the MaxScale instance, it is clear that MaxScale's PAMAuth authenticator module is still authenticating the client locally as well:
*** Tue May 21 21:55:56 2019
|
mariadb:auth - @ is authenticating as alice
|
*** Tue May 21 21:55:56 2019
|
mariadb:account - @ is authenticating as alice
|
This makes sense to me, because I checked the source code, and I did not find any indication that setting proxy_protocol=on for a server gets rid of the local authentication step that MaxScale performs.
proxy_protocol isn't checked before calling gw_read_do_authentication:
And proxy_protocol isn't checked within gw_read_do_authentication:
And it still calls the authenticate() function for the authenticator module:
And the function that's called for PAMAuth doesn't seem to take any shortcuts if proxy_protocol is defined either:
Is this working as-intended, or is MaxScale actually supposed to skip the local authentication step when the proxy protocol is used with the backend servers?