AWSで学ぶTerraform実践①〜AWSリソースを作成する（初級編）

# はじめに
みなさんIaCしてますか？
IaCツールといえばTerraformとAnsibleの二大巨頭なイメージがあり、どっちを使うか？みたいな話題をよく耳にしますが、個人的にはAWS/Azure/GCPといったパブリッククラウドのプロビジョニングはTerraform、オンプレミスのネットワーク設定や仮想サーバ内の設定はAnsibleがそれぞれ強いイメージです。
ただ昨今ではやはりパブリッククラウドの利用とそれに伴うIaC化が活発な印象があるので、ここらで一度**Terraformの利用方法をチュートリアル形式で学ぶコンテンツ**を作ってみようと思います。

## チュートリアルのセクション
Tutorial-1. [AWSリソースを作成する（初級編）](https://qiita.com/shin7446/items/9ce36f1eb0846d95fa73) ←本記事
Tutorial-2. [Local Valuesとリソース参照の活用](https://qiita.com/shin7446/9b94bdd2087aa7b5512d)
Tutorial-3. [countを使って複数のリソースを一気に作る]()
Tutorial-4. [TerraformでAWSリソースを作成する（中級編）]()
Tutorial-5. [for_eachを使ってよりフレキシブルな繰り返し処理を実現する]()
Tutorial-6. [moduleを使ってresourceを共通化する]()
Tutorial-7. [TerraformでAWSリソースを作成する（上級編）]()
Extra-1. Secret情報を暗号化してGitにアップする
Extra-2. tfstateファイルに外部のストレージを利用する
Extra-3. 他のTerraformで管理しているリソースを参照する

## チュートリアルで目指すゴール
* Terraformの基本的な利用方法を理解する
* tfファイルの記述方法やディレクトリ構成を理解する
* **現場である程度のレベルでTerraform導入を実施することができる**

### 注意事項
このチュートリアルはTerraformを初めて触る人が順番にセクションを実施することで実践的なノウハウを習得することを目標としています。そのため、チュートリアルの中ではあえて非推奨な記述を行うことがありますが、Terraformの理解を深めるためのプロセスとしてご容赦ください。

## 前提条件
チュートリアルは全体的に以下を前提として進行します。
* ある程度AWSのサービスとその関連性を理解している（AWS-SAAレベル)
* terraformを実行できる環境がある
    * Terraformのインストール方法は[こちら](https://qiita.com/tanamoru/items/196004686a471a3b7e2f)などを参照ください。
    * 今回は **Terraform v1.4.4** を利用します。
* AWSアカウントを持っており、AdministratorAccess権限を持つIAMユーザーを利用できる


# 本編
では、ここからチュートリアルを始めていきます。
このセクションでは、AWSの簡単な構成のデプロイを通じて、Terraformの基本的な記述方法を理解します。

# 本セクションのゴール
以下のような構成をTerraformでデプロイできること
* VPCを作成し、その中にEC2インスタンスを作成する
* インターネットを経由して、EC2インスタンスにアクセスできることを確認する
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/6edc2e01-3780-9e65-0bb0-76d7ee5c8bdf.png)


# 事前準備
作業用フォルダを作成します。
terraformはディレクトリでソースを管理するので、ローカルに作業用のディレクトリを作成しておきます。
```.コマンド
mkdir -p ~/terraform-tutorial/tutorial-1
cd ~/terraform-tutorial/tutorial-1
```

# 環境設定用の.tfファイルを作成→初期化を実行する
## tfファイルについて
Terraformでは、デプロイするリソース情報や認証情報などの情報を **.tfファイル** で記載します。
Terraformコマンドの実行時、カレントディレクトリにある.tfファイルをすべて読み込みます。
そのため、全ての情報をひとつの.tfファイルに書いてしまっても問題ありませんが、管理面が煩雑になるので、いくつかの要素に分けて.tfファイルを作成します。

## 環境設定用の.tfファイル
terraformを実行するために、いくつか環境設定のようなファイルを作成する必要があります。
今回は以下の2つのファイルを作成します。
* provider.tf
* versions.tf

### provider.tf
Terraformにおいて、どのプロバイダー（AWS,Azure,GCP,K8sなど）のリソースをデプロイするかを**Provider**と呼ばれるコンポーネントで定義します。
AWS Providerではアクセスキーとシークレットキー、デフォルトのリージョン設定が必要になります。（aws-cliにおけるaws configureを入力した際に必要な値と一緒）
ここでは`AdministratorAccess`の権限をもつIAMユーザーの情報を入力ください。
```provider.tf
provider aws {
  access_key = "XXXXXXXXXXXXXXXXXXXXXXXXX"
  secret_key = "YYYYYYYYYYYYYYYYYYYYYYYYY"
  region     = "ap-northeast-1"
}
```

### versions.tf
ProviderやTerraform自体のバージョンの整合性を取っておくと、今後バージョンアップがあったときになぜかエラーになる、といった事象を防げます。
ここではAWSのProviderとTerraformのバージョンを指定して、これ以外のバージョンのものを使おうとした時には実行前にエラーになるようにしています。
AWS Providerの最新バージョンは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest)で確認できます。
```versions.tf
terraform {
  required_version = "= 1.4.4"
  required_providers {
    aws         = "= 4.61.0"
  }
}
```

