[Azure] TerraformでのLinux OS設定(custom_dataとremote-exec)記法メモ

カスタムデータ(Custom Data)は、Azureで仮想マシン作成時にOS上での設定(apt install等)をおこなうための機能です。

Terraformでも対応していますが、オプション項目で [ドキュメント](https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html) には記法の記載が無かったので、書き方をまとめておきます。例はUbuntuのものです。

Terraformの同様な機能にprovisioner(remote-exec)もあるので、最後にその例も記載しています。

# 1) custom_data使用(シェルスクリプト)

azurerm_virtual_machineブロック -> os_profile -> custom_data に実行したい内容をそのまま記載します。

```terraform
resource "azurerm_virtual_machine" "tf_name_vm1" {
  # ※ここではcustom_dataに必要な部分のみ記載しています※

  os_profile {
    custom_data    = <<-EOF
      #!/bin/bash
      apt-get update
      apt-get -y dist-upgrade
      apt install -y nginx
      apt install -y nodejs
      apt install -y npm
      EOF
  }
}
```

スクリプトを別のファイルで管理したい場合は、custom_dataに$file変数を記載しても動きません。template_fileとしてファイルを記載し、custom_dataではそのrendered属性を参照する必要があります。

```terraform
data "template_file" "my_init_script" {
  template = "${file("/home/azureuser/init_test.sh")}"
}

resource "azurerm_virtual_machine" "tf_name_vm1" {
  # ※ここではcustom_dataに必要な部分のみ記載しています※

  os_profile {
    custom_data = "${data.template_file.my_init_script.rendered}"
  }
}
```

custom_dataはroot権限で実行されるのでsudoは無くても構いません。

```
$ cat init_test.sh
#!/bin/bash
apt-get update
apt-get -y dist-upgrade
apt install -y nginx
apt install -y nodejs
apt install -y npm
```

# 2) custom_data使用(cloud-init)

[Cloud Init](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/using-cloud-init) に対応したOSであれば、同様に os_profile -> custom_data に実行したい内容をそのまま記載できます。

```terraform
resource "azurerm_virtual_machine" "tf_name_vm1" {
  # ※ここではcustom_dataに必要な部分のみ記載しています※

  os_profile {
    custom_data    = <<-EOF
      #cloud-config
      package_upgrade: true
      packages:
        - nginx
        - nodejs
        - npm
      EOF
  }
}
```

スクリプトを別のファイルで管理したい場合も、同様にtemplate_fileとしてファイルを記載し、custom_dataではそのrendered属性を参照する必要があります。

```terraform
data "template_file" "my_init_script" {
  template = "${file("/home/azureuser/cloud_init_test.yml")}"
}

resource "azurerm_virtual_machine" "tf_name_vm1" {
  # ※ここではcustom_dataに必要な部分のみ記載しています※

  os_profile {
    custom_data = "${data.template_file.my_init_script.rendered}"
  }
}
```

```
$ cat cloud_init_test.yml
#cloud-config
package_upgrade: true
packages:
  - nginx
  - nodejs
  - npm
```


# 3) provisioner(remote-exec)使用

remote-execはTerraformの機能で、Ansibleと同様に仮想マシンにSSH接続して設定を行うものです。以下が設定例です。

```terraform
resource "azurerm_network_interface" "tf_name_nic1" { # NICの設定
  # ※ここではremote-execに必要な部分のみ記載しています※

  ip_configuration {
    private_ip_address_allocation = "Static"    # VM作成直後にSSH接続する必要があるため、
    private_ip_address            = "10.10.0.5" # 静的IPアドレスを割り当てる。
  }
}

resource "azurerm_virtual_machine" "tf_name_vm1" {
  # ※ここではremote-execに必要な部分のみ記載しています※

  os_profile {
    admin_username = "azureuser" # VM上のユーザ
  }

  os_profile_linux_config {
    ssh_keys {
      path     = "/home/azureuser/.ssh/authorized_keys"                  # VM上のユーザ(azureuser)の鍵設定
      key_data = "${file("/home/ubuntu/azureuser-key/.ssh/id_rsa.pub")}" # 設定する鍵(指定してあるファイルはTerraformを実行するユーザのローカルファイル)
    }
  }

  provisioner "remote-exec" {
    connection {
      host = "10.10.0.5" # azurerm_network_interfaceで設定したIPアドレス
      type = "ssh"
      user = "azureuser" # os_profileで設定したユーザ
      private_key = "${file("/home/ubuntu/azureuser-key/.ssh/id_rsa")}" # os_profile_linux_configで設定した鍵(のプライベートキー)
    }
    inline = [ # 実行するスクリプト
      "sudo apt-get update",
      "sudo apt-get -y dist-upgrade",
      "sudo apt install -y nginx",
      "sudo apt install -y nodejs"
      "sudo apt install -y npm"
    ]
  }
}
```

ここでのポイントは、

- VM作成直後にSSH接続するため、静的IPを設定しておく
- 設定したIPと鍵を使うよう、provisioner(remote-exec)ブロック内の設定を記載する
- 鍵はパスフレーズなしにする必要がある

の3点です。現状、SSH接続に使う鍵にはパスフレーズが設定されていると実行エラーになってしまいます。

```terraform
Error: Failed to read ssh private key: password protected keys are
not supported. Please decrypt the key prior to use.
```

以上が記法の例となります。

remote-execは [ドキュメント](https://www.terraform.io/docs/provisioners/remote-exec.html) には「この機能は"last resort"で、クラウド標準の機能を優先して使うべき」という旨の記載があるのですが、実行すると結果が標準出力に出るのでエラーの調査がしやすいというメリットがあります（custom_dataを間違えて途中で止まった場合の調査は大変...）。実績のない設定の検証用途で使うのがよさそうです。

# link

- [Terraform Docs: remote-exec](https://www.terraform.io/docs/provisioners/remote-exec.html)
- [Terraform Docs: virtual_machine](https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html)
- [Cloud Init](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/using-cloud-init)