Terraformのメモ

# 背景・目的
TerraformでNW関係のリソースを作成したときのメモです。

# まとめ

|分類|目的|
|:--|:--|
|NW|[VPCを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#vpc)|
||[サブネットを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%82%B5%E3%83%96%E3%83%8D%E3%83%83%E3%83%88)|
||[複数サブネットを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E8%A4%87%E6%95%B0%E3%82%B5%E3%83%96%E3%83%8D%E3%83%83%E3%83%88)|
||[IGWを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4)|
||[EIPを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#eip%E3%81%A8nat-gateway)|
||[NATGWを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#eip%E3%81%A8nat-gateway)|
||[ルートテーブルを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%83%AB%E3%83%BC%E3%83%88%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)|
|S3|[バケットを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%83%90%E3%82%B1%E3%83%83%E3%83%88)|
||[バケットポリシーを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC)|
||[VPCeを作成する](https://qiita.com/zumax/items/71184fc108b6894e5b27#vpces3-gateway)|
|全般|[掃除する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E6%8E%83%E9%99%A4)|
||[プランファイルを使って削除する](https://qiita.com/zumax/items/71184fc108b6894e5b27#%E3%83%97%E3%83%A9%E3%83%B3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B)|


# 実践
## VPC
1. CIDRの変数を定義します
    ```terraform
    variable "vpc_cidr" {
      description = "vpc cidr"
      type        = string
      default     = "100.0.0.0/16"
    }
    ```
1. VPCを作成します
    ```terraform
    resource "aws_vpc" "terraform_vpc" {
      cidr_block           = var.vpc_cidr
      enable_dns_support   = true
      enable_dns_hostnames = true
      tags = {
        Name = "terraform_vpc"
      }
    }
    ```

1. `terraform apply`します
1. できました。AZ毎に作っていますが、一つでも問題ありません
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/44baf8a7-4a66-e1be-74c4-57269a0b23b7.png)


## サブネット
1. サブネットを作成します
    ```terraform
    ### サブネット
    resource "aws_subnet" "webSubnet01" {
      vpc_id = aws_vpc.terraform_vpc.id
      cidr_block = "100.0.0.0/24"
      availability_zone = "ap-northeast-1a"
      tags = {
        Name = "webSubnet01"
      }
    }
    ```
1. `terraform apply`します
1. できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/0f2e5c72-7d17-a5f6-1b2c-808843db1cec.png)

### 複数サブネット
1. 変数を定義します
    ```terraform
    variable "subnets" {
      type = map(any)
      default = {
        public_subnets = {
          public01 = {
            name = "public01",
            cidr = "100.0.0.0/24",
            az   = "ap-northeast-1a"
          },
          public02 = {
            name = "public02",
            cidr = "100.0.1.0/24",
            az   = "ap-northeast-1c"
          },
          public03 = {
            name = "public03",
            cidr = "100.0.2.0/24",
            az   = "ap-northeast-1d"
          },
        }
        private_subnets = {
          private01 = {
            name = "private01",
            cidr = "100.0.10.0/24",
            az   = "ap-northeast-1a"
          },
          private02 = {
            name = "private02",
            cidr = "100.0.11.0/24",
            az   = "ap-northeast-1c"
          },
          private03 = {
            name = "private03",
            cidr = "100.0.12.0/24",
            az   = "ap-northeast-1d"
          },
        },
        db_subnets = {
          db01 = {
            name = "db01",
            cidr = "100.0.20.0/24",
            az   = "ap-northeast-1a"
          },
          db02 = {
            name = "db02",
            cidr = "100.0.21.0/24",
            az   = "ap-northeast-1c"
          },
          db03 = {
            name = "db03",
            cidr = "100.0.22.0/24",
            az   = "ap-northeast-1d"
          },
        }
      }
    }
    ```

1. サブネットを作成します
    ```terraform
    resource "aws_subnet" "public_subnets" {
      for_each = var.subnets.public_subnets
    
      vpc_id = aws_vpc.terraform_vpc.id
    
      cidr_block        = each.value.cidr
      availability_zone = each.value.az
    
      tags = {
        Name = "${each.value.name}"
      }
    }
    
    resource "aws_subnet" "private_subnets" {
      for_each = var.subnets.private_subnets
    
      vpc_id = aws_vpc.terraform_vpc.id
    
      cidr_block        = each.value.cidr
      availability_zone = each.value.az
    
      tags = {
        Name = "${each.value.name}"
      }
    }
    
    resource "aws_subnet" "db_subnets" {
      for_each = var.subnets.db_subnets
    
      vpc_id = aws_vpc.terraform_vpc.id
    
      cidr_block        = each.value.cidr
      availability_zone = each.value.az
    
      tags = {
        Name = "${each.value.name}"
      }
    }
    ```

1. `terraform apply`します
1. できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/b5001ae9-a888-00fa-6d65-b6b2c1209a6a.png)


## インターネットゲートウェイ
1. IGWを作成します
    ```terraform
    resource "aws_internet_gateway" "terraform_igw" {
      vpc_id = aws_vpc.terraform_vpc.id
    
      tags = {
        Name = "terraform-igw"
      }
    
    }
    ```
1. `terraform apply`します
1. できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ac25015b-b156-104b-f381-10bedfc52a6f.png)


## EIPとNat Gateway
1. EIPとNATを作成します
    ```terraform
    # Elastic IP
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip
    resource "aws_eip" "nat_eip" {
      domain = "vpc"
      
      tags = {
        Name = "nat-eip"
      }
    
    }

    # NAT Gateway
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway
    resource "aws_nat_gateway" "nat_gateway" {
      allocation_id = aws_eip.nat_eip.id
      subnet_id     = aws_subnet.public_subnets["public01"].id
    
      tags = {
        Name = "nat-gateway"
      }
      
    }
    ```
1. `terraform apply`します
1. できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/89e3e8bf-f4a4-91f5-8d64-3c9764a7a438.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/f049fc03-b1e8-1a34-3c23-d0fb076ae029.png)

