Quantcast
Channel: Percona Database Performance Blog
Viewing all articles
Browse latest Browse all 1786

MySQL Partial Revokes Privileges

$
0
0
mysql partial revokes

Have you ever encountered situations where you want to grant a user access to all databases except a few? Or have you ever tried to revoke partial privileges from a user and you have gotten the below error message? If yes, then this article may interest you.

ERROR 1141 (42000): There is no such grant defined for user username on host '%';

Recently, one of our clients requested to REVOKE partial privileges for a single database from a user having ALL the privileges for all the databases, meaning GRANT ALL ON *.* TO ‘username’@’hostname.’ Prior to MySQL 8.0.16, it was not possible to grant privileges that apply globally except for certain schemas. As of MySQL 8.0.16, that is possible if the partial_revokes system variable is enabled. 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. Privilege restrictions thus imposed may be useful for the 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.

However, be mindful that in the case of replication scenarios, if partial_revokes is enabled on any host, it must be enabled on all hosts. 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.

When partial_revokes is enabled, an extended syntax is recorded in the binary log for GRANT statements, including the current user that issued the statement and their currently active roles. If a user or a role recorded in this way does not exist on the replica, the replication applier thread stops at the GRANT statement with an error. Ensure that all user accounts that issue or might issue GRANT statements on the replication source server also exist on the replica and have the same set of roles as they have on the source. Partial revokes of schema-level privileges appear in SHOW GRANTS output as REVOKE statements.

Enabling partial revokes

The partial_revokes system variable controls whether privilege restrictions can be placed on accounts. By default, partial_revokes is disabled, and attempts to partially revoke global privileges produce an error:

To permit the REVOKE operation, enable partial_revokes:

SET PERSIST partial_revokes = ON;

Let us understand the partial revokes better through an example use case. Here, we have a user with the username ‘developer,’ and we will demonstrate to you how we can partially revoke privileges from this user with the MySQL partial_revoke variable. 

mysql> show grants for 'developer'@'%'G
*************************** 1. row ***************************
Grants for developer@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `developer`@`%`
*************************** 2. row ***************************
Grants for developer@%: GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ABORT_EXEMPT,AUDIT_ADMIN,AUTHENTICATION_POLICY_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,FIREWALL_EXEMPT,FLUSH_OPTIMIZER_COSTS,FLUSH_STATUS,FLUSH_TABLES,FLUSH_USER_RESOURCES,GROUP_REPLICATION_ADMIN,GROUP_REPLICATION_STREAM,INNODB_REDO_LOG_ARCHIVE,INNODB_REDO_LOG_ENABLE,PASSWORDLESS_USER_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SENSITIVE_VARIABLES_OBSERVER,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SHOW_ROUTINE,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,TELEMETRY_LOG_ADMIN,XA_RECOVER_ADMIN ON *.* TO `developer`@`%`

Let’s try to revoke the privilege from ‘developer’@’%’ only for the classicmodels database.

mysql> REVOKE ALL ON classicmodels.* FROM 'developer'@'%'; 
ERROR 1141 (42000): There is no such grant defined for user 'developer' on host '%'

mysql> REVOKE SELECT, INSERT, UPDATE, DELETE, CREATE, DROP ON classicmodels.* FROM 'developer'@'%';
ERROR 1141 (42000): There is no such grant defined for user 'developer' on host '%'

So, by default, partial revoke is disabled in MySQL 8. Either you can revoke all privileges or none if the user is assigned all privileges like the one in the example above.

mysql> REVOKE ALL ON *.* FROM 'developer'@'%';
Query OK, 0 rows affected (0.01 sec)

mysql> show grants for 'developer'@'%' G
*************************** 1. row ***************************
Grants for developer@%: GRANT USAGE ON *.* TO `developer`@`%`
1 row in set (0.00 sec)

Now, let’s give another try to the same user, but this time, we should be enabling the variable ‘partial_revokes’ as shown below. With ‘partial_revokes’ enabled, the partial revoke succeeds:

mysql> show grants for 'developer'@'%' G
*************************** 1. row ***************************
Grants for developer@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `developer`@`%`
*************************** 2. row ***************************
Grants for developer@%: GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ABORT_EXEMPT,AUDIT_ADMIN,AUTHENTICATION_POLICY_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,FIREWALL_EXEMPT,FLUSH_OPTIMIZER_COSTS,FLUSH_STATUS,FLUSH_TABLES,FLUSH_USER_RESOURCES,GROUP_REPLICATION_ADMIN,GROUP_REPLICATION_STREAM,INNODB_REDO_LOG_ARCHIVE,INNODB_REDO_LOG_ENABLE,PASSWORDLESS_USER_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SENSITIVE_VARIABLES_OBSERVER,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SHOW_ROUTINE,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,TELEMETRY_LOG_ADMIN,XA_RECOVER_ADMIN ON *.* TO `developer`@`%`
*************************** 3. row ***************************
Grants for developer@%: REVOKE SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `classicmodels`.* FROM `developer`@`%`
3 rows in set (0.00 sec)

Tested for Percona Server for MySQL 8.0.32: 

mysql> GRANT ALL privileges ON *.* TO 'developer'@'%';
Query OK, 0 rows affected (0.17 sec)

mysql> SHOW GRANTS FOR 'developer'@'%' G
*************************** 1. row ***************************
Grants for developer@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `rfc`@`localhost`
*************************** 2. row ***************************
Grants for developer@%: GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ABORT_EXEMPT,AUDIT_ADMIN,AUTHENTICATION_POLICY_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,FIREWALL_EXEMPT,FLUSH_OPTIMIZER_COSTS,FLUSH_STATUS,FLUSH_TABLES,FLUSH_USER_RESOURCES,GROUP_REPLICATION_ADMIN,GROUP_REPLICATION_STREAM,INNODB_REDO_LOG_ARCHIVE,INNODB_REDO_LOG_ENABLE,PASSWORDLESS_USER_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SENSITIVE_VARIABLES_OBSERVER,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SHOW_ROUTINE,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,XA_RECOVER_ADMIN ON *.* TO `rfc`@`localhost`
2 rows in set (0.22 sec)

