Azure Database for MySQLをTerraformで構築してみます。
Terraformの構成
サーバとデータベース
Azure Database for MySQLを構築する際、最低限必要になるのはazurerm_mysql_server
とazurerm_mysql_database
でしょう。
リソース名が示唆する通り、Azure Database for MySQLは物理的なサーバと、その上で動作するデータベースの2種類になります。サーバ側はSKUやストレージサイズ、冗長性やネットワークアクセスに関する設定を指定します。一方でデータベース設定はその上で動くデータベースのcharset
等を指定することになります。
resource "azurerm_mysql_server" "this" { name = var.server_name location = var.location resource_group_name = var.resource_group_name sku_name = var.sku_name storage_mb = var.storage_mb version = var.mysql_version tags = var.tags administrator_login = var.administrator_login administrator_login_password = var.administrator_login_password auto_grow_enabled = true backup_retention_days = var.backup_retention_days geo_redundant_backup_enabled = var.geo_redundant_backup_enabled infrastructure_encryption_enabled = var.infrastructure_encryption_enabled public_network_access_enabled = var.public_network_access_enabled ssl_enforcement_enabled = var.ssl_enforcement_enabled ssl_minimal_tls_version_enforced = var.ssl_enforcement_enabled? var.ssl_minimal_tls_version_enforced : "TLSEnforcementDisabled" identity { type = "SystemAssigned" } } resource "azurerm_mysql_database" "this" { name = var.database_name resource_group_name = var.resource_group_name server_name = azurerm_mysql_server.this.name charset = var.charset collation = var.collation }
ネットワークアクセス制御
ネットワークアクセスはazurerm_mysql_firewall_rule
とazurerm_mysql_virtual_network_rule
で絞る形になります。
ファイアウォールルール
azurerm_mysql_firewall_rule
はインターネットやAzure自体からのネットワークアクセスの許可・非許可を制御します。
図としてはAzure Database for MySQL サーバーのファイアウォール規則に記載の以下の図がわかりやすいでしょう。
ここでは、以下のような形でIPアドレスの範囲をfrom-toで複数指定することを前提にしてみます。
permit_ip_ranges = { tokyo = ["203.0.113.0", "203.0.113.5"] osaka = ["203.0.113.129", "203.0.113.130"] }
そうすると、ファイアウォールルールの指定は以下のようになるでしょうか。
resource "azurerm_mysql_firewall_rule" "this" { for_each = var.permit_ip_ranges name = format("%s-fwrule-%s", var.server_name, each.key) resource_group_name = var.resource_group_name server_name = azurerm_mysql_server.this.name start_ip_address = each.value[0] end_ip_address = each.value[1] }
なお、Azure ServiceのInternal IPから接続を許可する場合は0.0.0.0
を指定する仕様になっています。
ただしこの場合、他のAzureユーザーのSubscriptionからも接続できてしまうので、当該設定をすることはほとんどないでしょう。
すべての Azure データセンターの IP アドレスからの接続を有効にすることを検討できます。 この設定は、Azure portal から [接続のセキュリティ] ウィンドウで、 [Azure サービスへのアクセス許可] オプションを [オン] にし、 [保存] を押すことで設定できます。 Azure CLI からは、ファイアウォール規則の設定で開始アドレスと終了アドレスを 0.0.0.0 にすることで同じことができます。
ちなみに、azurerm_mysql_server.public_network_access_enabled
は、Azureコンソール上の「パブリックネットワークアクセスの拒否」設定に対応しています。この値をfalse
にすると、ファイアウォール規則は無効となり、設定を入れても接続はできません。
また、この値をfalse
にしている状態だと、ファイアウォールルールの変更をしようと思っても以下のようなエラーが返却されます。
│ Error: deleting Firewall Rule: (Name "kiririmode-mysql-fwrule-home" / Server Name "kiririmode-mysql" / Resource Group "rg_kiririmode_mysql"): mysql.FirewallRulesClient#Delete: Failure sending request: StatusCode=0 -- Original Error: Code="FeatureSwitchNotEnabled" Message="Requested feature is not enabled"
VNETサービスエンドポイント
また、VNetからの接続の可否はVNetサービスエンドポイントに対応するazurerm_mysql_virtual_network_rule
で制御します。
Terraformでは、接続を許可するサブネットのIDを渡す形の制御になります。
resource "azurerm_mysql_virtual_network_rule" "example" { for_each = var.vnet_rules name = format("%s-vnetrule-%s", var.server_name, each.key) resource_group_name = var.resource_group_name server_name = azurerm_mysql_server.this.name subnet_id = each.value }
接続確認
インターネットからの接続
ファイアウォールルールを設定して、接続確認をしてみました。
もちろん、azurerm_mysql_server.public_network_access_enabled
にはtrue
を設定しています。
自分のグローバルIPアドレスを設定すると、確かに自分の端末からのMySQL接続が可能になります。
$ mysql --version mysql Ver 8.0.25 for macos11.3 on x86_64 (Homebrew) $ mysql -h kiririmode-mysql.mysql.database.azure.com -u 'kiririmode@kiririmode-mysql' -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 64455 Server version: 5.6.47.0 Source distribution
逆にファイアウォールルールを外すと、認証後エラーになります。
$ mysql -h kiririmode-mysql.mysql.database.azure.com -u 'kiririmode@kiririmode-mysql' -p Enter password: ERROR 9000 (HY000): Client with IP address 'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server.
VNETからの接続
VNETサービスエンドポイント経由での接続を試してみます。 まずはサービスエンドポイントを設定している場合。以下のように、接続できていることがわかります。
$ uname -a Linux reachable-machine 5.4.0-1048-azure #50~18.04.1-Ubuntu SMP Fri May 14 15:30:12 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux $ mysql --version mysql Ver 14.14 Distrib 5.7.34, for Linux (x86_64) using EditLine wrapper $ mysql -h kiririmode-mysql.mysql.database.azure.com -u 'kiririmode@kiririmode-mysql' -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 64533 Server version: 5.6.47.0 Source distribution
ここから、MySQL側のサービスエンドポイント設定を外してみます。 同一VMに接続した上でMySQL接続を試すと、対象VNETからの接続が許可されていないとしてエラーになることがわかります。
$ mysql -h kiririmode-mysql.mysql.database.azure.com -u 'kiririmode@kiririmode-mysql' -p Enter password: ERROR 9009 (28000): Client from Azure Virtual Networks is not allowed to access the server. Please make sure your Virtual Network is correctly configured.
まとめ
というわけで、TerraformからAzure Database for MySQLの構築を試してみました。
このほか、azurerm_mysql_configuration
でサーバーパラメータを管理できるなど、色々とIaCで管理できそうです。