暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Keyring 搭建主从

00后DBA实录 2024-11-06
64

前言

前面讲了 MySQL keyring 加密,我写这两篇也是有小伙伴说:对 8.0 的 keyring 搭建主从步骤不太熟悉,有验证过的文档嘛?

但是我直接写搭建的话有点太粗糙了,所以就有了上一篇,这篇就是回答小伙伴的问题了,怎么使用 Keyring(下面统称密钥环) 搭建主从。

密钥环对主从的影响

首先我们需要知道密钥环对主从的影响的哪些?

我们知道密钥环可以管理 binlog 的加密密钥,binlog 是主从复制的关键,那么哪个参数控制加密 binlog ,还记得吗?

答案是:binlog_encryption

binlog_encryption
同时也加密 Relay Log。

我们可以看看官网对此的描述:

可以看到 binlog_encryption
是 8.0.14 引入的,红色的框框起来的说明了会对 binary log files 和 relay log files 都加密。

上一篇我们测试过,启动了 binlog_encryption
二进制日志是无法查看的。

那么就可以得出密钥环主从相当于普通的主从的作用:

有助于保护 binary log files 和 relay log files  文件及其中包含的潜在敏感数据免遭外部攻击者滥用,同时也防止操作系统用户未经授权地查看这些文件。(文件使用的加密算法是 AES 高级加密标准密码算法)

主从的基础架构图

下面看看普通主从的基础架构图:

图片来源:bilibili 2022 年1月黑马程序员MySQL数据库课程(我懒得画哈哈哈,借用一下黑马程序员那边画的图。)

简单讲解一下过程:

  • 当在副本服务器上发出 START REPLICA
    语句时,副本会创建一个 I/O(接收器)线程,该线程连接到源服务器并请求源发送二进制日志中记录的更新。(此线程在线程表显示为 Binlog Dump)
  • 源服务器发送完 binlog 中的更改后,IO 线程会将其写入 relay log
  • 然后再由 SQL 线程来重放 relay log 中记录的 binlog 更改。

那么就可以从格式说 relaylog ≈ binlog,所以 binlog_encryption
同时加密 relaylog/binlog ,格式几乎类似,写的内容也是相同的,只不过位置不同,肯定可以加密了。

注意:这里我并没有说明从库的 binlog 的概念,因为在主从原理,不需要从库的 binlog。写不写从库的 binlog 由 log_replica_updates
(8.0.26)/log_slave_updates
参数控制。

讲完这个大家是不是就可以得出一个明确的解决方案了。

  • 主加密 binlog
  • 从接收 binlog,但是不写自己的 binlog(除非这个从做为别的从的主,要不然没有意义,主要作用就是保护 binlog)
  • mysqlbinlog 持续拉取 binlog

解决方案演示

下面我就来演示一下这个解决方案。这里主要讲 keyring 主从搭建过程,不对主从搭建/keyring 配置做讲解,keyring 详细配置请参考上一篇。

我这里配置为:

主加密 binlog,从不加密也不写 binlog,使用 mysqlbinlog 获取未加密 binlog。

当然大家也可以在从使用密钥环,开启对 relay log 的加密(我这里懒得搞了)。

配置密钥环组件

这里只需要对主的 binlog 加密即可,大家可以可选的在从上也配置密钥环。主要配置项和详解参考上一篇,这里只给出命令:

先配置一下全局清单文件,输入到 basedir

cat <<EOF > /application/mysql_8_3306/bin/mysqld.my
{
  "read_local_manifest": true
}
EOF

配置本地清单文件,输入到 datadir

cat <<EOF> /data/mysql_8_3306/mysqld.my
{
  "components": "file://component_keyring_file"
}
EOF

mysql 的 os 用户需要为只读权限,最后的 r-- 表示其他用户只读,mysql 也属于其中。

[root@master ~]# ll /application/mysql_8_3306/bin/mysqld.my /data/mysql_8_3306/mysqld.my
-rw-r--r-- 1 root root 34 11月  4 14:31 /application/mysql_8_3306/bin/mysqld.my
-rw-r--r-- 1 root root 52 11月  4 14:31 /data/mysql_8_3306/mysqld.my

