8.2.12 使用部分撤销的权限限制
如果系统变量partial_revokes
被启用,那么可以授予全局有效的权限。具体来说,对于拥有全局级别权限的用户,partial_revokes
允许为特定的模式撤销权限,同时保留对其他模式的权限。通过这种方式实施的权限限制对于管理那些拥有全局权限但不应访问某些模式的账户非常有用。例如,可以允许一个账户修改任何表,但排除在mysql
系统模式中的表。
为了简洁,以下的CREATE USER
语句不包括密码。对于生产环境,请始终为账户分配密码。
系统变量partial_ revokes
控制是否可以对账户实施权限限制。默认情况下,partial_ revokes
被禁用,并且尝试部分撤销全局权限会产生错误:
mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> REVOKE INSERT ON world.* FROM u1;
ERROR 1141 (42000): There is no such grant defined for user 'u1' on host '%'
为了允许REVOKE
操作,启用partial_ revokes
:
SET PERSIST partial_revokes = ON;
SET PERSIST
为当前运行的MySQL实例设置一个值。它还将保存这个值,使其在服务器重启后继续有效。要更改运行中的MySQL实例的值而不让其在重启后继续有效,请使用GLOBAL
关键字而不是PERSIST
。请参阅第15.7.6.1节,“SET 语法用于变量赋值”。
当partial_ revokes
被启用时,部分撤销操作成功:
mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@% |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+
SHOW GRANTS
将部分撤销作为REVOKE
语句在其输出中列出。结果表明,u1
拥有全局SELECT
和INSERT
权限,但不能对INSERT
权限在world
模式中的表进行操作。这意味着u1
对world
模式的表只能读取。
服务器将通过部分撤销实施的权限限制记录在mysql. user
系统表中。如果一个账户有部分撤销,它的User_ attributes
列值将包含一个Restrictions
属性:
mysql> SELECT User, Host, User_attributes->>'$.Restrictions'
FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
+------+------+------------------------------------------------------+
| User | Host | User_attributes->>'$.Restrictions' |
+------+------+------------------------------------------------------+
| u1 | % | [{"Database": "world", "Privileges": ["INSERT"]}] |
+------+------+------------------------------------------------------+
尽管可以对任何模式实施部分撤销,但对mysql
系统模式的权限限制尤其有用,因为它是保护普通账户不能修改系统账户的一种策略。请参阅保护系统账户不被普通账户操作。
部分撤销操作受以下条件限制:
-
可以对不存在的模式实施部分撤销,但只有当撤销的权限是全局授予时。否则,如果权限不是全局授予,尝试为不存在的模式撤销权限会产生错误。
-
部分撤销仅适用于模式级别。您不能使用部分撤销来实施只在全局有效(如
FILE
或BINLOG_ ADMIN
)的权限,或者表、列或存储程序的权限。 -
在权限分配中,启用
partial_revokes
会导致MySQL将未转义的_
和%
SQL通配符字符解释为字面字符,就像它们被转义为\_
和partial_revokes
的安装,建议避免在权限分配中使用未转义的通配符字符。
如前所述,部分撤销数据库级别的权限在SHOW GRANTS
输出中以REVOKE
语句形式出现,这与表示数据库级别权限的SHOW GRANTS
不同。
-
当授予时,数据库级别的权限以自己的
GRANT
语句形式出现在输出中:mysql> CREATE USER u1; mysql> GRANT UPDATE ON mysql.* TO u1; mysql> GRANT DELETE ON world.* TO u1; mysql> SHOW GRANTS FOR u1; +---------------------------------------+ | Grants for u1@% | +---------------------------------------+ | GRANT USAGE ON *.* TO `u1`@`%` | | GRANT UPDATE ON `mysql`.* TO `u1`@`%` | | GRANT DELETE ON `world`.* TO `u1`@`%` | +---------------------------------------+
-
当撤销时,数据库级别的权限在输出中消失,不会以
REVOKE
语句形式出现:mysql> REVOKE UPDATE ON mysql.* FROM u1; mysql> REVOKE DELETE ON world.* FROM u1; mysql> SHOW GRANTS FOR u1; +--------------------------------+ | Grants for u1@% | +--------------------------------+ | GRANT USAGE ON *.* TO `u1`@`%` | +--------------------------------+
当一个用户授予权限时,授权者对该权限的任何限制都会被继承给授权者,除非授权者已经拥有没有这些限制的权限。考虑以下两个用户,其中一个拥有全局SELECT
权限:
CREATE USER u1, u2;
GRANT SELECT ON *.* TO u2;
假设一个管理用户admin
拥有全局但部分撤销的SELECT
权限:
mysql> CREATE USER admin;
mysql> GRANT SELECT ON *.* TO admin WITH GRANT OPTION;
mysql> REVOKE SELECT ON mysql.* FROM admin;
mysql> SHOW GRANTS FOR admin;
+------------------------------------------------------+
| Grants for admin@% |
+------------------------------------------------------+
| GRANT SELECT ON *.* TO `admin`@`%` WITH GRANT OPTION |
| REVOKE SELECT ON `mysql`.* FROM `admin`@`%` |
+------------------------------------------------------+
如果admin
授予全局的SELECT
权限给u1
和u2
,结果对每个用户都不同:
-
如果
admin
授予全局的SELECT
权限给u1
,没有任何SELECT
权限的u1
会继承admin
权限的限制:mysql> GRANT SELECT ON *.* TO u1; mysql> SHOW GRANTS FOR u1; +------------------------------------------+ | Grants for u1@% | +------------------------------------------+ | GRANT SELECT ON *.* TO `u1`@`%` | | REVOKE SELECT ON `mysql`.* FROM `u1`@`%` | +------------------------------------------+
-
另一方面,
u2
已经拥有全局SELECT
权限没有限制。授予权限只能增加给授权者的现有权限,而不能减少它们,所以如果admin
授予全局的SELECT
权限给u2
,u2
不会继承admin
的限制:mysql> GRANT SELECT ON *.* TO u2; mysql> SHOW GRANTS FOR u2; +---------------------------------+ | Grants for u2@% | +---------------------------------+ | GRANT SELECT ON *.* TO `u2`@`%` | +---------------------------------+
如果一个GRANT
语句包含一个AS user
子句,权限的限制是应用于由该子句指定的用户/角色组合的,而不是执行语句的用户。有关AS
子句的信息,请参阅第15.7.1.6节,“GRANT语句”。
对新权限授予给一个帐户的限制会添加到该帐户任何现有限制上:
mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@% |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%` |
+---------------------------------------------------------+
mysql> REVOKE DELETE, UPDATE ON db2.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@% |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `db2`.* FROM `u1`@`%` |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%` |
+---------------------------------------------------------+
权限限制的聚合适用于当权限被显式部分撤销(如前所述)以及当限制隐式继承自执行语句或AS user
子句中指定的用户时。
如果一个帐户对某个数据库有权限限制:
-
该帐户不能授予其他帐户在受限数据库或其中任何对象上的权限。
-
另一个没有限制的用户执行以下语句:
CREATE USER u1; GRANT SELECT, INSERT, UPDATE ON *.* TO u1; REVOKE SELECT, INSERT, UPDATE ON mysql.* FROM u1; GRANT SELECT ON mysql.user TO u1; -- grant table privilege GRANT SELECT(Host,User) ON mysql.db TO u1; -- grant column privileges
结果是,该帐户拥有这些权限,并且可以在受限数据库中进行有限操作:
mysql> SHOW GRANTS FOR u1; +-----------------------------------------------------------+ | Grants for u1@% | +-----------------------------------------------------------+ | GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%` | | REVOKE SELECT, INSERT, UPDATE ON `mysql`.* FROM `u1`@`%` | | GRANT SELECT (`Host`, `User`) ON `mysql`.`db` TO `u1`@`%` | | GRANT SELECT ON `mysql`.`user` TO `u1`@`%` | +-----------------------------------------------------------+
如果一个帐户对全局权限有限制,限制会通过以下任何操作被移除:
-
授予该权限给该帐户以不带限制的全局权限。
-
在数据库级别授予该权限。
-
撤销该权限以全局形式。
考虑一个用户 u1
,该用户在全局层面上持有多个权限,但对 INSERT
、UPDATE
和DELETE
进行了限制:
mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+----------------------------------------------------------+
| Grants for u1@% |
+----------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE INSERT, UPDATE, DELETE ON `mysql`.* FROM `u1`@`%` |
+----------------------------------------------------------+
授予全局权限给 u1
由一个没有任何限制的账户移除权限限制。例如,要移除 INSERT
的限制:
mysql> GRANT INSERT ON *.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@% |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `mysql`.* FROM `u1`@`%` |
+---------------------------------------------------------+
授予权限给 u1
在模式层面上移除权限限制。例如,要移除 UPDATE
的限制:
mysql> GRANT UPDATE ON mysql.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@% |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE DELETE ON `mysql`.* FROM `u1`@`%` |
+---------------------------------------------------------+
撤销全局权限会移除权限,包括对其进行的任何限制。例如,要移除 DELETE
的限制(以牺牲所有 DELETE
访问为代价):
mysql> REVOKE DELETE ON *.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-------------------------------------------------+
| Grants for u1@% |
+-------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%` |
+-------------------------------------------------+
如果一个账户在全局和模式层面上都持有权限,你必须在模式层面上两次撤销它才能实现部分撤销。假设 u1
持有这些权限,其中 INSERT
在 world
模式上也被持有:
mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> GRANT INSERT ON world.* TO u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@% |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| GRANT INSERT ON `world`.* TO `u1`@`%` |
+-----------------------------------------+
撤销 INSERT
在 world
上撤销了模式层面的权限 (SHOW GRANTS
不再显示模式层面的 GRANT
语句):
mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@% |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
+-----------------------------------------+
撤销 INSERT
在 world
上再次进行了部分撤销,移除了全局权限 (SHOW GRANTS
现在包括一个模式层面的 REVOKE
语句):
mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@% |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+
为某些模式提供访问权限,但不为其他模式提供访问,可以通过部分撤销来实现,而不是授予模式层面的访问权限而不授予全局权限。两种方法各有优势和劣势。
授予模式层面的权限并且不授予全局权限:
-
添加新模式:默认情况下,新模式对现有账户是不可访问的。对于任何应该对其有访问权限的账户,DBA 必须授予模式层面的访问权限。
-
添加新账户:DBA 必须为每个应对其有访问权限的模式授予模式层面的访问权限。
授予全局权限并使用部分撤销:
-
添加新模式:新模式对现有持有全局权限的账户是可访问的。对于任何这样的账户,如果应该对其保持不可访问,DBA 必须添加一个部分撤销。
-
添加新账户:DBA 必须授予全局权限,并在每个受限制模式上为其添加部分撤销。
使用显式模式层面的授予更适合对几个模式有有限访问的账户。使用部分撤销的方法更适合拥有广泛访问所有模式(除了少数几个)的大型账户。
一旦启用,partial_ revokes
就不能被禁用,如果有任何账户持有权限限制。若存在这样的账户,禁用 partial_ revokes
将失败:
-
对于尝试在启动时禁用
partial_ revokes
,服务器将记录一个错误消息并启用partial_ revokes
。 -
对于尝试在运行时禁用
partial_ revokes
,将发生错误,并且partial_ revokes
的值保持不变。
要禁用 partial_ revokes
时存在限制,首先必须移除这些限制:
-
确定哪些账户有部分撤销:
SELECT User, Host, User_attributes->>'$.Restrictions' FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
-
对于每个这样的账户,移除其权限限制。假设前一步骤显示账户
u1
有以下限制:[{"Database": "world", "Privileges": ["INSERT", "DELETE"]
限制移除可以通过多种方式进行:
-
全局授予权限,不受限制:
GRANT INSERT, DELETE ON *.* TO u1;
-
在模式级别授予权限:
GRANT INSERT, DELETE ON world.* TO u1;
-
全局撤销权限(假设不再需要):
REVOKE INSERT, DELETE ON *.* FROM u1;
-
删除账户本身(假设不再需要):
DROP USER u1;
-
在删除所有权限限制后,可以禁用部分撤销:
SET PERSIST partial_revokes = OFF;
部分撤销和复制
在复制场景中,如果partial_revokes
在任何主机上启用,它必须在所有主机上启用。否则,REVOKE
语句来部分撤销一个全局权限不会对所有参与复制的主机产生相同的效果,这可能导致复制不一致或错误。
当partial_revokes
启用时,一个扩展的语法在二进制日志中记录用于GRANT
语句的语句,包括发出该语句的当前用户及其当前活动角色。如果在复制源服务器上记录的用户或角色的用户或角色不存在于副本中,复制应用程序线程会在GRANT
语句处停止并出现错误。确保所有在复制源服务器上发出或可能发出GRANT
语句的用户帐户也存在于副本中,并且它们在源服务器和副本上拥有的角色集相同。