web-dev-qa-db-fra.com

MySQL accorde tous les privilèges à la base de données sauf une table

J'ai été incapable de trouver une solution raisonnable pour atteindre les objectifs suivants:

Je souhaite avoir un utilisateur qui a TOUS les privilèges sur une base de données (ou une série de bases de données avec le même schéma), sauf pour une table, pour laquelle ils n'auront que des privilèges SELECT.

Essentiellement, je veux que l'utilisateur ait la liberté de contrôler une base de données mais ne puisse pas mettre à jour une table spécifique.

Jusqu'ici j'ai essayé, en vain:

  • Octroyer tous les privilèges sur cette base de données (nom_base. *), Puis spécifiquement attribuer uniquement les privilèges de sélection sur la table souhaitée (en espérant que cela écraserait le "tout", stupide, je le sais).

  • Accorder tous les privilèges sur cette base de données (nom_base. *), Puis révoquer les opérations d'insertion, de mise à jour et de suppression. Mais cela a généré une erreur disant qu'il n'y avait pas de règle d'attribution pour db_name.table_name.

D'après ce que j'ai pu rassembler, je devrai octroyer individuellement tous les privilèges sur chaque table de la base de données, à l'exception de la table en lecture seule.

S'il vous plaît, quelqu'un me dit qu'il existe un moyen plus simple

Note : J'utilise MySQL 5.1. La dernière disponible sur Ubuntu 10.04.

23
xzyfer

Je sais que ceci est un ancien post, mais je pensais ajouter quelque chose à la question de @tdammers pour que les autres le voient. Vous pouvez également effectuer un SELECT CONCAT sur information_schema.tables pour créer vos commandes d'octroi, sans avoir à écrire un script séparé.

Tout d'abord, révoquez tous les privilèges de cette base de données:

REVOKE ALL PRIVILEGES ON db.* FROM user@localhost;  

Puis créez vos déclarations GRANT:

SELECT CONCAT("GRANT UPDATE ON db.", table_name, " TO user@localhost;")
FROM information_schema.TABLES
WHERE table_schema = "YourDB" AND table_name <> "table_to_skip";

Copiez et collez les résultats dans votre client MySQL et exécutez-les tous.

28
Carlos

Selon les critères de reconnaissance, oui, vous devez accorder individuellement par table. Mais bon, vous avez un ordinateur là-bas. Les ordinateurs sont très efficaces pour automatiser des tâches répétitives, alors pourquoi ne créez-vous pas un script qui:

  1. Obtenir une liste de toutes les tables de la base de données (SHOW TABLES;)
  2. Accordez toutes les autorisations pour chaque élément de la liste.
  3. Révoquer les autorisations sur la table spéciale

Ou, alternativement: 2. Pour chaque élément de la liste, vérifiez s'il s'agit de la table spéciale; si c'est pas , accorder toutes les permissions

La raison pour laquelle je ne donne pas de code, c'est que cela peut être fait dans n'importe quel langage de script utilisant les fonctionnalités de MySQL, même le script Shell; utilisez ce que vous utilisez le mieux.

6
tdammers

Voici un brouillon de ce que j'utilise pour attribuer des rôles dans MariaDB. Peut-être qu'organiser un EVENT le rendrait plus cool :-)

DELIMITER $$

DROP PROCEDURE IF EXISTS refreshRoles $$
CREATE PROCEDURE refreshRoles ()
  COMMENT 'Grant SELECT on new databases/tables, revoke on deleted'
BEGIN
  DECLARE done BOOL;
  DECLARE db VARCHAR(128);
  DECLARE tb VARCHAR(128);
  DECLARE rl VARCHAR(128);
  DECLARE tables CURSOR FOR
    SELECT table_schema, table_name, '_bob_live_sg' FROM information_schema.tables
    WHERE table_schema LIKE '%bob\_live\_sg' AND
      (  false
      OR table_name LIKE 'bundle%'
      OR table_name LIKE 'cart%'
      OR table_name LIKE 'catalog%'
      OR table_name LIKE 'url%'
      );

  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=true;

  CREATE ROLE IF NOT EXISTS '_bob_live_sg';
  REVOKE ALL, GRANT OPTION FROM '_bob_live_sg';

  OPEN tables;
  SET done = false;
  grant_loop: LOOP
    FETCH tables INTO db, tb, rl;
    IF done THEN
      LEAVE grant_loop;
    END IF;
    SET @g = CONCAT('GRANT SELECT ON `', db, '`.`', tb, '` TO ', rl);
    PREPARE g FROM @g;
    EXECUTE g;
    DEALLOCATE PREPARE g;
  END LOOP;
  CLOSE tables;
