📘

Amazon VPC×Terraform

2022/10/28に公開約9,000字

Amazon VPCとは

VPC(Virtual Private Cloud)とはAWS内に作成されるプライベートネットワーク空間のことです。

仮想ネットワークを作ることで、パブリックネットワークには任意ユーザがアクセスできるようにし、プライベートネットワークには自社の秘密情報(DB、認証情報等)を保持し社内の人間だけが見れるようにするなどのセキュリティを考慮したアーキテクチャ設計が可能になります。

Amazon VPCの構成要素・依存関係

Amazon VPCを構築するためには、下記のような構成要素・依存関係を理解する必要があります。

  • サブネット
    VPCを細分化したCIDRブロックのことです。つまり、サブネットはVPCに依存していることになります。
  • ルートテーブル
    異なるネットワーク間をつなぐ経路を示すものです。サブネットをパブリック・プライベート用にそれぞれ組み分けした際、ルートテーブルアソシエーションにより各サブネットと各ルートテーブルを関連付けます。
  • インターネットゲートウェイ
    VPCとインターネットとの外部通信を可能にするリソースのことです。

Amazon VPCを構築

Terraformでリソースを作成していきます。
https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest

完成イメージ

構築手順

  1. VPCを作成
  2. サブネットを作成
  3. ルートテーブルを作成
  4. インターネットゲートウェイを作成

1. VPCを作成

cidr_block = "192.168.0.0/20"の仮想ネットワークを構築します。

resource "aws_vpc" "vpc" {
  cidr_block                       = "192.168.0.0/20"
  instance_tenancy                 = "default"
  enable_dns_support               = true
  enable_dns_hostnames             = true
  assign_generated_ipv6_cidr_block = false

  tags = {
    Name    = "${var.project}-${var.environment}-vpc"
    Project = var.project
    Env     = var.environment
  }
}

tagsにはプロジェクト名、環境名を含めます。

terraform.tfvars
project     = "zenn"
environment = "stg"

terraform plan実行時に下記ログが出力されます。

 # aws_vpc.vpc will be created
  + resource "aws_vpc" "vpc" {
      + arn                                  = (known after apply)   
      + assign_generated_ipv6_cidr_block     = false
      + cidr_block                           = "192.168.0.0/20"      
      + default_network_acl_id               = (known after apply)   
      + default_route_table_id               = (known after apply)
      ...
      + tags                                 = {
      + "Env"     = "stg"
      + "Name"    = "zenn-stg-vpc"
      + "Project" = "zenn"
    }

VPCのCIDRblockの設定等のリソースが反映可能なことが分かれば、
terraform apply -auto-approveでリモートに反映させます。

AWSコンソール画面でリソースの反映を確認します。

2. サブネットを作成

作成したVPC内に2つのAZ(Availavility Zone)を設定し、各AZ内にパブリック・プライベートサブネットを作成します

  • 完成イメージ

基本的なリソースの書き方はEC2,VPCの構築方法と変わりません。

resource "aws_subnet" "public_subnet_1a" {
  vpc_id                  = aws_vpc.vpc.id //作成したVPCをtfファイル内で参照
  availability_zone       = "ap-northeast-1a" //1つ目のAZ
  cidr_block              = "192.168.1.0/24" //VPCから細分化したCIDRblock
  map_public_ip_on_launch = true //IPアドレスを自動で割り当てる(プライベート:false)

  tags = {
    Name    = "${var.project}-${var.environment}-public-subnet-1a"
    Project = var.project
    Env     = var.environment
    Type    = "public"
  }
}

terraform plan実行時に下記ログが出力されます。

aws_vpc.vpc: Refreshing state... [id=vpc-0fe7175fb0f062e2e]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_subnet.private_subnet_1a will be created
  + resource "aws_subnet" "private_subnet_1a" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-1a" 
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "192.168.3.0/24"  

VPCの参照、CIDRblockの設定等のリソースが反映可能なことが分かれば、terraform apply -auto-approveでリモートに反映させます。

AWSコンソール画面でリソースの反映を確認します。

3. ルートテーブルを作成

  • 完成イメージ

まずは、パブリック、プライベート用にルートテーブルのリソースを定義します。

resource "aws_route_table" "public_rt" { //ルートテーブルリソース
  vpc_id = aws_vpc.vpc.id //作成した親のVPC

  tags = {
    Name    = "${var.project}-${var.environment}-public-rt" //public subnet用のルートテーブル名
    Project = var.project
    Env     = var.environment
    Type    = "public" //サブネットは公開?非公開?
  }
}

resource "aws_route_table" "private_rt" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-private-rt" //pprivate subnet用のルートテーブル名
    Project = var.project
    Env     = var.environment
    Type    = "private"
  }
}

次に、各ルートテーブルで関連付けたいサブネットを指定します。
例)AZ(1a)のパブリックサブネットをパブリック用のルートテーブルに関連付ける

resource "aws_route_table_association" "public_rt_1a" {
  route_table_id = aws_route_table.public_rt.id
  subnet_id      = aws_subnet.public_subnet_1a.id //ルートテーブルとサブネットの関連付け
}

他3つも同様の手順です。リソースに問題なさそうですね。

