6.2.12 Privilege Restriction Using Partial Revokes使用部分撤销的特权限制

Prior to MySQL 8.0.16, it is not possible to grant privileges that apply globally except for certain schemas. 在MySQL 8.0.16之前,除了某些模式外,不可能授予全局适用的特权。As of MySQL 8.0.16, that is possible if the partial_revokes system variable is enabled. 从MySQL 8.0.16开始,如果启用了partial_revokes系统变量,这是可能的。Specifically, for users who have privileges at the global level, partial_revokes enables privileges for specific schemas to be revoked while leaving the privileges in place for other schemas. 具体来说,对于在全局级别拥有权限的用户,partial_revokes允许撤销特定模式的权限,同时保留其他模式的权限。Privilege restrictions thus imposed may be useful for administration of accounts that have global privileges but should not be permitted to access certain schemas. 因此施加的特权限制可能有助于管理具有全局特权但不应被允许访问某些模式的帐户。For example, it is possible to permit an account to modify any table except those in the mysql system schema.例如,可以允许帐户修改mysql系统模式中的表之外的任何表。

Note注意

For brevity, CREATE USER statements shown here do not include passwords. For production use, always assign account passwords.为简洁起见,此处显示的CREATE USER语句不包括密码。对于生产使用,始终分配帐户密码。

Using Partial Revokes使用部分撤销

The partial_revokes system variable controls whether privilege restrictions can be placed on accounts. partial_revokes系统变量控制是否可以对帐户施加权限限制。By default, partial_revokes is disabled and attempts to partially revoke global privileges produce an error:默认情况下,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 '%'

To permit the REVOKE operation, enable partial_revokes:要允许REVOKE操作,请启用partial_revokes

SET PERSIST partial_revokes = ON;

SET PERSIST sets the value for the running MySQL instance. SET PERSIST设置正在运行的MySQL实例的值。It also saves the value, causing it to carry over to subsequent server restarts. 它还保存了该值,使其延续到后续的服务器重启。To change the value for the running MySQL instance without having it carry over to subsequent restarts, use the GLOBAL keyword rather than PERSIST. 要更改正在运行的MySQL实例的值而不将其转移到后续重启,请使用GLOBAL关键字而不是PERSISTSee Section 13.7.6.1, “SET Syntax for Variable Assignment”.请参阅第13.7.6.1节,“变量赋值的SET语法”

With partial_revokes enabled, the partial revoke succeeds:启用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 lists partial revokes as REVOKE statements in its output. SHOW GRANTS在其输出中将部分撤销作为REVOKE语句列出。The result indicates that u1 has global SELECT and INSERT privileges, except that INSERT cannot be exercised for tables in the world schema. 结果表明,u1具有全局SELECTINSERT权限,但不能对world模式中的表执行INSERTThat is, access by u1 to world tables is read only.也就是说,u1world表的访问是只读的。

The server records privilege restrictions implemented through partial revokes in the mysql.user system table. 服务器在mysql.user系统表中记录通过部分撤销实现的权限限制。If an account has partial revokes, its User_attributes column value has a Restrictions attribute:如果帐户有部分撤销,则其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"]}] |
+------+------+------------------------------------------------------+
Note注意

Although partial revokes can be imposed for any schema, privilege restrictions on the mysql system schema in particular are useful as part of a strategy for preventing regular accounts from modifying system accounts. 尽管可以对任何模式实施部分撤销,但作为防止常规帐户修改系统帐户的策略的一部分,对mysql系统模式的特权限制尤其有用。See Protecting System Accounts Against Manipulation by Regular Accounts.请参阅保护系统帐户免受常规帐户的操纵

