terraform で Azure VM + bastion の構築をやってみた

Azure を触る機会があったので、terraform でリソースを作ってみた。
普段は AWS を使っている。

Azure の方がプロキシ環境下での bastion 接続が便利なのと
AWS よりちょっと安い気がする。windows server については。

[microsoft のドキュメント](https://learn.microsoft.com/ja-jp/azure/developer/terraform/overview)を参考にやってみた。

[ソースコードはこちら](https://github.com/onzuka24/tf-azure-sample)

## 構成について

仮想ネットワークを作成し、その中に VM を作成する。
インターネット接続用のインターフェースと、bastion 用のインターフェースを作成する。
bastion については後述。

## 構築

### リソースグループの作成

terraform を実行させるためのユーザーとリソースグループを作成する。

terraform を実行する時は環境変数のアクセスキーを使うようになっているので、
ついでに環境変数に登録しておく。

Microsoft のサイトにあったものをほぼそのまま使っているが、一応載せておくとこんな感じ。

```sh
RESOURCE_GROUP_NAME=tfstate
STORAGE_ACCOUNT_NAME=tfstate$RANDOM
CONTAINER_NAME=tfstate

# Create resource group
az group create --name $RESOURCE_GROUP_NAME --location eastus

# Create storage account
az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob

# Create blob container
az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME
```

### tf ファイル作成

windows server 用の設定事項を記入する。
(vm_size は無料枠のを使ってみたら windows がまともに動かなかった)

tf ファイルだけ見るとよく分からない設定項目もあるので、Azure ポータルから作成するときの設定を参考にするとわかりやすかった。

`vm.tf` から一部だけ紹介。

```hcl
resource "azurerm_virtual_network" "main" {
  name                = "${var.stage}_network"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_subnet" "internal" {
   (省略)
}

resource "azurerm_network_interface" "main" {
   (省略)
}

resource "azurerm_virtual_machine" "winserver" {
  name                  = "${var.stage}_vm_ad"
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.main.id]
  vm_size               = "Standard_B2s"
  # vm_size               = "Standard_B2ms"

  delete_os_disk_on_termination    = true
  delete_data_disks_on_termination = true

  # copy properties in createion pages on browser
  # イメージ選択ページの「使用状況情報とサポート」から転記する
  storage_image_reference {
    publisher = "microsoftwindowsserver"
    offer     = "windowsserver"
    sku       = "2022-datacenter-azure-edition-hotpatch"
    version   = "latest"
  }
  storage_os_disk {
    name              = "osdisk1"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
  os_profile {
    computer_name  = "${var.stage}-main"
    admin_username = var.vm_admin
    admin_password = var.vm_password
  }
  os_profile_windows_config {
    provision_vm_agent         = false
    enable_automatic_upgrades  = false
    # timezone                   = "UTC"
    timezone                   = "Tokyo Standard Time"
    # winrm                      = {
    #   protocol = "HTTPS"
    #   certificate_url = ""
    # }
    # additional_unattend_config = {}
  }
  tags = {
    environment = var.stage
  }
}

resource "azurerm_subnet" "bastion_subnet" {
   (省略)
}

resource "azurerm_public_ip" "bastion_ip" {
   (省略)
}

resource "azurerm_bastion_host" "bastion" {
  name                = "${var.stage}_bastion"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  sku                 = "Developer"
  ip_configuration {
    name                 = "configuration_bastion"
    subnet_id            = azurerm_subnet.bastion_subnet.id
    public_ip_address_id = azurerm_public_ip.bastion_ip.id
  }
  tags = {
    environment = var.stage
  }
}
```

### terraform 実行

```
terraform init
terraform apply --var-file=<stage>.tfvars
```

先ほど環境変数に登録したアクセスキーで Azure の操作が実行される。（多分）

## bastion

### bastion について

windows の VM に接続するときに、bastion を使って接続することができる。
ブラウザ上でRDPするような形になる。

bastion との接続は HTTPS なので、RDP用にポートを開ける必要がない。

### SKU とお値段

検証用には `Developer` (dev) で十分だった。USリージョンでしか使えず、機能に制限もあるが、無料。VM も US リージョンにする必要があるので注意。

最初はよくわからなかったので Basic でやってたら、１日で１５００円くらいかかった。VM よりよっぽど高くつく。
VM と違って停止できないので、ちょっと痛い出費になる。

該当箇所はこんな感じ。`main.tf` でリソースグループを作る時に `westus` を指定して、`vm.tf` で bastion を作る時に `Developer` を指定している。

```hcl
# main.tf の一部

resource "azurerm_resource_group" "rg" {
  name     = "${var.stage}_resource_group"
  location = "westus"
}
```

```hcl
# vm.tf の一部

resource "azurerm_bastion_host" "bastion" {
  sku                 = "Developer"
}
```

## VM の停止設定について

terraform からの設定項目は見つけられなかった。作成後にブラウザから手動で設定して対応した。
シャットダウンして課金されなくなるような動きで、再開時にはデータはそのまま残っている。

## おわりに

VM を使うだけであれば Azure にこだわる必要はないが、windows server については AWS でやるよりだいぶラクだった。