END $$

DELIMITER ;

CALL refreshRoles;
1
Igor

Malheureusement, MySQL intègre des méthodes naturelles pour effectuer des tâches sélectives/exceptionnelles. 

Vous pouvez utiliser le script ci-dessous (script bash de la console linux)

#!/bin/bash

# Define the database and root authorization details
db_Host='localhost'
db_name='adhoctuts'
db_user='root'
db_pass='Adhoctuts2018#'

# Define the query to get the needed tables
table_list=$(mysql -h $db_Host -u $db_user -p"$db_pass" -se "select concat(table_schema,'.',table_name) from information_schema.tables where table_schema='$db_name' and table_name not like 'tbl1' AND table_name not like '\_\_%';" $db_name | cut -f1)

# Convert the query result into the array
table_arr=(${table_list//,/ })

# Declare the associative array of the users as username=>password pair
# e.g: declare -A user_list=(["'user1'"]="pass1" ["'user2'"]="pass2")
# In our case there is a single user
declare -A user_list=(["'aht_r'@'localhost'"]="Adhoctuts2018#")
for user in "${!user_list[@]}"
do
    pass=${user_list[$user]}
    # Recreate user
    mysql -h $db_Host -u $db_user -p"$db_pass" -se "drop user if exists $user; create user $user identified by '$pass';"

    # Provide SELECT privilege
    mysql -h $db_Host -u $db_user -p"$db_pass" -se "revoke all privileges, grant option from $user;" $db_name
    mysql -h $db_Host -u $db_user -p"$db_pass" -se "grant usage on $db_name.* TO $user;" $db_name
    for tbl in "${table_arr[@]}"; do
        echo "grant select on $tbl TO $user"
        mysql -h $db_Host -u $db_user -p"$db_pass" -se "grant select on $tbl TO $user;" $db_name    
    done
done

Si vous avez une console Windows, vous pouvez utiliser le fichier .bat suivant: 

@ECHO OFF
%= Define the database and root authorization details =% 
set db_Host=192.168.70.138
set db_name=adhoctuts
set db_user=adhoctuts
set db_pass=Adhoctuts2018#

mysql -h %db_Host% -u %db_user% -p"%db_pass%" -se "select concat(table_schema,'.',table_name) from information_schema.tables where table_schema='%db_name%' and table_name not like 'tbl1' AND table_name not like '\_\_%%';" %db_name% > tbls

setlocal EnableDelayedExpansion
set user_cnt=2
set user[1]='Adhoctuts1'@'192.168.%%.%%'
set pass[1]=Adhoctuts1_2018#
set user[2]='Adhoctuts2'@'192.168.%%.%%'
set pass[2]=Adhoctuts2_2018#

set i=1
:loop
    set user=!user[%i%]!
    set pass=!pass[%i%]!
    mysql -h %db_Host% -u %db_user% -p"%db_pass%" -se "drop user if exists %user% ; create user %user%  identified by '%pass%';"
    mysql -h %db_Host% -u %db_user% -p"%db_pass%" -se "revoke all privileges, grant option from %user%;" %db_name%      
    for /F "usebackq delims=" %%a in ("tbls") do (
        mysql -h %db_Host% -u %db_user% -p"%db_pass%" -se "grant select on %%a TO %user%;" %db_name%
    )
    if %i% equ %user_cnt% goto :end_loop
    set /a i=%i%+1
goto loop

:end_loop
del /f tbls

Commencez par écrire la requête pour obtenir la liste des tables nécessaires, puis définissez la liste des utilisateurs pour lesquels vous souhaitez accorder un accès. Vous devez exécuter le script chaque fois que la structure de la base de données change. J'ai créé un court tutoriel séparé pour les tâches sélectives/exceptionnelles de MySQL. 

https://adhoctuts.com/mysql-selective-exceptional-permissions-and-backup-restore/

https://youtu.be/8fWQbtIISdc

0
user628176