mysql>  select @@partial_revokes;
+-------------------+
| @@partial_revokes |
+-------------------+
|                 0 |
+-------------------+
1 row in set (0.13 sec)

mysql> REVOKE ALL privileges ON new_db.* FROM 'developer'@'%'; 
ERROR 1141 (42000): There is no such grant defined for user 'developer' on host '%' mysql>

## Now enable partial_revoke:
mysql> set global partial_revokes =1;
Query OK, 0 rows affected (0.13 sec)

mysql>  select @@partial_revokes;
+-------------------+
| @@partial_revokes |
+-------------------+
|                 1 |
+-------------------+
1 row in set (0.01 sec)

mysql>  REVOKE ALL privileges ON new_db.* FROM 'developer'@'%';
Query OK, 0 rows affected (0.06 sec)

mysql> SHOW GRANTS FOR 'developer'@'%' G
*************************** 1. row ***************************
Grants for developer@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `rfc`@`localhost`
*************************** 2. row ***************************
Grants for developer@%: GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ABORT_EXEMPT,AUDIT_ADMIN,AUTHENTICATION_POLICY_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,FIREWALL_EXEMPT,FLUSH_OPTIMIZER_COSTS,FLUSH_STATUS,FLUSH_TABLES,FLUSH_USER_RESOURCES,GROUP_REPLICATION_ADMIN,GROUP_REPLICATION_STREAM,INNODB_REDO_LOG_ARCHIVE,INNODB_REDO_LOG_ENABLE,PASSWORDLESS_USER_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SENSITIVE_VARIABLES_OBSERVER,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SHOW_ROUTINE,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,XA_RECOVER_ADMIN ON *.* TO `rfc`@`localhost`
*************************** 3. row ***************************
Grants for developer@%: REVOKE SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `new_db`.* FROM `rfc`@`localhost`
3 rows in set (0.22 sec)

Disabling partial revokes

Once enabled, partial_revokes cannot be disabled if any account has privilege restrictions. If any such account exists, disabling partial_revokes fails:

  • For attempts to disable partial_revokes at startup, the server logs an error message and enables partial_revokes.
  • For attempts to disable partial_revokes at runtime, an error occurs, and the partial_revokes value remains unchanged.

To disable partial_revokes when restrictions exist, the restrictions first must be removed:

  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:
    [{"Database": "world", "Privileges": ["INSERT", "DELETE"]

Restriction removal can be done in various ways:

  • Grant the privileges globally, without restrictions:

GRANT INSERT, DELETE ON *.* TO user1;

  • Grant the privileges at the schema level:

GRANT INSERT, DELETE ON db_name.* TO user1;

  • Revoke the privileges globally (assuming that they are no longer needed):

REVOKE INSERT, DELETE ON *.* FROM user1;

  • Remove the account itself (assuming that it is no longer needed):

DROP USER user1;

After all privilege restrictions are removed, it is possible to disable partial revokes:

SET PERSIST partial_revokes = OFF;

How to implement partial revoke on MySQL 5.7 or MariaDB?

So the question is, if you are using MySQL Server 5.7 or any of the MariaDB servers, how do you work this out? Suppose there are the below databases, and we need to REVOKE privileges from a user for one of the databases only, say, database_03.

mysql_instace01 (none)> show databases;
+--------------------------+
| Database                 |
+--------------------------+
| information_schema       |
| mysql                    |
| mysql_logs               |
| performance_schema       |
| database_01              |
| database_02              |
| database_03              |
| database_04              |
+--------------------------+
7 rows in set (0.00 sec)

Perform the following steps:

  1. If the user is created with GRANT ALL PRIVILEGES ON *.*

MariaDB [(none)]> SHOW GRANTS FOR 'username'@'%';
*************************** 1. row ***************************
Grants for username@% : GRANT ALL PRIVILEGES ON *.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string'
1 row in set (0.000 sec)

  1. We need to remove all privileges from that user first.

REVOKE ALL PRIVILEGES ON *.* FROM `username`@`%`;

  1. Then we will again grant privileges to that user for the rest of the DBs except for database_03.

GRANT ALL PRIVILEGES ON information_schema.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON mysql.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON mysql_logs.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON performance_schema.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON database_01.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON database_02.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';
GRANT ALL PRIVILEGES ON database_04.* TO `username`@`%` IDENTIFIED BY PASSWORD 'password_string';

  1. Verify if the grants are all set.

MariaDB [(none)]> SHOW GRANTS FOR 'username'@'%';

Conclusion

The partial revokes feature is controlled through a system variable ‘partial_revokes’ with default as OFF.  You need to turn ON the value of the system variable in order to use this feature. You cannot turn OFF the system variable ‘partial_revokes’ as long as there exists at least one partial revoke on a database.

Partial revokes do not support the grants with wildcard characters; hence, it does not treat the wildcard characters ‘_’ and ‘%’ specially.

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.

I hope this blog post is helpful in giving a fairly good idea about partial revokes on database objects. You might be excited to try out your use cases!

Percona Distribution for MySQL is the most complete, stable, scalable, and secure open source MySQL solution available, delivering enterprise-grade database environments for your most critical business applications… and it’s free to use!

 

Try Percona Distribution for MySQL today!


Viewing all articles
Browse latest Browse all 1786

Trending Articles