【MySQL 8.0】搭建一个使用 SSL 加密的 MySQL 主从复制拓扑(基于 Binlog 行复制)

之前,我们一起搭建了一个极简 MySQL 主从复制拓扑(基于 Binlog 行复制),这是一个不安全的复制拓扑,优点是性能高。生产环境中核心数据库系统的首要任务是安全、稳定,其次才是性能,这叫做关键任务型(Mission-Critical)应用程序。这也是 Oracle 、DB2、MS SQL Server 三家曾经为什么能近乎垄断全球数据库生产环境市场的原因。

笔者最初是因为测试 Mycat2 而搭建了一个使用 SSL 加密的复制拓扑,没有采用 Mycat2 建议的非安全的复制拓扑。在调试成功后,又搭建了非安全的复制拓扑。

下面来一起学习一下如何搭建一个安全的MySQL 主从复制拓扑吧!


先决条件

  • 源(或主)主服务器开启 SSL 加密连接。
  • (建议)在副本(或从)服务器配置复制通道时必须使用 SSL 连接。
  • 配置复制源时必须设置 SOURCE_SSL=1 才能使用 SOURCE_SSL_CASOURCE_SSL_CAPATH(不建议使用) 、SOURCE_SSL_CERTSOURCE_SSL_KEY 这些参数。
  • 非安全的复制拓扑的先决条件要求。

搭建

配置源、副本服务器选项文件

即配置主、从服务器选项文件。

Source 服务器 /etc/my.cnf 配置如下:

[mysqld@mycat]
log_timestamps=SYSTEM
port=3307
socket=/var/lib/mysql/mycat/mysql.sock
tmpdir=/tmp
datadir=/var/lib/mysql/mycat
log_bin=bin-mycat.log
lower_case_table_names=1

log-error=/var/log/mysqld-mycat.log
slow-query-log-file=/var/log/mysqld_mycat-slow.log
pid-file=/var/run/mysqld/mysqld-mycat.pid

innodb_buffer_pool_size=128M
innodb_redo_log_capacity=100M
innodb_flush_log_at_trx_commit=1
sync_binlog=1

#replication for mycat
server_id=1
##SSL authority
ssl_ca=ca.pem
ssl_cert=server-cert.pem
ssl_key=server-key.pem
#require_secure_transport=ON

Replica 服务器 /etc/my.cnf 配置如下:

[mysqld@mycat]
log_timestamps=SYSTEM
port=3307
socket=/var/lib/mysql/mycat/mysql.sock
tmpdir=/tmp
datadir=/var/lib/mysql/mycat
log_bin=bin-mycat.log
lower_case_table_names=1

log-error=/var/log/mysqld-mycat.log
slow-query-log-file=/var/log/mysqld_mycat-slow.log
pid-file=/var/run/mysqld/mysqld-mycat.pid

innodb_buffer_pool_size=128M
innodb_redo_log_capacity=100M
innodb_flush_log_at_trx_commit=1
sync_binlog=1

#replication for mycat
server_id=2

配置完成后分别启动两个 MySQL 实例。

验证启用了 SSL 连接

使用 mysql 连接到 Source 服务器验证:

mysql> \s

出现 SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 即证明使用了 SSL 加密连接。

在这里插入图片描述

虽然已经证明使用了 SSL 加密连接,但因为默认的 --ssl-mode=PREFERRED ,没有进行证书验证,无法防止中间人攻击(Man-in-the-middle Attacks)。所以,下面我们再使用 --ssl-mode=VERIFY_CA 验证一下。

先复制 Source 服务器上的 datadir 数据目录中的 ca.pemclient-cert.pemclient-key.pem 到 Replica 服务器上。

[root@ic-source mycat]$ scp ca.pem client-*.pem replica1:/usr/local/etc/cert_source/
ca.pem                                                                   100% 1147   506.2KB/s   00:00    
client-cert.pem                                                          100% 1192     1.1MB/s   00:00    
client-key.pem                                                           100% 1704     1.5MB/s   00:00   

注意,要修改 CA 文件的属主为 mysql 操作系统用户,否则在配置复制源时会报错。

