🍣

Azure Database for MySQL Flexible serverのAAD認証を試す

2022/10/05に公開約11,100字

はじめに

先日(2022/9月末)、MicrosoftからAzureの各種サービスのリタイアのお知らせが一斉に発表されましたね。

Basic Public IP Addressや、Basic Load Balancerのリタイアも衝撃的ですが、Azure Database for MySQL single serverも2024年9月にリタイアが発表されました。

Action required: Migrate to Azure Database for MySQL Flexible Server by 16 September 2024

「いや、お前まだAzure AD認証サポートしていないじゃん」と思ったら、同じタイミングでFlexible serverでのAzure AD認証がパブリックプレビューになっていたので試しました。

Active Directory authentication - Azure Database for MySQL - Flexible Server Preview

大まかな構築手順

全体像は以下の通りです。

img

今回はAzure AD認証は以下の方法を試します。

  • Azure ADグループでの管理者認証 (2)
  • Azure ADユーザ認証 (3)
  • VMのSystem Managed Identityによる認証 (4)

Azureリソースの構築

こちらは今回はAzure portalでサクッと作成します。

img

一応セキュリティを考慮して、MySQLは仮想ネットワーク内に配置しました。

基本的に上の図の通りにAzureリソースを準備します。

MySQL Flexible serverの以下のAzure ADに関する設定は後述するので、まずは作成した仮想マシン(Ubuntu)にAzure CLIとmysql-clientのパッケージはインストールしておきましょう。

img

Linux に Azure CLI をインストールする

私はUbuntu 20.04 LTSを使いましたので以下の手順となります。

sudo apt remove azure-cli -y && sudo apt autoremove -y 
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

mysql-clientは以下で導入です。

sudo apt install mysql-client

後で使うので、jqも入れておきます。

sudo apt install jq

MySQL Flexible serverの診断設定ではauditログをLog Analyticsに送信する設定のほかに、サーバパラメータのaudit_log_enabledもONに変更しておきます。

これで、MySQLの認証ログが指定したLog AnalyticsのAzureDiagnosticsテーブルに出力されるようになります。

img

img

後の構築、設定は頑張ってください。Bicepなどによるデプロイテンプレートは後日公開したいと思いますが未定です。

とりあえずMySQL Flexible server構築時に指定したサーバ管理者ログイン名とパスワードでログインします。

mysql -h (MySQLサーバ名).mysql.database.azure.com -u dbadmin -p

ユーザはdbadminだけですね(他にもあるけど内部管理用なので気にしない)

mysql> select user,plugin from mysql.user;
+------------------+-----------------------+
| user             | plugin                |
+------------------+-----------------------+
| dbadmin          | mysql_native_password |
| azure_superuser  | mysql_native_password |
| azure_superuser  | mysql_native_password |
| mysql.infoschema | caching_sha2_password |
| mysql.session    | caching_sha2_password |
| mysql.sys        | caching_sha2_password |
+------------------+-----------------------+
6 rows in set (0.00 sec)

mysql>

AAD認証の設定

まずはAzure portalなどで、Azure ADの新たなグループを作成しておきます。
今回は「mysql-admin」というグループを作成しました。

※オブジェクトIDなど、この先実際の値がそのまま掲載されますが、本記事公開時点ではすべてのリソース類は削除済みなので問題ありません。

img

MySQL Flexible serverの「認証(プレビュー)」ブレードから、以下のように「アクセスの割当先」「ユーザー割り当てマネージドID」「Azure AD管理者名」を設定して、最後保存します。

img

mysql.userテーブルに、ちゃんと追加されていますね。

mysql> select user,plugin from mysql.user;
+------------------+-----------------------+
| user             | plugin                |
+------------------+-----------------------+
| dbadmin          | mysql_native_password |
| mysql-admin      | aad_auth              |
| azure_superuser  | mysql_native_password |
| azure_superuser  | mysql_native_password |
| mysql.infoschema | caching_sha2_password |
| mysql.session    | caching_sha2_password |
| mysql.sys        | caching_sha2_password |
+------------------+-----------------------+
7 rows in set (0.00 sec)

AAD認証の設定2

これが実は大事なのですが、MySQL Flexible serverのプラグインは先に設定したUser Managed ID (id-mysql-aadauth)を使って、Azure ADのユーザやグループの参照を行います。