Partial revoke operations are subject to these conditions:部分撤销操作受以下条件的约束:

  • It is possible to use partial revokes to place restrictions on nonexistent schemas, but only if the revoked privilege is granted globally. If a privilege is not granted globally, revoking it for a nonexistent schema produces an error.可以使用部分撤销来对不存在的模式施加限制,但前提是撤销的特权是全局授予的。如果未全局授予特权,则对不存在的模式撤销特权会产生错误。

  • Partial revokes apply at the schema level only. You cannot use partial revokes for privileges that apply only globally (such as FILE or BINLOG_ADMIN), or for table, column, or routine privileges.部分撤销仅适用于架构级别。您不能对仅全局适用的特权(如FILEBINLOG_ADMIN)或表、列或例程特权使用部分撤销。

  • In privilege assignments, enabling partial_revokes causes MySQL to interpret occurrences of unescaped _ and % SQL wildcard characters in schema names as literal characters, just as if they had been escaped as \_ and \%. 在特权分配中,启用partial_revokes会导致MySQL将模式名称中出现的未转义_%SQL通配符解释为文字字符,就像它们被转义为\_\%一样。Because this changes how MySQL interprets privileges, it may be advisable to avoid unescaped wildcard characters in privilege assignments for installations where partial_revokes may be enabled.因为这会改变MySQL解释特权的方式,所以对于可能启用partial_revokes的安装,建议在特权分配中避免使用未转义的通配符。

As mentioned previously, partial revokes of schema-level privileges appear in SHOW GRANTS output as REVOKE statements. 如前所述,模式级特权的部分撤销以REVOKE语句的形式出现在SHOW GRANTS输出中。This differs from how SHOW GRANTS represents plain schema-level privileges:这与SHOW GRANTS表示“普通”模式级权限的方式不同:

  • When granted, schema-level privileges are represented by their own GRANT statements in the output:当被授予时,模式级特权在输出中由它们自己的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`@`%` |
    +---------------------------------------+
  • When revoked, schema-level privileges simply disappear from the output. They do not appear as REVOKE statements:当被撤销时,模式级权限会从输出中消失。它们不会以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`@`%` |
    +--------------------------------+

When a user grants a privilege, any restriction the grantor has on the privilege is inherited by the grantee, unless the grantee already has the privilege without the restriction. 当用户授予特权时,授予人对特权的任何限制都由受让人继承,除非受让人已经拥有没有限制的特权。Consider the following two users, one of whom has the global SELECT privilege:考虑以下两个用户,其中一个具有全局SELECT权限:

CREATE USER u1, u2;
GRANT SELECT ON *.* TO u2;

Suppose that an administrative user admin has a global but partially revoked SELECT privilege:假设管理用户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`@`%`          |
+------------------------------------------------------+

If admin grants SELECT globally to u1 and u2, the result differs for each user:如果adminu1u2全局授予SELECT,则每个用户的结果都不同:

  • If admin grants SELECT globally to u1, who has no SELECT privilege to begin with, u1 inherits the admin privilege restriction:如果adminu1全局授予SELECT权限,而u1一开始就没有SELECT权限,则u1将继承管理员权限限制:

    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`@`%` |
    +------------------------------------------+
  • On the other hand, u2 already holds a global SELECT privilege without restriction. 另一方面,u2已经不受限制地拥有全局SELECT特权。GRANT can only add to a grantee's existing privileges, not reduce them, so if admin grants SELECT globally to u2, u2 does not inherit the admin restriction:GRANT只能增加被授予者的现有权限,而不能减少它们,因此如果adminu2全局授予SELECT权限,u2不会继承admin限制:

    mysql> GRANT SELECT ON *.* TO u2;
    mysql> SHOW GRANTS FOR u2;
    +---------------------------------+
    | Grants for u2@%                 |
    +---------------------------------+
    | GRANT SELECT ON *.* TO `u2`@`%` |
    +---------------------------------+

If a GRANT statement includes an AS user clause, the privilege restrictions applied are those on the user/role combination specified by the clause, rather than those on the user who executes the statement. 如果GRANT语句包含AS user子句,则应用的特权限制是对该子句指定的用户/角色组合的特权限制,而不是对执行该语句的用户的特权限制。For information about the AS clause, see Section 13.7.1.6, “GRANT Statement”.有关AS子句的信息,请参阅第13.7.1.6节,“GRANT语句”