## terraform init
Terraformのワークスペースの初期化や、プラグインをダウンロードするために `terraform init` を実行します。
これによってprovider.tfで指定したProviderのプラグインを取得できます。
```.コマンド
terraform init
```
```.実行結果
Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "4.61.0"...
- Installing hashicorp/aws v4.61.0...
- Installed hashicorp/aws v4.61.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.
```

取得したプラグインは `.terraform` ディレクトリに格納されます。
```.コマンド
tree -a
```
```.実行結果
.
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── aws
│                   └── 4.61.0
│                       └── darwin_arm64
│                           └── terraform-provider-aws_v4.61.0_x5
├── .terraform.lock.hcl
├── provider.tf
└── versions.tf

7 directories, 4 files
```

# デプロイ用のtfファイル作成→実行
Terraformからソースをデプロイする際は、 `Resource` というコンポーネントを使います。
Resourceが記載された.tfファイルを格納したフォルダでデプロイ実行コマンドを入力すると、自動でデプロイが実行されます。
各種Resourceの記述方法については、作成したいリソースをGoogleで検索して、検索結果のTemplateを基本コピペして使うだけで殆ど問題ありません。
例えばRDSをTerraformコードにしたいときは「terraform AWS RDS resource」のように検索するとトップにTerraform公式サイトが出てきます。

## VPCの作成
まずはじめにVPCを作成します。
### .tfファイルの作成
VPCをデプロイするためのResourceの.tfファイルを作成します。
このResourceの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc)
* `enable_dns_hostnames` をtrueにしておくことで、VPC内からでもエンドポイントのドメイン名を解決できます。
```vpc.tf
resource "aws_vpc" "vpc" {
  cidr_block           = "192.168.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "tutorial-vpc"
  }
}
```
今のフォルダ構成は以下の通り
```
.
├── .terraform
├── .terraform.lock.hcl
├── provider.tf
├── versions.tf
└── vpc.tf
```

### デプロイの実行
実際にコマンドを実行してデプロイしてみます。
`terraform plan` を実行すると、カレントディレクトリ内の.tfファイルを読み取って、どんなAWSリソースがデプロイされるのか確認できます。
構文エラーがあればこのplan時に弾かれるので、実行前は必ずplanを実行するようにしましょう。
```.コマンド
terraform plan
```
```.実行結果
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc.vpc will be created
  + resource "aws_vpc" "tutorial_vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "192.168.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "tutorial-vpc"
        }
      + tags_all                             = {
          + "Name" = "tutorial-vpc"
        }
    }

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

───────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to
take exactly these actions if you run "terraform apply" now.
```

