Azureの各種リソースをTerraformで構築する(2) Azure Key Vaultに登録したデータを使ってAzure Database for PostgreSQLを作成する

はじめに

先日、Azureの各種リソースをTerraformで構築する方法を記しました。

miyohide.hatenablog.com

今回は、このお話の続きです。

以下のエントリーでAzure KeyVaultをSpring Bootで書いたアプリケーションで使う方法を記しました。

miyohide.hatenablog.com

この記事ではデータベースを手で作成し、ユーザやパスワードはAzure Key Vaultに別途登録したのですが、何かと手間です。

そこで、あらかじめAzure Key Vaultに登録しておいたユーザやパスワードを使ってデータベースをTerraformで作成する方法を記します。

TerraformでAzure Key Vaultのシークレットデータを読み込む

Terraformで既存のAzure Key Vaultのシークレットデータを読み込むには、Data Sourceのazurerm_key_vaultとazurerm_key_vault_secretを使うと良さそうです。

対象のKey Vaultをazurerm_key_vaultで指定します。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault

azurerm_key_vaultで得られたidを使ってazurerm_key_vault_secretから対象のデータを取得します。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret

具体的な実装は以下の通り。

data "azurerm_key_vault" "keyvault" {
  name = var.keyvault_name
  resource_group_name = var.keyvault_resource_group
}

data "azurerm_key_vault_secret" "database-user" {
  name = "app-database-user"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

data "azurerm_key_vault_secret" "database-password" {
  name = "app-database-password"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

ここでは、Azure Key Vaultのシークレットに登録しているapp-database-userapp-database-passwordを使ってAzure Database for PostgreSQLを作成します。

f:id:miyohide:20210822151209p:plain

なお、Azure Key Vaultにはバージョンという概念があります。

docs.microsoft.com

同時に複数のバージョンを有効化することができるのですが、複数のバージョンを有効化したままでは今回の処理はうまく動きませんでした。どれか一つだけを有効化した方が良いかなとおもます。

f:id:miyohide:20210822155844j:plain

Azure Database for PostgreSQLの作成

TerraformでAzure Database for PostgreSQLを作成する方法は、以下のドキュメントを参考にしました。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_database

ユーザやパスワードはAzure Key Vaultのデータを使います。ユーザはdata.azurerm_key_vault_secret.database-user.value、パスワードはdata.azurerm_key_vault_secret.database-password.valueと指定してあげればOKです。

具体的な実装は以下の通りです。

resource "azurerm_postgresql_server" "pg-server" {
  name = var.postgresql_server_name
  resource_group_name = azurerm_resource_group.rg.name
  location = azurerm_resource_group.rg.location

  administrator_login = data.azurerm_key_vault_secret.database-user.value
  administrator_login_password = data.azurerm_key_vault_secret.database-password.value

  sku_name = var.postgresql_sku_name
  version = var.postgresql_version

  storage_mb = var.postgresql_storage

  public_network_access_enabled = true
  ssl_enforcement_enabled = true
  ssl_minimal_tls_version_enforced = "TLS1_2"
}

resource "azurerm_postgresql_database" "pg-db" {
  name = "app_production"
  resource_group_name = azurerm_resource_group.rg.name
  server_name = azurerm_postgresql_server.pg-server.name
  charset = "utf8"
  collation = "Japanese_Japan.932"
}

変数の利用

上記の例でvar.からはじまるものはTerraformの変数の機能を使っています。

www.terraform.io

今回は以下のような記述をvariables.tfとして記述しました。

variable "keyvault_name" {
  type = string
}

variable "keyvault_resource_group" {
  type = string
}

variable "postgresql_server_name" {
  type = string
}

variable "postgresql_version" {
  type = string
  default = "11"
}

variable "postgresql_sku_name" {
  type = string
  default = "B_Gen5_1"
}

variable "postgresql_storage" {
  type = number
  default = 5120
}

実装の全体と実行

最終的な実装は以下の通りになりました。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }

  required_version = ">= 0.14.9"
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-railsapp"
  location = "japaneast"
}

data "azurerm_key_vault" "keyvault" {
  name = var.keyvault_name
  resource_group_name = var.keyvault_resource_group
}

data "azurerm_key_vault_secret" "database-user" {
  name = "app-database-user"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

data "azurerm_key_vault_secret" "database-password" {
  name = "app-database-password"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

resource "azurerm_postgresql_server" "pg-server" {
  name = var.postgresql_server_name
  resource_group_name = azurerm_resource_group.rg.name
  location = azurerm_resource_group.rg.location

  administrator_login = data.azurerm_key_vault_secret.database-user.value
  administrator_login_password = data.azurerm_key_vault_secret.database-password.value

  sku_name = var.postgresql_sku_name
  version = var.postgresql_version

  storage_mb = var.postgresql_storage

  public_network_access_enabled = true
  ssl_enforcement_enabled = true
  ssl_minimal_tls_version_enforced = "TLS1_2"
}

resource "azurerm_postgresql_database" "pg-db" {
  name = "app_production"
  resource_group_name = azurerm_resource_group.rg.name
  server_name = azurerm_postgresql_server.pg-server.name
  charset = "utf8"
  collation = "Japanese_Japan.932"
}

あとはこれを実行します。

variables.tfdefaultを指定していない項目に対して値を入力すると...

f:id:miyohide:20210822153419j:plain

無事作成されました。

f:id:miyohide:20210822153534p:plain

接続

接続してみます。Cloud Shellから接続するときはAzure Database for PostgreSQLの設定で「Azureサービスへのアクセスを許可」を「はい」に変更する必要があります。

f:id:miyohide:20210822153757j:plain

ユーザやパスワード、データベースを指定すると無事接続できました。

f:id:miyohide:20210822154309p:plain

注意点

最初、データベースの作成時にcollationja_JP.utf8に指定したら以下のエラーメッセージが出ました。

azurerm_postgresql_database.pg-db: Creating...
azurerm_postgresql_database.pg-db: Still creating... [10s elapsed]
╷
│ Error: Code="InvalidDatabaseCollation" Message="The provided database collation is invalid."
│
│   with azurerm_postgresql_database.pg-db,
│   on main.tf line 50, in resource "azurerm_postgresql_database" "pg-db":
│   50: resource "azurerm_postgresql_database" "pg-db" {

いろいろと調べてみると、Azure Database for PostgreSQLWindows上で動いているようで、そのためにja_JP.utf8は使えないそうです。

asazure.hatenablog.jp

lets.postgresql.jp

上で接続結果の画像を載せましたが、compiled by Visual C++ build 1800, 64-bitとあることからもWindowsベースで動いているような気がします。