19.3.3 复制权限检查
默认情况下,MySQL 复制(包括组复制)不在事务已经被另一个服务器接受的情况下,对事务在副本或组成员上应用时执行权限检查。您可以创建一个用户帐户,具有适当的权限,以便应用通常在通道上复制的事务,并将其指定为PRIVILEGE_CHECKS_USER
帐户,以便在复制应用程序中使用CHANGE REPLICATION SOURCE TO
语句。然后,MySQL 将对每个事务进行检查,以验证您已经授权该通道的操作。帐户也可以安全地由管理员用于从mysqlbinlog输出中应用或重新应用事务,例如,以恢复通道上的复制错误。
使用PRIVILEGE_CHECKS_USER
帐户可以帮助保护复制通道免受未经授权或意外的操作。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
的值。它还将在复制通道之间 normalize行为,以便从不同源服务器获取数据。
您可以授予REPLICATION_APPLIER
权限,以便用户账户在复制器线程中出现为PRIVILEGE_CHECKS_USER
,并执行内部使用的BINLOG
语句,用于mysqlbinlog。PRIVILEGE_CHECKS_USER
账户的用户名和主机名必须遵循第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
语句,以便账户管理语句不添加到二进制日志中并发送到复制通道(见第15.4.1.3节,“SET sql_log_bin Statement”)。
默认情况下,caching_sha2_password
身份验证插件是新用户的默认身份验证插件(详见第8.4.1.2节,“Caching SHA-2 Pluggable Authentication”)。要使用该插件身份验证的用户账户连接到服务器,您需要设置加密连接,如第19.3.1节,“Setting Up Replication to Use Encrypted Connections”中所述,或者启用未加密连接以支持使用RSA密钥对的密码交换。
在设置用户账户后,使用GRANT
语句授予额外的权限,以便用户账户能够执行您期望的数据库更改,例如更新特定的表单,如服务器上保留的表单。这些相同的权限也允许管理员使用该账户,如果需要手动在复制通道上执行这些事务。如果尝试执行未授予适当权限的操作,操作将被禁止,复制applier线程将以错误停止。第19.3.3.1节,“Privileges For The Replication PRIVILEGE_CHECKS_USER Account”解释了该账户需要的额外权限。例如,要授予priv_repl
用户账户在db1
中的cust
表中添加行的INSERT
权限,使用以下语句:
mysql> GRANT INSERT ON db1.cust TO 'priv_repl'@'%.example.com';
您使用CHANGE REPLICATION SOURCE TO
语句将PRIVILEGE_CHECKS_USER
账户分配到复制通道上。如果复制正在运行,先使用STOP REPLICA
,然后使用CHANGE REPLICATION SOURCE TO
语句,最后使用START REPLICA
语句。使用行基于的二进制日志记录强烈建议在设置PRIVILEGE_CHECKS_USER
时,您可以使用语句设置REQUIRE_ROW_FORMAT
来强制执行该设置。
当您重启复制通道时,动态权限检查将从该点开始应用。但是,静态全局权限直到您重新加载授权表才会在applier的上下文中生效,因为这些权限对已连接的客户端没有更改。要激活静态权限,请执行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
帐户的用户名和主机名在性能chemareplication_applier_configuration
表中显示,其中它们被正确转义,以便将其复制到SQL语句中以执行单个事务。
如果您使用Rewriter
插件,您应该授予PRIVILEGE_CHECKS_USER
帐户SKIP_QUERY_REWRITE
权限。这防止了由该用户发出的语句被重写。请参阅第7.6.4节,“The Rewriter Query Rewrite Plugin”,了解更多信息。
当REQUIRE_ROW_FORMAT
为复制通道设置时,复制applier不会创建或删除临时表,因此不会设置pseudo_thread_id
会话系统变量。它不会执行LOAD DATA INFILE
指令,因此不会尝试访问或删除与数据加载关联的临时文件(记录为Format_description_log_event
)。它不会执行INTVAR
、RAND
和USER_VAR
事件,这些事件用于重现客户端连接状态以实现语句级别复制。 (除非是与DDL查询关联的USER_VAR
事件,这些事件将被执行。)它不会执行任何在DML事务中记录的语句。如果复制applier在尝试队列或应用事务时检测到这些类型的事件,事件将不被应用,并且复制将以错误停止。
您可以在复制通道上设置REQUIRE_ROW_FORMAT
,无论您是否设置了PRIVILEGE_CHECKS_USER
账户。设置该选项时实施的限制可以提高复制通道的安全性,即使不进行特权检查。您也可以在使用mysqlbinlog时指定--require-row-format
选项,以强制执行基于行的复制事件在mysqlbinlog输出中。
安全上下文。 默认情况下,当复制应用程序线程启动时,使用指定的PRIVILEGE_CHECKS_USER
账户时,安全上下文将使用默认角色,或者在activate_all_roles_on_login
设置为ON
时使用所有角色。
您可以使用角色为账户提供通用的特权集,该账户用于作为PRIVILEGE_CHECKS_USER
账户,例如。这里,相比于直接将INSERT
特权授予用户账户的db1.cust
表,就将该特权授予角色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
账户的特权,但不执行密码验证,也不执行与账户管理相关的检查,例如检查账户是否锁定。创建的安全上下文在复制应用程序线程的整个生命周期中保持不变。