Terraform で Azure SQL Server
Azure には SQLServer の PaaS サービスが存在します。主に2種類で、Azure SQL Database と Azure SQL Database Managed Instance です。
まずは、SQLServer に関する2つの PaaS について解説していきます。
SQL Database と SQL Database Managed Instance
SQLServer はサーバー(インスタンス)とデータベースという2層構造になっています。
本当にざっくりとしたイメージですが、Azure ではこのサーバー(インスタンス)とデータベースの両方のレイヤーで PaaS を提供しています。
サーバー(インスタンス)で提供されるサービスが SQL Database Managed Instance で、データベース単位で提供されるサービスが SQL Database です。
機能の差異
SQL Database はデータベースの PaaS ということもあり、UTC で固定、SQL Serverのネイティブバックアップを利用できない(BACKUP/RESTOREステートメントをサポートしていない)といった制限がありました。
SQL Database Managed Instance ではそういった制限はなく設定やバックアップリストアが可能ですので、オンプレから Azure への移行についても SQL Database Managed Instance であればよりスムーズに行えるようになっています。
詳しくは @IT さんの記事をご覧ください。各サービスの細かい違いまで説明されいますのでとても分かりやすいです。
今回は特に難しいことはせず、SQLServer を立ててログインするくらいの確認にしたいと思いますので、SQL Database で立てたいと思います。
azurerm_mssql と azurerm_sql
Azure Provider を確認すると、"azurerm_mssql_" "azurerm_sql_" で始まる resource がこれだけ存在するのが分かります。
- azurerm_mssql_database
- azurerm_mssql_database_extended_auditing_policy
- azurerm_mssql_database_vulnerability_assessment_rule_baseline
- azurerm_mssql_elasticpool
- azurerm_mssql_server
- azurerm_mssql_server_extended_auditing_policy
- azurerm_mssql_server_security_alert_policy
- azurerm_mssql_server_vulnerability_assessment
- azurerm_mssql_virtual_machin
- azurerm_sql_active_directory_administrator
- azurerm_sql_database
- azurerm_sql_elasticpool
- azurerm_sql_failover_group
- azurerm_sql_firewall_rule
- azurerm_sql_server
- azurerm_sql_virtual_network_rule
たくさんありますが、いったいどの resource を使えば良いのでしょうか。色々と調べてみました。
azurerm_mssql系 vs azurerm_sql系
まず、上記のリストを眺めていて大きな疑問が沸きました。それは、SQL Database に関する resource が2つ存在していたということです。
これらはどのような違いがるのでしょうか。調べてたところ、この issue に辿り着きました。こちらの issue は2020年4月に作られたもので、以下の内容が書かれていました。
the azurerm_mssql_database resource is the new version of azurerm_sql_database that is using a newer version of the API that supports more features. As such we have been migrating all the supported features of the old resource to the new and it should support everything that azurerm_sql_database does.
要約すると以下のようなことです。
azurerm_mssql_database は新しい API 機能に対応した azurerm_sql_database の新バージョンです。そのため、azurerm_sql_database の持つ全ての機能を azurerm_mssql_database へ統合させなくてはなりません。
しかし、2021年1月時点において対応が完了していません。現在はその移行時期であり、どちらを使うべきか判断がつきません。
とりあえず、困ったら "azurerm_mssql系" を使うこととします。
やってみる
では、Terraform を使って SQL Database を作ってみたいと思います。
構成イメージ図
ポイント
以下のような制限を設けます。
- SQL Database は Virtual Machine からのみアクセスを許可する。
- SQL Database は Availability Zone 冗長構成とする。
- StorggeAccount に AuditLogging を設定する。
main.tf
Virtual Machine を作成するところまでは過去の記事「Terraform で Azure Virtual Machine」を参考ください。下記のソースコードは SQL Database に関連したものだけ掲載しています。
Subnet
ポイントは SQL Database を配置するサブネットに service_endpoints "Microsoft.Sql" を指定することです。
resource "azurerm_subnet" "subnet02" {
name = "subnet02"
virtual_network_name = azurerm_virtual_network.vnet01.name
resource_group_name = azurerm_resource_group.test01.name
enforce_private_link_endpoint_network_policies = false
enforce_private_link_service_network_policies = false
address_prefixes = ["10.7.2.0/24"]
service_endpoints = ["Microsoft.Sql"]
}
Security Group
Virtual Machine の存在するアプリケーショングループのみから通信を許可します。
resource "azurerm_network_security_group" "sg02" {
name = "sg02"
location = azurerm_resource_group.test01.location
resource_group_name = azurerm_resource_group.test01.name
security_rule {
name = "DenyALL"
priority = 1002
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
source_address_prefix = "*"
destination_port_range = "*"
destination_address_prefix = "*"
}
security_rule {
name = "SQLServer"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
source_application_security_group_ids = [azurerm_application_security_group.nicsg01.id]
destination_port_range = "1433"
destination_address_prefix = "VirtualNetwork"
}
tags = {
"Owner" = "koizumi",
"Env" = "test01"
}
}
resource "azurerm_subnet_network_security_group_association" "sg02" {
subnet_id = azurerm_subnet.subnet02.id
network_security_group_id = azurerm_network_security_group.sg02.id
}
StorageAccount
AuditLogging を設定するための準備として、StorageAccount を作成しておきます。こちらは特別な設定はしていません。
resource "azurerm_storage_account" "test01" {
name = "koizumitest01sqlserver"
resource_group_name = azurerm_resource_group.test01.name
location = azurerm_resource_group.test01.location
account_tier = "Standard"
account_replication_type = "LRS"
tags = {
"Owner" = "koizumi",
"Env" = "test01"
}
}
SQL Server & SQL Database
SQL Database のインスタンスとデータベースを作成します。
resource "azurerm_mssql_server" "sqlserver01" {
name = "koizumi-sqlserver01"
resource_group_name = azurerm_resource_group.test01.name
location = azurerm_resource_group.test01.location
version = "12.0"
administrator_login = "adminsqlserver"
administrator_login_password = "xxxxxxxxxxxxxx"
public_network_access_enabled = true
tags = {
"Owner" = "koizumi",
"Env" = "test01"
}
}
resource "azurerm_mssql_database" "test01" {
name = "test01"
server_id = azurerm_mssql_server.sqlserver01.id
collation = "SQL_Latin1_General_CP1_CI_AS"
license_type = "LicenseIncluded"
max_size_gb = 4
read_scale = true
sku_name = "BC_Gen5_2"
zone_redundant = true
tags = {
"Owner" = "koizumi",
"Env" = "test01"
}
}
VNet for SQL Server
SQL Database を VNet に乗せます。そして、ファイヤーウォールでアクセス制限します。
ポイントは、こちらのページ下部の "Note" に記載されています。
The Azure feature Allow access to Azure services can be enabled by setting start_ip_address and end_ip_address to 0.0.0.0 which (is documented in the Azure API Docs).
要約すると以下のようになります。
start_ip_address と end_ip_address を 0.0.0.0 に指定すると、Azure Service からの通信を許可する設定となります。
正直、わっかりづらいなと思ってしまいました。
resource "azurerm_sql_virtual_network_rule" "sqlvnetrule01" {
name = "sqlvnetrule01"
resource_group_name = azurerm_resource_group.test01.name
server_name = azurerm_mssql_server.sqlserver01.name
subnet_id = azurerm_subnet.subnet02.id
}
resource "azurerm_sql_firewall_rule" "sqlfirewall01" {
name = "sqlfirewall01"
resource_group_name = azurerm_resource_group.test01.name
server_name = azurerm_mssql_server.sqlserver01.name
start_ip_address = "0.0.0.0"
end_ip_address = "0.0.0.0"
}
resource "azurerm_sql_firewall_rule" "sqlfirewall02" {
name = "sqlfirewall02"
resource_group_name = azurerm_resource_group.test01.name
server_name = azurerm_mssql_server.sqlserver01.name
start_ip_address = azurerm_network_interface.nic01.private_ip_address
end_ip_address = azurerm_network_interface.nic01.private_ip_address
}
デプロイ
それでは、デプロイしてみます。
動作確認
データベースにユーザーを作成して、そのユーザーでログインした結果が、StorageAccount に監査ログとして出力されているかを確認してみたいと思います。
Azure の WindowsServer には "Azure Data Studio" というものが内蔵されています。SSMS みたいなものですね。これを使って SQL Database にアクセスできます。
上記の実行結果が以下です。
以上で SQL Database の接続確認は完了です。
Terraform で困ったこと
実は、Azure の SQLServer のサービスには managed instance というサービスが存在すると最初に述べましたが、該当する resource が Terraform azure provider には存在しませんでした(2021年1月5日時点)。
また、Private Endpoint を利用したセキュアなネットワーク構成も存在するのですが、それに対応する resource も見つけることができませんでした。
やはり、後追いで Terraform にリリースされるため仕方のないことですが、現場で Terraform を採用するかどうか判断する場合は注意した方が良いですね。
今回は以上です。