Mysql
 sql >> Database >  >> RDS >> Mysql

Come utilizzare i ruoli che sono cambiati in MySQL 8.0

La sicurezza del database è importante per qualsiasi configurazione di MySQL. Gli utenti sono la base di qualsiasi sistema. In termini di sistemi di database, generalmente li considero in due gruppi distinti:

  1. Utenti di applicazioni, servizi o programmi - sostanzialmente clienti o clienti che utilizzano un servizio.
  2. Sviluppatori di database, amministratori, analisti, ecc… - Coloro che mantengono, lavorano o monitorano l'infrastruttura del database.

Sebbene ogni utente debba accedere al database a un certo livello, tali autorizzazioni non sono tutte uguali.

Ad esempio, clienti e clienti hanno bisogno di accedere ai dati dei loro "account utente correlati", ma anche quelli dovrebbero essere monitorati con un certo livello di controllo. Tuttavia, alcune tabelle e dati dovrebbero essere rigorosamente off-limits (ad es. tabelle di sistema).

Tuttavia:

  • L'analista ha bisogno di 'accesso in lettura ', per raccogliere informazioni e approfondimenti tramite query sulle tabelle...
  • Gli sviluppatori richiedono una serie di autorizzazioni e privilegi per svolgere il proprio lavoro...
  • I DBA necessitano di privilegi di tipo 'root' o simili per eseguire lo spettacolo...
  • Gli acquirenti di un servizio devono visualizzare la cronologia degli ordini e dei pagamenti...

Puoi immaginare (lo so di sì) quanto sia difficile un compito che gestisce più utenti o gruppi di utenti all'interno di un ecosistema di database.

Nelle versioni precedenti di MySQL, un ambiente multiutente è stabilito in modo alquanto monotono e ripetitivo.

Tuttavia, la versione 8 implementa una caratteristica standard SQL eccezionale e potente - Ruoli - che allevia una delle aree più ridondanti dell'intero processo:l'assegnazione dei privilegi a un utente.

Allora, qual è un ruolo in MySQL?

Puoi sicuramente visitare MySQL nel 2018:cosa c'è in 8.0 e altre osservazioni, ho scritto per il blog di Multiplenines qui dove menziono i ruoli per una panoramica di alto livello. Tuttavia, dove li ho solo riassunti lì, questo post attuale sembra approfondire e concentrarsi esclusivamente sui ruoli.

Ecco come la documentazione in linea di MySQL definisce un ruolo:"Un ruolo MySQL è una raccolta denominata di privilegi".

Questa definizione da sola non sembra utile?

Ma come?

Vedremo negli esempi che seguono.

Prendere nota degli esempi forniti

Gli esempi inclusi in questo post si trovano in una workstation/ambiente personale di sviluppo e apprendimento per "utente singolo", quindi assicurati di implementare quelle migliori pratiche che ti avvantaggiano per le tue esigenze o requisiti particolari. I nomi utente e le password mostrati sono puramente arbitrari e deboli.

Utenti e privilegi nelle versioni precedenti

In MySQL 5.7 i ruoli non esistono. L'assegnazione dei privilegi agli utenti avviene individualmente. Per capire meglio cosa forniscono i ruoli, non usiamoli. Non ha alcun senso, lo so. Ma, man mano che avanziamo nel post, lo farà.

Di seguito creiamo alcuni utenti:

CREATE USER 'reader_1'@'localhost' IDENTIFIED BY 'some_password'; 
CREATE USER 'reader_writer'@'localhost' IDENTIFIED BY 'another_password'; 
CREATE USER 'changer_1'@'localhost' IDENTIFIED BY 'a_password';

Quindi a questi utenti vengono concessi alcuni privilegi:

GRANT SELECT ON some_db.specific_table TO 'reader_1'@'localhost';
GRANT SELECT, INSERT ON some_db.specific_table TO 'reader_writer'@'localhost';
GRANT UPDATE, DELETE ON some_db.specific_table TO 'changer_1'@'localhost';

Wow, felice che sia finita. Ora torniamo a...

E proprio così, hai una richiesta per implementare altri due utenti di "sola lettura"...

Torna al tavolo da disegno:

CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2'; 
CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';

Assegnando anche loro i privilegi:

GRANT SELECT ON some_db.specific_table TO 'reader_2'@'localhost';
GRANT ALL ON some_db.specific_table TO 'reader_3'@'localhost';

Riesci a vedere come questo sia poco produttivo, pieno di ripetizioni e soggetto a errori? Ma, soprattutto, hai colto l'errore?

Buon per te!