aws_vpc.vpc: Refreshing state... [id=vpc-0fe7175fb0f062e2e]
aws_subnet.public_subnet_1c: Refreshing state... [id=subnet-03b17d87111e01ace]
aws_subnet.private_subnet_1a: Refreshing state... [id=subnet-0e38200d797bd3cdd]
aws_subnet.public_subnet_1a: Refreshing state... [id=subnet-03cccadaead637f2e]
aws_subnet.private_subnet_1c: Refreshing state... [id=subnet-0ce1f56157198fbb4]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

リモートに反映します。

OKです!

4. インターネットゲートウェイを作成

インターネットゲートウェイを作成します。

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name    = "${var.project}-${var.environment}-igw"
    Project = var.project
    Env     = var.environment
  }
}

パブリックサブネットに紐づいたルートテーブルと関連付けます(VPCへのアタッチ)。

resource "aws_route" "public_rt_igw_r" {
  route_table_id         = aws_route_table.public_rt.id //インターネット疎通はpublicのみ可能
  destination_cidr_block = "0.0.0.0/0" //送信先(外側への通信を全て許可)
  gateway_id             = aws_internet_gateway.igw.id
}

インターネットゲートウェイをVPCへアタッチできましたね。


VPCを作成しましたのでセキュリティグループ(ネットワーク内の通信設定)を追加でやってみます!

SGとは

SG(Security Group)とは、ファイアウォールの役割を担う通信のフィルタリング機能のことです。

インバウンド(入力通信)とアウトバウンド(出力通信)に対して許可するプロトコルとポート番号を設定することで、特定の通信方式とポート番号でのみで通信が可能になり、不特定多数のユーザアクセスを割けることができます。

SGの構成要素・依存関係

一般に、セキュリティグループは目的毎に設定する必要があります。
例えば、Web3層アーキテクチャにおいては、各層毎にセキュリティグループを作成する必要があります。

  • Webアプリケーションサーバ
    ユーザとの相互通信とアプリ側へのリクエスト
  • アプリケーションサーバ
    APIリクエスト・返却・サービス処理等
    運用メンテナンス
  • DBサーバ
    APIリクエストに応じたデータ返却

詳しくはこちら
https://www.softbank.jp/biz/blog/cloud-technology/articles/202206/web-3-tier-architecture/

SGを構築

Terraformでリソースを作成していきます。

完成イメージ

矢印の方向に通信が可能になるようセキュリティグループを作成していきます。

構築手順

  1. Webアプリケーションサーバグループ作成
  2. アプリケーションサーバグループ作成
  3. 運用保守サーバグループ作成
  4. DBサーバグループ作成

1. Webアプリケーションサーバグループ作成

まずはセキュリティグループを定義します。

resource "aws_security_group" "web_sg" {
  name        = "${var.project}-${var.environment}-web-front-app-sg"
  description = "web front app server security group" //クライアント相互部分
  vpc_id      = aws_vpc.vpc.id //親VPCのID

  tags = {
    Name    = "${var.project}-${var.environment}-web-front-app-sg"
    Project = var.project
    Env     = var.environment
  }
}

次に、ファイアウォールの設定を行います。

I/O プロトコル ポート番号
インバウンド TCP 80/443
アウトバウンド TCP 3000
  • インバウンド
resource "aws_security_group_rule" "web_in_http" {
  security_group_id = aws_security_group.web_sg.id //定義したセキュリティグループを指定
  type              = "ingress" //インバウンド
  protocol          = "tcp"
  from_port         = 80 //HTTPのサーバは、 80番ポートでパケットを待っていることが多いため
  to_port           = 80
  cidr_blocks       = ["0.0.0.0/0"] //任意ユーザがアクセス可能
}

resource "aws_security_group_rule" "web_in_https" {
  security_group_id = aws_security_group.web_sg.id 
  type              = "ingress"
  protocol          = "tcp"
  from_port         = 443 //WebサーバがHTTPSでWebブラウザなどと通信するために用いるため
  to_port           = 443
  cidr_blocks       = ["0.0.0.0/0"] //任意ユーザがアクセス可能
}
  • アウトバウンド
resource "aws_security_group_rule" "web_out_tcp3000" {
  security_group_id        = aws_security_group.web_sg.id 
  type                     = "egress" //アウトバウンド
  protocol                 = "tcp"
  from_port                = 3000
  to_port                  = 3000
  source_security_group_id = aws_security_group.app_sg.id //次に設定するAPIサーバ用SGのID
}

2. アプリケーションサーバグループ

I/O プロトコル ポート番号
インバウンド TCP 3000
アウトバウンド TCP 3306
TCP 80/443

3. 運用保守サーバグループ作成

I/O プロトコル ポート番号
インバウンド TCP 3000
TCP 22
アウトバウンド TCP 80/443

4. DBサーバグループ作成

I/O プロトコル ポート番号
インバウンド TCP 3306

AWSコンソール画面でリソースの反映を確認します。

まとめ

今回はAmazon VPCの基礎および構築手順を学びました。
次回はAmazon RDSを構築します。

最後までお読みいただきありがとうございました。

GitHubで編集を提案

Discussion

ログインするとコメントできます