默认情况下,MySQL 复制(包括组复制)不会在副本或组成员上应用事务时执行权限检查。当您创建一个具有适当权限的用户帐户来应用通常在通道上复制的事务,并将其指定为复制应用程序的 PRIVILEGE_CHECKS_USER 帐户时,MySQL 将检查每个事务以验证您是否授权了该操作。该帐户也可以由管理员安全地用于应用或重新应用来自 mysqlbinlog 输出的事务,例如从通道上的复制错误中恢复。
使用 PRIVILEGE_CHECKS_USER 帐户可以帮助保护复制通道免受未经授权或意外的特权操作的影响。该帐户提供了额外的一层安全性,在以下情况下:
-
您在组织网络上的服务器实例和云服务提供商的服务器实例之间进行复制。
-
您想将多个本地或离站部署作为单独的单位管理,而不授予一个管理员帐户在所有部署上的权限。
-
您想拥有一个管理员帐户,该帐户仅授予管理员在复制通道和它复制的数据库上执行直接相关操作的权限,而不是在服务器实例上拥有广泛的权限。
您可以通过在 CHANGE REPLICATION SOURCE TO
语句中添加一个或两个选项来增加复制通道的安全性,例如:
-
REQUIRE_ROW_FORMAT 选项使复制通道仅接受基于行的复制事件。当 REQUIRE_ROW_FORMAT 设置时,您必须在源服务器上使用基于行的二进制日志记录 (
binlog_format=ROW
)。使用基于语句的二进制日志记录,PRIVILEGE_CHECKS_USER 帐户可能需要管理员级别的权限来成功执行事务。 -
REQUIRE_TABLE_PRIMARY_KEY_CHECK 选项使复制通道使用自己的主键检查策略。将其设置为 ON 意味着总是需要主键,将其设置为 OFF 意味着从不需要主键。默认设置为 STREAM,使用从源服务器上复制的值来设置会话变量
sql_require_primary_key
。当 PRIVILEGE_CHECKS_USER 设置时,将 REQUIRE_TABLE_PRIMARY_KEY_CHECK 设置为 ON 或 OFF 意味着用户帐户不需要会话管理员级别的权限来设置受限的会话变量,这些变量是更改sql_require_primary_key
值所需的。它还标准化了来自不同源的复制通道的行为。
您授予REPLICATION_APPLIER
权限,以便用户账户出现在复制应用程序线程中,并执行mysqlbinlog使用的内部使用BINLOG
语句。该账户名称和主机名称必须遵循Section 8.2.4, “指定账户名称”中描述的语法,并且用户不能是匿名用户(用户名为空)或CURRENT_USER。要创建新账户,请使用CREATE USER
。要授予该账户REPLICATION_APPLIER
权限,请使用GRANT
语句。例如,要创建一个用户账户priv_repl,该账户可以由管理员从example.com域中的任何主机手动使用,并需要加密连接,请发出以下语句:
mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repl'@'%.example.com' IDENTIFIED BY 'password' REQUIRE SSL;
mysql> GRANT REPLICATION_APPLIER ON *.* TO 'priv_repl'@'%.example.com';
mysql> SET sql_log_bin = 1;
这些SET sql_log_bin语句用于确保账户管理语句不添加到二进制日志中并发送到复制通道中(见Section 15.4.1.4, “SET sql_log_bin语句”)。
默认情况下,新的用户使用Section 8.4.1.2, “Caching SHA-2可插拔身份验证”中的caching_sha2_password身份验证插件。要连接到服务器使用该插件身份验证的用户账户,您必须设置加密连接,如Section 19.3.1, “设置复制以使用加密连接”所述,或者启用未加密的连接以支持使用RSA密钥对交换密码。
设置用户账户后,使用GRANT
语句授予额外的权限,以便用户账户可以执行数据库更改,这些权限也使管理员可以手动执行这些事务。如果尝试执行未授予适当权限的操作,将被禁止并停止复制应用程序线程。 Section 19.3.3.1, “复制PRIVILEGE_CHECKS_USER账户的权限”解释了账户需要的其他权限。例如,要授予priv_repl用户账户INSERT
权限以添加行到db1中的cust表,请发出以下语句:
mysql> GRANT INSERT ON db1.cust TO 'priv_repl'@'%.example.com';
您可以使用CHANGE REPLICATION SOURCE TO
语句分配复制通道的PRIVILEGE_CHECKS_USER账户。如果复制正在运行,请在CHANGE REPLICATION SOURCE TO
语句之前发出STOP REPLICA
,并在之后发出START REPLICA
。强烈建议在PRIVILEGE_CHECKS_USER设置时使用基于行的二进制日志记录;您可以使用语句设置REQUIRE_ROW_FORMAT以强制执行此操作。
当您重新启动复制通道时,从那时起将应用动态权限检查。但是,静态全局权限直到您重新加载授权表时才生效,因为这些权限不会在连接的客户端上更改。要激活静态权限,请执行flush-privileges操作。这可以通过发出FLUSH PRIVILEGES
语句或执行mysqladmin flush-privileges或mysqladmin reload命令来实现。
例如,要在运行的副本上启动特权检查通道 channel_1
,请发出以下语句:
mysql> STOP REPLICA FOR CHANNEL 'channel_1';
mysql> CHANGE REPLICATION SOURCE TO
> PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',
> REQUIRE_ROW_FORMAT = 1 FOR CHANNEL 'channel_1';
mysql> FLUSH PRIVILEGES;
mysql> START REPLICA FOR CHANNEL 'channel_1';
如果您不指定通道且没有其他通道存在,则语句将应用于默认通道。用户名称和主机名称为 PRIVILEGE_CHECKS_USER
帐户的通道显示在性能模式 replication_applier_configuration
表中,其中它们被正确地转义,以便可以直接复制到 SQL 语句中,以执行单个事务。
如果您使用 Rewriter
插件,应该授予 PRIVILEGE_CHECKS_USER
用户帐户 SKIP_QUERY_REWRITE
权限。这将阻止该用户发出的语句被重写。请参阅 第 7.6.4 节,“Rewriter 查询重写插件”,以获取更多信息。
当 REQUIRE_ROW_FORMAT
为复制通道设置时,复制应用程序不创建或删除临时表,因此不设置 pseudo_thread_id
会话系统变量。它不执行 LOAD DATA INFILE
指令,因此不尝试访问或删除与数据加载相关的临时文件(记录为 Format_description_log_event
)。它不执行 INTVAR
、RAND
和 USER_VAR
事件,这些事件用于重现客户端的连接状态以进行基于语句的复制。(一个例外是与 DDL 查询相关的 USER_VAR
事件,这些事件将被执行。)它不执行任何在 DML 事务中记录的语句。如果复制应用程序在尝试队列或应用事务时检测到这些类型的事件,事件将不被应用,复制将停止并出现错误。
您可以为复制通道设置 REQUIRE_ROW_FORMAT
,无论是否设置 PRIVILEGE_CHECKS_USER
帐户。当您设置此选项时,增加了复制通道的安全性,即使没有特权检查。您还可以在使用 mysqlbinlog 时指定 --require-row-format
选项,以强制行基于复制事件在 mysqlbinlog 输出中。
安全上下文。 默认情况下,当复制应用程序线程以 PRIVILEGE_CHECKS_USER
帐户启动时,安全上下文将使用默认角色创建,或者如果 activate_all_roles_on_login
设置为 ON
,则使用所有角色。
您可以使用角色来提供通用权限集给作为 PRIVILEGE_CHECKS_USER
帐户的帐户,如以下示例所示。在这里,而不是直接授予用户帐户 db1.cust
表的 INSERT
权限,如前一个示例所示,这个权限被授予角色 priv_repl_role
,连同 REPLICATION_APPLIER
权限。然后,该角色被用于授予两个用户帐户的权限集,这两个帐户现在都可以用作 PRIVILEGE_CHECKS_USER
帐户:
mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repa'@'%.example.com'
IDENTIFIED BY 'password'
REQUIRE SSL;
mysql> CREATE USER 'priv_repb'@'%.example.com'
IDENTIFIED BY 'password'
REQUIRE SSL;
mysql> CREATE ROLE 'priv_repl_role';
mysql> GRANT REPLICATION_APPLIER TO 'priv_repl_role';
mysql> GRANT INSERT ON db1.cust TO 'priv_repl_role';
mysql> GRANT 'priv_repl_role' TO
'priv_repa'@'%.example.com',
'priv_repb'@'%.example.com';
mysql> SET DEFAULT ROLE 'priv_repl_role' TO
'priv_repa'@'%.example.com',
'priv_repb'@'%.example.com';
mysql> SET sql_log_bin = 1;
请注意,当复制应用程序线程创建安全上下文时,它检查 PRIVILEGE_CHECKS_USER
帐户的权限,但不执行密码验证,也不执行帐户管理相关的检查,例如检查帐户是否被锁定。创建的安全上下文将在复制应用程序线程的整个生命周期中保持不变。