Terraform小ネタ集

みなさんこんばんは、今緊急できーた書いているんですけど、[@seumo](https://zenn.dev/seumo)と申します🐭

この記事は 富士通クラウドテクノロジーズ Advent Calendar 2023 の 16 日目の記事です。

昨日は @tanopanta さんの Swaggerをオシャレに公開したい！ on GitLab Pagesという記事でした。  
GitLab PagesはGitLab環境さえあれば自分でサーバーなどを建てずともサイトを公開できるのでとても便利なのですがSwaggerUIを置くのも良さそうですね！

さて今回なんですけども、わたくし今業務でTerraformを使ってニフクラ環境を構築している訳なんですが、その中で意外と知られていない便利だなと思ったことがあるのでいくつか紹介していきたいと思います！

### ファイアウォールルールを書くときはfor_eachが便利🐭

[nifcloud_security_group_rule](https://registry.terraform.io/providers/nifcloud/nifcloud/latest/docs/resources/security_group_rule)では、一つのリソースで一つのルールしか定義できないんですよね。
でも許可したいルールがたくさんあるよというときりリソースをたくさん書くのは大変です、そこでfor_eachを使って以下のようにループで展開すると便利です。

```hcl

locals {
  internal_ipaddresses = {
    network1 = "192.168.1.0/24"
    network2 = "10.0.1.0/24"
    network3 = "172.10.1.0/16"
  }
}

resource "nifcloud_security_group_rule" "this" {
  for_each = internal_ipaddresses

  cidr_ip              = each.value
  description          = each.key
  from_port            = "22"
  protocol             = "TCP"
  security_group_names = ["ssh"]
  to_port              = "22"
  type                 = "IN"
}
```

### NATルールを書くときはdynamicが便利🐭

先ほどのfor_eachと似てますが、ルーターに設定するNATテーブルについても同様に、例えば全てのサーバーから共通グローバルにNATしたいのような場合 snatをたくさん定義しなくてはならず大変です、そこでdynamicで動的に定義すると簡潔に書けます。

```hcl
locals {
      instances = [
        {
            instance_id        = "instance01"
            private_ip_address = "192.168.0.1"
        },
        {
            instance_id        = "instance02"
            private_ip_address = "192.168.0.2"
        },
        {
            instance_id        = "instance03"
            private_ip_address = "192.168.0.3"
        },
      ],
}

resource "nifcloud_nat_table" "this" {
  dynamic "snat" {
    for_each = local.instances

    content {
      description                   = "${snat.value.instance_id} to Global"
      outbound_interface_network_id = "net-COMMON_GLOBAL"
      protocol                      = "ALL"
      source_address                = snat.value.private_ip_address
    }
  }
}

```

### moduleにproviderを渡せる🐭

複雑なインフラ構成になると、複数のリージョンにリソースを作成したいというケースもあると思います、単一リージョンであれば環境変数に定義しておけばいいですが、異なるリージョンにApplyするたびに環境変数を切り替えるのは大変です、そこで作成したいリソースをmodule化し各リージョンを定義したproviderを渡すことで対応できます。

```hcl:modules/this
terraform {
  required_providers {
    nifcloud = {
      source = "nifcloud/nifcloud"
    }
  }
}

variable "zone" {
  description = "The nifcloud zone"
  type        = string
}

resource "nifcloud_security_group" "this" {
  availability_zone = var.zone
  group_name        = "Fw"
}
```

```hcl:main.tf
terraform {
  required_providers {
    nifcloud = {
      source                = "nifcloud/nifcloud"
      configuration_aliases = [nifcloud.west, nifcloud.east]
    }
  }
}

provider "nifcloud" {
  alias = "west"

  region = "jp-west-1"
}

provider "nifcloud" {
  alias = "east"

  region = "jp-east-1"
}

module "east" {
  source = "modules/this"

  providers = {
    nifcloud = nifcloud.east
  }
  zone = "east-11"
}

module "west" {
  source = "modules/this"

  providers = {
    nifcloud = nifcloud.west
  }
  zone = "west-11"
}
```

### SSHキーは生成できる🐭

[terraform-provider-nifcloud
](https://github.com/nifcloud/terraform-provider-nifcloud)のREADEMにのっているサンプルのように、SSHキーは公開鍵をアップロードすることができますが、元々公開鍵を持っていない場合にコンパネでSSHキーを作る時のようにその場で生成できないのかというとtls_private_keyリソースをを使えば普通にできます。

```hcl
resource "nifcloud_key_pair" "this" {
  key_name   = "webkey"
  public_key = base64encode(tls_private_key.this.public_key_openssh)
}

resource "tls_private_key" "this" {
  algorithm = "RSA"
}
```

## まとめ

いくつかTerraformの小ネタ集を書いてみました、他にもこんな使い方あるよと思いついた方がいたらぜひコメント欄に投稿とLGMT+qiitaお願いいたします。

明日は @earth429 さんがPrometheus系の記事を公開してくれるようなのでお楽しみに！