インフラのコード化：CloudShellでTerraformを使ってAWSネットワークを作成する手順

## はじめに
AWSでのネットワーク構成は、VPC、サブネット、ルートテーブル、インターネットゲートウェイなど、複数のリソースを組み合わせて設定する必要があります。

:::note warn
**手動での構築は時間がかかる上、ミスが発生しやすいため、Infrastructure as Code (IaC) ツールを活用することが重要です。**
:::

記事内容は将来の自分への備忘録として記録したものであるため、ご了承ください。

## 自動化する構成について
今回は、Terraform を使用して、以下の構成を自動化してみました。

![スクリーンショット 2024-11-17 1.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1b693f95-9c3d-c47f-e8ea-14673b71e149.png)

インフラのコード化が目的であるため、構築するのはシングルAZ構成とし、それをゴールとします。

:::note info
- **VPC**
- **パブリックサブネットとプライベートサブネット**
- **インターネットゲートウェイ (IGW)**
- **NATゲートウェイ**
- **各サブネットに適したルートテーブル**
:::

## Terraformについて
Terraform は、HashiCorp社が提供するオープンソースのIaCツールです。Terraformを使うことで以下のメリットがあります。

![スクリーンショット 2024-10-26 8.26.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/a1531ea9-3a09-2a88-6aae-c6ee8c04baae.png)
引用画像：https://sdpf.ntt.com/services/docs/fic/tutorials/terraform/rsts/Terraform/about_terraform.html

:::note info
- **再現性：**
コードを使って同じ構成を何度でも再現可能。
- **効率化：**
手動作業を減らし、エラーを防ぐ。
- **変更管理：**
コードの変更をバージョン管理できる。
:::

Terraform は宣言的な構文でインフラをコードとして記述し、AWS をはじめとするさまざまなクラウドプロバイダーで利用できます。

## コード紹介
以下は、Terraform を使って AWS のネットワークを構成するコードの詳細です。

:::note warn
**ここでは、重要な箇所をピックアップして紹介します。**
:::

最後に、全体のコードをまとめて記載します。

### AWSプロバイダーの設定

まず、AWS プロバイダーを指定し、東京リージョンでリソースを作成するように設定しています。

```tf
provider "aws" {
  region = "ap-northeast-1"  # 東京リージョン
}
```

### VPC作成

VPC の IP アドレス範囲を指定し、DNS 解決を有効化しています。

```tf
resource "aws_vpc" "terraform_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "terraform-vpc" }
}
```

### サブネット作成

**パブリックサブネット**

パブリック用のサブネットを作成し、アベイラビリティゾーン（AZ）は ``ap-northeast-1a`` を選択しています。

```tf
resource "aws_subnet" "public_subnet" {
  vpc_id            = aws_vpc.terraform_vpc.id
  cidr_block        = "10.0.0.0/20"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "terraform-subnet-public1-ap-northeast-1a" }
}
```

**プライベートサブネット**

プライベート用のサブネットも作成し、アベイラビリティゾーン（AZ）は ``ap-northeast-1a`` を選択しています。

```tf
resource "aws_subnet" "private_subnet" {
  vpc_id            = aws_vpc.terraform_vpc.id
  cidr_block        = "10.0.128.0/20"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "terraform-subnet-private1-ap-northeast-1a" }
}
```

### インターネットゲートウェイ (IGW) の設定

VPC にインターネットアクセスを提供するための IGW を作成し、アタッチします。

```tf
resource "aws_internet_gateway" "terraform_igw" {
  vpc_id = aws_vpc.terraform_vpc.id
  tags = { Name = "terraform-igw" }
}
```

### NATゲートウェイとルートテーブル
**NAT用Elastic IP**

NAT ゲートウェイのために Elastic IP を作成します。

```tf
resource "aws_eip" "terraform_eip" {
  vpc = true
  tags = { Name = "terraform-eip-ap-northeast-1a" }
}
```

**NATゲートウェイ**

作成した Elastic IP を使用して、NAT ゲートウェイを設定します。

```tf
resource "aws_nat_gateway" "terraform_nat" {
  allocation_id = aws_eip.terraform_eip.id
  subnet_id     = aws_subnet.public_subnet.id
  tags = { Name = "terraform-nat-public1-ap-northeast-1a" }
  depends_on = [aws_eip.terraform_eip]
}
```

## 完成した全体のコード

上記の内容を反映させた、実際に完成したコードは以下になります。