デプロイは `terraform apply` コマンドを実行します。
plan時と同様の内容が出力されるので、問題なければ `Enter a value:` に `yes` と入力してデプロイ実行します。
するとデプロイが走り、しばらくすると完了した旨のメッセージが出力されます。
```.コマンド
terraform apply
```
```.実行結果
---omit(planと同様)---
  Enter a value: yes  ←yesを入力

aws_vpc.vpc: Creating...
aws_vpc.vpc: Still creating... [10s elapsed]
aws_vpc.vpc: Creation complete after 12s [id=vpc-04fb5154d22486542]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```
AWSコンソールを見ると、Subnetが作成されていることがわかります。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/65c1d601-925e-5fd3-0ef7-d8d1663b145e.png)

## tfstateファイルについて
最初のapplyが完了した時、カレントディレクトリに `terraform.tfstate` というファイルが生成されます。
このファイルは実際にデプロイしたリソースの情報をjson形式で保存しているものです。
今後 `terraform apply` で差分実行したときは、`terraform.tfstate`ファイル、実機、tfファイルの3つの情報を元に差分を検出し、実行されます。
「tfstateなんて見ずに実機とtfファイルの差分だけ見りゃよくね？」と思う人もいるかもしれませんが、リソースの依存関係など、実機にない情報も必要らしく、このファイルも状態管理には必要です。詳しくは[公式ページ](https://developer.hashicorp.com/terraform/language/state/purpose)で説明されています。

ちなみにVPCを作成した段階のtfstateファイルは以下のような形になっています。
```terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.4.4",
  "serial": 1,
  "lineage": "a2216e14-10e4-bfb0-99e2-d69cfa87452d",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "aws_vpc",
      "name": "vpc",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:XXXXXXXXXXXX:vpc/vpc-04fb5154d22486542",
            "assign_generated_ipv6_cidr_block": false,
            "cidr_block": "192.168.0.0/16",
            "default_network_acl_id": "acl-07759005723d928fc",
            "default_route_table_id": "rtb-0ab93bd6a0c2cf95e",
            "default_security_group_id": "sg-0f7cc93c60b68fbb6",
            "dhcp_options_id": "dopt-01152b10208f13dd5",
            "enable_classiclink": false,
            "enable_classiclink_dns_support": false,
            "enable_dns_hostnames": true,
            "enable_dns_support": true,
            "enable_network_address_usage_metrics": false,
            "id": "vpc-04fb5154d22486542",
            "instance_tenancy": "default",
            "ipv4_ipam_pool_id": null,
            "ipv4_netmask_length": null,
            "ipv6_association_id": "",
            "ipv6_cidr_block": "",
            "ipv6_cidr_block_network_border_group": "",
            "ipv6_ipam_pool_id": "",
            "ipv6_netmask_length": 0,
            "main_route_table_id": "rtb-0ab93bd6a0c2cf95e",
            "owner_id": "878728386472",
            "tags": {
              "Name": "tutorial-vpc"
            },
            "tags_all": {
              "Name": "tutorial-vpc"
            }
          },
          "sensitive_attributes": [],
          "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="
        }
      ]
    }
  ],
  "check_results": null
}
```

## Internet Gatewayの作成
では次にInternet Gatewayを作成していきます。

### .tfファイルの作成
Internet GatewayをデプロイするためのResourceの.tfファイルを作成します。
このResourceの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway)
* `vpc_id` には、先ほど作成したVPCのIDを入力しておきます。これによってこのInternet Gatewayは `tutorial-vpc` 内に作成されます。 
```internet_gateway.tf
resource "aws_internet_gateway" "igw" {
  vpc_id = "vpc-04fb5154d22486542"

  tags = {
    Name = "tutorial-igw"
  }
}
```
### デプロイの実行
`terraform apply` でInternet Gatewayを作成します。
```.コマンド
terraform plan
terraform apply
```
コンソールで確認すると、たしかにInternet Gatewayが作成されています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/e04c45bc-89b4-cfa7-4488-b8a147960555.png)