[root@ic-replica1 lib]# chown -R mysql:mysql /usr/local/etc/cert_source/
[root@ic-replica1 lib]# ll /usr/local/etc/cert_source/
总用量 12
-rw-r--r-- 1 mysql mysql 1147 51 18:52 ca.pem
-rw-r--r-- 1 mysql mysql 1192 51 18:52 client-cert.pem
-rw------- 1 mysql mysql 1704 51 18:52 client-key.pem

然后在 Replcia 服务器上强制使用证书认证连接到 Source 服务器上的 MySQL 实例。

注意
ssl-* 这类 SSL 选项的值是指路径,需要使用绝对路径或相对于当前命令行所在目录 $PWD 的相对目录。因而,使用 mysql 客户端连接到 MySQL 服务器时需要 cd CA文件所在目录 ,或使用绝对路径。

例如,我的当前目录是 /var/lib ,SSL 参数使用绝对路径,执行:

[root@ic-replica1 lib]# pwd
/var/lib
[root@ic-replica1 lib]# mysql -uroot -p -P3307 -hsource --ssl-mode=verify_ca --ssl-ca=/usr/local/etc/cert_source/ca.pem --ssl-cert=/usr/local/etc/cert_source/client-cert.pem --ssl-key=/usr/local/etc/cert_source/client-key.pem -e '\s'
Enter password: 
--------------
mysql  Ver 8.0.31 for Linux on x86_64 (MySQL Community Server - GPL)

Connection id:          22938
Current database:
Current user:           root@replica1
SSL:                    Cipher in use is ECDHE-RSA-AES128-GCM-SHA256
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         8.0.31 MySQL Community Server - GPL
Protocol version:       10
Connection:             source via TCP/IP
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    utf8mb4
Conn.  characterset:    utf8mb4
TCP port:               3307
Binary data as:         Hexadecimal
Uptime:                 3 days 17 hours 30 min 17 sec

Threads: 6  Questions: 17832  Slow queries: 3  Opens: 429  Flush tables: 3  Open tables: 338  Queries per second avg: 0.055
--------------

无报错即验证成功。

如果不指定证书,会报错:

[root@ic-replica1 lib]# mysql -uroot -p -P3307 -hsource --ssl-mode=verify_ca  -e '\s'
Enter password: 
ERROR 2026 (HY000): SSL connection error: CA certificate is required if ssl-mode is VERIFY_CA or VERIFY_IDENTITY

创建复制用户

此处我额外创建了一个角色 role_repl 以复用。

mysql> create role `role_repl`;
Query OK, 0 rows affected (0.01 sec)
GRANT REPLICATION SLAVE ON *.* TO `role_repl` WITH GRANT OPTION;
mysql> create user repl1 identified by 'Repl?111' default role `role_repl`;
Query OK, 0 rows affected (0.00 sec)

mysql> show grants for repl1 using `role_repl`;
+-----------------------------------------------------------------+
| Grants for repl1@%                                              |
+-----------------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `repl1`@`%` WITH GRANT OPTION |
| GRANT `role_repl`@`%` TO `repl1`@`%`                            |
+-----------------------------------------------------------------+
2 rows in set (0.00 sec)

获取复制源服务器的二进制日志坐标

即获取主服务器的二进制日志坐标。

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: bin-mycat.000009
         Position: 4029
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.01 sec)

配置复制源

在从服务器上配置复制源为主服务器。

mysql> change replication source to
    -> source_host='source',
    -> source_port=3307,
    -> source_user='repl1',
    -> source_password='Repl?111',
    -> source_log_file='bin-mycat.000009',
    -> source_log_pos=4029,
    -> source_ssl=1,
    -> source_ssl_ca='/usr/local/etc/cert_source/ca.pem',
    -> source_ssl_cert='/usr/local/etc/cert_source/client-cert.pem',
    -> source_ssl_key='/usr/local/etc/cert_source/client-key.pem';
Query OK, 0 rows affected, 2 warnings (0.00 sec)

开启复制

在从服务器上开启复制。

