🥅

Terraform × VPCで仮想ネットワークを構築した

2024/03/24に公開

目的

  • せっかくなのでクラウドインフラへの知見を深めたい。
    • AWS Cognitoを活用しているので、インフラ構成はAWSを用いる。
    • Terraformでの管理を前提とする。

目指すもの

  • 個人で開発した「認証機能しかないアプリ」を本番環境で運用したい。
  • まずはECRに登録したコンテナイメージをECS上にデプロイするところまでを目標とする。

設計図

  • 留意点:ユーザー認証周りはALBとCognitoで連携できるが、今回はなぜかアプリ側で認証機能を書いているので、微妙な構成になっている。

VPC

  • リソースの配置、接続性、セキュリティなどを制御可能な仮想ネットワーク
    • 仮想ネットワーク内のインスタンスのアクセス制限
    • 独自の IP アドレス範囲の選択
    • サブネットの作成
    • ルートテーブルの設定
    • ゲートウェイ・エンドポイントの設定

VPC Network

  • 大枠のネットワーク aws_vpcを定義する。
    • enable_dns_support:DNS 解決をサポートするかどうか
    • cidr_block
      • 将来的なサービスの拡張性よりIPを枯渇させない、サブネットとIPの計算が楽になるという理由で /16 を選択した。
resource "aws_vpc" "vpc_network" {
  cidr_block           = var.vpc_network # "192.168.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
}

Public Subnet

  • インターネット経由でアクセスできるサブネット。
    • map_public_ip_on_launch:パブリックIPは「必要」
resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.vpc_network.id
  availability_zone       = var.region # "ap-northeast-1a"
  cidr_block              = var.public_subnet # "192.168.1.0/24"
  map_public_ip_on_launch = true
}

Private Subnet

  • インターネット経由でアクセスできないサブネット。
    • map_public_ip_on_launch:パブリックIPは「不要」
resource "aws_subnet" "private_subnet" {
  vpc_id                  = aws_vpc.vpc_network.id
  availability_zone       = var.region # "ap-northeast-1a"
  cidr_block              = var.private_subnet # "192.168.2.0/24"
  map_public_ip_on_launch = false
}

ここまでの構成図

Internet Gateway

  • 外部インターネットとVPC間を双方向に接続する時の窓口となるゲートウェイ。
resource "aws_internet_gateway" "internet_gateway" {
  vpc_id = aws_vpc.vpc_network.id
}
  • ルーティングテーブルを作成する。
    • ルーター内で経路情報を指し示す経路表を示す。
resource "aws_route_table" "public_routes" {
  vpc_id = aws_vpc.vpc_network.id
}
resource "aws_route" "public_igw_route" {
  route_table_id              = aws_route_table.public_routes.id
  gateway_id                  = aws_internet_gateway.internet_gateway.id
}

VPC EndPoint

VPCエンドポイントとは...?

  • VPCと他のサービス(ECR)間の通信を可能にするVPCコンポーネント
    • 接続が発生するたびにコストがかかるNATゲートウェイを使用するより、コスト的に◎
    • コンテナー内のログをCloudWatchに送信する。 → logs
    • AWS Systems Manager パラメータストア経由で環境変数を使用する。 → ssm

Interface型

  • vpc_endpoint_type:ECRに対応している Interface型を採用する。
  • security_group_ids:次章でセキュリティグループに関する設定を説明する。

VPCエンドポイントとAWSサービスとの通信は、Amazonのネットワーク内で完結している。
このネットワークをPrivateLinkと呼ぶが、PrivateLink接続できるものはInterface型を用いる。

resource "aws_vpc_endpoint" "interface_endpoint" {
  vpc_id            = aws_vpc.vpc_network.id
  for_each          = toset(var.vpc_endpoints_interface)
  # ["ecr.dkr", "ecr.api", "logs", "ssm"]
  service_name      = "com.amazonaws.ap-northeast-1.${each.value}"
  vpc_endpoint_type = "Interface"

  subnet_ids         = [aws_subnet.private_subnet.id]
  security_group_ids = [var.vpc_endpoints_security_groups]
  depends_on = [
    aws_vpc.vpc_network, aws_subnet.private_subnet
  ]

  private_dns_enabled = true
}

Gateway型

  • vpc_endpoint_type:設置時間に応じて費用が発生しないGateway型を採用する。
resource "aws_vpc_endpoint" "gateway_endpoint" {
  vpc_id            = aws_vpc.vpc_network.id
  for_each          = toset(var.vpc_endpoints_gateway) # ["s3"]
  service_name      = "com.amazonaws.ap-northeast-1.${each.value}"
  vpc_endpoint_type = "Gateway"
}

ここまでの構成図

Discussion