Pur concedendo privilegi a questi due utenti aggiuntivi, io accidentalmente concesso TUTTI i privilegi al nuovo utente reader_3.

Ops.

Un errore che chiunque potrebbe fare.

Inserisci i ruoli MySQL

Con ruoli, gran parte dei precedenti sistematici l'assegnazione e la delega dei privilegi può essere in qualche modo snellita .

La creazione degli utenti rimane sostanzialmente la stessa, ma si tratta di assegnare privilegi tramite ruoli diversi:

mysql> CREATE USER 'reader_1'@'localhost' IDENTIFIED BY 'some_password';
Query OK, 0 rows affected (0.19 sec)
mysql> CREATE USER 'reader_writer'@'localhost' IDENTIFIED BY 'another_password';
Query OK, 0 rows affected (0.22 sec)
mysql> CREATE USER 'changer_1'@'localhost' IDENTIFIED BY 'a_password';
Query OK, 0 rows affected (0.08 sec)
mysql> CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2';
Query OK, 0 rows affected (0.28 sec)
mysql> CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';
Query OK, 0 rows affected (0.12 sec)

Interrogando la tabella di sistema mysql.user, puoi vedere che gli utenti appena creati esistono:

(Nota:ho diversi account utente in questo ambiente di apprendimento/sviluppo e ho soppresso gran parte dell'output per una migliore chiarezza sullo schermo.)

mysql> SELECT User FROM mysql.user;
+------------------+
| User             |
+------------------+
| changer_1        |
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
| reader_1         |
| reader_2         |
| reader_3         |
| reader_writer    |
| root             |
|                  | --multiple rows remaining here...
+------------------+
23 rows in set (0.00 sec)

Ho questa tabella arbitraria e dati di esempio:

mysql> SELECT * FROM name;
+--------+------------+
| f_name | l_name     |
+--------+------------+
| Jim    | Dandy      |
| Johhny | Applesauce |
| Ashley | Zerro      |
| Ashton | Zerra      |
| Ashmon | Zerro      |
+--------+------------+
5 rows in set (0.00 sec)

Usiamo ora i ruoli per stabilire e assegnare i privilegi ai nuovi utenti per utilizzare la tabella dei nomi.

Innanzitutto, crea i ruoli:

mysql> CREATE ROLE main_read_only;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE ROLE main_read_write;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE ROLE main_changer;
Query OK, 0 rows affected (0.14 sec)

Nota di nuovo la tabella mysql.user:

mysql> SELECT User FROM mysql.user;
+------------------+
| User             |
+------------------+
| main_changer     |
| main_read_only   |
| main_read_write  |
| changer_1        |
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
| reader_1         |
| reader_2         |
| reader_3         |
| reader_writer    |
| root             |
|                  |
+------------------+
26 rows in set (0.00 sec)

Sulla base di questo output, possiamo supporre; che in sostanza, i ruoli sono in effetti gli utenti stessi.

Quindi, assegnazione dei privilegi:

mysql> GRANT SELECT ON practice.name TO 'main_read_only';
Query OK, 0 rows affected (0.14 sec)
mysql> GRANT SELECT, INSERT ON practice.name TO 'main_read_write';
Query OK, 0 rows affected (0.07 sec)
mysql> GRANT UPDATE, DELETE ON practice.name TO 'main_changer';
Query OK, 0 rows affected (0.16 sec)

Un breve intermezzo

Apetta un minuto. Posso semplicemente accedere ed eseguire qualsiasi attività con gli account del ruolo stessi? Dopotutto, sono utenti e hanno i privilegi richiesti.

Proviamo ad accedere al database dello studio con il ruolo main_changer:

:~$ mysql -u main_changer -p practice
Enter password: 
ERROR 1045 (28000): Access denied for user 'main_changer'@'localhost' (using password: YES

Il semplice fatto che ci venga presentata una richiesta di password è una buona indicazione che non possiamo (almeno in questo momento). Come ricorderete, non ho impostato una password per nessuno dei ruoli durante la loro creazione.

Che cosa ha da dire la colonna stringa_autenticazione delle tabelle di sistema mysql.user?

mysql> SELECT User, authentication_string, password_expired
    -> FROM mysql.user
    -> WHERE User IN ('main_read_only', 'root', 'main_read_write', 'main_changer')\G
*************************** 1. row ***************************
                 User: main_changer
authentication_string: 
     password_expired: Y
*************************** 2. row ***************************
                 User: main_read_only
authentication_string: 
     password_expired: Y
*************************** 3. row ***************************
                 User: main_read_write
authentication_string: 
     password_expired: Y
*************************** 4. row ***************************
                 User: root
authentication_string: ***various_jumbled_mess_here*&&*&*&*##
     password_expired: N
4 rows in set (0.00 sec)

Ho incluso l'utente root tra i nomi dei ruoli per il controllo del predicato IN() per dimostrare semplicemente che ha una stringa_autenticazione, mentre i ruoli no.

Questo passaggio nella documentazione di CREATE ROLE lo chiarisce bene:"Un ruolo quando viene creato è bloccato, non ha password e gli viene assegnato il plug-in di autenticazione predefinito. (Questi attributi del ruolo possono essere modificati in seguito con l'istruzione ALTER USER, dagli utenti che hanno il privilegio globale CREATE USER.)"

Tornando all'attività in questione, ora possiamo assegnare i ruoli agli utenti in base al livello di privilegi necessario.

Notare che non è presente alcuna clausola ON nel comando:

mysql> GRANT 'main_read_only' TO 'reader_1'@'localhost', 'reader_2'@'localhost', 'reader_3'@'localhost';
Query OK, 0 rows affected (0.13 sec)
mysql> GRANT 'main_read_write' TO 'reader_writer'@'localhost';
Query OK, 0 rows affected (0.16 sec)
mysql> GRANT 'main_changer', 'main_read_only' TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.13 sec)

Potrebbe creare meno confusione se utilizzi una sorta di "convenzione di denominazione". ' quando si stabiliscono i nomi dei ruoli (non so se MySQL ne fornisce uno in questo momento... Community?) se non altro per differenziarli visivamente dai normali utenti "senza ruolo".

C'è ancora del lavoro da fare

È stato semplicissimo, vero?

Meno ridondante rispetto al vecchio modo di assegnazione di privilegi.

Mettiamo al lavoro quegli utenti ora.

Possiamo vedere i privilegi concessi per un utente con la sintassi SHOW GRANTS. Ecco cosa è attualmente assegnato all'account utente reader_1:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost';
+------------------------------------------------------+
| Grants for [email protected]                        |
+------------------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost`         |
| GRANT `main_read_only`@`%` TO `reader_1`@`localhost` |
+------------------------------------------------------+
2 rows in set (0.02 sec)

Sebbene ciò fornisca un output informativo, puoi 'sintonizzare ' la dichiarazione per informazioni ancora più dettagliate su eventuali privilegi esatti forniti da un ruolo assegnato includendo una clausola USING nell'istruzione SHOW GRANTS e nominando il nome dei ruoli assegnati:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost' USING 'main_read_only';
+-------------------------------------------------------------+
| Grants for [email protected]                               |
+-------------------------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost`                |
| GRANT SELECT ON `practice`.`name` TO `reader_1`@`localhost` |
| GRANT `main_read_only`@`%` TO `reader_1`@`localhost`        |
+-------------------------------------------------------------+
3 rows in set (0.00 sec)

Dopo aver effettuato l'accesso con reader_1:

mysql> SELECT * FROM practice.name;
ERROR 1142 (42000): SELECT command denied to user 'reader_1'@'localhost' for table 'name'

Cosa diavolo? A quell'utente sono stati concessi privilegi SELECT tramite il ruolo main_read_only.

Per indagare, visitiamo 2 nuove tabelle nella versione 8, in particolare per i ruoli.

La tabella mysql.role_edges mostra quali ruoli sono stati concessi a tutti gli utenti:

mysql> SELECT * FROM mysql.role_edges;
+-----------+-----------------+-----------+---------------+-------------------+
| FROM_HOST | FROM_USER       | TO_HOST   | TO_USER       | WITH_ADMIN_OPTION |
+-----------+-----------------+-----------+---------------+-------------------+
| %         | main_changer    | localhost | changer_1     | N                 |
| %         | main_read_only  | localhost | changer_1     | N                 |
| %         | main_read_only  | localhost | reader_1      | N                 |
| %         | main_read_only  | localhost | reader_2      | N                 |
| %         | main_read_only  | localhost | reader_3      | N                 |
| %         | main_read_write | localhost | reader_writer | N                 |
+-----------+-----------------+-----------+---------------+-------------------+
6 rows in set (0.00 sec)

Ma credo che l'altra tabella aggiuntiva, mysql.default_roles, ci aiuterà meglio a risolvere i problemi SELECT per l'utente reader_1:

mysql> DESC mysql.default_roles;
+-------------------+----------+------+-----+---------+-------+
| Field             | Type     | Null | Key | Default | Extra |
+-------------------+----------+------+-----+---------+-------+
| HOST              | char(60) | NO   | PRI |         |       |
| USER              | char(32) | NO   | PRI |         |       |
| DEFAULT_ROLE_HOST | char(60) | NO   | PRI | %       |       |
| DEFAULT_ROLE_USER | char(32) | NO   | PRI |         |       |
+-------------------+----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM mysql.default_roles;
Empty set (0.00 sec)

Set di risultati vuoto.

Affinché un utente possa utilizzare un ruolo - e in definitiva i privilegi, all'utente deve essere assegnato un ruolo predefinito.

mysql> SET DEFAULT ROLE main_read_only TO 'reader_1'@'localhost', 'reader_2'@'localhost', 'reader_3'@'localhost';
Query OK, 0 rows affected (0.11 sec)

(Un ruolo predefinito può essere assegnato a più utenti in un comando come sopra...)

mysql> SET DEFAULT ROLE main_read_only, main_changer TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.10 sec)

