MySQL的主从复制默认是明文传送的,如果在生产环境中跨网络传送,数据的安全性就无法完全保证,为了解决这一问题,我们需要一种安全的方式进行传送,即基于SSL加密进行数据传输。在进行SSL加密传输时可能需要先了解CA、证书及SSL相关知识才能更好地明白为何基于SSL的传输就会更加安全。CA、证书及SSL相关知识在本章节不会多加一说明,详情可以看本博客提供的“信息安全之PKI及数字证书介绍”和“HTTPS协议和原理介绍”章节。
首先Master和Slave上分别检查SSL状态信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> show global variables like '%ssl%'; +---------------+----------+ | Variable_name | Value | +---------------+----------+ | have_openssl | DISABLED | | have_ssl | DISABLED | | ssl_ca | | | ssl_capath | | | ssl_cert | | | ssl_cipher | | | ssl_crl | | | ssl_crlpath | | | ssl_key | | +---------------+----------+ 9 rows in set (0.00 sec) |
确保你看到的是disabled,而不是NO的选项。这表示你的mysql服务器支持ssl,只是没有在启动的时候开启ssl功能,当服务器启动ssl功能的时候,你会看到图中的disabled会显示yes。
下面需要开启支持SSL并设置加密方法,私钥文件等信息。
首先说明一点,我的实验环境把CA服务器、主服务器和从服务器都放在了同一台服务器上面。
1)配置CA服务器
1 2 3 4 5 |
$ cd /etc/pki/CA $ (umask 077;openssl genrsa -out private/cakey.pem 2048) $ openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 3650 $ touch {index.txt,serial} $ echo 01 > serial |
下面是我自签证书时填写的信息:
1 2 3 4 5 6 7 |
Country Name (2 letter code) [XX]:cn State or Province Name (full name) []:sh Locality Name (eg, city) [Default City]:sh Organization Name (eg, company) [Default Company Ltd]:ej Organizational Unit Name (eg, section) []:tech Common Name (eg, your name or your server's hostname) []:mysql.ywnds.com Email Address []:123@ywnds.com |
2)Master服务器生成证书
1 2 3 4 |
$ mkdir /ssl $ cd /ssl $ (umask 077;openssl genrsa -out master.key 2048) $ openssl req -new -key master.key -out master.csr |
3)CA为Master签署证书
1 |
$ openssl ca -in /ssl/master.csr -out /ssl/master.crt -days 3650 |
PS:需要把证书(master.csr)和key(master.key)从Master服务器上复制到CA服务器上,然后在CA服务器签完证书后把证书master.crt再复制到Master服务器/data/mysql/ssl目录下(我这里是同台服务器,略过此步骤)。
4)Slave服务器生成证书
1 2 3 4 |
$ mkdir /ssl $ cd /ssl $ (umask 077;openssl genrsa -out slave.key 2048) $ openssl req -new -key slave.key -out slave.csr |
5)CA为Slave签署证书
1 |
$ openssl ca -in /ssl/slave.csr -out /ssl/slave.crt -days 3650 |
PS:需要把证书(slave.csr)和key(slave.key)从Slave服务器上复制到CA服务器上,然后在CA服务器签完证书后把证书slave.crt再复制到Slave服务器/data/mysql/ssl目录下(我这里是同台服务器,略过此步骤)。
这里特别要注意一下,两个证书的签署是否成功。另外这几个证书的签署输入信息最好都一样。我这边由于主从都是在同一台机器上进行的,所以Common Name部分是一样的,所以我在为Slave签署证书时报错了,如下:
1 2 |
failed to update database TXT_DB error number 2 |
主要原因是因为两个证书的主机名一样导致的,解决办法把/etc/pki/CA/index.txt.attr这个文件中的unique_subject = yes改为unique_subject = no。就是不做唯一性限制。再或者把index.txt这个文件删除,然后新建一个。
我的环境是同一台服务器,所以现在我们来看一下相关的文件。
1 2 3 4 5 6 |
$ ll /data/mysql/ssl -rw-r--r-- 1 mysql mysql 1375 Nov 24 16:35 cacert.pem -rw-r--r-- 1 mysql mysql 4547 Nov 24 16:54 master.crt -rw------- 1 mysql mysql 1675 Nov 24 15:24 master.key -rw-r--r-- 1 mysql mysql 4547 Nov 24 17:01 slave.crt -rw------- 1 mysql mysql 1679 Nov 24 15:24 slave.key |
6)将CA证书复制到Master和Slave
1 2 |
$ mkdir /data/mysql/ssl $ cp /etc/pki/CA/cacert.pem /data/mysql/ssl |
7)Master和Slave配置SSL
master
1 2 3 4 |
[mysqld] ssl-ca = /data/mysql/ssl/cacert.pem #指定CA文件位置; ssl-cert = /data/mysql/ssl/master.crt #指定证书文件位置; ssl-key = /data/mysql/ssl/master.key #指定密钥所在位置; |
slave
1 2 3 4 |
[mysqld] ssl-ca = /data/mysql/ssl/cacert.pem #指定CA文件位置; ssl-cert = /data/mysql/ssl/slave.crt #指定证书文件位置; ssl-key = /data/mysql/ssl/slave.key #指定密钥所在位置; |
PS:把两个节点都重启一下。
然后再master上面应该会看到如下信息,如果have_openssl和have_ssl的值不为YES,那么你需要看一下错误日志中有什么报错信息(本人在做的时候就碰到了证书签署的时候有问题,导致ssl一直起不来)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> show global variables like '%ssl%'; +---------------+----------------------------+ | Variable_name | Value | +---------------+----------------------------+ | have_openssl | YES | | have_ssl | YES | | ssl_ca | /data/mysql/ssl/cacert.pem | | ssl_capath | | | ssl_cert | /data/mysql/ssl/master.crt | | ssl_cipher | | | ssl_crl | | | ssl_crlpath | | | ssl_key | /data/mysql/ssl/master.key | +---------------+----------------------------+ 9 rows in set (0.01 sec) |
8)Master上创建复制用户
1 2 |
mysql> grant replication slave on *.* to 'backup'@'%' identified by '123456' REQUIRE SSL; mysql> flush privileges; |
REQUIRE SSL表示此用户必须使用SSL连接。
9)Slave上连接Master配置
1 2 3 4 5 6 7 8 9 |
mysql> change master to master_host='10.0.60.143', master_user='backup', master_password='123456', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154, MASTER_SSL=1, MASTER_SSL_CA='/data/mysql/ssl/cacert.pem', MASTER_SSL_CERT = '/data/mysql/ssl/slave.crt', MASTER_SSL_KEY = '/data/mysql/ssl/slave.key'; |
PS:需要注意的一点是,如果主从的SSL配置有问题,那么这个change master就会有问题的。
10)查看Slave状态信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.0.60.143 Master_User: backup Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.00001 Read_Master_Log_Pos: 417 Relay_Log_File: relay-log.00001 Relay_Log_Pos: 630 Relay_Master_Log_File: mysql-bin.00001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: test1,test2 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_Master_Log_Pos: 417 Relay_Log_Space: 1044 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: Yes Master_SSL_CA_File: /data/mysql/ssl/cacert.pem Master_SSL_CA_Path: Master_SSL_Cert: /data/mysql/ssl/slave.crt Master_SSL_Cipher: Master_SSL_Key: /data/mysql/ssl/slave.key |
然后你可以在master写入数据,看看slave是否正常同步。
以上配置是MySQL 5.7之前的版本,从MySQL 5.7开始,配置SSL复制就更加简洁了。如果仔细阅读MySQL 5.7的安装文档INSTALL-BINARY,会发现5.7的安装文档在初始化数据目录之后还额外多做了一个操作,这是之前版本所没有的操作,而该步骤即是对于SSL的安装与配置。
1 |
shell> bin/mysql_ssl_rsa_setup |
运行完命令mysql_ssl_rsa_setup后会发现数据目录下多出了一些以pem结尾的文件,而这些文件就是开启SSL连接所需要的文件:
1 2 3 4 5 6 7 8 |
server-cert.pem server-key.pem client-cert.pem client-key.pem ca.pem ca-key.pem public_key.pem private_key.pem |
PS:如果你是yum安装,那么直接执行mysql_ssl_rsa_setup,就会在/var/log/mysql/目录下就会生成这些文件。
有了这些证书之后,就不需要再自己进行证书的创建了,省去很多事。比如我这里就可以直接把这些证书和key复制到指定的目录使用。
1 |
$ cp -frp /var/lib/mysql/{server-cert.pem,server-key.pem,client-cert.pem,client-key.pem,ca.pem,ca-key.pem} /data/mysql/ssl/ |
更详细的可以看这篇文章:MySQL 5.7客户端使用加密连接。
然后我们也可以使用客户端直接连接测试SSL连接(MySQL 5.7默认就是使用SSL进行连接)。
1 |
$ mysql -ubackup -p -h10.0.60.143 --ssl-ca=/data/mysql/ssl/ca.pem --ssl-cert=/data/mysql/ssl/client-cert.pem --ssl-key=/data/mysql/ssl/client-key.pem |
然后就可以确认是否加密了。
1 2 3 4 5 6 7 8 |
mysql> \s -------------- mysql Ver 14.14 Distrib 5.7.16, for Linux (x86_64) using EditLine wrapper Connection id: 4 Current database: Current user: backup@10.0.60.143 SSL: Cipher in use is DHE-RSA-AES256-SHA |
或
1 2 3 4 5 6 7 |
mysql> SHOW STATUS LIKE 'Ssl_cipher'; +---------------+--------------------+ | Variable_name | Value | +---------------+--------------------+ | Ssl_cipher | DHE-RSA-AES256-SHA | +---------------+--------------------+ 1 row in set (0.00 sec) |
我们可以看到SSL字段显示的加密方式为DHE-RSA-AES256-SHA。
如果没有加密,你看到的信息就为SSL: Not in use。