## Subnetの作成
次にEC2インスタンスを立てるSubnetを作成します。

### .tfファイルの作成
SubnetをデプロイするためのResourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet)
* `vpc_id` は `tutorial_vpc` のIDを入力します。
* `cidr_block` のCIDRはVPC CIDRの範囲内に指定します。
```subnet.tf
resource aws_subnet subnet {
  vpc_id            = "vpc-04fb5154d22486542"
  cidr_block        = "192.168.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tutorial-public-subnet"
  }
}
```

### デプロイの実行
`terraform apply` でSubnetを作成します。
```.コマンド
terraform plan
terraform apply
```
コンソールで確認すると、たしかにSubnetが作成されています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/c7413bad-92a2-b2a0-8e56-743ad5418f8c.png)

## Route Tableの作成
作成したSubnetとInternet GatewayをRoute Tableで結び付けないと、VPC内のEC2のインターネットに通信できません。そのため、Internet Gatewayへの通信用のRoute Tableを作成します。

### .tfファイルの作成
Route Tableをデプロイするためのresourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table)
* `vpc_id` は `tutorial-vpc` のIDを入力します。
* `gateway_id` は `tutorial-igw` のIDを入力します。
```route_table.tf
resource aws_route_table route_table {
  vpc_id = "vpc-04fb5154d22486542"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "igw-0e204fdaad34cae29"
  }
  tags = {
    Name = "tutorial-route-table"
  }
}
```
#### デプロイの実行
`terraform apply` でRoute Tableを作成します。
```
terraform plan
terraform apply
```
コンソールで確認すると、たしかにRoute Tableが作成されています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/e6c32061-7d6d-1de8-05bf-d64c8062c776.png)


## Route TableとSubnetの関連付け
作成したRoute TableとSubnetを関連付けます。

### .tfファイルの作成
Route TableとSubnetを関連づけるためのResourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association)
* `subnet_id` は先ほど作成したSubnetのIDを指定します。
* `route_table_id` は先ほど作成したRoute TableのIDを指定します。

```route_table_association.tf
resource aws_route_table_association rta {
  subnet_id      = "subnet-0bf5661c57db0d425"
  route_table_id = "rtb-072ca46273b6a88e6"
}
```
#### デプロイの実行
`terraform apply` でRoute TableとSubnetを関連づけます。
```.コマンド
terraform plan
terraform apply
```
コンソールで確認すると、たしかにRoute TableとSubnetが関連づけられています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/4d375f00-88ba-2b24-8400-cc982b3c5221.png)



## 秘密鍵・公開鍵の作成
EC2インスタンスを作成する際、GUIで行った場合はAWS側でSSHキーの作成＆公開鍵の設定までやってくれますが、aws-cliやTerraformで実行する場合は事前に作成したSSHキーのインポートしか対応していません。そのため、事前にSSHのキーペアを作成しておく必要があります。
```.コマンド
ssh-keygen -t rsa -b 4096

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/XXX/.ssh/id_rsa): /Users/XXX/.ssh/aws-ec2
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/XXX/.ssh/aws-ec2.
Your public key has been saved in /Users/XXX/.ssh/aws-ec2.pub
The key fingerprint is:
-------omit-------------
```
```.コマンド
ll ~/.ssh/

-rw-------  1 XXX        XXX        3326 11月 26 01:10 aws-ec2
-rw-r--r--  1 XXX        XXX         781 11月 26 01:10 aws-ec2.pub
```

## キーペアのアップロード
作成したSSH公開鍵をAWS上にアップロードします。

