terraformでVPCを構築する方法


誰もが新しいAWSアカウントを適用した後にVPCを構築する必要がある最も重要なことの一つです.このブログの目的は、terraformを使って構築するのを助けることです.

ネットワーク設計


  • パブリックサブネット:ウェブサイトの展開は、インターネットによって直接アクセスすることができます
  • プライベートサブネット:アプリケーションの展開のみ公共のサブネット内のウェブサイトにアクセスすることができます.また、アプリケーションはNATゲートウェイを介してインターネットにアクセスすることができます
  • ハウツービルド


    VPCを作成する前に、インストールする必要がありますTerraForm ファースト.

    コード構造


    infrastructure
    ├── module
    │   └── networking
    │       ├── main.tf
    │       ├── outputs.tf
    │       └── variables.tf
    ├── region
    │   └── virginia
    │       ├── main.tf
    │       └── providers.tf
    └── setup
        ├── main.tf
        ├── outputs.tf
        ├── providers.tf
        └── variables.tf
    

    セットアップ環境


    ソースコードsetup フォルダは次のようになります.
  • メイン.TF
  • locals {
      region = var.region
    }
    
    # Define a s3 bucket to store terraform state file.
    resource "aws_s3_bucket" "terraform_state" {
      bucket        = format("terraform-state-%s", local.region)
      force_destroy = false
      lifecycle {
        ignore_changes = [bucket]
      }
    }
    
    resource "aws_s3_bucket_versioning" "terraform_state" {
      bucket = aws_s3_bucket.terraform_state.id
      versioning_configuration {
        status = "Enabled"
      }
    }
    
    resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
      bucket = aws_s3_bucket.terraform_state.bucket
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm = "AES256"
        }
      }
    }
    
  • 出力.TF
  • output "s3_bucket_terraform_state" {
      value = aws_s3_bucket.terraform_state.bucket
    }
    
  • プロバイダ.TF
  • terraform {
      required_version = ">= 0.13.7"
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = ">= 4.8.0"
        }
      }
    }
    
  • 変数.TF
  • variable "region" {
      description = "The name of the aws Region"
      type        = string
    }
    
    そして、リモートバックエンド用のS 3バケットを作成する必要がありますs3_bucket_terraform_state .
    $ terraform init
    
    $ terraform apply
    

    ネットワーキング


    ソースコードnetworking フォルダは次のようになります.
  • メイン.TF
  • locals {
      name                       = var.name
      cidr_block                 = var.vpc_cidr_block
      public_subnets_cidr_block  = var.public_subnets_cidr_block
      private_subnets_cidr_block = var.private_subnets_cidr_block
      availability_zones         = var.availability_zones
      tags                       = var.vpc_tags
    }
    
    # VPC
    resource "aws_vpc" "vpc" {
      cidr_block           = local.cidr_block
      enable_dns_hostnames = true
      enable_dns_support   = true
    
      tags = merge( {
        Name = local.name
      }, local.tags)
    }
    
    # Subnets
    # Internet Gateway for Public Subnet
    resource "aws_internet_gateway" "internet_gateway" {
      vpc_id = aws_vpc.vpc.id
      tags   = merge({
        Name = "${local.name} Internet Gateway"
      }, local.tags)
    }
    
    # EIP for NAT
    resource "aws_eip" "nat_eip" {
      vpc        = true
      depends_on = [aws_internet_gateway.internet_gateway]
    }
    
    # NAT
    resource "aws_nat_gateway" "nat_gateway" {
      allocation_id = aws_eip.nat_eip.id
      subnet_id     = element(aws_subnet.public_subnet.*.id, 0)
    
      tags = merge({
        Name = "${local.name} Nat Gateway"
      }, local.tags)
    }
    
    # Public subnet
    resource "aws_subnet" "public_subnet" {
      vpc_id                  = aws_vpc.vpc.id
      count                   = length(local.public_subnets_cidr_block)
      cidr_block              = element(local.public_subnets_cidr_block, count.index)
      availability_zone       = element(local.availability_zones, count.index)
      map_public_ip_on_launch = true
      tags                    = merge( {
        Name = "${local.name} Public Subnet ${element(var.availability_zones, count.index)}"
      }, local.tags)
    }
    
    # Private Subnet
    resource "aws_subnet" "private_subnet" {
      vpc_id                  = aws_vpc.vpc.id
      count                   = length(local.private_subnets_cidr_block)
      cidr_block              = element(local.private_subnets_cidr_block, count.index)
      availability_zone       = element(local.availability_zones, count.index)
      map_public_ip_on_launch = false
      tags                    = merge({
        Name = "${local.name} Private Subnet ${element(var.availability_zones, count.index)}"
      }, local.tags)
    }
    
    
    # Routing tables to route traffic for Private Subnet
    resource "aws_route_table" "private" {
      vpc_id = aws_vpc.vpc.id
    
      tags = merge({
        Name = "${local.name} Private Route Table"
      }, local.tags)
    }
    
    # Routing tables to route traffic for Public Subnet
    resource "aws_route_table" "public" {
      vpc_id = aws_vpc.vpc.id
    
      tags = merge({
        Name = "${local.name} Public Route Table"
      }, local.tags)
    }
    
    # Route for Internet Gateway
    resource "aws_route" "public_internet_gateway" {
      route_table_id         = aws_route_table.public.id
      destination_cidr_block = "0.0.0.0/0"
      gateway_id             = aws_internet_gateway.internet_gateway.id
    }
    
    # Route for NAT
    resource "aws_route" "private_nat_gateway" {
      route_table_id         = aws_route_table.private.id
      destination_cidr_block = "0.0.0.0/0"
      nat_gateway_id         = aws_nat_gateway.nat_gateway.id
    }
    
    # Route table associations for Public Subnets
    resource "aws_route_table_association" "public" {
      count          = length(local.public_subnets_cidr_block)
      subnet_id      = element(aws_subnet.public_subnet.*.id, count.index)
      route_table_id = aws_route_table.public.id
    }
    
    # Route table associations for Private Subnets
    resource "aws_route_table_association" "private" {
      count          = length(local.private_subnets_cidr_block)
      subnet_id      = element(aws_subnet.private_subnet.*.id, count.index)
      route_table_id = aws_route_table.private.id
    }
    
    # Default Security Group of VPC
    resource "aws_security_group" "security_group" {
      name        = "${local.name} Security Group"
      description = "Default SG to allow traffic from the VPC"
      vpc_id      = aws_vpc.vpc.id
      depends_on  = [
        aws_vpc.vpc
      ]
    
      ingress {
        from_port = "0"
        to_port   = "0"
        protocol  = "-1"
        self      = true
      }
    
      egress {
        from_port = "0"
        to_port   = "0"
        protocol  = "-1"
        self      = "true"
      }
    
      tags = merge({}, local.tags)
    }
    
  • 出力.TF
  • output "vpc_id" {
      value = aws_vpc.vpc.id
    }
    
    output "public_subnets_id" {
      value = [aws_subnet.public_subnet.*.id]
    }
    
    output "private_subnets_id" {
      value = [aws_subnet.private_subnet.*.id]
    }
    
    output "security_groups_ids" {
      value = [aws_security_group.security_group.id]
    }
    
    output "public_route_table" {
      value = aws_route_table.public.id
    }
    
  • 変数.TF
  • variable "name" {
      description = "The VPC name"
    }
    
    variable "vpc_cidr_block" {
      description = "CIDR block of the vpc"
    }
    
    variable "public_subnets_cidr_block" {
      type        = list
      description = "CIDR block for Public Subnet"
    }
    
    variable "private_subnets_cidr_block" {
      type        = list
      description = "CIDR block for Private Subnet"
    }
    
    variable "availability_zones" {
      type        = list
      description = "AZ in which all the resources will be deployed"
    }
    
    variable "vpc_tags" {
      description = "A map of tags to add to VPC"
      type        = map(string)
      default     = {}
    }
    

    ビルドVPC


    ソースコードvirginia フォルダは次のようになります.
  • メイン.TF
  • locals {
      // the region code of virginia
      region             = "us-east-1"
      availability_zones = ["${local.region}a", "${local.region}b", "${local.region}c"]
      tags               = {
        "Environment" : "PROD"
        "Project" : "Infrastructure"
      }
    }
    
    provider "aws" {
      region = local.region
    }
    
    module "Networking" {
      source                     = "../../module/networking"
      name                       = "VPC"
      availability_zones         = local.availability_zones
      vpc_cidr_block             = "10.0.0.0/16"
      public_subnets_cidr_block  = ["10.0.32.0/24", "10.0.96.0/24", "10.0.224.0/24"]
      private_subnets_cidr_block = ["10.0.0.0/19", "10.0.64.0/19", "10.0.128.0/19"]
      vpc_tags                   = local.tags
    }
    
  • プロバイダ.TF
  • terraform {
      required_version = ">= 0.13.7"
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = ">= 4.8.0"
        }
      }
    
      backend "s3" {
        // the s3 bucket name
        bucket  = "*********"
        key     = "terraform/backend.tfstate"
        region  = "us-east-1"
        encrypt = "true"
      }
    }
    
    今、我々はVPCを構築することができます
    $ terraform init
    
    $ terraform apply
    

    結果