先の設定でAAD管理者はAzure portalから行ったのですが、その後の追加ユーザはすべてMySQL上で行うため、このUser Managed IDにAzure ADの必要な権限を追加する必要があります。

公式ドキュメントには以下のように書かれています。

Active Directory authentication - Azure Database for MySQL - Flexible Server Preview - Permissions

User Managed IDにDirectory Readersロールを割り当てるか、以下のアクセス権限を与えてな。

  • User.Read.All
  • GroupMember.Read.All
  • Application.Read.ALL

残念ながらこちらの具体的な手順は書かれていませんでした(本記事執筆時点)。

私もまだこの部分はしっかりした手順を確立できていないため、とりあえずレベルですがWindows PowerShellで権限を付与するスクリプトを以下に貼ります。

解せないとは思いますが、手元のWindows PowerShellにAzureADモジュールをインストールして実施してくださいませ。

grant-aad.ps1
$msiId = "先の例でいうところのid-mysql-aadauthのオブジェクト(プリンシパル)ID"
 
Connect-AzureAD
$graph = Get-AzureADServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'"

$userReadPermission = $graph.AppRoles `
    | where Value -Like "User.Read.All" `
    | Select-Object -First 1

$groupReadPermission = $graph.AppRoles `
    | where Value -Like "GroupMember.Read.All" `
    | Select-Object -First 1

$appReadPermission = $graph.AppRoles `
    | where Value -Like "Application.Read.All" `
    | Select-Object -First 1
 
$msi = Get-AzureADServicePrincipal -ObjectId $msiId
 
New-AzureADServiceAppRoleAssignment `
    -Id $userReadPermission.Id `
    -ObjectId $msi.ObjectId `
    -PrincipalId $msi.ObjectId `
    -ResourceId $graph.ObjectId
 
New-AzureADServiceAppRoleAssignment `
    -Id $groupReadPermission.Id `
    -ObjectId $msi.ObjectId `
    -PrincipalId $msi.ObjectId `
    -ResourceId $graph.ObjectId
 
New-AzureADServiceAppRoleAssignment `
    -Id $appReadPermission.Id `
    -ObjectId $msi.ObjectId `
    -PrincipalId $msi.ObjectId `
    -ResourceId $graph.ObjectId

こちらの情報は以下の記事を参考にさせてもらいました。

Easy Auth と Managed Identity を使ってグループ情報でのアクセス制限を行う

How to Authenticate With Microsoft Graph API Using Managed Service Identity

MySQLへのAAD認証確認

さて、動作確認とAADユーザの追加を試していきましょう。

Azure AD管理者(グループ)でのログイン確認

最初に貼った全体像でいうと (2) の認証です。

Ubuntu VMからMySQLにログインします。

az account clear
az login --tenant (自身のテナント名)
mysql -h (MySQLサーバ名).mysql.database.azure.com -u mysql-admin --enable-cleartext-plugin --password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken)

正常にログインできました。

mysql> show processlist;
+-----+-------------+-------------------+------+---------+------+-------+------------------+
| Id  | User        | Host              | db   | Command | Time | State | Info             |
+-----+-------------+-------------------+------+---------+------+-------+------------------+
| 111 | mysql-admin | 192.168.0.4:39466 | NULL | Query   |    0 | init  | show processlist |
+-----+-------------+-------------------+------+---------+------+-------+------------------+
1 row in set (0.00 sec)

他のユーザ(Managed ID)の追加は、すべてAAD認証でログインした管理者が行うため、このログインセッションから、他のユーザの追加を行ってしまいます。

先の全体像の図でいうと、(3)個別ユーザ、(4)System Managed IDになります。

mysql> SET aad_auth_validate_oids_in_tenant = OFF;
mysql> CREATE AADUSER 'yotan' IDENTIFIED BY '9e1e68b3-4448-4a41-882b-XXXXXXXXXXXX';
mysql> CREATE AADUSER 'mysql-system' IDENTIFIED BY '9a4c57e7-f0ca-40e8-b247-XXXXXXXXXXXX';

それぞれのユーザ名は好きにつけてよいと思います。IDENTIFIED BYで指定するIDはそれぞれ

  • AADユーザプロパティに表示されている「オブジェクトID」
  • VMに設定したシステム割り当て済みの「オブジェクト(プリンシパル)ID」