然后配置密钥环组件的配置文件

先配置一下全局配置文件,输入到 plugin_dir

cat <<EOF> /application/mysql_8_3306/lib/plugin/component_keyring_file.cnf
{
  "read_local_config": true
}
EOF

[root@master ~]# ll /application/mysql_8_3306/lib/plugin/component_keyring_file.cnf
-rw-r--r-- 1 root root 32 11月  4 14:34 /application/mysql_8_3306/lib/plugin/component_keyring_file.cnf

配置本地配置文件,输入到 data_dir

cat <<EOF> /data/mysql_8_3306/component_keyring_file.cnf
{
  "path": "/log/component_keyring_file",
  "read_only": false
}
EOF

[root@master ~]# ll /data/mysql_8_3306/component_keyring_file.cnf
-rw-r--r-- 1 root root 66 11月  4 14:34 /data/mysql_8_3306/component_keyring_file.cnf

创建密钥环文件

mkdir /log
chown mysql.mysql /log
touch /log/component_keyring_file
chown mysql.mysql /log/component_keyring_file

查看一下

[root@master ~]# ll /log/component_keyring_file
-rw-r--r-- 1 mysql mysql 0 11月  4 14:37 /log/component_keyring_file

配置主从

master 主要配置内容:

gtid_mode=ON
enforce_gtid_consistency=true
#log_replica_updates=OFF(可选),我这里默认
binlog_encryption=ON

replica 上的主要配置内容:

gtid_mode=ON
log_replica_updates=OFF
enforce_gtid_consistency=true

主从都重启 mysqld

systemctl restart mysqld

看看密钥环组件服务是否正常。

root@localhost [(none)] 15:04:12 > SELECT * FROM performance_schema.keyring_component_status;
+---------------------+-----------------------------+
| STATUS_KEY          | STATUS_VALUE                |
+---------------------+-----------------------------+
| Component_name      | component_keyring_file      |
| Author              | Oracle Corporation          |
| License             | GPL                         |
| Implementation_name | component_keyring_file      |
| Version             | 1.0                         |
| Component_status    | Active                      |
| Data_file           | /log/component_keyring_file |
| Read_only           | No                          |
+---------------------+-----------------------------+
8 rows in set (0.01 sec)

Component_status
Active
,已经启动了。

看看 binlog

root@localhost [(none)] 15:04:14 > show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000012 |       220 | No        |
| mysql-bin.000013 |       732 | Yes       |
| mysql-bin.000014 |       709 | Yes       |
+------------------+-----------+-----------+
3 rows in set (0.00 sec)

root@localhost [(none)] 15:05:40 > show master status;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                          |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000014 |      197 |              |                  | 541e12fa-d5f5-11ed-8994-000c29c34822:1-105 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec)

当前正在使用 mysql-bin.000014

重启之前立刻切了一个日志 mysql-bin.000014
并开启了二进制加密。因为我重启了 2 次所以切了 2 个(mysql-bin.000013
mysql-bin.000014
)。

在主上创建用户,复制到从。

create user if not exists replica@'192.168.58.%' identified  by '123456';
grant replication slave ,replication client on *.* to replica@'192.168.58.%';

从连接主

reset master;
set global gtid_purged='541e12fa-d5f5-11ed-8994-000c29c34822:1-105';
change replication source to source_host='192.168.58.30',source_user='replica',source_password='123456',source_auto_position=1,get_source_public_key=1,source_port=3306;
start slave;

查看一下

root@localhost [(none)] 15:16:46 > show replica status\G
*************************** 1. row ***************************
          ······
          Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
          ······

OK没问题。

查看从的 pos 点

root@localhost [(none)] 15:26:48 > show master status;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                          |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000003 |      197 |              |                  | 541e12fa-d5f5-11ed-8994-000c29c34822:1-112 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec)

在主上插入点数据,测试结果:

create database enc;
use enc;
create table t1(id int primary key);
insert into t1 select 1;

再次查看

