TerraformのバックエンドをTerraformで作る

# 概要
* Terraformのバックエンドとして、S3とDynamoDBを利用することが出来る。
* リモートに状態を保存し編集ロックすることで、同時開発による状態の破損を防ぐことが出来る。
* また、秘密情報を含むtfstateをGitHub等に上げることを回避できる。
  * Sensitive values in state の項を参照 (https://learn.hashicorp.com/tutorials/terraform/sensitive-variables)

# 検証したバージョン

```shell
Terraform v1.1.2
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v4.18.0
```

# サンプルコード

#### ディレクトリ構造
```shell
backend/ # backendを作成する部分
　├ main.tf
　└ provider.tf

s3_sample/ # backendを利用するサンプル
　├ backend.config 
　├ backend.tf
　├ main.tf
　└ provider.tf
```

#### backend/main.tf
```terraform
locals {
  backend_name = "backend-sample"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "tfstate-${local.backend_name}"
}

resource "aws_s3_bucket_public_access_block" "terraform_state" {
  bucket                  = aws_s3_bucket.terraform_state.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_dynamodb_table" "terraform_locks" {
  name           = "tflocks-${local.backend_name}"
  hash_key       = "LockID"
  read_capacity  = 1
  write_capacity = 1

  attribute {
    name = "LockID"
    type = "S"
  }
}

```

* S3のパブリックアクセスは不要なので全て閉じる。
* read_capacity/write_capacityは、DynamoDBの読み書きスループットを決める値。小さいほうが安く済むし、Backendとしての利用なら1で十分。

#### backend/provider.tf
```terraform
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.18.0"
    }
  }
  required_version = "~> 1.1.0"
}

provider "aws" {
  region     = "ap-northeast-1"
  access_key = "my-access-key" # 各自の環境に合わせて修正
  secret_key = "my-secret-key" # 各自の環境に合わせて修正
}
```

#### s3_sample/backend.config 
```terraform
bucket          = "tfstate-backend-sample"
dynamodb_table  = "tflocks-backend-sample"
encrypt         = true
region          = "ap-northeast-1"
```

#### s3_sample/backend.tf
```terraform
terraform {
  backend "s3" {
    key = "sample.tfstate"
  }
}
```
* keyは作成されるtfstateファイル名。
* 複数のTerraformで同じバックエンドを共有する場合、ここを変える。


#### s3_sample/main.tf
```terraform
resource "aws_s3_bucket" "sample" {
  bucket = "bucket-sample-okmnjiuhb" # 各自で修正
}

resource "aws_s3_bucket_public_access_block" "sample" {
  bucket                  = aws_s3_bucket.sample.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
```

* サンプル用に適当なS3バケットを作成。


#### s3_sample/provider.tf
```terraform
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.18.0"
    }
  }
  required_version = "~> 1.1.0"
}

provider "aws" {
  region     = "ap-northeast-1"
  access_key = "my-access-key" # 各自の環境に合わせて修正
  secret_key = "my-secret-key" # 各自の環境に合わせて修正
}
```
# 実行方法

##### 1. バックエンドのデプロイ
```shell
cd backend
terraform init
terraform plan
terraform apply
```
##### 2. 作成したバックエンドを使ったリソースのデプロイ

```shell
cd s3_sample
terraform init -backend-config=./backend.config
terraform plan
terraform apply
```

# バックエンドの中身


s3_sample/backend.tfで指定したkey名で、tfstateが出力される。
![s3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107679/41dde206-f3e7-755e-8c69-feb2fb03aac7.png)

Terraform Applyで止めてDynamoDBを見てみると、ロック用のレコードが登録されている。
Whoにユーザ名が表示されている。
![dynamo.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107679/566f360f-fd78-63a7-5f8d-520cafd8792e.png)