Terraformを使用したAzure VM構築

# はじめに
IaCツールの1つであるTerraformのスクリプトを作成し、MicrosoftのAzure環境にVMインスタンスを構築してみました。ここでは、スクリプトの参考例をご紹介します。

# 検証環境
Windows10 Home Edition
Terraform V1.1.9 on windows_amd64
provider：registry.terraform.io/hashicorp/azurerm v3.6.0

# 今回Azure上に構築する環境
下記のリソースを全て東日本リージョンに作成するものとします。
* リソースグループ
* VNET(仮想ネットワーク)
    * IPアドレス範囲：10.0.0.0/16
* サブネット
    * IPアドレス範囲：10.0.1.0/24
* NSG(ネットワーク・セキュリティー・グループ)
    * 外部からのSSH接続(ポート:22)を許可するようにします。
* NIC(ネットワーク・インタフェース・カード)
    * VMインスタンスに少なくとも1つは必要です。
* Public IP
    * VMインスタンスにssh接続する際に必要になります。
* Linux VMインスタンス
    * Linuxのディストリビューションには、Ubuntu Server 18.04 LTSを使用するものとします。

なお、Azureではサブネットを作成すれば自動的にシステムルートが作成されるため、AWSやIBM Cloudのようなルートテーブルの設定は不要になります。これについては下記サイトに記載があります。
[仮想ネットワーク トラフィックのルーティング](https://docs.microsoft.com/ja-jp/azure/virtual-network/virtual-networks-udr-overview)

# Azureへの事前認証
Terraformを使用してAzure環境構築を行う場合には、事前にAzureへの認証が必要になります。以下のリンク先に事前認証設定方法をまとめていますので、ご参照ください。
[TerraformでAzure環境構築するための事前のAzure認証設定](https://qiita.com/duelist2020jp/items/c2b99ecfba2196ae65fc)

# 今回作成したTerraformスクリプト
下記のTerraform Azure Providerの紹介サイトを参考に作成しました。
[Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)

上記リンク先を元に、今回作成したスクリプトは下記のものになります。スクリプト名はmain.tfとしておきます。

```hcl:main.tf
terraform{
    required_providers{
        azurerm={
            source  = "hashicorp/azurerm"
            version = "=3.6.0"
        }
    }
}

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}
}

# Create Resource Group
resource "azurerm_resource_group" "rg"{
    name = "My-RG"
    location = "Japan East"
}

#Create Virtual Network
resource "azurerm_virtual_network" "vnet"{
    name = "Test-VNET"
    resource_group_name = azurerm_resource_group.rg.name
    location = azurerm_resource_group.rg.location
    address_space = ["10.0.0.0/16"]

    tags = {
        Name = "Test"
    }

}

#Create Subnet
resource "azurerm_subnet" "subnet"{
    name = "Test-Public-Subnet"
    resource_group_name = azurerm_resource_group.rg.name
    virtual_network_name = azurerm_virtual_network.vnet.name
    address_prefixes = ["10.0.1.0/24"]
}

#Create Network Security Group
resource "azurerm_network_security_group" "nsg"{
    name = "TestVM-Security-Group"
    resource_group_name = azurerm_resource_group.rg.name
    location = azurerm_resource_group.rg.location

    security_rule{
        name = "sg-ssh22"
        protocol = "Tcp"
        priority = 300
        direction = "Inbound"
        access = "Allow"
        source_port_range = "*"
        destination_port_range = 22
        source_address_prefix = "*"
        destination_address_prefix = "*"
    }
     
    tags={
        Name = "Test-SG"
    } 

}

#Association between Subnet and Network Security Group
resource "azurerm_subnet_network_security_group_association" "nsga"{
    network_security_group_id = azurerm_network_security_group.nsg.id
    subnet_id = azurerm_subnet.subnet.id
}

#Create public ip
resource "azurerm_public_ip" "public_ip"{
    name = "Test-Public-IP"
    resource_group_name = azurerm_resource_group.rg.name
    location = azurerm_resource_group.rg.location
    allocation_method = "Dynamic"
}

#Create Network Interface Card
resource "azurerm_network_interface" "nic"{
    name = "Test-NIC"
    resource_group_name = azurerm_resource_group.rg.name
    location = azurerm_resource_group.rg.location

    ip_configuration{
        name = "internal"
        private_ip_address_allocation = "Dynamic"
        subnet_id = azurerm_subnet.subnet.id
        public_ip_address_id = azurerm_public_ip.public_ip.id
    }

    tags = {
        Name = "Test-NIC"
    }

}

#Association between Network Interface Card and Network Security Group
resource "azurerm_network_interface_security_group_association" "nisga"{
    network_interface_id = azurerm_network_interface.nic.id
    network_security_group_id = azurerm_network_security_group.nsg.id
}

#Create Linux VM Instance
resource "azurerm_linux_virtual_machine" "lvm"{
    name = "Test-VM"
    resource_group_name = azurerm_resource_group.rg.name
    location = azurerm_resource_group.rg.location
    size = "Standard_A1_v2"
    admin_username = "adminuser"
    
    network_interface_ids = [
        azurerm_network_interface.nic.id,
    ]

    admin_ssh_key{
        username = "adminuser"
        public_key = file("~/.ssh/Az-Test-VM_key.pub")
    }

    os_disk{
        caching = "ReadWrite"
        storage_account_type = "Standard_LRS"
    }

    source_image_reference{
        publisher = "Canonical"
        offer = "UbuntuServer"
        sku = "18.04-LTS"
        version = "latest"
    }

    tags = {
        Name = "Test"
    }

}
```

# Terraformスクリプトによる環境作成
* main.tfファイルのあるフォルダ上で、下記のコマンドを順番に実施するだけでOKです。
   * terraform plan
       * シンタックスエラーなどがあれば、そこでわかります。
   * terraform apply
       * Do you want to perform these actions?と聞いてくるので、yesを応答する。
* 問題なく環境作成できているか否かは、実際にAzureポータルログオンして確認するか、Azure CLIを使用して確認します。

# 作成したAzure VMインスタンスへの接続確認
今回VMインスタンスに付与されたPublic IPは、20.89.139.115です。こちらに対して、秘密鍵(~/.ssh/Az-Test-VM_key)、ログオン用ユーザーID(adminuser)でssh接続を実施します。

```console
$ ssh -i ~/.ssh/Az-Test-VM_key adminuser@20.89.139.115
The authenticity of host '20.89.139.115 (20.89.139.115)' can't be established.
ECDSA key fingerprint is SHA256:0oLoQhIdZSCYCV90FWnldDXISEpLln8m+sTDMD1vfrw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '20.89.139.115' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1078-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun May 22 09:11:04 UTC 2022

  System load:  0.08              Processes:           117
  Usage of /:   4.8% of 28.90GB   Users logged in:     0
  Memory usage: 10%               IP address for eth0: 10.0.1.4
  Swap usage:   0%

0 updates can be applied immediately.



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

adminuser@Test-VM:~$ 
```
無事、Azure VMインスタンスに接続できました！

# Terraformスクリプトによる環境破棄
* main.tfファイルのあるフォルダ上で、下記のコマンドを実施するだけでOKです。
   * terraform destroy
       * Do you want to destroy all resources?と聞いてくるので、yesを応答する。
* 問題なく環境破棄されたか否かは、実際にAzureポータルログオンして確認するか、Azure CLIを使用して確認します。

# さいごに
今回は以下を実施し、問題ないことを確認しました。
* Terraformスクリプトを使用して、Microsoft Azure環境にVMインスタンスを構築・破棄できること。
* 構築したVMインスタンスにssh接続ができること。

ただ、スクリプトをいきなり書くよりは、Azureポータルから実際にVMインスタンス構築を実施し、Azure慣れしてからの方が良いと思いました。