root@localhost [(none)] 15:28:04 > show master status;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                          |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000003 |      197 |              |                  | 541e12fa-d5f5-11ed-8994-000c29c34822:1-115 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec)

可以看到是不写 binlog 的

这里大家思考一个问题,主配置加密 binlog,从未配置加密然后写自己的 binlog,这样的情况下从的 binlog 是否加密?

我们测试一下:

从配置为

log_replica_updates=ON

master上执行

root@localhost [(none)] 15:13:57 > create database test;
Query OK, 1 row affected (0.01 sec)

root@localhost [(none)] 15:20:00 > use test;
Database changed
root@localhost [test] 15:20:04 > create table t1(id int primary key);
Query OK, 0 rows affected (0.17 sec)

root@localhost [test] 15:20:06 > insert into t1 select 1;
Query OK, 1 row affected (0.07 sec)
Records: 1  Duplicates: 0  Warnings: 0

root@localhost [test] 15:20:48 > insert into t1 select 2;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

binlog 内容为

[root@slave1 mysql_8_3306]# mysqlbinlog  --base64-output=DECODE-ROWS -vv mysql-bin.000002|grep -E 'create|INSERT'  -A 2
#241104 14:44:11 server id 40  end_log_pos 126 CRC32 0x17aa6488         Start: binlog v 4, server v 8.0.32 created 241104 14:44:11 at startup
ROLLBACK/*!*/;
# at 126
--
create database test
/*!*/;
# at 961
--
create table t1(id int primary key)
/*!*/;
# at 1168
--
### INSERT INTO `test`.`t1`
### SET
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
--
### INSERT INTO `test`.`t1`
### SET
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */

为什么能看见?

虽然主做了加密,但是从对 binlog 读取的时候做了解密,然后写入自己的时候是未加密的,所以能明文看见。

所以要么对从使用 log_replica_updates=OFF
要么将从也配置为加密(加密了也解析不了,只能做为下一层结构的 IO 拉取信息)。

配置拉取未加密 binlog

我是配了从不写 binlog,所以下面就使用 mysqlbinlog 拉取主上的 binlog。

刚才是从 mysql-bin.000014
开始的。

建个目录放 binlog

mkdir -p /log/binlog

所属用户无所谓,能调用 mysqlbinlog 就行

[root@slave1 mysql_8_3306]# ll /log/binlog -d
drwxr-xr-x. 2 root root 6 11月  4 15:52 /log/binlog

连接

mysqlbinlog  -R --raw --host=192.168.58.30 --stop-never --user=replica --password=123456 --result-file=/log/binlog/ --connection-server-id=5 mysql-bin.000014 &

看一下,可以看到没问题:

[root@slave1 binlog]# ll
总用量 4
-rw-r-----. 1 root root 2650 11月  4 16:03 mysql-bin.000014

我们在主切换个日志看看,再做一些操作看看:

root@localhost [enc] 15:28:17 > flush binary logs;
Query OK, 0 rows affected (0.04 sec)

[root@slave1 binlog]# ll
总用量 8
-rw-r-----. 1 root root 2697 11月  4 16:04 mysql-bin.000014
-rw-r-----. 1 root root  197 11月  4 16:04 mysql-bin.000015

可以看到已经读取过来了。

主上做一些操作。

root@localhost [enc] 16:05:17 > insert into t1 select 2;
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0

root@localhost [enc] 16:05:25 > insert into t1 select 3;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

读取一下看看