```main.tf
# AWSプロバイダー設定
# 東京リージョンでリソースを作成
provider "aws" {
  region = "ap-northeast-1"
}

# VPC作成
# CIDRブロックを10.0.0.0/16で設定。DNSサポートとホスト名を有効化。
resource "aws_vpc" "terraform_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-vpc"
  }
}

# パブリックサブネット作成
# パブリック用のサブネットを作成、AZはap-northeast-1a
resource "aws_subnet" "public_subnet" {
  vpc_id            = aws_vpc.terraform_vpc.id
  cidr_block        = "10.0.0.0/20"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "terraform-subnet-public1-ap-northeast-1a"
  }
}

# プライベートサブネット作成
# プライベート用のサブネットを作成、AZはap-northeast-1a
resource "aws_subnet" "private_subnet" {
  vpc_id            = aws_vpc.terraform_vpc.id
  cidr_block        = "10.0.128.0/20"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "terraform-subnet-private1-ap-northeast-1a"
  }
}

# インターネットゲートウェイ作成
# VPCにインターネットアクセスを提供するためのIGWを作成
resource "aws_internet_gateway" "terraform_igw" {
  vpc_id = aws_vpc.terraform_vpc.id

  tags = {
    Name = "terraform-igw"
  }
}

# パブリックルートテーブル作成
# 全トラフィック（0.0.0.0/0）をインターネットゲートウェイにルーティング
resource "aws_route_table" "public_rtb" {
  vpc_id = aws_vpc.terraform_vpc.id

  tags = {
    Name = "terraform-rtb-public"
  }
}

resource "aws_route" "public_route" {
  route_table_id         = aws_route_table.public_rtb.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.terraform_igw.id
}

# パブリックサブネットとルートテーブルを関連付け
resource "aws_route_table_association" "public_rtb_assoc" {
  subnet_id      = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_rtb.id
}

# NAT用のElastic IPを作成
# NATゲートウェイのIPアドレスを確保
resource "aws_eip" "terraform_eip" {
  vpc = true

  tags = {
    Name = "terraform-eip-ap-northeast-1a"
  }
}

# NATゲートウェイ作成
# プライベートサブネットのアウトバウンド通信をインターネットに転送
resource "aws_nat_gateway" "terraform_nat" {
  allocation_id = aws_eip.terraform_eip.id
  subnet_id     = aws_subnet.public_subnet.id

  tags = {
    Name = "terraform-nat-public1-ap-northeast-1a"
  }
  depends_on = [aws_eip.terraform_eip]  # Elastic IPの作成を待つ
}

# プライベートルートテーブル作成
# 全トラフィックをNATゲートウェイにルーティング
resource "aws_route_table" "private_rtb" {
  vpc_id = aws_vpc.terraform_vpc.id

  tags = {
    Name = "terraform-rtb-private1-ap-northeast-1a"
  }
}

resource "aws_route" "private_route" {
  route_table_id         = aws_route_table.private_rtb.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.terraform_nat.id
}

# プライベートサブネットとルートテーブルを関連付け
resource "aws_route_table_association" "private_rtb_assoc" {
  subnet_id      = aws_subnet.private_subnet.id
  route_table_id = aws_route_table.private_rtb.id
}
```

## 実際にやってみた

ここでは、CloudShellでの Terraform のセットアップが完了していることを前提に進めます。

**まだセットアップが完了していない方は、過去の記事を参考にしてセットアップを実施してください。**

https://qiita.com/free-honda/items/19b4e7db8b8f24d41277

まず、以下のコマンドを入力して、**main.tf**というファイルを作成します。

```bash
vi main.tf
```

``vi``では、ファイル編集後にESCキーを押し、``:wq``で保存して終了します。

```main.tf
# 上記の完成した全体のコードをコピーして貼り付けてください。
```

次に、以下のコマンドで Terraform を初期化します。

```bash
terraform init
```

実際に、以下のように「``Terraform has been successfully initialized!``」と表示され、成功が確認できました。

```bash
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

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.
```

次に、以下のコマンドを入力して、確認メッセージが表示されたら「``yes``」と入力します。

```bash
terraform apply
```

その後、以下のように「``Apply complete! Resources: 12 added, 0 changed, 0 destroyed.``」と表示され、作成が成功したことが確認できました。

![スクリーンショット 2024-11-17 1.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c3356544-3934-dfa9-7e6f-8f6bf29926e6.png)

VPC、サブネット、IGW、NAT ゲートウェイが正しく作成され、想定通りのネットワーク構成が確認できました。

![スクリーンショット 2024-11-17 1.32.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/54cfaee8-a52b-e41a-c5ec-8c33f88d4ba1.png)

:::note
**AWS コンソール上から AWS の VPC などのネットワークが作成されていることが確認できました。**
:::

![スクリーンショット 2024-11-17 1.34.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c1f479d4-cb03-1976-5916-51d62f0eab48.png)

これにより、インフラのコード化は大成功です！

```bash
terraform destroy
```

Terraformを使用して作成したAWSリソースを削除するには、上記のコマンドを実行すると一瞬で消えるので便利です。

## まとめ
Terraformを使うことで、AWSのネットワーク構成を効率的に自動化できました。


:::note warn
**コード化することで変更管理が容易になり、今後の拡張や改善もスムーズに行える点が大きなメリットです。**
:::

今回の構成を基に、さらにセキュリティグループやEC2インスタンスの構築なども行い、AWS環境の理解を深めていきたいと思います。

## 参考記事

https://qiita.com/Mouflon_127000/items/767b964c833ed0428eb6

https://qiita.com/keke21/items/6daaa8a5b9b360ad2369