Restrictions on new privileges granted to an account are added to any existing restrictions for that account:对授予帐户的新特权的限制将添加到该帐户的任何现有限制中:

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`@`%`                |
+---------------------------------------------------------+

Aggregation of privilege restrictions applies both when privileges are partially revoked explicitly (as just shown) and when restrictions are inherited implicitly from the user who executes the statement or the user mentioned in an AS user clause.特权限制的聚合既适用于部分明确撤销特权的情况(如刚刚所示),也适用于从执行语句的用户或AS user子句中提到的用户隐式继承限制的情况。

If an account has a privilege restriction on a schema:如果帐户对架构有特权限制:

  • The account cannot grant to other accounts a privilege on the restricted schema or any object within it.该帐户无法向其他帐户授予受限架构或其中任何对象的权限。

  • Another account that does not have the restriction can grant privileges to the restricted account for the restricted schema or objects within it. Suppose that an unrestricted user executes these statements:另一个没有限制的帐户可以为受限制的帐户授予权限,以访问其中的受限制架构或对象。假设一个不受限制的用户执行以下语句:

    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

    The resulting account has these privileges, with the ability to perform limited operations within the restricted schema:生成的帐户具有以下特权,能够在受限架构内执行有限的操作:

    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`@`%`                |
    +-----------------------------------------------------------+

If an account has a restriction on a global privilege, the restriction is removed by any of these actions:如果帐户对全局权限有限制,则可以通过以下任何操作删除该限制:

  • Granting the privilege globally to the account by an account that has no restriction on the privilege.通过对权限没有限制的帐户全局授予该帐户权限。

  • Granting the privilege at the schema level.在架构级别授予特权。

  • Revoking the privilege globally.在全球范围内撤销特权。

Consider a user u1 who holds several privileges globally, but with restrictions on INSERT, UPDATE and DELETE:考虑一个用户u1,他在全局拥有多个权限,但对INSERTUPDATEDELETE有限制:

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`@`%` |
+----------------------------------------------------------+

Granting a privilege globally to u1 from an account with no restriction removes the privilege restriction. For example, to remove the INSERT restriction:从没有限制的帐户全局授予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`@`%`        |
+---------------------------------------------------------+

Granting a privilege at the schema level to u1 removes the privilege restriction. 在架构级别向u1授予特权会消除特权限制。For example, to remove the UPDATE restriction:例如,要删除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`@`%`                |
+---------------------------------------------------------+

Revoking a global privilege removes the privilege, including any restrictions on it. 撤销全局特权会删除特权,包括对它的任何限制。For example, to remove the DELETE restriction (at the cost of removing all DELETE access):例如,要删除DELETE限制(以删除所有DELETE访问为代价):

mysql> REVOKE DELETE ON *.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-------------------------------------------------+
| Grants for u1@%                                 |
+-------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%` |
+-------------------------------------------------+

If an account has a privilege at both the global and schema levels, you must revoke it at the schema level twice to effect a partial revoke. 如果一个帐户在全局和架构级别都有特权,则必须在架构级别撤销两次才能实现部分撤销。Suppose that u1 has these privileges, where INSERT is held both globally and on the world schema:假设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`@`%`   |
+-----------------------------------------+

Revoking INSERT on world revokes the schema-level privilege (SHOW GRANTS no longer displays the schema-level GRANT statement):撤销world上的INSERT将撤销架构级权限(SHOW GRANTS不再显示架构级GRANT语句):

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@%                         |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
+-----------------------------------------+

Revoking INSERT on world again performs a partial revoke of the global privilege (SHOW GRANTS now includes a schema-level REVOKE statement):再次撤销world上的INSERT会部分撤销全局权限(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`@`%` |
+------------------------------------------+

Partial Revokes Versus Explicit Schema Grants部分撤销与显式模式授予

To provide access to accounts for some schemas but not others, partial revokes provide an alternative to the approach of explicitly granting schema-level access without granting global privileges. The two approaches have different advantages and disadvantages.为了为某些模式而不是其他模式提供对帐户的访问,部分撤销提供了一种替代方法,可以在不授予全局权限的情况下显式授予模式级访问权限。这两种方法各有优缺点。