mysql> start replica;
Query OK, 0 rows affected (0.01 sec)

mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: source
                  Source_User: repl1
                  Source_Port: 3307
                Connect_Retry: 60
              Source_Log_File: bin-mycat.000009
          Read_Source_Log_Pos: 4029
               Relay_Log_File: ic-replica1-relay-bin.000002
                Relay_Log_Pos: 326
        Relay_Source_Log_File: bin-mycat.000009
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 4029
              Relay_Log_Space: 542
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File: /usr/local/etc/cert_source/ca.pem
           Source_SSL_CA_Path: 
              Source_SSL_Cert: /usr/local/etc/cert_source/client-cert.pem
            Source_SSL_Cipher: 
               Source_SSL_Key: /usr/local/etc/cert_source/client-key.pem
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Source_Server_Id: 1
                  Source_UUID: fefc2e34-d95f-11ed-9382-000c298d6cb9
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 86400
                  Source_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Source_SSL_Crl: 
           Source_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Source_TLS_Version: 
       Source_public_key_path: 
        Get_Source_public_key: 0
            Network_Namespace: 
1 row in set (0.00 sec)

结果如下图所示,没有报错即搭建成功。
在这里插入图片描述

验证

在主服务器上查看有哪些副本服务器、建库、建表:

mysql> show replicas;
+-----------+------+------+-----------+--------------------------------------+
| Server_Id | Host | Port | Source_Id | Replica_UUID                         |
+-----------+------+------+-----------+--------------------------------------+
|         2 |      | 3307 |         1 | 72e8f54a-d965-11ed-8c0b-000c298656b1 |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)

mysql> create database mycat;
Query OK, 1 row affected (0.00 sec)

mysql> use mycat;
Database changed
mysql> create table m1(id int primary key);
Query OK, 0 rows affected (0.06 sec)

mysql> insert into m1 values (1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

在从服务器上验证是否同步成功:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mycat              |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+
6 rows in set (0.01 sec)

mysql> use mycat;
Database changed
mysql> table m1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set (0.00 sec)

可以看到已经同步成功了。

进阶

上面我们并没有限制复制用户强制使用 SSL 加密连接。在副本上要求加密连接并不能确保源需要来自副本的加密连接。如果要确保源只接受使用加密连接连接的副本,应使用 REQUIRE SSL 。例如:

先在 Replica 服务器上关闭复制:

mysql> stop replica;
Query OK, 0 rows affected, 1 warning (0.00 sec)

再在 Source 服务器上创建用户

mysql> ALTER USER repl1 REQUIRE SSL;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status\G
*************************** 1. row ***************************
             File: bin-mycat.000011
         Position: 1352
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)

在 Replica 服务器上重新配置复制源的日志起始位置,并启动,查看有无报错:

mysql> change replication source to source_log_pos=1352;
Query OK, 0 rows affected (0.04 sec)

mysql> start replica;
Query OK, 0 rows affected (0.04 sec)

mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: source
                  Source_User: repl1
                  Source_Port: 3307
                Connect_Retry: 60
              Source_Log_File: bin-mycat.000011
          Read_Source_Log_Pos: 1352
               Relay_Log_File: ic-replica1-relay-bin.000002
                Relay_Log_Pos: 326
        Relay_Source_Log_File: bin-mycat.000011
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 1352
              Relay_Log_Space: 542
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File: /usr/local/etc/cert_source/ca.pem
           Source_SSL_CA_Path: 
              Source_SSL_Cert: /usr/local/etc/cert_source/client-cert.pem
            Source_SSL_Cipher: 
               Source_SSL_Key: /usr/local/etc/cert_source/client-key.pem
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Source_Server_Id: 1
                  Source_UUID: fefc2e34-d95f-11ed-9382-000c298d6cb9
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 86400
                  Source_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Source_SSL_Crl: 
           Source_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Source_TLS_Version: 
       Source_public_key_path: 
        Get_Source_public_key: 0
            Network_Namespace: 
1 row in set (0.00 sec)

可以看到没有报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独上西楼影三人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值