## ルートテーブル
1. ルートテーブルを作成します
    ```terraform
    
    # Public Subnet Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table
    resource "aws_route_table" "public_route_table" {
      for_each = var.subnets.public_subnets
      vpc_id   = aws_vpc.terraform_vpc.id
    
      tags = {
        Name = "public-route-table-${each.key}"
      }
    }
    
    # Public Subnet Route
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route
    resource "aws_route" "public_route" {
      for_each               = var.subnets.public_subnets
      route_table_id         = aws_route_table.public_route_table[each.key].id
      destination_cidr_block = "0.0.0.0/0"
      gateway_id             = aws_internet_gateway.terraform_igw.id
    
    }
    
    # Associate Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association
    resource "aws_route_table_association" "public_route_table_association" {
      for_each = var.subnets.public_subnets
    
      # subnet_id      = aws_subnet.public_subnets["public01"].id
      subnet_id      = aws_subnet.public_subnets[each.key].id
      route_table_id = aws_route_table.public_route_table[each.key].id
    }
    
    # Private Subnet Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table
    resource "aws_route_table" "private_route_table" {
      for_each = var.subnets.private_subnets
      vpc_id   = aws_vpc.terraform_vpc.id
    
      tags = {
        Name = "private-route-table-${each.key}"
      }
    }
    
    # Private Subnet Route
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route
    resource "aws_route" "private_route" {
      for_each               = var.subnets.private_subnets
      route_table_id         = aws_route_table.private_route_table[each.key].id
      nat_gateway_id         = aws_nat_gateway.nat_gateway.id
      destination_cidr_block = "0.0.0.0/0"
    }
    
    # Associate Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association
    resource "aws_route_table_association" "private_route_table_association" {
      for_each = var.subnets.private_subnets
    
      subnet_id      = aws_subnet.private_subnets[each.key].id
      route_table_id = aws_route_table.private_route_table[each.key].id
    
    }
    
    # DB Subnet Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table
    resource "aws_route_table" "db_route_table" {
      for_each = var.subnets.db_subnets
      vpc_id   = aws_vpc.terraform_vpc.id
    
      tags = {
        Name = "db-route-table-${each.key}"
      }
    }
    
    # Associate Route Table
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association
    resource "aws_route_table_association" "db_route_table_association01" {
      for_each = var.subnets.db_subnets
    
      subnet_id      = aws_subnet.db_subnets[each.key].id
      route_table_id = aws_route_table.db_route_table[each.key].id
    }
    ````
1. `terraform apply`します
1. できました

## S3 Bucket
### バケット
1. S3バケットを作成します
    ```terraform
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket
    resource "aws_s3_bucket" "terraform_demo" {
      bucket = "terraform-demo-${data.aws_caller_identity.this.account_id}"
    }
    ```
1. `terraform apply`します
1. できました

### バケットポリシー
1. S3バケットポリシーを作成します
    ```terraform
    resource "aws_s3_bucket_policy" "terraform_demo" {
      bucket = aws_s3_bucket.terraform_demo.id
    
      policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Sid       = "AllowSSLRequestsOnly"
            Effect    = "Deny"
            Principal = "*"
            Action    = "s3:*"
            Resource = [
              aws_s3_bucket.terraform_demo.arn,
              "${aws_s3_bucket.terraform_demo.arn}/*",
            ]
            Condition = {
              Bool = {
                "aws:SecureTransport" = "false"
              }
            }
          }
        ]
      })
    }
    ```
1. `terraform apply`します
1. 作成されました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/05b36c17-bf63-4f63-7aaf-822f77d38b12.png)

## VPCe(S3 Gateway)
1. VPCeを作成します
    ```terraform
    # VPCe for S3
    # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint
    ## VPCエンドポイント
    resource "aws_vpc_endpoint" "s3Endpoint" {
      for_each          = var.subnets.private_subnets
      vpc_id            = aws_vpc.terraform_vpc.id
      service_name      = "com.amazonaws.ap-northeast-1.s3"
      vpc_endpoint_type = "Gateway"
      route_table_ids   = [aws_route_table.private_route_table[each.key].id]
    }
    ```
1. `terraform apply`します
1. 作成されました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c5a32aa3-1430-49a0-1b86-4aa7f093cd1e.png)



## 掃除
1. 最後に`terraform destroy`します
1. 消えました
    ```bash
    Destroy complete! Resources: 38 destroyed.
    ```

## プランファイルを使って削除する
1. SSOログインします
    ```bash
    aws sso login --profile プロファイル名
    ```
1. 環境変数に設定します
    ```bash
    export AWS_PROFILE=プロファイル名     
    ```
1. terraform initを実行します
    ```bash
    terraform init
    ```
1. 削除プランを取得します
    ```bash
    terraform plan -destroy -out=tfplan
    ```
1. プランファイルを使用して削除する
    ```bash
    terraform apply "tfplan"
    ```


# 考察
今回は、Terraformでネットワークを作成してみました。今後は他のリソースも作成していきます。

# 参考
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet

https://dev.classmethod.jp/articles/terraform-network-variable/