terraform_remote_state を試す

## はじめに
[terraform_remote_state](https://developer.hashicorp.com/terraform/language/state/remote-state-data) を使うと、コード分離された別のフォルダなどで動作する Terraform の State ファイル内の Output の値を参照することができる

ここでは、Google Cloud 向けの Terraoform コードをもとに、`GCS` をバックエンドストレージにしている例で試した結果を記載する 
([その他対応バックエンド](https://developer.hashicorp.com/terraform/language/state/remote-state-data#alternative-ways-to-share-data-between-configurations). AWS, Azure の例は記載されているドキュメント紹介のみ記載)

`terraform_remote_state` を使用することで、`prod`, `dev` などで環境をフォルダで分けて同じことをするコード構成などで (フォルダ分離して中身はほぼコピペなような構成で)、
参照するバックエンド(バケット名)を変えるだけで複数の参照データを置き換えることも可能になる
(`prefix`を同じくする構成であれば。コピペ時に値の置き換えミスなどが起きにくくできる) 


以降に試した結果などを記載するが、公式ドキュメントがわかりやすいのでそちらを参照するでも十分理解できる内容になっている
(公式ドキュメント : [gcs](https://developer.hashicorp.com/terraform/language/settings/backends/gcs#data-source-configuration), [s3](https://developer.hashicorp.com/terraform/language/settings/backends/s3#data-source-configuration), [azurerm](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm#data-source-configuration))

## GCS Backend / Google Cloud で試す

参照先[ドキュメントリンク](https://developer.hashicorp.com/terraform/language/settings/backends/gcs#data-source-configuration)

ここでは、プロジェクト作成時の課金アカウントを他で作成したアカウントIDと課金アカウントを値参照し、
プロジェクトが所属するフォルダを作成する際に親フォルダのIDを参照するように、
GCS をバックエンドにしているステートファイルから ID を取得する

`terraform_remote_state` は output したデータのみが参照可能なので、
参照先コードに参照したいデータの`output`を追加して外部から参照可能にする

下記コード例での実施環境などの補足 ([追加前の環境説明記事](https://qiita.com/suzuyui/items/879dfa5d837a19c39a54))

- workspace を使用している
    - ここでは `dev` を指定している
- project を作成するコードの追加
    - project 作成コードは元になるコードは以下に projects フォルダを作成して別コードフォルダで実施している 
    - 追加 project の中身の内容は[別記事参照](https://qiita.com/suzuyui/items/5b3ec78ab54794b536f6#%E6%A7%8B%E7%AF%89-google-cloud) 
        - terraform_remote_state を試すこととは直接関係なく、これを作る際にこれを試したという意味
    - ここでの GCS の参照先(親フォルダなどの作成先)の `prefix` は `terraform/state` (実施環境の値)
- 実施内容 : プロジェクトを作成するフォルダIDと課金IDを他のステートファイルを参照して取得する
    - プロジェクト側
        - data.terraform_remote_state.state.outputs.organization_service_folder_id
        - data.terraform_remote_state.state.outputs.host_billing_account
    - 参照先側
        - output "organization_service_folder_id"
        - output "host_billing_account"

コード記載例全体 : https://github.com/suzuyu/terraform-public/releases/tag/v1.2.0

```terraform:コード例_project作成フォルダ側抜粋(data.terraform_remote_stateの使用)
# 環境の値になる variables の定義は、ここでは記載を省略している

# ステートファイルの参照
data "terraform_remote_state" "state" {
  backend   = "gcs"
  workspace = "dev" # workspace を使用している場合は指定する. workspace を使用してない場合は指定不要
  config = {
    bucket = var.terraform_state_bucket_name # 参照する GCS を指定する
    prefix = "terraform/state"　# 参照する Terraform が指定している prefix を記載する
  }
}

# フォルダの作成で parent フォルダの参照に data.terraform_remote_state を使用
resource "google_folder" "folder" {
  display_name = var.folder_name
  parent       = data.terraform_remote_state.state.outputs.organization_service_folder_id # 組織のサービス向けフォルダ ID を参照して、配下にフォルダを作成する
}

# プロジェクト作成で billing_account (課金アカウント) の ID を他のプロジェクトのものと同じになるように data.terraform_remote_state を使用
resource "google_project" "main" {
  name            = var.project_id
  project_id      = var.project_id
  billing_account = data.terraform_remote_state.state.outputs.host_billing_account # SharedVPC の host プロジェクトの課金 ID を参照して、同じ課金アカウントを使用する
  folder_id       = google_folder.folder.name
}
```

参照先コードで output 未設定の場合は、terraform_remote_state で参照できるように **output の追加**をする

```diff_terraform:コード例_参照先別フォルダ抜粋(参照のためoutputの追加)
# 環境の値になる variables の定義は、ここでは記載を省略している

# backend
terraform {
  backend "gcs" {
    bucket = "YOUR_TERRAFORM_GCS_BUCKET"
    prefix = "terraform/state"
  }
}

# サービス向けフォルダ
resource "google_folder" "organization_service_folder" {
  display_name = "service"
  parent       = join("/", ["organizations", var.gcp_common.org_id])
}

+ # terraform_remote_state で参照できるように output の追加
+ output "organization_service_folder_id" {
+   value = google_folder.organization_service_folder.id
+ }


# ホストプロジェクト
resource "google_project" "host_project" {
  name       = var.host_project_name
  project_id = var_host_project_name
  billing_account = var.gcp_common.billing_account
  folder_id       = google_folder.host_host_folder.name

  depends_on = [
    google_folder.host_host_folder,
  ]
}

+ # terraform_remote_state で参照できるように output の追加
+ output "host_billing_account" {
+   value = google_project.host_project.billing_account
+ }
```

## AWS, Azure の場合 / ドキュメント参照先・ドキュメント先の記載コード例

AWS, Azure でも基本的に対応することは変わらないので、試すことは省略して、
下記ドキュメントリンクと、ドキュメント先記載のコード例を抜粋して紹介する

基本的には `backend` で種類を指定して、`config` でパラメータを指定する terraform.backend の際と同じように値を設定するだけ

### S3 Backend / AWS

[ドキュメントリンク](https://developer.hashicorp.com/terraform/language/settings/backends/s3#data-source-configuration) (下記コード例もドキュメントから抜粋)

```terraform:コード例
data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "terraform-state-prod"
    key    = "network/terraform.tfstate"
    region = "us-east-1"
  }
}
```

### Azure Storage / Azure

[ドキュメントリンク](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm#data-source-configuration) (下記コード例もドキュメントから抜粋)

```terraform:コード例
data "terraform_remote_state" "foo" {
  backend = "azurerm"
  config = {
    storage_account_name = "terraform123abc"
    container_name       = "terraform-state"
    key                  = "prod.terraform.tfstate"
  }
}
```

## おわりに
terraform_remote_state を試した
terraform コードをフォルダ分離して管理する場合、場合によっては分離されたリソースの値参照する場合にはこちらが有用そう

[terragrunt](https://terragrunt.gruntwork.io/) を使用するとさらに管理に良いらしいので比較検討をするのが良さそう

## 参照

https://developer.hashicorp.com/terraform/language/state/remote-state-data

https://developer.hashicorp.com/terraform/language/settings/backends/gcs#data-source-configuration

https://developer.hashicorp.com/terraform/language/settings/backends/s3#data-source-configuration

https://developer.hashicorp.com/terraform/language/settings/backends/azurerm#data-source-configuration