diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 03e8dc00c..c71fffdc9 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -1073,23 +1073,36 @@ closed. For more information about persistent connections, please read the [Administration Tutorial](../Tutorials/Administration-Tutorial.md). -#### `use_proxy_protocol` +#### `proxy_protocol` -If `use_proxy_protocol` is set to `yes`, MaxScale will send a proxy protocol +If `proxy_protocol` is set to `on`, MaxScale will send a +[PROXY protocol](http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) header when connecting client sessions to the server. The header contains the original client IP address and port, as seen by MaxScale. The server will then read the header and perform authentication as if the connection originated from -this address instead of the MaxScale IP address. With this feature, the user +this address instead of MaxScale's IP address. With this feature, the user accounts on the backend server can be simplified to only contain the actual client hosts and not the MaxScale host. -Currently, using this feature is unpractical due to the restrictiveness of the -proxy protocol. The protocol requires that *all* connections from proxy enabled -addresses must send a valid proxy header. MaxScale has other connections to the -servers in addition to client sessions, e.g. monitors, and the server will -refuse these due to the lack of the header. To bypass this restriction, the -server monitor needs to be disabled and the service listener needs to be +PROXY protocol will be supported by MariaDB 10.3, which this feature has been +tested with. To use it, enable the PROXY protocol in MaxScale for every +compatible server and configure the MariaDB servers themselves to accept the +protocol headers from MaxScale's IP address. On the server side, the protocol +should be enabled only for trusted IPs, as it allows the sender to spoof the +connection origin. If a proxy header is sent to a server not expecting it, the +connection will fail. Usually PROXY protocol should be enabled for every +server in a cluster, as they typically have similar grants. + +Other SQL-servers may support PROXY protocol as well, but the implementation may +be highly restricting. Strict adherence to the protocol requires that the +backend server does not allow mixing of un-proxied and proxied connections from +a given IP. MaxScale requires normal connections to backends for monitoring and +authentication data queries, which would be blocked. To bypass this restriction, +the server monitor needs to be disabled and the service listener needs to be configured to disregard authentication errors (`skip_authentication=true`). +Server states also need to be set manually in MaxAdmin. These steps are *not* +required for MariaDB 10.3, since its implementation is more flexible and allows +both PROXY-headered and headerless connections from a proxy-enabled IP. #### `authenticator` diff --git a/include/maxscale/server.h b/include/maxscale/server.h index 635958e10..9675c8008 100644 --- a/include/maxscale/server.h +++ b/include/maxscale/server.h @@ -39,7 +39,7 @@ extern const char CN_MONITORPW[]; extern const char CN_MONITORUSER[]; extern const char CN_PERSISTMAXTIME[]; extern const char CN_PERSISTPOOLMAX[]; -extern const char CN_USE_PROXY_PROTOCOL[]; +extern const char CN_PROXY_PROTOCOL[]; /** * The server parameters used for weighting routing decissions @@ -133,7 +133,7 @@ typedef struct server uint8_t charset; /**< Default server character set */ bool is_active; /**< Server is active and has not been "destroyed" */ bool created_online; /**< Whether this server was created after startup */ - bool use_proxy_protocol; /**< Send proxy-protocol header when connecting client sessions. */ + bool proxy_protocol; /**< Send proxy-protocol header to backend when connecting client sessions. */ #if defined(SS_DEBUG) skygw_chk_t server_chk_tail; #endif diff --git a/server/core/config.cc b/server/core/config.cc index 1b0f89d2d..90ec6962c 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -269,7 +269,7 @@ const char *server_params[] = CN_SSL_KEY, CN_SSL_VERSION, CN_SSL_CERT_VERIFY_DEPTH, - CN_USE_PROXY_PROTOCOL, + CN_PROXY_PROTOCOL, NULL }; @@ -2953,7 +2953,25 @@ int create_new_server(CONFIG_CONTEXT *obj) } } - server->use_proxy_protocol = config_get_bool(obj->parameters, CN_USE_PROXY_PROTOCOL); + const char* proxy_protocol = config_get_value_string(obj->parameters, CN_PROXY_PROTOCOL); + if (*proxy_protocol) + { + int truth_value = config_truth_value(proxy_protocol); + if (truth_value == 1) + { + server->proxy_protocol = true; + } + else if (truth_value == 0) + { + server->proxy_protocol = false; + } + else + { + MXS_ERROR("Invalid value for '%s' for server %s: %s", + CN_PROXY_PROTOCOL, server->unique_name, proxy_protocol); + error_count++; + } + } MXS_CONFIG_PARAMETER *params = obj->parameters; diff --git a/server/core/server.cc b/server/core/server.cc index ab2d6cde9..b549bab8f 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -56,7 +56,7 @@ const char CN_MONITORPW[] = "monitorpw"; const char CN_MONITORUSER[] = "monitoruser"; const char CN_PERSISTMAXTIME[] = "persistmaxtime"; const char CN_PERSISTPOOLMAX[] = "persistpoolmax"; -const char CN_USE_PROXY_PROTOCOL[] = "use_proxy_protocol"; +const char CN_PROXY_PROTOCOL[] = "proxy_protocol"; static SPINLOCK server_spin = SPINLOCK_INIT; static SERVER *allServers = NULL; @@ -141,7 +141,7 @@ SERVER* server_alloc(const char *name, const char *address, unsigned short port, server->is_active = true; server->created_online = false; server->charset = SERVER_DEFAULT_CHARSET; - server->use_proxy_protocol = false; + server->proxy_protocol = false; spinlock_acquire(&server_spin); server->next = allServers; @@ -570,9 +570,9 @@ dprintServer(DCB *dcb, const SERVER *server) dcb_printf(dcb, "\tSSL CA certificate: %s\n", l->ssl_ca_cert ? l->ssl_ca_cert : "null"); } - if (server->use_proxy_protocol) + if (server->proxy_protocol) { - dcb_printf(dcb, "\tProxy protocol enabled.\n"); + dcb_printf(dcb, "\tPROXY protocol: on.\n"); } } @@ -1173,9 +1173,9 @@ static bool create_server_config(const SERVER *server, const char *filename) dprintf(file, "%s=%ld\n", CN_PERSISTMAXTIME, server->persistmaxtime); } - if (server->use_proxy_protocol) + if (server->proxy_protocol) { - dprintf(file, "%s=yes\n", CN_USE_PROXY_PROTOCOL); + dprintf(file, "%s=on\n", CN_PROXY_PROTOCOL); } for (SERVER_PARAM *p = server->parameters; p; p = p->next) diff --git a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c index 0c3a17c5c..6d23b21e6 100644 --- a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c +++ b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c @@ -198,7 +198,7 @@ static int gw_create_backend_connection(DCB *backend_dcb, protocol->fd, session->client_dcb->fd); - if (server->use_proxy_protocol) + if (server->proxy_protocol) { gw_send_proxy_protocol_header(backend_dcb); } @@ -919,7 +919,7 @@ static int gw_write_backend_event(DCB *dcb) if (backend_protocol->protocol_auth_state == MXS_AUTH_STATE_PENDING_CONNECT) { backend_protocol->protocol_auth_state = MXS_AUTH_STATE_CONNECTED; - if (dcb->server->use_proxy_protocol) + if (dcb->server->proxy_protocol) { gw_send_proxy_protocol_header(dcb); } @@ -1906,6 +1906,8 @@ static void gw_send_proxy_protocol_header(DCB *backend_dcb) GWBUF *headerbuf = gwbuf_alloc_and_load(strlen(proxy_header), proxy_header); if (headerbuf) { + MXS_INFO("Sending proxy-protocol header '%s' to backend %s.", proxy_header, + backend_dcb->server->unique_name); if (!dcb_write(backend_dcb, headerbuf)) { gwbuf_free(headerbuf);