### .tfファイルの作成
キーのアップロード用のresourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair)

* public_keyには公開鍵(`aws-ec2.pub`)の中身を記載します。
```key.tf
resource "aws_key_pair" "tutorial_key" {
  key_name   = "tutorial-key"
  public_key = "ssh-rsa AAAAB3NzaC1yc2---omit---XXX"
}
```

### デプロイの実行
`terraform apply` で公開鍵をアップロードします。
```.コマンド
terraform plan
terraform apply
```
コンソールで確認すると、キーがアップロードされていることがわかります。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/120d1608-b014-594d-7aa7-357109f74de0.png)


## Security Groupの作成
EC2インスタンスの作成時、Security Groupの指定が必要ですが、デフォルトのSecurity Groupを使うと0.0.0.0/0で22番ポートを公開しかねません。キーペアでアクセス制御できているので問題はないですが、念の為特定のアクセス元のみを許可するSecurity Groupを事前に作成しておきます。

### .tfファイルの作成
Security Group用のResourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group)
* インバウンドルール（ingress）に自分の作業端末のIPからのSSHアクセスを許可します。
* アウトバウンドルール（egress）は全ての通信を許可します。
```security_group.tf
resource "aws_security_group" "sg" {
  name        = "tutorial-security-group"
  description = "Allow SSH inbound traffic from XXX"
  vpc_id      = "vpc-04fb5154d22486542"

  ingress {
    description = "SSH from XXX"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["XXX.XXX.XXX.XXX/32"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "tutorial-security-group"
  }
}
```

#### デプロイの実行
`terraform apply` でSecurity Groupを作成します。
```.コマンド
terraform plan
terraform apply
```
画面で確認すると、たしかにSecurity Groupが作成されています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/8901b347-436c-98cf-76cc-324501bbf379.png)


## EC2インスタンスの作成
インスタンス作成時に必要なKeyとSecurity Groupの作成が完了したので、実際にインスタンスをデプロイしていきます。

### .tfファイルの作成
EC2インスタンス用のresourceの.tfファイルを作成します。
このリソースの公式ドキュメントは[こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance)
* `ami` は `ap-northeast-1` のAmazon Linuxのイメージを指定します。
* `subnet_id` は作成したSubnetのIDを指定します。
* `key_name` は作成したキーの名前を指定します。
* `vpc_security_group_ids` は作成したSecurity GroupのIDを指定します。
```instance.tf
resource aws_instance instance {
  ami                         = "ami-02a2700d37baeef8b"
  instance_type               = "t2.micro"
  subnet_id                   = "subnet-0bf5661c57db0d425"
  associate_public_ip_address = true
  key_name                    = "tutorial-key"
  vpc_security_group_ids      = ["sg-09e5b29077cb81637"]

  tags = {
    Name = "tutorial-instance"
  }
}
```
### デプロイの実行
`terraform apply` でEC2インスタンスをデプロイします。
```.コマンド
terraform plan
terraform apply
```
コンソールで確認すると、たしかにEC2インスタンスが作成されています。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419286/846cba97-2d62-8280-2a96-851a5708006b.png)


## EC2へSSHアクセス

これで目的の構成をデプロイできたので、EC2へアクセスしてみます。
```.コマンド
ssh -i ./aws-ec2 ec2-user@43.207.107.19
```
```.実行結果
The authenticity of host '43.207.107.19 (43.207.107.19)' can't be established.
ED25519 key fingerprint is SHA256:D+N8jZVoLknkReqOBEr8zJS1HHfkyLt1Ks+DCuxUmhs.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '43.207.107.19' (ED25519) to the list of known hosts.
Enter passphrase for key './aws-ec2':
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-192-168-1-197 ~]$
```

ということで、無事EC2インスタンスへSSHアクセスすることができました。


# デプロイしたリソースの削除
このチュートリアルで構築した環境を削除する方法は3つあります。

