GitHubActions + TerraformでNWを作成してみた

# 背景・目的

以前、下記の記事でTerraform＋GitHubActionsを使用してS3を構築してみました。
今回は、AWSのNWを同様に作成します。
- [GitHub Actionsで実行しているTerraformをモジュール化してみた](https://qiita.com/zumax/items/e8cc506c345f32f2b4bf)
- [GitHubActionsとTerraformでS3バケットを作成してみた](https://qiita.com/zumax/items/f78dd92219ecfb9503be)

# 実践
今回、構築したい環境は下記のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e376b6e7-255d-b999-3133-2e90e602985a.png)

ディレクトリ構造は、下記のとおりです。terraform-modules配下に、vpcモジュールを用意しています。
```bash
terraform-modules/
└── s3/
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
└── vpc/
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
├── main.tf
├── variables.tf
├── terraform.tfvars
├── backend.tf
```

## IAMポリシー
1. AWSにサインインし、IAMに移動します
1. 対象のIAMロールをクリックします
1. VPCが作成できるように、IAMポリシーを追加します
    ```json
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:DeleteSubnet",
                "ec2:DeleteTags",
                "ec2:CreateVpc",
                "ec2:AttachInternetGateway",
                "ec2:DescribeVpcAttribute",
                "ec2:ReplaceRoute",
                "ec2:DeleteRouteTable",
                "ec2:ModifySubnetAttribute",
                "ec2:AssociateRouteTable",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeAvailabilityZones",
                "ec2:CreateRoute",
                "ec2:CreateInternetGateway",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:CreateSecurityGroup",
                "ec2:DescribeAccountAttributes",
                "ec2:ModifyVpcAttribute",
                "ec2:DeleteInternetGateway",
                "ec2:DescribeRouteTables",
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:CreateTags",
                "ec2:DescribeVpcPeeringConnections",
                "ec2:DeleteRoute",
                "ec2:CreateRouteTable",
                "ec2:DetachInternetGateway",
                "ec2:DisassociateRouteTable",
                "ec2:DescribeSecurityGroups",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:DescribeVpcs",
                "ec2:DeleteSecurityGroup",
                "ec2:DeleteVpc",
                "ec2:CreateSubnet",
                "ec2:DescribeSubnets"
            ],
            "Resource": "*"
        }
    ```

## VPCモジュール
1. `terraform-modules`配下に、`vpc`フォルダを作成します

### main.tf
1. `main.tf`を作成します
    ```terraform
    resource "aws_vpc" "this" {
      cidr_block = var.vpc_cidr
      tags       = var.tags
    }
    
    resource "aws_internet_gateway" "this" {
      vpc_id = aws_vpc.this.id
      tags   = var.tags
    }
    
    resource "aws_subnet" "public" {
      count                   = length(var.azs)
      vpc_id                  = aws_vpc.this.id
      cidr_block              = cidrsubnet(var.vpc_cidr, 3, count.index)
      availability_zone       = var.azs[count.index]
      map_public_ip_on_launch = true
      tags                    = merge(var.tags, { "Name" = format("%s-public-subnet-%d", var.project_name, count.index + 1) })
    }
    
    resource "aws_subnet" "private" {
      count             = length(var.azs)
      vpc_id            = aws_vpc.this.id
      cidr_block        = cidrsubnet(var.vpc_cidr, 3, count.index + length(var.azs))
      availability_zone = var.azs[count.index]
      tags              = merge(var.tags, { "Name" = format("%s-private-subnet-%d", var.project_name, count.index + 1) })
    }
    
    resource "aws_subnet" "db" {
      count             = length(var.azs)
      vpc_id            = aws_vpc.this.id
      cidr_block        = cidrsubnet(var.vpc_cidr, 3, count.index + 2 * length(var.azs))
      availability_zone = var.azs[count.index]
      tags              = merge(var.tags, { "Name" = format("%s-db-subnet-%d", var.project_name, count.index + 1) })
    }
    
    resource "aws_route_table" "public" {
      vpc_id = aws_vpc.this.id
      tags   = merge(var.tags, { "Name" = format("%s-public-rt", var.project_name) })
    }
    
    resource "aws_route" "igw" {
      route_table_id         = aws_route_table.public.id
      destination_cidr_block = "0.0.0.0/0"
      gateway_id             = aws_internet_gateway.this.id
    }
    
    resource "aws_route_table_association" "public" {
      count          = length(var.azs)
      subnet_id      = aws_subnet.public[count.index].id
      route_table_id = aws_route_table.public.id
    }
    
    ```
### variables.tf
1. `variables.tf`を作成します
    ```terraform
    variable "vpc_cidr" {
      description = "The CIDR block for the VPC"
      type        = string
    }
    
    variable "azs" {
      description = "List of availability zones"
      type        = list(string)
    }
    
    variable "tags" {
      description = "A map of tags to assign to the resources"
      type        = map(string)
      default     = {}
    }
    
    variable "project_name" {
      description = "The name of the project"
      type        = string
    }
    ```

### outputs.tf
1. `outputs.tf` を作成します
    ```terraform
    output "vpc_id" {
      description = "The ID of the VPC"
      value       = aws_vpc.this.id
    }
    
    output "public_subnets" {
      description = "The IDs of the public subnets"
      value       = aws_subnet.public[*].id
    }
    
    output "private_subnets" {
      description = "The IDs of the private subnets"
      value       = aws_subnet.private[*].id
    }
    
    output "db_subnets" {
      description = "The IDs of the DB subnets"
      value       = aws_subnet.db[*].id
    }
    ```
## ルートモジュールの作成
1. ルートモジュールの配下のファイルを修正します

### main.tfの修正
1. `main.tf`を作成します
    - vpc モジュールを呼び出す箇所を追加
    - outputを追加
    ```terraform
    data "aws_caller_identity" "this" {}
    
    module "s3" {
      source      = "./terraform-modules/s3"
      bucket_name = format("%s-%s", var.bucket_name, "${data.aws_caller_identity.this.account_id}")
      tags        = var.s3_tags
    }
    
    module "vpc" {
      source       = "./terraform-modules/vpc"
      vpc_cidr     = var.vpc_cidr
      azs          = var.azs
      tags         = var.vpc_tags
      project_name = var.project_name
    }
    
    output "bucket_id" {
      value = module.s3.bucket_id
    }
    
    output "bucket_arn" {
      value = module.s3.bucket_arn
    }
    
    output "bucket_region" {
      value = module.s3.bucket_region
    }
    
    output "vpc_id" {
      value = module.vpc.vpc_id
    }
    
    output "public_subnets" {
      value = module.vpc.public_subnets
    }
    
    output "private_subnets" {
      value = module.vpc.private_subnets
    }
    
    output "db_subnets" {
      value = module.vpc.db_subnets
    }

    ```
### variables.tfの修正
1. `variables.tf` を修正します
    ```terraform
    variable "bucket_name" {
      description = "The name of the S3 bucket"
      type        = string
    }
    
    variable "s3_tags" {
      description = "A map of tags to assign to the resource"
      type        = map(string)
      default     = {}
    }
    
    variable "vpc_cidr" {
      description = "The CIDR block for the VPC"
      type        = string
    }
    
    variable "azs" {
      description = "List of availability zones"
      type        = list(string)
    }
    
    variable "vpc_tags" {
      description = "A map of tags to assign to the resources"
      type        = map(string)
      default     = {}
    }
    
    variable "project_name" {
      description = "The name of the project"
      type        = string
    }
    ```
### terraform.tfvarsの修正
1. `terraform.tfvars` を修正します
    - VPC関連の変数を定義します
    ```terraform
    bucket_name = "terraform-demo"
    s3_tags = {
      "Environment" = "prod"
      "Project"     = "TerraformExample"
    }
    
    vpc_cidr = "10.0.0.0/16"
    azs      = ["ap-northeast-1a", "ap-northeast-1c"]
    vpc_tags = {
      "Environment" = "prod"
      "Project"     = "TerraformExample"
    }
    project_name = "my-vpc-project"
    ```

## 確認
1. Commit & Pushします。成功しました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8f5334ad-a299-6843-484d-129e4a6b3bb4.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/54509b22-2a3f-5c0b-f6c4-253f54886945.png)
1. VPCもできていました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/0bbae0c4-43b6-31b6-b346-2219e28dbcce.png)



# 考察
今回、VPC等をTerraformで作成しました。
次回は、コンテナアプリケーションを動かすためのインフラを構築したいと思います。


# 参考
https://qiita.com/zumax/items/e8cc506c345f32f2b4bf

https://qiita.com/zumax/items/f78dd92219ecfb9503be