(Un utente può avere più ruoli predefiniti specificati come nel caso del cambio utente_1...)

L'utente reader_1 è ora connesso...

mysql> SELECT CURRENT_USER();
+--------------------+
| CURRENT_USER()     |
+--------------------+
| [email protected] |
+--------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE()       |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.03 sec)

Possiamo vedere il ruolo attualmente attivo e anche che reader_1 può emettere comandi SELECT ora:

mysql> SELECT * FROM practice.name;
+--------+------------+
| f_name | l_name     |
+--------+------------+
| Jim    | Dandy      |
| Johhny | Applesauce |
| Ashley | Zerro      |
| Ashton | Zerra      |
| Ashmon | Zerro      |
+--------+------------+
5 rows in set (0.00 sec)

Altre sfumature nascoste

C'è un'altra parte importante del puzzle dobbiamo capire.

Esistono potenzialmente 3 diversi "livelli" o "varianti" di assegnazione dei ruoli:

SET ROLE …;
SET DEFAULT ROLE …;
SET ROLE DEFAULT …;

Concederò un ruolo aggiuntivo all'utente reader_1 e quindi effettuerò il login con quell'utente (non mostrato):

mysql> GRANT 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)

Poiché il ruolo main_read_write ha il privilegio INSERT, l'utente reader_1 può ora eseguire quel comando giusto?