1. .tfファイル内のresourceの記述を削除 or コメントアウトして `terraform apply`　を実行する
1. ファイルの拡張子を変更（ex : aaa.tf→aaa.tf_old）して `terraform apply` を実行する
1. `terraform destroy`を実行する



## 1. .tfファイル内のresourceの記述を削除 or コメントアウトする
試しにRoute TableとSubnetを紐付けている"route_table_association.tf"ファイルをコメントアウトしてみます。
```route_table_association.tf
#resource aws_route_table_association rta {
#  subnet_id      = "subnet-0bf5661c57db0d425"
#  route_table_id = "rtb-072ca46273b6a88e6"
#}
```

この状態でplanを実行してみる見てもらうとわかる通り、紐付けのリソースを削除する旨の内容が出力されます。
```.コマンド
terraform plan
```
```.実行結果
---omit---

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_route_table_association.rta will be destroyed
  # (because aws_route_table_association.rta is not in configuration)
  - resource "aws_route_table_association" "rta" {
      - id             = "rtbassoc-089a58f9f877fe6d8" -> null
      - route_table_id = "rtb-072ca46273b6a88e6" -> null
      - subnet_id      = "subnet-0bf5661c57db0d425" -> null
    }

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

───────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to
take exactly these actions if you run "terraform apply" now.
```
問題なければ `terraform apply` します。
```.コマンド
terraform apply
```
```.実行結果
---omit(Planと同様)---

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_route_table_association.rta: Destroying... [id=rtbassoc-089a58f9f877fe6d8]
aws_route_table_association.rta: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
```

この状態で実際にSSHをすると、アクセスできないことがわかります。
```.コマンド
ssh -i ./aws-ec2 ec2-user@43.207.107.19 -vvv
---omit---
debug3: ssh_connect_direct: entering
debug1: Connecting to 43.207.107.19 [43.207.107.19] port 22.
debug3: set_sock_tos: set socket 3 IP_TOS 0x48


＜以降、返答なし＞
```

## 2. ファイルの拡張子を変更する（ex : aaa.tf→aaa.tf_old）
削除したいリソースに紐づく.tfファイルの拡張子を変更します。
```.コマンド
mv route_table_association.tf route_table_association.tf_old
```
その後の挙動はコメントアウト時と同様です。


## 3. terraform destroy
terraformでは特定のリソースもしくは全てのリソースを削除するためのコマンド `terraform destroy` が存在します。
全てのリソースを削除する場合は以下のコマンドを実行します。
```.コマンド
terraform plan -destroy
terraform destroy
```

特定のリソースを削除したいときは-targetオプションでリソースを指定します。
```.コマンド
terraform plan -destroy -target aws_route_table_association.rta
terraform destroy -target aws_route_table_association.rta
```
ターゲットの指定は `<resource種別>.<resource名>` で行います。例えば `aws_route_table_association` Resourceで作成した `rta` のコンポーネントを削除する場合は `aws_route_table_association.rta`と指定します。

# 環境のクリーンアップ
最後にこのセクションで作成した一連のリソースを削除します。
```.コマンド
terraform plan -destroy
terraform destroy
```

# おわりに
このセクションではTerraformのplan/apply/destroyと基本的な操作と、AWSの簡易的な構成をデプロイするためのtfファイルの書き方について学びました。次回のセクション「[AWSで学ぶTerraform実践②〜Local Valuesとリソース参照の活用](https://qiita.com/shin7446/9b94bdd2087aa7b5512d)」では、tfファイルのより効率的な記述方法について学んでいきます。

# 参考
今回使用したコードは以下のリポジトリにアップしています。
https://github.com/skitamura7446/terraform-tutorial/tree/master/tutorial-1
※各種tfファイル内のIDやAWSアカウントの情報、ec2の公開鍵などは個人で利用したものを記載しているため、このリポジトリをそのままapplyすることはできないこと、ご注意ください。