terraformをフレキシブルな変数化に組み直す

# terraformをフレキシブルな変数化に組み直す

★ この記事は3年前に執筆し、投稿し忘れていたものを投稿したものです

## はじめに

これまで、terraformに触れ、いくつかのAWSリソースの構築を試してきました。
この検証で使用したterraformを有志に紹介し、試してもらう際に一つ困ったことがありました。
それは、AWSリソース名が重複してしまうこと．．．
この問題を解決すべく、terraformの記述を変えず、変数定義だけ変更して対応できるように改修しました。

##


## 改修前のterraform

弊社のルールで、AWSリソース名の先頭には誰が作ったものかわかるように社員番号等で特定できるようにするというルールが有りました。
以下のterraformの「xxxxxxxx」は社員番号が記述されていると読み替えてください。

```
resource "aws_codecommit_repository" "xxxxxxxx_test" {
  repository_name = "xxxxxxxx_test"
  description     = "This is the Sample App Repository"
}
```

このterraformを有志に展開し、試してもらうと、repository_nameが重複してエラーになってしまいます。

## 改修後のterraform

そこで、terraform内に社員番号等の固有情報を保持せず、変数で補填するよう改修。
「xxxxxxxx」だった箇所を、「${var.user_prefix}」に置き換えます。

```
resource "aws_codecommit_repository" "repository" {
  repository_name = "${var.user_prefix}_test"
  description     = "This is the ${var.user_prefix} Sample App Repository"
}
```

## 変数定義ファイル

このファイルには、どのような変数を使用するのか、また、AWS接続設定を定義しておきます。
ポイントは、このファイルにも固有情報は含んでいない点です。

```
# AWS接続に必要な個人情報の宣言
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "aws_region" {}

# AWS接続設定
provider "aws" {
    access_key = "${var.aws_access_key}"
    secret_key = "${var.aws_secret_key}"
    region     = "${var.aws_region}"
}

# 使用する変数の宣言
variable "user_prefix" {}
```

## 固有情報定義ファイル

そして、このファイルに固有情報を定義します。
固有情報定義ファイルは共通的なファイル名でもよいか？とも思ったのですが、ここは個人単位にファイルを分けることにしました。
この考え方で用意しておけば、仮に、個人情報単位ではなく、開発、検証、商用と、環境単位に分けるという考え方にも応用できるからと考えたからです。

ファイル名は任意ですが、わかりやすいように社員番号を使用した「xxxxxxxx.tfvars」としました。
※固有情報はマスクしています

```
# AWS接続情報
aws_access_key = "xxxxxxxx"
aws_secret_key = "xxxxxxxx"
aws_region     = "us-west-2"

# 社員番号
user_prefix = "xxxxxxxx"
```

## 固有情報定義ファイルを指定してterraform planを実行

では、固有情報定義ファイルを指定して、terraform planを実行してみます。
変数の箇所が、ちゃんと固有情報に置き換わり実行されていることが確認出来ます。


```
# terraform plan -var-file=xxxxxxxx.tfvars


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_codecommit_repository.repository will be created
  + resource "aws_codecommit_repository" "repository" {
      + arn             = (known after apply)
      + clone_url_http  = (known after apply)
      + clone_url_ssh   = (known after apply)
      + description     = "This is the xxxxxxxx Sample App Repository"
      + id              = (known after apply)
      + repository_id   = (known after apply)
      + repository_name = "xxxxxxxx_test"
      + tags_all        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.
```


## 固有情報定義ファイルを指定してterraform applyを実行

では、いよいよ固有情報定義ファイルを指定して、terraform applyを実行してみます。
変数の箇所が、ちゃんと固有情報に置き換わり構築されていることが確認出来ます。

```
# terraform apply -var-file=xxxxxxxx.tfvars -auto-applove

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_codecommit_repository.repository will be created
  + resource "aws_codecommit_repository" "repository" {
      + arn             = (known after apply)
      + clone_url_http  = (known after apply)
      + clone_url_ssh   = (known after apply)
      + description     = "This is the xxxxxxxx Sample App Repository"
      + id              = (known after apply)
      + repository_id   = (known after apply)
      + repository_name = "xxxxxxxx_test"
      + tags_all        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_codecommit_repository.repository: Creating...
aws_codecommit_repository.repository: Creation complete after 2s [id=xxxxxxxx_test]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

## 検証後は削除します

永続的にしようる環境ではなく、検証で作成した環境のため、最後には削除します。
このときも固有情報定義ファイルを指定して削除しました。
今回は対象リソースが一つだけだったので「-target」は指定していません。

```
# terraform destroy -var-file=xxxxxxxx.tfvars
aws_codecommit_repository.repository: Refreshing state... [id=xxxxxxxx_test]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_codecommit_repository.repository has been changed
  ~ resource "aws_codecommit_repository" "repository" {
        id              = "xxxxxxxx_test"
      + tags            = {}
        # (7 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using
ignore_changes, the following plan may include actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_codecommit_repository.repository will be destroyed
  - resource "aws_codecommit_repository" "repository" {
      - arn             = "arn:aws:codecommit:xxxxxxx:xxxxxxxx:xxxxxxxx_test" -> null
      - clone_url_http  = "https://git-codecommit.us-west-2.amazonaws.com/v1/repos/xxxxxxxx_test" -> null
      - clone_url_ssh   = "ssh://git-codecommit.us-west-2.amazonaws.com/v1/repos/xxxxxxxx_test" -> null
      - description     = "This is the xxxxxxxx Sample App Repository" -> null
      - id              = "xxxxxxxx_test" -> null
      - repository_id   = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx" -> null
      - repository_name = "xxxxxxxx_test" -> null
      - tags            = {} -> null
      - tags_all        = {} -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes


aws_codecommit_repository.repository: Destroying... [id=xxxxxxxx_test]
aws_codecommit_repository.repository: Destruction complete after 1s

Destroy complete! Resources: 1 destroyed.
```

## おわりに

これまでの検証はあまり変数化を意識出来ておりませんでしたが、変数化することで実行時にできるだけ手を加えなくても良い構成に改修できたかと思います。
これで、固有情報定義ファイルだけ修正すれば、有志も同じ検証を行うことができるようになりました。

まだ調査していませんが、この固有情報定義ファイルをファイルとして保持するのではなく、どこか別の箇所に保持しておき、実行時にそこから補填するような仕組みができないか？ということも考え始めています。
これができると、ファイルの修正は全く必要なく、固有情報を保持している箇所だけ修正するだけで、フレキシブルに環境を構築できるようになると思います。
このあたりの構想については一緒に活動している有志に相談しつつ検討を進めていきたいと思います。