mysql> INSERT INTO name(f_name, l_name)
    -> VALUES('Josh', 'Otwell');
ERROR 1142 (42000): INSERT command denied to user 'reader_1'@'localhost' for table 'name'

Cosa sta succedendo qui?

Questo può aiutare...

mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE()       |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.00 sec)

Ricordiamo, inizialmente abbiamo impostato l'utente reader_1 un ruolo predefinito di main_read_only. È qui che dobbiamo usare uno di quei 'livelli' distinti di ciò che termo vagamente 'impostazione del ruolo':

mysql> SET ROLE main_read_write;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+-----------------------+
| CURRENT_ROLE()        |
+-----------------------+
| `main_read_write`@`%` |
+-----------------------+
1 row in set (0.00 sec)

Ora riprova con INSERT:

mysql> INSERT INTO name(f_name, l_name)
    -> VALUES('Josh', 'Otwell');
Query OK, 1 row affected (0.12 sec)

Tuttavia, una volta che l'utente reader_1 si disconnette, il ruolo main_read_write non sarà più attivo quando reader_1 accede nuovamente. Sebbene all'utente reader_1 sia concesso il ruolo main_read_write, non è l'impostazione predefinita.

Veniamo ora a conoscere il 3° 'livello' di 'impostazione del ruolo', SET ROLE DEFAULT.