となります。

mysql> select user,plugin from mysql.user;
+------------------+-----------------------+
| user             | plugin                |
+------------------+-----------------------+
| dbadmin          | mysql_native_password |
| mysql-admin      | aad_auth              |
| mysql-system     | aad_auth              |
| yotan            | aad_auth              |
| azure_superuser  | mysql_native_password |
| azure_superuser  | mysql_native_password |
| mysql.infoschema | caching_sha2_password |
| mysql.session    | caching_sha2_password |
| mysql.sys        | caching_sha2_password |
+------------------+-----------------------+
9 rows in set (0.01 sec)

このままでは追加したユーザに何もMySQLの権限がないので、少し追加しておきました。

mysql> GRANT CREATE, SELECT, INSERT, UPDATE, DELETE ON *.* TO `yotan`@`%`;
mysql> GRANT CREATE, SELECT, INSERT, UPDATE, DELETE ON *.* TO `mysql-system`@`%`;
mysql> FLUSH PRIVILEGES;

AADユーザでのログイン

こちらは先のAAD管理者ログインと同様のコマンドで、-u パラメータを先で指定したAADユーザ名にするだけです。

mysql -h (MySQLサーバ名).mysql.database.azure.com -u yotan --enable-cleartext-plugin --password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken)

正常にログインできましたね。

mysql> show processlist;
+-----+-------+-------------------+------+---------+------+-------+------------------+
| Id  | User  | Host              | db   | Command | Time | State | Info             |
+-----+-------+-------------------+------+---------+------+-------+------------------+
| 114 | yotan | 192.168.0.4:52516 | NULL | Query   |    0 | init  | show processlist |
+-----+-------+-------------------+------+---------+------+-------+------------------+
1 row in set (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.01 sec)

System Managed IDでのログイン

通常はアプリケーションからはこちらか、User Managed IDでのログインになるかと。

今回はSDKなどは使わず、curlで認証トークンを取得してMySQLにログインします。

accessToken=$(curl -s 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fossrdbms-aad.database.windows.net' -H Metadata:true | jq -r .access_token)
mysql -h ktkrmysql.mysql.database.azure.com -u mysql-system --enable-cleartext-plugin --password=$accessToken

ばっちりです

mysql> show processlist;
+-----+--------------+-------------------+------+---------+------+-------+------------------+
| Id  | User         | Host              | db   | Command | Time | State | Info             |
+-----+--------------+-------------------+------+---------+------+-------+------------------+
| 116 | mysql-system | 192.168.0.4:43756 | NULL | Query   |    0 | init  | show processlist |
+-----+--------------+-------------------+------+---------+------+-------+------------------+
1 row in set (0.01 sec)

MySQLの権限も強めに設定したのでいろいろできますね。

mysql> CREATE DATABASE hogehoge;
Query OK, 1 row affected (0.03 sec)

mysql> USE hogehoge;
Database changed
mysql> create table users (id int, name varchar(10));
Query OK, 0 rows affected (0.12 sec)

mysql> show tables;
+--------------------+
| Tables_in_hogehoge |
+--------------------+
| users              |
+--------------------+
1 row in set (0.01 sec)

mysql>

authlogの確認

MySQLのauthlogをLog Analyticsに転送設定を行っているので、最後にそちらを確認しましょう。

以下のクエリで確認しました。

AzureDiagnostics
| where Category == 'MySqlAuditLogs'
| order by TimeGenerated
| project TimeGenerated, event_subclass_s, user_s, external_user_s

Azure ADの認証はevent_subclass_sが「AADAUTH」となります。通常はuser_sにMySQLからCREATE AADUSERで登録した名前が入りますが、こちらがAzure ADのグループだった場合には
external_user_sに実際に認証を行ったAzure ADユーザ名が入ってきます(素晴らしい)。

img

おわりに

本機能がGAした際には仕様が変わってくるかもしれませんが、まずはAzure Database for MySQL Flexible serverのAAD認証がちゃんと利用できそうだということが確認できました。

実はSingle serverの方はすでにAAD認証が前から使えていたのですが、Azure ADのグループで認証すると実際には誰がログインしたのかを判別する手段がなく、困っていたところでした。

本記事が参考になれば幸いです。

以上。

Discussion

ログインするとコメントできます