ProxySQL支持白名单(white list)和黑名单(black list), 其支持方式还是通过路由规则来实现的。它强悍的路由功能似乎无所不能啊!但这种方式并不能阻止用户连接,只是阻止任何的查询!

黑名单

对黑名单的支持很简单,比如我们想禁止某个IP访问只需在mysql_query_rules里面插入一条记录。

1
2
insert into mysql_query_rules (rule_id,active,client_addr,error_msg,apply)values(3,1,'192.168.216.146','this ip is banned!',1);
load mysql query rules to run;

这样IP192.168.216.146 依然可以连接,但不能做任何的查询!

1
2
mysql> select * from sbtest1 limit 2;
ERROR 1148 (42000): this ip is banned!

白名单

对白名单的支持就有些复杂了。因为白名单有许多,应用端往往同一个服务会部署多个副本,我们数据库端为每个服务创建一个账号,在指定规则的时候,需要绑定mysql_query_rules.usernamemysql_query_rules.client_addr, 这样只有username,client_addr以及我们的路由规则都匹配的时候才算匹配。这会导致同一条规则会有多条记录因为client_addr不同。 若在mysql_query_rules中匹配不到任何规则,则会走该用户所定义的default_hostgroup。这达不到黑名单的目的。因此我们需要定义一个rule_id很大的规则,批量任何的SQL,然后设定一个error_msg予以禁止。这样才能达到目的。
这会给规则表的维护带来困难!

另一种比较好的办法是使用规则链(chained rules),这可以使得mysql_query_rules表不那么乱。下面详细说下这种方式。

  1. 插入一条规则匹配所有的SQL,指定白名单IP(白名单过滤规则)
    1
    insert into mysql_query_rules (rule_id,active,client_addr,match_digest,flagOUT,apply)values(5,1,'192.168.216.146','.',10,0);

注意,这条规则的rule_id应该是比较小的值,确保所有SQL匹配都用到;这条规则指定了flagOUT=10,apply=0,在得到匹配后,并不应用,而是继续匹配下一条规则(flagIN=10的规则)。

  1. 将其它所有可用的SQL匹配规则的flagIN设为10,以承接白名单过滤的路由规则。
  2. 插入一条禁止所有SQL的规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    insert into mysql_query_rules (rule_id,active,match_digest,error_msg,apply)values(100000,1,'.','Access banned, maybe your IP is not allowed to do this',1');

    mysql> select rule_id, active, flagIN,flagOUT,client_addr,match_digest,error_msg,apply from runtime_mysql_query_rules;
    +---------+--------+--------+---------+-----------------+----------------------+--------------------------------------------------------+-------+
    | rule_id | active | flagIN | flagOUT | client_addr | match_digest | error_msg | apply |
    +---------+--------+--------+---------+-----------------+----------------------+--------------------------------------------------------+-------+
    | 10 | 1 | 0 | 10 | 192.168.216.146 | . | NULL | 0 |
    | 20 | 1 | 10 | NULL | NULL | ^SELECT.*FOR UPDATE$ | NULL | 1 |
    | 30 | 1 | 10 | NULL | NULL | ^SELECT | NULL | 1 |
    | 100000 | 1 | 0 | NULL | NULL | . | Access banned, maybe your IP is not allowed to do this | 1 |
    +---------+--------+--------+---------+-----------------+----------------------+--------------------------------------------------------+-------+
    5 rows in set (0.00 sec)

即,如果在规则表中没有匹配到任何规则,则禁止走该用户默认的hostgroup。注意,这条规则的rule_id应该最大,之后不应该再有其它规则!

这种方式的特点是,规则表不太乱,有几个白名单,就插入几条白名单过滤规则就行了,实用性较强!但它也带来了一定的维护的难度,如在白名单上使用了链式路由规则,如果再有其它的需求需要使用链式路由规则呢?整个规则链就要统一调整,而且这种需求很难提前规划。