🏞️

Terraformのbackend設定を.tfファイルから分離する方法まとめ

2024/03/30に公開

概要

同じ Terraform のソースから複数の環境を作成するため、
.tfファイルに backend の設定を記載せずに.tfbackendファイルを使用して定義しようとしたところ少しハマりました。

原因とそもそもの backend 定義のルール理解のため、
terraform の backend に関して深掘りしてまとめました。

ハマった時の状況

個人開発で backend の設定は別ファイルに分離したく、以下のように試しました。
結果、backend が local 扱いにされてハマりました。

https://zenn.dev/link/comments/81a6eb77ddd22a

main.tf には特に backend ブロックの定義はなし

main.tf
# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
}

dev 環境用の tfbackend ファイルを作成

backend/dev.tfbackend
bucket = ****
key    = "****dev.tfstate"
region = "ap-northeast-1"
profile = ****

作成した tfbackend を使用して terraform init

terraform init -reconfigure -backend-config="backend/dev.tfbackend"

warn が出力される。
backend の定義が見つからず、local 扱いになっていた。

-backend-configの設定だけではだめだったっぽい。

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v3.76.1

╷
│ Warning: Missing backend configuration
│
│ -backend-config was used without a "backend" block in the configuration.
│
│ If you intended to override the default local backend configuration,
│ no action is required, but you may add an explicit backend block to your
│ configuration to clear this warning:
│
│ terraform {
│   backend "local" {}
│ }
│
│ However, if you intended to override a defined backend, please verify that
│ the backend configuration is present and valid.
│
╵

main.tf に backend の設定を記載すると解決しました。

main.tf
# ------------------------
# - Terraform configuratoions
# ------------------------
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  backend "s3" {
    bucket = ****
    key    = "****dev.tfstate"
    region = "ap-northeast-1"
    profile = ****
  }
}

公式ドキュメントには下記の記載があった

If a configuration includes no backend block, Terraform defaults to using the local backend, which stores state as a plain file in the current working directory.

そもそも.tfファイルでバックエンド種類として s3 を指定していなかったので当然といえば当然。

以下、公式のドキュメントを参考にしています。
https://developer.hashicorp.com/terraform/language/settings/backends/configuration

そもそも Terraform における backend とは

Terraform の tfstate ファイルの保存場所を定義するもの。
Terraform は tfstate を使って管理するリソース群の状態を追跡する。

Terraform Cloud と統合するか、backend を定義することで
複数個所から共通の tfstate にアクセス、すなわち共通のリソースにアクセスできるようになる。

backend の種類

複数パターン選択が可能。

選択したものによってただのリモートディスクのように機能するものや、
操作中に state のロックができるものもある。

例えばs3の backend はDynamoDBを介することでロックと一貫性チェックサポートも可能。

backend の設定

Terraform Cloud を使用する場合は自動的に state を管理してくれるので、backend の設定は不要。

設定する場合、トップレベルの terraform ブロック内にネストした backend ブロックを追加する。

backend ブロックで使われる引数は、選択した backend の種類の固有のもの

terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  # terraformブロックにネストしたbackendブロック
  backend "s3" {
    bucket = ****
    key    = "****dev.tfstate"
    region = "ap-northeast-1"
    profile = ****
  }
}

リモートサービスに state ファイルを保存することで、複数の人からアクセスできるようにする。

機密性が高い情報(ARN や DB のパスワード等)が含まれるので、リモートの state にアクセスするにはアクセス認証情報が要る。
AWS であれば、profile 名を指定する等。

backend ブロックの引数について

backend ブロックで必要な引数をすべて指定する必要はない。
ただし、省略された引数は init で提供されなければならない。
引数を省略する場合は最低でも空の backend 構成を指定する必要がある。

terraform {
  backend "s3" {
  }
}

最終的な設定は.terraformディレクトリにプレーンテキストで保存される。
.terraformディレクトリは基本的にバージョン管理から除外される。

backend ブロックで省略された引数をinitで提供する例

コマンドライン引数でキーと値のペアを一つ指定する場合
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  backend "s3" {
    bucket = ****
    # keyを省略
    region = "ap-northeast-1"
    profile = ****
  }
}
terraform init -backend-config="key=dev.tfstate"
対話的入力

対話的入力が無効でなければ、必要な値を質問してくる。

terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  backend "s3" {
    # bucketとkeyを省略
    region = "ap-northeast-1"
    profile = ****
  }
}
> terraform init

Initializing the backend...
Backend configuration changed!

Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.

bucket
  The name of the S3 bucket

  Enter a value: {bucketを入力}

key
  The path to the state file inside the bucket

  Enter a value: {keyを入力}
別ファイルで指定

backend ブロックの内容を記載するファイルを作成し、それを指定する。
ブロックでラップする必要はない。

ファイル名は*.backendname.tfbackend(例: config.consul.tfbackend)が推奨。

bucket = ****
key    = "****dev.tfstate"
region = "ap-northeast-1"
profile = ****
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  backend "s3" {
    # ブロックだけ記載
  }
}
terraform init -backend-config="{tfbackendファイルパスを指定}"
コマンドラインで指定
terraform {
  required_version = ">1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }
  backend "s3" {
    # ブロックだけ記載
  }
}
terraform init \
    -backend-config="bucket=****" \
    -backend-config="key=****dev.tfstate" \
    -backend-config="region=ap-northeast-1" \
    -backend-config="profile=****"

結論

.tfファイルから分離する場合、
最低でも空の backend ブロックを記載し、backend の種類を定義する必要があります。

Discussion