[root@slave1 binlog]# mysqlbinlog --base64-output=DECODE-ROWS -vv mysql-bin.000015
# The proper term is pseudo_replica_mode, but we use this compatibility alias
# to make the statement usable on server versions 8.0.24 and older.
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#241104 16:04:19 server id 30  end_log_pos 126 CRC32 0xb2cee189         Start: binlog v 4, server v 8.0.32 created 241104 16:04:19
# at 126
#241104 16:04:19 server id 30  end_log_pos 197 CRC32 0xd7fe31aa         Previous-GTIDs
# 541e12fa-d5f5-11ed-8994-000c29c34822:1-115
# at 197
#241104 16:05:25 server id 30  end_log_pos 276 CRC32 0x989a61d4         GTID    last_committed=0        sequence_number=1       rbr_only=yesoriginal_committed_timestamp=1730707525696194    immediate_commit_timestamp=1730707525696194     transaction_length=271
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1730707525696194 (2024-11-04 16:05:25.696194 CST)
# immediate_commit_timestamp=1730707525696194 (2024-11-04 16:05:25.696194 CST)
/*!80001 SET @@session.original_commit_timestamp=1730707525696194*//*!*/;
/*!80014 SET @@session.original_server_version=80032*//*!*/;
/*!80014 SET @@session.immediate_server_version=80032*//*!*/;
SET @@SESSION.GTID_NEXT= '541e12fa-d5f5-11ed-8994-000c29c34822:116'/*!*/;
# at 276
#241104 16:05:25 server id 30  end_log_pos 350 CRC32 0xa255f941         Query   thread_id=8     exec_time=0     error_code=0
SET TIMESTAMP=1730707525/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
BEGIN
/*!*/;
# at 350
#241104 16:05:25 server id 30  end_log_pos 397 CRC32 0x88c80df6         Table_map: `enc`.`t1` mapped to number 103
# has_generated_invisible_primary_key=0
# at 397
#241104 16:05:25 server id 30  end_log_pos 437 CRC32 0xcd0289a0         Write_rows: table id 103 flags: STMT_END_F
### INSERT INTO `enc`.`t1`
### SET
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
# at 437
#241104 16:05:25 server id 30  end_log_pos 468 CRC32 0x1fee3b2b         Xid = 100
COMMIT/*!*/;
# at 468
#241104 16:05:27 server id 30  end_log_pos 547 CRC32 0xab841eb8         GTID    last_committed=1        sequence_number=2       rbr_only=yesoriginal_committed_timestamp=1730707527894748    immediate_commit_timestamp=1730707527894748     transaction_length=271
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1730707527894748 (2024-11-04 16:05:27.894748 CST)
# immediate_commit_timestamp=1730707527894748 (2024-11-04 16:05:27.894748 CST)
/*!80001 SET @@session.original_commit_timestamp=1730707527894748*//*!*/;
/*!80014 SET @@session.original_server_version=80032*//*!*/;
/*!80014 SET @@session.immediate_server_version=80032*//*!*/;
SET @@SESSION.GTID_NEXT= '541e12fa-d5f5-11ed-8994-000c29c34822:117'/*!*/;
# at 547
#241104 16:05:27 server id 30  end_log_pos 621 CRC32 0xedbdab41         Query   thread_id=8     exec_time=0     error_code=0
SET TIMESTAMP=1730707527/*!*/;
BEGIN
/*!*/;
# at 621
#241104 16:05:27 server id 30  end_log_pos 668 CRC32 0xef6b5466         Table_map: `enc`.`t1` mapped to number 103
# has_generated_invisible_primary_key=0
# at 668
#241104 16:05:27 server id 30  end_log_pos 708 CRC32 0x207895de         Write_rows: table id 103 flags: STMT_END_F
### INSERT INTO `enc`.`t1`
### SET
###   @1=3 /* INT meta=0 nullable=0 is_null=0 */
# at 708
#241104 16:05:27 server id 30  end_log_pos 739 CRC32 0x7d8d8f8d         Xid = 101
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

没问题啦。

总结

我这里只是提供思路,具体大家想要什么方案请自行选择。

我给的方案为 :

  • 主加密 binlog
  • 从接收 binlog,但是不写自己的 binlog
  • mysqlbinlog 持续拉取 binlog

这个方案的缺点:

mysqlbinlog 没有断联续连的功能,怎么解决的问题这里不做讨论,大家可以自行写脚本完成此功能。

参考

https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html#sysvar_binlog_encryption

bilibili 2022 年1月黑马程序员MySQL数据库课程

https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html


往期回顾


感谢阅读!关注我获取更多精彩内容。 


文章转载自00后DBA实录,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论