Granting schema-level privileges and not global privileges:授予架构级别权限而非全局权限:

  • Adding a new schema: The schema is inaccessible to existing accounts by default. For any account to which the schema should be accessible, the DBA must grant schema-level access.添加新架构:默认情况下,现有帐户无法访问该架构。对于应该可以访问模式的任何帐户,DBA必须授予模式级访问权限。

  • Adding a new account: The DBA must grant schema-level access for each schema to which the account should have access.添加新帐户:DBA必须为帐户应该访问的每个模式授予模式级访问权限。

Granting global privileges in conjunction with partial revokes:授予全局权限并同时进行部分撤销:

  • Adding a new schema: The schema is accessible to existing accounts that have global privileges. For any such account to which the schema should be inaccessible, the DBA must add a partial revoke.添加新架构:具有全局权限的现有帐户可以访问该架构。对于模式不可访问的任何此类帐户,DBA必须添加部分撤销。

  • Adding a new account: The DBA must grant the global privileges, plus a partial revoke on each restricted schema.添加新帐户:DBA必须授予全局权限,并对每个受限制的模式进行部分撤销。

The approach that uses explicit schema-level grant is more convenient for accounts for which access is limited to a few schemas. The approach that uses partial revokes is more convenient for accounts with broad access to all schemas except a few.对于访问权限仅限于少数模式的帐户,使用显式模式级授权的方法更方便。使用部分撤销的方法对于可以广泛访问除少数模式之外的所有模式的帐户来说更方便。

Disabling Partial Revokes禁用部分撤销

Once enabled, partial_revokes cannot be disabled if any account has privilege restrictions. 一旦启用,如果任何帐户有权限限制,则无法禁用partial_revokesIf any such account exists, disabling partial_revokes fails:如果存在任何此类帐户,则禁用partial_revokes失败:

  • For attempts to disable partial_revokes at startup, the server logs an error message and enables partial_revokes.对于在启动时禁用partial_revokes的尝试,服务器会记录一条错误消息并启用partial_revokes

  • For attempts to disable partial_revokes at runtime, an error occurs and the partial_revokes value remains unchanged.对于在运行时尝试禁用partial_revokes,会发生错误,partial_revokes值保持不变。

To disable partial_revokes when restrictions exist, the restrictions first must be removed:要在存在限制时禁用partial_revokes,必须首先删除限制:

  1. Determine which accounts have partial revokes:确定哪些帐户有部分撤销:

    SELECT User, Host, User_attributes->>'$.Restrictions'
    FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
  2. For each such account, remove its privilege restrictions. Suppose that the previous step shows account u1 to have these restrictions:对于每个这样的帐户,删除其权限限制。假设上一步显示帐户u1具有以下限制:

    [{"Database": "world", "Privileges": ["INSERT", "DELETE"]

    Restriction removal can be done various ways:解除限制可以通过多种方式进行:

    • Grant the privileges globally, without restrictions:在全球范围内无限制地授予特权:

      GRANT INSERT, DELETE ON *.* TO u1;
    • Grant the privileges at the schema level:在架构级别授予权限:

      GRANT INSERT, DELETE ON world.* TO u1;
    • Revoke the privileges globally (assuming that they are no longer needed):全局撤销特权(假设不再需要):

      REVOKE INSERT, DELETE ON *.* FROM u1;
    • Remove the account itself (assuming that it is no longer needed):删除帐户本身(假设不再需要):

      DROP USER u1;

After all privilege restrictions are removed, it is possible to disable partial revokes:删除所有特权限制后,可以禁用部分撤销:

SET PERSIST partial_revokes = OFF;

Partial Revokes and Replication部分撤销和复制

In replication scenarios, if partial_revokes is enabled on any host, it must be enabled on all hosts. 在复制场景中,如果在任何主机上启用了partial_revokes,则必须在所有主机上启用它。Otherwise, REVOKE statements to partially revoke a global privilege do not have the same effect for all hosts on which replication occurs, potentially resulting in replication inconsistencies or errors.否则,用于部分撤销全局权限的REVOKE语句对发生复制的所有主机没有相同的效果,可能会导致复制不一致或错误。