Aurora Serverless v2(MySQL)のマスターユーザ同等の権限のユーザを作ってみた

    Aurora Serverless v2(MySQL)のマスターユーザ同等の権限のユーザを作ってみた

    本記事はAsiaQuest Advent Calendarの16日目です。

    目次

      はじめに

      クラウドインテグレーション部の渡邊です。
      今回は、Aurora Serverless v2(MySQL)のマスターユーザ同等の権限のユーザを作成する手順、作成時の注意点を説明します。

      以下にも記載の通り、アプリケーションによるマスターユーザの使用は非推奨であるため、今回の手順を参考に、権限をカスタムするとよいと思います。

      アプリケーションではマスターユーザーを直接使用しないことを強くお勧めします。代わりに、アプリケーションに必要な最小の特権で作成されたデータベースユーザーを使用するというベストプラクティスに従ってください。

      引用元:Amazon Aurora MySQL でのセキュリティ

      環境情報

      • Amazon Linux 2023
      • mysql Ver 15.1 Distrib 10.5.20-MariaDB, for Linux (x86_64) using EditLine wrapper
      • Aurora MySQL 8.0

      事前準備

      クライアント側で以下の環境変数を設定してください(<>には実際のエンドポイントを入れる)。

      DB_ENDPOINT=<test-db-clusterのエンドポイント>

      実際にやってみた

      ユーザ作成

      テスト用のユーザ(以降、テストユーザと呼ぶ)を作成します。

      # DBへadminユーザでログイン
      [ec2-user@ip-10-0-1-233 ~]$ mysql -h ${DB_ENDPOINT} -P 3306 -u admin -p
      Enter password:
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 45
      Server version: 8.0.23 Source distribution

      Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      # ユーザと接続できるホスト情報を取得
      MySQL [(none)]> SELECT user, host FROM mysql.user;
      +-----------------------+-----------+
      | user | host |
      +-----------------------+-----------+
      | AWS_COMPREHEND_ACCESS | % |
      | AWS_LAMBDA_ACCESS | % |
      | AWS_LOAD_S3_ACCESS | % |
      | AWS_SAGEMAKER_ACCESS | % |
      | AWS_SELECT_S3_ACCESS | % |
      | admin | % |
      | rds_superuser_role | % |
      | mysql.infoschema | localhost |
      | mysql.session | localhost |
      | mysql.sys | localhost |
      | rdsadmin | localhost |
      +-----------------------+-----------+
      11 rows in set (0.002 sec)

      # テストユーザの作成
      MySQL [(none)]> CREATE USER 'test'@'%' IDENTIFIED BY 'Passw0rd!';
      Query OK, 0 rows affected (0.018 sec)

      MySQL [(none)]> SELECT user, host FROM mysql.user;
      +-----------------------+-----------+
      | user | host |
      +-----------------------+-----------+
      | AWS_COMPREHEND_ACCESS | % |
      | AWS_LAMBDA_ACCESS | % |
      | AWS_LOAD_S3_ACCESS | % |
      | AWS_SAGEMAKER_ACCESS | % |
      | AWS_SELECT_S3_ACCESS | % |
      | admin | % |
      | rds_superuser_role | % |
      | test | % |
      | mysql.infoschema | localhost |
      | mysql.session | localhost |
      | mysql.sys | localhost |
      | rdsadmin | localhost |
      +-----------------------+-----------+
      12 rows in set (0.022 sec)

      接続元のホストを制限せずに、ユーザを作成します。

      たとえば、接続元のホストをlocalhostとすると、リモート接続によるログインに失敗するため注意してください。

      # DBへtest-localユーザでログイン
      [ec2-user@ip-10-0-1-233 ~]$ mysql -h ${DB_ENDPOINT} -P 3306 -u 'test-local' -p
      Enter password:
      ERROR 1045 (28000): Access denied for user 'test-local'@'10.0.1.233' (using password: YES)

      接続元IPアドレスで絞る方法も可能ですが、今回はAWS環境を前提としており、基本的に接続元IPアドレス等はセキュリティグループで制限します。
      なお、以下はクライアントのプライベートIPアドレスを指定して、接続元を制限している例です。

      [ec2-user@ip-10-0-1-233 ~]$ mysql -h  ${DB_ENDPOINT} -P 3306 -u 'admin' -p
      Enter password:
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 2927
      Server version: 8.0.23 Source distribution

      Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      # test-remote1ユーザを作成
      MySQL [(none)]> CREATE USER 'test-remote1'@'10.0.1.233' IDENTIFIED BY 'Passw0rd!';
      Query OK, 0 rows affected (0.029 sec)

      MySQL [(none)]> SELECT user, host FROM mysql.user;
      +-----------------------+------------+
      | user | host |
      +-----------------------+------------+
      | 1$%&#*tmp-1110 | % |
      | AWS_COMPREHEND_ACCESS | % |
      | AWS_LAMBDA_ACCESS | % |
      | AWS_LOAD_S3_ACCESS | % |
      | AWS_SAGEMAKER_ACCESS | % |
      | AWS_SELECT_S3_ACCESS | % |
      | admin | % |
      | rds_superuser_role | % |
      | test | % |
      | tmp-1110 | % |
      | test-remote1 | 10.0.1.233 |
      | mysql.infoschema | localhost |
      | mysql.session | localhost |
      | mysql.sys | localhost |
      | rdsadmin | localhost |
      | test-local | localhost |
      +-----------------------+------------+
      16 rows in set (0.002 sec)

      # ログアウト
      MySQL [(none)]> exit
      Bye

      # DBへtest-remote1ユーザでログイン
      [ec2-user@ip-10-0-1-233 ~]$ mysql -h ${DB_ENDPOINT} -P 3306 -u 'test-remote1' -p
      Enter password:
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 2933
      Server version: 8.0.23 Source distribution

      Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      # 認証済みユーザー名の表示
      MySQL [(none)]> SELECT user(), current_user();
      +-------------------------+-------------------------+
      | user() | current_user() |
      +-------------------------+-------------------------+
      | test-remote1@10.0.1.233 | test-remote1@10.0.1.233 |
      +-------------------------+-------------------------+
      1 row in set (0.004 sec)

      以上を踏まえて、今回は接続元を制限せずにユーザを作成しました。

      マスターユーザ作成時にあった命名の制約は、通常のユーザ作成時にはその制約がなかったです。

      マスターユーザー名 は文字 (A~Z と a~z) で始まり、文字、数字 (0~9)、およびアンダースコア (_) のみを使用する必要があります。  

      a_user_with_the_same_privileges_as_a_master_user_01

      # 1$%&#*tmp-1110ユーザを作成
      MySQL [(none)]> CREATE USER '1$%&#*tmp-1110'@'%' IDENTIFIED BY 'Passw0rd!';
      Query OK, 0 rows affected (0.046 sec)

      MySQL [(none)]> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE ROLE, DROP ROLE ON *.* TO `1$%&#*tmp-1110`@`%` WITH GRANT OPTION;
      Query OK, 0 rows affected (0.018 sec)

      MySQL [(none)]> exit
      Bye

      # DBへ1$%&#*tmp-1110ユーザでログイン
      [ec2-user@ip-10-0-1-233 ~]$ mysql -h ${DB_ENDPOINT} -P 3306 -u '1$%&#*tmp-1110' -p
      Enter password:
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 2646
      Server version: 8.0.23 Source distribution

      Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      MySQL [(none)]> SELECT user, host FROM mysql.user;
      +-----------------------+-----------+
      | user | host |
      +-----------------------+-----------+
      | 1$%&#*tmp-1110 | % |
      | AWS_COMPREHEND_ACCESS | % |
      | AWS_LAMBDA_ACCESS | % |
      | AWS_LOAD_S3_ACCESS | % |
      | AWS_SAGEMAKER_ACCESS | % |
      | AWS_SELECT_S3_ACCESS | % |
      | admin | % |
      | rds_superuser_role | % |
      | test | % |
      | mysql.infoschema | localhost |
      | mysql.session | localhost |
      | mysql.sys | localhost |
      | rdsadmin | localhost |
      +-----------------------+-----------+

      ただし、MySQLでは「-」が特殊文字扱いになるので、基本的に利用は避けてください。
      ユーザ作成時には、マスターユーザ作成時にあった制約を守るのが無難かと思います。

       

      権限付与

      マスターユーザと同等の権限付与ができるかやってみます。
      まず、テストユーザの権限の初期状態を確認します。
      USAGEは権限がないことを示すため、なにも動作しないことを表します。

      # testユーザの権限を確認
      MySQL [(none)]> show grants for 'test'@`%`;
      +--------------------------------------+
      | Grants for test@% |
      +--------------------------------------+
      | GRANT USAGE ON *.* TO `test`@`%` |
      +--------------------------------------+
      1 row in set (0.004 sec)

      次に、マスターユーザがどのような権限を持っているのか確認します。
      マスターユーザはrds_superuser_roleがアタッチされているので、ロールの権限を確認します。

      # adminユーザの権限を確認
      MySQL [(none)]> show grants for 'admin'@`%`;
      +-----------------------------------------------+
      | Grants for admin@% |
      +-----------------------------------------------+
      | GRANT USAGE ON *.* TO `admin`@`%` |
      | GRANT `rds_superuser_role`@`%` TO `admin`@`%` |
      +-----------------------------------------------+
      2 rows in set (0.003 sec)

      # rds_superuser_roleロールの権限を確認
      MySQL [(none)]> SHOW GRANTS FOR 'rds_superuser_role'@'%';
      +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      | Grants for rds_superuser_role@% |
      +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE ROLE, DROP ROLE ON *.* TO `rds_superuser_role`@`%` WITH GRANT OPTION |
      | GRANT APPLICATION_PASSWORD_ADMIN,CONNECTION_ADMIN,REPLICATION_APPLIER,ROLE_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,XA_RECOVER_ADMIN ON *.* TO `rds_superuser_role`@`%` WITH GRANT OPTION |
      | GRANT `AWS_COMPREHEND_ACCESS`@`%`,`AWS_LAMBDA_ACCESS`@`%`,`AWS_LOAD_S3_ACCESS`@`%`,`AWS_SAGEMAKER_ACCESS`@`%`,`AWS_SELECT_S3_ACCESS`@`%` TO `rds_superuser_role`@`%` |
      +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      3 rows in set (0.002 sec)

      確認した結果、静的権限、動的権限、AWS用のロールが付与されています。
      以下のように、マスタユーザのロールを付与することも可能です。

      # rds_superuser_roleロールをtestユーザへ付与
      MySQL [(none)]> GRANT `rds_superuser_role`@`%` TO `test`@`%`;
      Query OK, 0 rows affected (0.076 sec)

      今回は、そのロールに含まれる権限およびAWS用のロールを、テストユーザに付与します。

      # adminに付与されていた静的権限をtestユーザへ付与
      MySQL [(none)]> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO `test`@`%` WITH GRANT OPTION;
      Query OK, 0 rows affected (0.005 sec)

      # adminに付与されていた動的権限をtestユーザへ付与
      MySQL [(none)]> GRANT APPLICATION_PASSWORD_ADMIN,CONNECTION_ADMIN,REPLICATION_APPLIER,ROLE_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,XA_RECOVER_ADMIN ON *.* TO `test`@`%` WITH GRANT OPTION;
      Query OK, 0 rows affected (0.024 sec)

      # adminに付与されていたAWS用のロールをtestユーザへ付与
      MySQL [(none)]> GRANT `AWS_COMPREHEND_ACCESS`@`%`,`AWS_LAMBDA_ACCESS`@`%`,`AWS_LOAD_S3_ACCESS`@`%`,`AWS_SAGEMAKER_ACCESS`@`%`,`AWS_SELECT_S3_ACCESS`@`%` TO `test`@`%` ;
      Query OK, 0 rows affected (0.028 sec)

      MySQL [(none)]> show grants for 'test'@`%`;
      +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      | Grants for test@% |
      +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE ROLE, DROP ROLE ON *.* TO `test`@`%` WITH GRANT OPTION |
      | GRANT APPLICATION_PASSWORD_ADMIN,CONNECTION_ADMIN,REPLICATION_APPLIER,ROLE_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,XA_RECOVER_ADMIN ON *.* TO `test`@`%` WITH GRANT OPTION |
      | GRANT `AWS_COMPREHEND_ACCESS`@`%`,`AWS_LAMBDA_ACCESS`@`%`,`AWS_LOAD_S3_ACCESS`@`%`,`AWS_SAGEMAKER_ACCESS`@`%`,`AWS_SELECT_S3_ACCESS`@`%` TO `test`@`%` |
      +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
      3 rows in set (0.004 sec)

      マスターユーザと同等の権限の付与に成功しました。
      アプリケーションのユーザの権限は最小限にするように、注意してください。
      以下の権限は、とくに慎重に検討する必要があります。

      DELETE
      DROP
      CREATE USER
      CREATE ROLE
      DROP ROLE

       

      テストユーザによる動作確認

      権限の付与に成功したので、一部の静的権限のみ動作確認を行います。

      [ec2-user@ip-10-0-1-233 ~]$ mysql -h  ${DB_ENDPOINT} -P 3306 -u test -p
      Enter password:
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 245
      Server version: 8.0.23 Source distribution

      Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      MySQL [(none)]> SELECT user(), current_user();
      +-----------------+----------------+
      | user() | current_user() |
      +-----------------+----------------+
      | test@10.0.1.233 | test@% |
      +-----------------+----------------+
      1 row in set (0.004 sec)

      # tmpという名前のデータベースを作成
      MySQL [(none)]> CREATE DATABASE tmp;
      Query OK, 1 row affected (0.027 sec)

      # データベースの一覧を確認
      MySQL [(none)]> SHOW databases;
      +--------------------+
      | Database |
      +--------------------+
      | information_schema |
      | mysql |
      | performance_schema |
      | sys |
      | tmp |
      +--------------------+
      5 rows in set (0.021 sec)

      # tmpという名前のデータベースを削除
      MySQL [(none)]> DROP DATABASE tmp;
      Query OK, 0 rows affected (0.081 sec)

      MySQL [(none)]> SHOW databases;
      +--------------------+
      | Database |
      +--------------------+
      | information_schema |
      | mysql |
      | performance_schema |
      | sys |
      +--------------------+
      4 rows in set (0.007 sec)

      動作確認完了です。マスターユーザと同等の権限を得られました。

      まとめ

      • 接続元のホストをユーザごとに制限できる
        • セキュリティが厳しい環境の場合、接続元ホストで絞る
      • マスターユーザ作成時にあった以下命名の制約は、通常のユーザ作成時にはない
        • 文字 (A~Z と a~z) で始まる
        • 文字、数字 (0~9)、およびアンダースコア (_) のみを使用する
      • USAGEは権限がないことを示す
      • マスターユーザはロールrds_superuser_roleがアタッチされており、そのロールには静的権限、動的権限、AWS用のロールが付与されている
      • アプリケーションのユーザの権限は最小限にする

       

      【参考】

      Master user account privileges

      MySQL が実行されている Amazon RDS DB インスタンスの別のマスターユーザーを作成する方法を教えてください。

      Aurora MySQL で Amazon Aurora 機械学習を使用する

      Trying to add the File permission to MySQL RDS instance access denied

      6.2.2 Privileges Provided by MySQL

      12.16 情報関数

      MySQLでハイフン使うと面倒

      今日は、MySQLでオブジェクト名にハイフンはエラーになるの日。