默认情况下,MySQL 复制(包括组复制)在将已由另一台服务器接受的事务应用到副本或组成员时不会执行权限检查。您可以创建一个具有适当权限的用户帐户来应用通常在通道上复制的事务,并将其指定为复制应用程序的 PRIVILEGE_CHECKS_USER
帐户,使用 CHANGE REPLICATION SOURCE TO
语句。然后,MySQL 会根据用户帐户的权限检查每个事务,以验证您是否已授权该通道进行该操作。该帐户也可以由管理员安全地使用来应用或重新应用 mysqlbinlog 的输出,例如从通道上的复制错误中恢复。
使用 PRIVILEGE_CHECKS_USER
帐户有助于保护复制通道免遭未经授权或意外使用特权或不需要的操作。 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
值所必需的。它还规范了不同源的复制通道之间的行为。
授予 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 语句”)。
caching_sha2_password
身份验证插件是新用户的默认插件(有关详细信息,请参阅 第 8.4.1.2 节“缓存 SHA-2 可插拔身份验证”)。要使用使用此插件进行身份验证的用户帐户连接到服务器,您必须要么设置加密连接(如 第 19.3.1 节“设置复制以使用加密连接” 中所述),要么启用未加密的连接以支持使用 RSA 密钥对交换密码。
设置好用户帐户后,请使用 GRANT
语句授予额外的权限,以使用户帐户能够进行您期望应用线程执行的数据库更改,例如更新服务器上持有的特定表。这些相同的权限使管理员能够在需要手动在复制通道上执行任何这些事务时使用该帐户。如果尝试执行未授予适当权限的意外操作,则操作将被拒绝,并且复制应用线程将停止并显示错误。第 19.3.3.1 节“复制 PRIVILEGE_CHECKS_USER 帐户的权限” 解释了帐户需要哪些其他权限。例如,要授予 priv_repl
用户帐户对 db1
中的 cust
表添加行的 INSERT
权限,请发出以下语句
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
语句或执行 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
权限授予用户帐户,而是将此权限以及 REPLICATION_APPLIER
权限授予角色 priv_repl_role
。然后使用该角色将权限集授予两个用户帐户,这两个帐户现在都可以用作 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
帐户的权限,但不会执行密码验证,也不会执行与帐户管理相关的检查,例如检查帐户是否已锁定。创建的安全上下文在复制应用线程的整个生命周期中保持不变。