Databasesikkerhed er vigtig for enhver MySQL-opsætning. Brugere er grundlaget for ethvert system. Med hensyn til databasesystemer tænker jeg generelt på dem i to adskilte grupper:
- Applikations-, tjeneste- eller programbrugere - dybest set kunder eller klienter, der bruger en tjeneste.
- Databaseudviklere, administratorer, analytikere osv... - De, der vedligeholder, arbejder med eller overvåger databaseinfrastrukturen.
Selvom hver bruger har brug for at få adgang til databasen på et eller andet niveau, er disse tilladelser ikke alle skabt ens.
For eksempel har kunder og kunder brug for adgang til deres 'relaterede brugerkonto'-data, men selv det bør overvåges med en vis grad af kontrol. Nogle tabeller og data bør dog være strengt off-limits (f.eks. systemtabeller).
Ikke desto mindre:
- Analytiker har brug for 'læseadgang ', for at opnå information og indsigt via forespørgselstabeller...
- Udviklere kræver en række tilladelser og privilegier for at udføre deres arbejde...
- DBA'er har brug for "root" eller lignende type privilegier for at køre showet...
- Købere af en tjeneste skal se deres ordre- og betalingshistorik...
Du kan forestille dig (jeg ved, jeg gør), hvor vanskelig en opgave det er at administrere flere brugere eller grupper af brugere i et databaseøkosystem.
I ældre versioner af MySQL etableres et flerbrugermiljø på en noget monoton og gentagen måde.
Alligevel implementerer version 8 en enestående og kraftfuld SQL-standardfunktion - Roler - som afhjælper et af de mere overflødige områder af hele processen:tildeling af privilegier til en bruger.
Så hvad er en rolle i MySQL?
Du kan helt sikkert besøge, MySQL i 2018:Hvad er i 8.0 og andre observationer, jeg skrev til Severalnines-bloggen her, hvor jeg nævner roller for et overblik på højt niveau. Men hvor jeg kun opsummerede dem der, ser dette nuværende indlæg ud til at gå dybere og udelukkende fokusere på roller.
Her er, hvordan online MySQL-dokumentationen definerer en rolle:"En MySQL-rolle er en navngivet samling af privilegier".
Virker den definition ikke alene nyttig?
Men hvordan?
Vi vil se i de følgende eksempler.
At notere de angivne eksempler
Eksemplerne inkluderet i dette indlæg er i en personlig 'enkeltbruger' udviklings- og læringsarbejdsstation/-miljø, så vær sikker på og implementer de bedste praksisser, der gavner dig til dine særlige behov eller krav. De viste brugernavne og adgangskoder er rent vilkårlige og svage.
Brugere og privilegier i tidligere versioner
I MySQL 5.7 eksisterer roller ikke. Tildeling af privilegier til brugere sker individuelt. For bedre at forstå, hvilke roller der giver, lad os ikke bruge dem. Det giver overhovedet ingen mening, det ved jeg. Men efterhånden som vi kommer videre gennem indlægget, vil det ske.
Nedenfor opretter vi nogle brugere:
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';
Så tildeles disse brugere nogle privilegier:
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';
Puha, glad for at det er slut. Nu tilbage til...
Og bare sådan har du en anmodning om at implementere yderligere to 'skrivebeskyttede' brugere...
Tilbage til tegnebrættet:
CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2';
CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';
Tildeler dem også privilegier:
GRANT SELECT ON some_db.specific_table TO 'reader_2'@'localhost';
GRANT ALL ON some_db.specific_table TO 'reader_3'@'localhost';
Kan du se, hvordan dette er mindre end produktivt, fuld af gentagelser og udsat for fejl? Men endnu vigtigere, fangede du fejlen?
Godt for dig!
Mens jeg tildelte privilegier til disse to ekstra brugere, ved et uheld tildelt ALLE privilegier til ny bruger reader_3.
Ups.
En fejl, som enhver kunne begå.
Indtast MySQL-roller
Med roller er meget af ovenstående systematisk privilegietildeling og delegering kan strømlines noget .
Brugeroprettelse forbliver grundlæggende den samme, men det er at tildele privilegier gennem roller, der er forskellige:
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)
Ved at forespørge på mysql.user-systemtabellen kan du se, at disse nyoprettede brugere eksisterer:
(Bemærk:Jeg har flere brugerkonti i dette lærings-/udviklingsmiljø og har undertrykt meget af outputtet for bedre klarhed på skærmen.)
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)
Jeg har denne vilkårlige tabel og eksempeldata:
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)
Lad os nu bruge roller til at etablere og tildele privilegier for de nye brugere til at bruge navnetabellen.
Først skal du oprette rollerne:
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)
Læg mærke til mysql.user-tabellen igen:
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)
Baseret på dette output kan vi formode; at roller i alt væsentligt er brugerne selv.
Dernæst privilegietildeling:
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)
Et kort mellemspil
Vent et øjeblik. Kan jeg bare logge ind og udføre eventuelle opgaver med selve rollekontiene? De er trods alt brugere, og de har de nødvendige privilegier.
Lad os prøve at logge ind på praksisdatabasen med rollen main_changer:
:~$ mysql -u main_changer -p practice
Enter password:
ERROR 1045 (28000): Access denied for user 'main_changer'@'localhost' (using password: YES
Den simple kendsgerning, at vi bliver præsenteret for en adgangskodeprompt, er en god indikation af, at vi ikke kan (i hvert fald på nuværende tidspunkt). Som du husker, har jeg ikke angivet en adgangskode til nogen af rollerne under deres oprettelse.
Hvad har mysql.user-systemtabellernes authentication_string-kolonne at sige?
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)
Jeg inkluderede root-brugeren blandt rollenavnene for IN()-prædikatkontrollen for blot at vise, at den har en authentication_string, hvor rollerne ikke har det.
Denne passage i CREATE ROLE-dokumentationen præciserer det fint:"En rolle, når den oprettes, er låst, har ingen adgangskode og er tildelt standardgodkendelses-plugin'et. (Disse rolleattributter kan ændres senere med ALTER USER-sætningen af brugere, der har globalt OPRET BRUGER-privilegium.)"
Tilbage til den aktuelle opgave, vi kan nu tildele rollerne til brugere baseret på deres nødvendige niveau af privilegier.
Bemærk, at der ikke er nogen ON-sætning i kommandoen:
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)
Det kan være mindre forvirrende, hvis du bruger en form for 'navngivningskonvention ' når jeg etablerer rollenavne, (jeg er ikke klar over, om MySQL tilbyder et på nuværende tidspunkt... Fællesskab?), hvis det ikke er af anden grund end at skelne mellem dem og almindelige 'ikke-rolle'-brugere visuelt.
Der er stadig noget arbejde tilbage at gøre
Det var super nemt var det ikke?
Mindre overflødig end den gamle måde af privilegietildeling.
Lad os sætte disse brugere i arbejde nu.
Vi kan se de tildelte privilegier for en bruger med SHOW GRANTS-syntaks. Her er, hvad der i øjeblikket er tildelt reader_1-brugerkontoen:
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)
Selvom det giver et informativt output, kan du 'tune ' erklæringen for endnu mere detaljeret information om eventuelle nøjagtige privilegier en tildelt rolle giver ved at inkludere en USING-sætning i SHOW GRANTS-erklæringen og navngive den tildelte rolles navn:
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)
Efter at have logget ind med reader_1:
mysql> SELECT * FROM practice.name;
ERROR 1142 (42000): SELECT command denied to user 'reader_1'@'localhost' for table 'name'
Hvad I alverden? Denne bruger fik SELECT-rettigheder gennem rollen main_read_only.
For at undersøge det, lad os besøge 2 nye tabeller i version 8, specifikt for roller.
Mysql.role_edges-tabellen viser, hvilke roller der er blevet tildelt til enhver bruger:
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)
Men jeg føler, at den anden ekstra tabel, mysql.default_roles, bedre vil hjælpe os med at løse SELECT-problemerne for bruger 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)
Tomt resultatsæt.
Det viser sig, at for at en bruger skal kunne bruge en rolle - og i sidste ende privilegierne - skal brugeren tildeles en standardrolle.
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)
(En standardrolle kan tildeles til flere brugere i én kommando som ovenfor...)
mysql> SET DEFAULT ROLE main_read_only, main_changer TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.10 sec)
(En bruger kan have flere standardroller specificeret som i tilfældet for user changer_1...)
Bruger reader_1 er nu logget ind...
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)
Vi kan se den aktuelt aktive rolle og også, at reader_1 kan udstede SELECT-kommandoer nu:
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)
Andre skjulte nuancer
Der er en anden vigtig del af puslespillet vi skal forstå.
Der er potentielt 3 forskellige 'niveauer' eller 'varianter' af rolletildeling:
SET ROLE …;
SET DEFAULT ROLE …;
SET ROLE DEFAULT …;
Jeg giver bruger reader_1 en ekstra rolle og logger derefter på med denne bruger (ikke vist):
mysql> GRANT 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)
Da rollen main_read_write har INSERT-privilegiet, kan bruger reader_1 nu køre den kommando ikke?
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'
Hvad sker der her?
Dette kan hjælpe...
mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE() |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.00 sec)
Husk, at vi oprindeligt satte bruger reader_1 som standardrolle main_read_only. Det er her, vi skal bruge et af de distinkte 'niveauer' af det, jeg løst betegner 'rolleindstilling':
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)
Prøv nu at INSERT igen:
mysql> INSERT INTO name(f_name, l_name)
-> VALUES('Josh', 'Otwell');
Query OK, 1 row affected (0.12 sec)
Men når først bruger reader_1 logger ud igen, vil rollen main_read_write ikke længere være aktiv, når reader_1 logger ind igen. Selvom bruger reader_1 har rollen main_read_write tildelt, er det ikke standard.
Lad os nu lære det 3. 'niveau' af 'rolleindstilling' at kende, SET ROLE DEFAULT.
Antag, at bruger reader_1 ikke har nogen roller tildelt endnu:
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)
Lad os TILDELE denne bruger 2 roller:
mysql> GRANT 'main_changer', 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.07 sec)
Tildel en standardrolle:
mysql> SET DEFAULT ROLE ‘main_changer’ TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)
Så med bruger reader_1 logget ind, er denne standardrolle aktiv:
mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE() |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)
Skift nu til rollen 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)
Men for at vende tilbage til den tildelte standardrolle, brug SET ROLE DEFAULT som vist nedenfor:
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)
Roller ikke tildelt
Selvom user changer_1 har 2 roller tilgængelige under en session:
mysql> SELECT CURRENT_ROLE();
+-----------------------------------------+
| CURRENT_ROLE() |
+-----------------------------------------+
| `main_changer`@`%`,`main_read_only`@`%` |
+-----------------------------------------+
1 row in set (0.00 sec)
Hvad sker der, hvis du forsøger at indstille en bruger til en rolle, de ikke har fået tildelt?
mysql> SET ROLE main_read_write;
ERROR 3530 (HY000): `main_read_write`@`%` is not granted to `changer_1`@`localhost`
Afvist.
Take Away
Intet brugeradministrationssystem ville være komplet uden muligheden for at begrænse eller endda fjerne adgangen til visse operationer, hvis behovet skulle opstå.
Vi har SQL REVOKE-kommandoen til vores rådighed for at fjerne privilegier fra brugere og roller.
Husk på, at rollen main_changer har dette sæt privilegier, i det væsentlige gør alle de brugere, der har tildelt denne rolle, det samme:
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)
For at vide, hvilke brugere denne ændring påvirkede, kan vi besøge tabellen mysql.role_edges igen:
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)
Og vi kan se, at user changer_1 ikke længere har DELETE-privilegiet:
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)
Endelig, hvis vi har brug for at slippe af med en rolle helt, har vi kommandoen DROP ROLE til det:
mysql> DROP ROLE main_read_only;
Query OK, 0 rows affected (0.17 sec)
Og ved at forespørge i tabellen mysql.role_edges, er rollen main_read_only blevet fjernet:
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:Denne fantastiske YouTube-video var en fantastisk læringsressource for mig på Roller.)
Dette eksempel på brugeroprettelse, rolletildeling og opsætning er i bedste fald rudimentært. Alligevel har roller deres eget sæt regler, der gør dem langt fra trivielle. Mit håb er, at jeg gennem dette blogindlæg har kastet lys over de områder, der er mindre intuitive end andre, hvilket gør det muligt for læserne bedre at forstå potentielle rolleanvendelser i deres systemer.
Tak fordi du læste med.