データベースのセキュリティは、MySQLのセットアップにとって重要です。ユーザーはあらゆるシステムの基盤です。データベースシステムに関しては、私は一般的に2つの異なるグループに分けて考えています。
- アプリケーション、サービス、またはプログラムのユーザー-基本的に、サービスを使用している顧客またはクライアント。
- データベース開発者、管理者、アナリストなど…-データベースインフラストラクチャを維持、操作、または監視する人。
各ユーザーはあるレベルでデータベースにアクセスする必要がありますが、それらの権限はすべて同じように作成されているわけではありません。
たとえば、クライアントと顧客は「関連するユーザーアカウント」データにアクセスする必要がありますが、それでもある程度の制御で監視する必要があります。ただし、一部のテーブルとデータは厳密に立ち入り禁止にする必要があります(システムテーブルなど)。
それにもかかわらず:
- アナリストには'読み取りアクセスが必要です '、テーブルのクエリを介して情報と洞察を獲得するには…
- 開発者は、作業を実行するために多数の権限と特権を必要とします…
- ショーを実行するには、DBAに「root」または同様のタイプの権限が必要です…
- サービスの購入者は、注文と支払いの履歴を確認する必要があります…
データベースエコシステム内で複数のユーザーまたはユーザーのグループを管理するタスクがどれほど難しいかを想像できます(私は知っています)。
MySQLの古いバージョンでは、マルチユーザー環境はやや単調で反復的な方法で確立されています。
それでも、バージョン8は、例外的で強力なSQL標準機能「ロール」を実装しています。これにより、プロセス全体の冗長な領域の1つであるユーザーへの特権の割り当てが軽減されます。
では、MySQLでの役割は何ですか?
きっとアクセスできます。2018年のMySQL:8.0の内容とその他の所見、私はここのいくつかのブログに、高レベルの概要の役割について言及しています。ただし、ここでそれらを要約しただけでは、この現在の投稿はさらに深くなり、役割のみに焦点を当てるように見えます。
オンラインのMySQLドキュメントでロールを定義する方法は次のとおりです。「MySQLロールは名前付きの特権のコレクションです」
その定義だけでも役立つと思いませんか?
しかし、どうやって?
次の例で確認します。
提供された例をメモする
この投稿に含まれている例は、個人的な「シングルユーザー」の開発および学習ワークステーション/環境に含まれているため、特定のニーズまたは要件に役立つベストプラクティスを必ず実装してください。示されているユーザー名とパスワードは純粋に恣意的で弱いものです。
以前のバージョンのユーザーと権限
MySQL 5.7では、ロールは存在しません。ユーザーへの特権の割り当ては個別に行われます。役割が提供するものをよりよく理解するために、それらを使用しないようにしましょう。それはまったく意味がありません、私は知っています。ただし、投稿を進めていくと、そうなります。
以下にいくつかのユーザーを作成します:
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';
次に、それらのユーザーにいくつかの特権が付与されます:
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';
ふぅ、それが終わってよかった。さて、戻って…
そして、ちょうどそのように、さらに2人の「読み取り専用」ユーザーを実装するリクエストがあります…
製図板に戻る:
CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2';
CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';
それらにも特権を割り当てます:
GRANT SELECT ON some_db.specific_table TO 'reader_2'@'localhost';
GRANT ALL ON some_db.specific_table TO 'reader_3'@'localhost';
これが生産性に欠け、繰り返しに満ち、エラーが発生しやすいことがわかりますか?しかし、もっと重要なことは、間違いを見つけましたか?
よろしくお願いします!
これらの2人の追加ユーザーに特権を付与しているときに、誤って 新しいユーザーreader_3にすべての権限を付与しました。
おっと。
誰もが犯す可能性のある間違い。
MySQLの役割を入力
役割がある場合、上記の体系的な 特権の割り当てと委任は、ある程度合理化できます 。
ユーザーの作成は基本的に同じですが、異なる役割を介して特権を割り当てます:
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)
mysql.userシステムテーブルをクエリすると、新しく作成されたユーザーが存在することがわかります。
(注:この学習/開発環境にはいくつかのユーザーアカウントがあり、画面上の明瞭さを高めるために出力の多くを抑制しています。)
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)
この任意のテーブルとサンプルデータがあります:
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)
次に、ロールを使用して、新しいユーザーが名前テーブルを使用するための特権を確立して割り当てます。
まず、役割を作成します:
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)
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)
この出力に基づいて、推測することができます。本質的に、役割は実際にはユーザー自身です。
次に、特権の割り当て:
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)
簡単な間奏
ちょっと待って。ログインして、ロールアカウント自体でタスクを実行できますか?結局のところ、彼らはユーザーであり、必要な特権を持っています。
main_changerの役割で練習データベースにログインしてみましょう:
:~$ mysql -u main_changer -p practice
Enter password:
ERROR 1045 (28000): Access denied for user 'main_changer'@'localhost' (using password: YES
パスワードプロンプトが表示されるという単純な事実は、(少なくとも現時点では)できないことを示す良い兆候です。ご存知のとおり、作成時にどの役割にもパスワードを設定しませんでした。
mysql.userシステムテーブルのauthentication_string列は何を言っている必要がありますか?
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)
IN()述語チェックのロール名にrootユーザーを含めて、ロールには認証文字列がないことを簡単に示しました。
CREATE ROLEドキュメントのこの箇所は、次のように明確に説明しています。「作成時のロールはロックされており、パスワードがなく、デフォルトの認証プラグインが割り当てられています。グローバルCREATEUSER特権。) "
手元のタスクに戻ると、必要な特権レベルに基づいてユーザーに役割を割り当てることができます。
コマンドにON句が含まれていないことに注意してください:
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)
ある種の'命名規則を使用すると、混乱が少なくなる可能性があります。 'ロール名を確立するとき(MySQLが現時点でロール名を提供しているかどうかはわかりません...コミュニティ?)、ロール名と通常の'非ロール'ユーザーを視覚的に区別する以外の理由がない場合。
まだやるべきことが残っています
とても簡単でしたね?
古い方法よりも冗長性が少ない 特権割り当ての。
それらのユーザーを今すぐ働かせましょう。
SHOWGRANTS構文を使用してユーザーに付与された特権を確認できます。現在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)
それは有益な出力を提供しますが、'調整することができます 'SHOW GRANTSステートメントにUSING句を含め、割り当てられたロールに名前を付けることにより、割り当てられたロールが提供する正確な特権に関するさらに詳細な情報のステートメント:
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)
reader_1でログインした後:
mysql> SELECT * FROM practice.name;
ERROR 1142 (42000): SELECT command denied to user 'reader_1'@'localhost' for table 'name'
一体全体?そのユーザーには、ロールmain_read_onlyを介してSELECT特権が付与されました。
調査するために、特に役割のために、バージョン8の2つの新しいテーブルにアクセスしてみましょう。
mysql.role_edgesテーブルは、すべてのユーザーに付与されている役割を示しています。
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)
しかし、他の追加のテーブルmysql.default_rolesは、ユーザーreader_1のSELECTの問題を解決するのに役立つと思います:
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)
空の結果セット。
結局のところ、ユーザーが役割(そして最終的には特権)を使用できるようにするには、ユーザーにデフォルトの役割を割り当てる必要があります。
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)
(デフォルトの役割は、上記のように1つのコマンドで複数のユーザーに割り当てることができます…)
mysql> SET DEFAULT ROLE main_read_only, main_changer TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.10 sec)
(ユーザーは、user changer_1の場合のように、複数のデフォルトの役割を指定できます…)
ユーザーreader_1がログインしました...
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)
現在アクティブな役割を確認できます。また、reader_1がSELECTコマンドを発行できるようになりました:
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)
その他の隠されたニュアンス
パズルにはもう1つの重要な部分があります 理解する必要があります。
役割の割り当てには、潜在的に3つの異なる「レベル」または「バリアント」があります。
SET ROLE …;
SET DEFAULT ROLE …;
SET ROLE DEFAULT …;
ユーザーreader_1に追加の役割を付与してから、そのユーザーでログインします(表示されていません):
mysql> GRANT 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)
ロールmain_read_writeにはINSERT特権があるため、ユーザーreader_1はそのコマンドを正しく実行できますか?
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'
ここで何が起こっているのですか?
これは役立つかもしれません...
mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE() |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.00 sec)
最初に、ユーザーreader_1をmain_read_onlyのデフォルトの役割に設定したことを思い出してください。ここで、私が大まかに言うものの明確な「レベル」の1つを使用する必要があります。 「役割設定」:
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)
次に、そのINSERTを再試行します:
mysql> INSERT INTO name(f_name, l_name)
-> VALUES('Josh', 'Otwell');
Query OK, 1 row affected (0.12 sec)
ただし、ユーザーreader_1がログアウトすると、reader_1が再度ログインしたときにロールmain_read_writeはアクティブではなくなります。ユーザーreader_1にはmain_read_writeロールが付与されていますが、これはデフォルトではありません。
ここで、「役割設定」の3番目の「レベル」であるSETROLEDEFAULTについて理解しましょう。
ユーザーreader_1にまだ役割が割り当てられていないとします:
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)
このユーザーに2つの役割を付与しましょう:
mysql> GRANT 'main_changer', 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.07 sec)
デフォルトの役割を割り当てます:
mysql> SET DEFAULT ROLE ‘main_changer’ TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)
次に、ユーザーreader_1がログインすると、そのデフォルトの役割がアクティブになります。
mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE() |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)
次に、ロール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)
ただし、割り当てられたデフォルトの役割に戻るには、以下に示すようにSETROLEDEFAULTを使用します。
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)
付与されていないロール
ユーザーchanger_1には、セッション中に使用できる2つの役割がありますが:
mysql> SELECT CURRENT_ROLE();
+-----------------------------------------+
| CURRENT_ROLE() |
+-----------------------------------------+
| `main_changer`@`%`,`main_read_only`@`%` |
+-----------------------------------------+
1 row in set (0.00 sec)
ユーザーに付与されていない役割を設定しようとするとどうなりますか?
mysql> SET ROLE main_read_write;
ERROR 3530 (HY000): `main_read_write`@`%` is not granted to `changer_1`@`localhost`
拒否されました。
テイクアウェイ
必要が生じた場合に特定の操作へのアクセスを制限したり、削除したりする機能がなければ、ユーザー管理システムは完成しません。
ユーザーとロールから特権を削除するためのSQLREVOKEコマンドを自由に使用できます。
ロールmain_changerにはこの一連の権限があることを思い出してください。基本的に、このロールを付与されたすべてのユーザーにも同様の権限があります。
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)
この変更がどのユーザーに影響を与えたかを知るために、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)
そして、ユーザーchanger_1には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)
最後に、役割を完全に取り除く必要がある場合は、そのためのDROPROLEコマンドがあります。
mysql> DROP ROLE main_read_only;
Query OK, 0 rows affected (0.17 sec)
また、mysql.role_edgesテーブルをクエリすると、ロールmain_read_onlyが削除されました:
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)
(ボーナス:この素晴らしいYouTubeビデオは、ロールに関する私にとって素晴らしい学習リソースでした。)
このユーザーの作成、役割の割り当て、およびセットアップの例は、せいぜい初歩的なものです。それでも、役割には、些細なこととはほど遠い独自の一連のルールがあります。このブログ投稿を通じて、他の領域よりも直感的でない領域に光を当て、読者がシステム内での潜在的な役割の使用をよりよく理解できるようになることを願っています。
読んでいただきありがとうございます。