Supponiamo che l'utente reader_1 non abbia ancora ruoli assegnati:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost';
+----------------------------------------------+
| Grants for [email protected]                |
+----------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost` |
+----------------------------------------------+
1 row in set (0.00 sec)

CONCEDIAMO a questo utente 2 ruoli:

mysql> GRANT 'main_changer', 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.07 sec)

Assegna un ruolo predefinito:

mysql> SET DEFAULT ROLE ‘main_changer’ TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)

Quindi con l'utente reader_1 connesso, quel ruolo predefinito è attivo:

mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE()     |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)

Ora passa al ruolo main_read_write:

mysql> SET ROLE 'main_read_write';
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT CURRENT_ROLE();
+-----------------------+
| CURRENT_ROLE()        |
+-----------------------+
| `main_read_write`@`%` |
+-----------------------+
1 row in set (0.00 sec)

Ma, per tornare al ruolo predefinito assegnato, usa SET ROLE DEFAULT come mostrato di seguito:

mysql> SET ROLE DEFAULT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE()     |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)

Ruoli non concessi

Anche se user changer_1 ha 2 ruoli disponibili durante una sessione:

mysql> SELECT CURRENT_ROLE();
+-----------------------------------------+
| CURRENT_ROLE()                          |
+-----------------------------------------+
| `main_changer`@`%`,`main_read_only`@`%` |
+-----------------------------------------+
1 row in set (0.00 sec)

Cosa succede se tenti di impostare un utente su un ruolo che non gli è stato concesso?

mysql> SET ROLE main_read_write;
ERROR 3530 (HY000): `main_read_write`@`%` is not granted to `changer_1`@`localhost`

Negato.

Porta via

Nessun sistema di gestione degli utenti sarebbe completo senza la possibilità di limitare o addirittura rimuovere l'accesso a determinate operazioni in caso di necessità.

Abbiamo il comando SQL REVOKE a nostra disposizione per rimuovere i privilegi da utenti e ruoli.

Ricordiamo che il ruolo main_changer ha questo set di privilegi, in sostanza, anche tutti gli utenti a cui è stato concesso questo ruolo:

mysql> SHOW GRANTS FOR main_changer;
+-----------------------------------------------------------------+
| Grants for [email protected]%                                       |
+-----------------------------------------------------------------+
| GRANT USAGE ON *.* TO `main_changer`@`%`                        |
| GRANT UPDATE, DELETE ON `practice`.`name` TO `main_changer`@`%` |
+-----------------------------------------------------------------+
2 rows in set (0.00 sec)
mysql> REVOKE DELETE ON practice.name FROM 'main_changer';
Query OK, 0 rows affected (0.11 sec)
mysql> SHOW GRANTS FOR main_changer;
+---------------------------------------------------------+
| Grants for [email protected]%                               |
+---------------------------------------------------------+
| GRANT USAGE ON *.* TO `main_changer`@`%`                |
| GRANT UPDATE ON `practice`.`name` TO `main_changer`@`%` |
+---------------------------------------------------------+
2 rows in set (0.00 sec)

Per sapere quali utenti ha interessato questa modifica, possiamo visitare di nuovo la tabella mysql.role_edges:

mysql> SELECT * FROM mysql.role_edges WHERE FROM_USER = 'main_changer';
+-----------+--------------+-----------+-----------+-------------------+
| FROM_HOST | FROM_USER    | TO_HOST   | TO_USER   | WITH_ADMIN_OPTION |
+-----------+--------------+-----------+-----------+-------------------+
| %         | main_changer | localhost | changer_1 | N                 |
+-----------+--------------+-----------+-----------+-------------------+
1 row in set (0.00 sec)

E possiamo vedere che user changer_1 non ha più il privilegio DELETE:

mysql> SHOW GRANTS FOR 'changer_1'@'localhost' USING 'main_changer';
+--------------------------------------------------------------------------+
| Grants for [email protected]                                           |
+--------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `changer_1`@`localhost`                            |
| GRANT UPDATE ON `practice`.`name` TO `changer_1`@`localhost`             |
| GRANT `main_changer`@`%`,`main_read_only`@`%` TO `changer_1`@`localhost` |
+--------------------------------------------------------------------------+
3 rows in set (0.00 sec)

Infine, se dobbiamo eliminare completamente un ruolo, abbiamo il comando DROP ROLE per questo:

mysql> DROP ROLE main_read_only;
Query OK, 0 rows affected (0.17 sec)

E interrogando la tabella mysql.role_edges, il ruolo main_read_only è stato rimosso:

mysql> SELECT * FROM mysql.role_edges;
+-----------+-----------------+-----------+---------------+-------------------+
| FROM_HOST | FROM_USER       | TO_HOST   | TO_USER       | WITH_ADMIN_OPTION |
+-----------+-----------------+-----------+---------------+-------------------+
| %         | main_changer    | localhost | changer_1     | N                 |
| %         | main_read_write | localhost | reader_1      | N                 |
| %         | main_read_write | localhost | reader_writer | N                 |
+-----------+-----------------+-----------+---------------+-------------------+
3 rows in set (0.00 sec)

(Bonus:questo fantastico video di YouTube è stato un'ottima risorsa di apprendimento per me sui ruoli.)

Questo esempio di creazione di utenti, assegnazione di ruoli e configurazione è nella migliore delle ipotesi rudimentale. Tuttavia, i ruoli hanno il loro insieme di regole che li rendono tutt'altro che banali. La mia speranza è che attraverso questo post del blog, ho fatto luce su quelle aree che sono meno intuitive di altre, consentendo ai lettori di comprendere meglio i potenziali usi dei ruoli all'interno dei loro sistemi.

Grazie per aver letto.