Terraform State を格納する S3 バケットを Terraform で作成する

現場で Terraform を扱うようになって慣れてきたけど, Terraform State を格納する S3 バケットを Terraform で管理できないのか凄く気になったので調査した。


## 結論

答えは [Terraform: Up & Running](https://www.oreilly.com/library/view/terraform-up/9781492046899/) に書いてあった。

1. 先ずは `backend` を設定せず, S3 バケット (と, ついでに DynamoDB テーブル) を作成する。
   * [この時点のソースコード](https://github.com/sb3f-ryo-sato/terraform-state/commit/b53f39d06c59024b3f27aae879289de64be320f4)
1. 続いて, backend を設定して `terraform init` すると local の state ファイルをコピーするか聞かれるので, `yes` でコピーする。
   * [この時点のソースコード](https://github.com/sb3f-ryo-sato/terraform-state/commit/3c14795afdb3d7a655c01118536cb3de5dd3ddad)


## 詳細

最初から `backend` を設定して `terraform init` すると, 当然ながら S3 バケットが存在しないためにエラーが出力される。

```bash
$ terraform init
Initializing modules...

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
│
│ Error: Failed to get existing workspaces: S3 bucket does not exist.
│ 
│ The referenced S3 bucket must have been previously created. If the S3 bucket
│ was created within the last minute, please wait for a minute or two and try
│ again.
│ 
│ Error: NoSuchBucket: The specified bucket does not exist
│      status code: 404, request id: HTB65E17X76ME9GS, host id: J5mzHH4n5s29B5KujKHW/arHsdbxMHzGOv5KWg+8NuEs8A8jUTVXz9VIzCP2ImRJnTezUB/pGTk=
```


そこで一旦, `backend` を設定せず, local に state ファイルを作成, そのまま `terraform apply` して S3 バケットを作成する。

```bash
$ terraform init
Initializing modules...
- terraform_state in ../../modules/terraform-state

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.65.0...
- Installed hashicorp/aws v3.65.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```


この状態で `backend` を設定し, 改めて `terraform init` する。
今度は local の state を S3 バケットにコピーしても良いか聞かれるので, `yes` と入力する。

```bash
$ terraform init
Initializing modules...

Initializing the backend...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the newly
  configured "s3" backend. Do you want to copy this state to the new "s3"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes
```


すると, local の state ファイルが S3 バケットにコピーされる。

```bash
Releasing state lock. This may take a few moments...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

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

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```


どっとはらい。