#95　AWSコンソールにおいて手動で作成したリソースをTerraformに取り込んでみる

# はじめに
AWSを使用してインフラを管理する中で、手動で作成したリソースをTerraformの管理下に置きたいという場面が多々あります。最近、terraformingというツールを使って手動で作成されたリソースをTerraformコードとして自動生成する機会がありましたので、AWSコンソールで作成したS3バケットをTerraformで管理する手順を共有したいと思います。

# 前提条件
•        Terraformがインストールされていること
•        AWS CLIが設定されていること
•        gem（RubyGems）がインストールされていること
•        すでにS3バケットがAWSコンソールで作成されていること
今回は以下のS3バケットを利用して、Terraformに取り込んでみます！
<br>
◆ S3 バケット 
バケット名：s3-terraforming-2024xxxx

# 手順
①        Terraformingのインストール
[terraforming](https://github.com/dtan4/terraforming)をインストールします。PowerShellやコマンドプロンプトで以下のコマンドを実行します。

```:Terminal
gem install terraforming
```

②        Terraform設定ファイルの作成 
まず、main.tfという名前でTerraformの設定ファイルを作成します。以下のようなシンプルな設定を作成してください。resourceブロックは後でterraformingやterraform importを使用して生成されたコードで置き換えます。

``` main.tf
provider "aws" {
    region = "ap-northeast-1"
    profile = "terraform" # 利用するAWS CLIのプロファイルをセット
}
```

```s3.tf
resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {}
```

③         Terraformの初期化
main.tfファイルを作成したディレクトリで、以下のコマンドを実行してTerraformを初期化します。

```Terminal
terraform init
```

④        既存のリソースをTerraformのstateファイルに取り込み
terraform importコマンドを利用するとAWS上に既に存在するリソースの情報をstateファイルに取り込むことができます。

```terminal
$ terraform import aws_s3_bucket.s3-terraforming-2024xxxx s3-terraforming-2024xxxx

aws_s3_bucket.s3-terraforming-2024xxxx: Importing from ID "s3-terraforming-2024xxxx"...
aws_s3_bucket.s3-terraforming-2024xxxx: Import prepared!
  Prepared aws_s3_bucket for import
aws_s3_bucket.s3-terraforming-2024xxxx: Refreshing state... [id=s3-terraforming-2024xxxx]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
```
これで手動作成したS3バケットがTerraformの管理下に置かれます。
しかし、importコマンドでできるのはstateファイルに取り込むまで、ソースコードにまで落とし込んでくれません。

⑤        リソースをソースコードに落とし込み
先ほどインストールしたterraformingを利用して、stateファイルからソースコードに落とし込んでみます。

```terminal
terraforming s3 --profile terraform > s3.tf
```
コマンドを実行するとAWS上で管理されているs3の情報を元にデータがソースコードに取り込まれます。ここで注意すべき点は、どうやらterraformingではAWSにあるすべてのバケット情報を取得してしまうようで、適宜いらないデータは手動で削除しなくてはならないようです。実際、私が上記のコマンドを実行した際は合計3つのバケットの情報がソースコードに取り込まれていたため、今回ターゲットとしているバケット以外のコードは削除しました。

```s3.tf
# terraformingによって取り込まれたS3のデータ
resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {
    bucket = "s3-terraforming-2024xxxx"
    acl    = "private"
}
```

⑥        Terraformの初期化と確認
Terraformを初期化し、設定内容が正しいか確認します。

```Terminal
terraform init
terraform plan

Terraform will perform the following actions:

  # aws_s3_bucket.s3-terraforming-2024xxxx will be updated in-place
  ~ resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {
      + acl                         = "private"
      + force_destroy               = false
        id                          = "s3-terraforming-2024xxxx"
        tags                        = {}
        # (9 unchanged attributes hidden)
        # (3 unchanged blocks hidden)
    }

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

⑦         動作確認
stateが正しく反映され、ソースコードの取得・修正も上手くいっているようなので、対象のバケットにタグを追加して既存のバケットを更新してみます。

```s3.tf
resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {
    bucket = "s3-terraforming-2024xxxx"
    acl    = "private"

    # 動作確認用にタグを追加
    tags = {
      name = "terrafoming"
    }
}
```

```Terminal
terraform plan

Terraform will perform the following actions:

  # aws_s3_bucket.s3-terraforming-2024xxxx will be updated in-place
  ~ resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {
      + acl                         = "private"
      + force_destroy               = false
        id                          = "s3-terraforming-2024xxxx"
      ~ tags                        = {
          + "name" = "terrafoming"
        }
      ~ tags_all                    = {
          + "name" = "terrafoming"
        }
        # (8 unchanged attributes hidden)
        # (3 unchanged blocks hidden)
    }

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

terraform apply -auto-approveを実行したらエラーが表示されました。
```Terminal
terraform apply -auto-approve

Error: putting S3 Bucket (s3-terraforming-2024xxxx) ACL: operation error S3: PutBucketAcl, https response error StatusCode: 400, RequestID: 77SY6CR3PNSGEGVJ, HostID: 6lBOIcz47wzrY4jPGUBfFWhM6bGg3WsxxMybYXaGxl3Pi0HGTdS3/Tu2PSNOUlcoSMTXoCqCkaQ=, api error AccessControlListNotSupported: The bucket does not allow ACLs
```

※このエラーはTerraformで利用されている”terraform-provider-aws”の記述方法が変わったことに起因するようです。terraformingは[”terraform-provider-aws”の最新の記述方法](https://github.com/hashicorp/terraform-provider-aws/pull/27197)に対応していないようなので、s3.tfを以下のように修正します。

``` s3.tf
resource "aws_s3_bucket" "s3-terraforming-2024xxxx" {
    bucket = "s3-terraforming-2024xxxx"
    # acl    = "private" ここをコメントアウト or 削除
    # 動作確認用にタグを追加
    tags = {
      name = "terrafoming"
    }
}
```

```Terminal
terraform apply -auto-approve
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
```

⑧        コンソールで更新を確認
ちゃんとタグが追加されていることが確認できました。
<img alt="erraforming-2" src="https://www.nxted.co.jp/blog/img/99/terraforming-2.png"> 
<br>

⑨        リソースの削除
今回作成したバケットは不要なため削除しておきます。
```Terminal
terraform destroy -auto-approve
```

# 注意点
terraformingを使って生成されたコードはそのままでは必ずしも完全ではないことがあるようです。特に、リソース名やタグなどの調整が必要な場合があるため、生成されたファイルを適切にレビューしてから適用することをお勧めします。

# まとめ
Terraformを使用することで、手動で作成したAWSリソースもコードベースで管理できるようになります。terraformingやterraform importコマンドを使えば、すでに存在するリソースを簡単にTerraform管理下に置くことができるため、インフラの整合性と再現性を確保するためにもぜひ試してみてください。