2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NAT Gatewayを複数のVPCで共有して課金を減らす!!!~with Transit Gateway~

Posted at

はじめに

NAT Gatewayは高い利用料金がかかる恐ろしいリソースです。
そのため、ワークロードを作成をするたびに何個もNATを作成したくはないです。
かといって1つのVPCに複数のワークロードを詰め込むのもちょっと・・・って感じですよね。

この課題を対処すべく、
①NATゲートウェイを持つネットワーク共有用VPCを作成し、
②複数のVPCとこの共有VPCを統合するアーキテクチャを作成してみます!!!

今回は、NATゲートウェイやインターネットゲートウェイを持たないVPCのEC2が、
ネットワーク共有VPCのリソースを利用し、SSMアクセス(インターネットアクセス)が可能となること、をゴールに作業していきます。

今回のアーキテクチャ

①NATゲートウェイを持つネットワーク共有用VPCを作成し、
②複数のVPCとこの共有VPCを統合するアーキテクチャはこんな感じです。

アーキテクチャ図

arch1.png

少しずつ説明します。

①NATゲートウェイを持つネットワーク共有用VPC

arch1_1.png

図のままのVPCで、publicサブネットとprivateサブネットを持ちます。
privateサブネットのトラフィックはpublicサブネットにルートされ、NATゲートウェイにパブリックIPを貸してもらって、インターネットゲートウェイからインターネットの世界に通信します。

ネットワーク共有用のVPCなので、VPC系リソース以外は作成しません。

ネットワークを貸してもらうVPC

arch1_2.png

図のままのVPCです。privateサブネットしか持っておらず、NATゲートウェイやインターネットゲートウェイを持っていません。
SSMエージェントのインストールされたEC2を作成しますが、インターネット接続が不可能なので、SSMログインができません。

②複数のVPCとこの共有VPCを統合するAWS Transit Gateway

arch1_3.png

今回の主役であるAWS Transit Gatewayです。

AWS Transit GatewayはVPCとVPCを通信可能にしてくれるサービスです。
(オンプレともごにょごにょできるが、今回は触れません)

異なるVPC間のリソース同士が通信可能にできるため、今回のようにVPCごとに責任範囲を分割しつつ、リソースを共有することができます。

細かいところは公式ドキュメントにおまかせします。

最後に再整理

arch1.png

再度アーキテクチャを確認します。
上部に存在するEC2が、Transitゲートウェイ経由でネットワーク共有VPCにアクセスし、
NATゲートウェイを通じてインターネットと通信し、SSMアクセスが可能になります。
Transitゲートウェイがハブになってくれるので、同じように複数のVPCが共有用VPCのNATゲートウェイを使用できる感じです。

やってみた

検証環境の準備

VPCとEC2の用意

まずはVPCとEC2を作成します。
Transitゲートウェイに重きを置きたいので、ここはさくっとterraformで作成します。

VPC+EC2作成Terraform
main.tf
############################################################################
## terraformブロック
############################################################################
terraform {
  # Terraformのバージョン指定
  required_version = "~> 1.7.0"

  # Terraformのaws用ライブラリのバージョン指定
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.33.0"
    }
  }
}

############################################################################
## providerブロック
############################################################################
provider "aws" {
  # リージョンを指定
  region = "ap-northeast-1"
}

locals {
  name = "test-transit-vpc"
}

############################################################################
## ネットワーク共有VPC
############################################################################
module "network_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.9.0" # TODO: providerと一緒に更新する

  name = "${local.name}-network"
  cidr = "10.0.1.0/24"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets = ["10.0.1.0/26", "10.0.1.64/26"]
  private_subnets = ["10.0.1.128/26", "10.0.1.192/26"]

  enable_nat_gateway = true
  single_nat_gateway = true

  tags = {
    Terraform   = "true"
    Environment = "dev"
    Group       = "${local.name}-network"
  }
}

############################################################################
## 共有ネットワーク使用VPC
############################################################################
module "private_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.9.0" # TODO: providerと一緒に更新する

  name = "${local.name}-private"
  cidr = "10.0.2.0/24"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = ["10.0.2.0/25", "10.0.2.128/25"]

  enable_nat_gateway = false

  tags = {
    Terraform   = "true"
    Environment = "dev"
    Group       = "${local.name}-private"
  }
}

########################################
## SSM Instance Profile
########################################
data "aws_iam_policy" "ssm" {
  arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

data "aws_iam_policy_document" "assume_role_ssm" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }

    actions = ["sts:AssumeRole"]
  }
}

resource "aws_iam_role" "ssm" {
  name               = "ec2-for-ssm"
  assume_role_policy = data.aws_iam_policy_document.assume_role_ssm.json
}

resource "aws_iam_role_policy_attachment" "ssm" {
  policy_arn = data.aws_iam_policy.ssm.arn
  role       = aws_iam_role.ssm.name
}

resource "aws_iam_instance_profile" "ec2_for_ssm" {
  name = "ec2-for-ssm-${local.name}"
  role = aws_iam_role.ssm.name
}

########################################
## EC2 Security Group
########################################
# 0.0.0.0/0を許可するセキュリティグループを作成
resource "aws_security_group" "allow_all_outbound" {
  name        = "allow_all_outbound_sg"
  description = "Allow all outbound traffic"
  vpc_id      = module.private_vpc.vpc_id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_all_outbound_sg"
  }
}

########################################
## SSM EC2 Instance
########################################
resource "aws_instance" "example" {
  ami           = "ami-0f75d1a8c9141bd00" # なんでもいいので一番上にでてきたやつ
  instance_type = "t2.micro"

  subnet_id = module.private_vpc.private_subnets[0]
  iam_instance_profile = aws_iam_instance_profile.ec2_for_ssm.name

  vpc_security_group_ids = [aws_security_group.allow_all_outbound.id]

  tags = {
    Name  = "private-instance"
    Group = "${local.name}-private"
  }
}

terraform init terraform apply してリソースを作成します。

作成されたリソースの確認
以下のCIDRで2つのVPCが作成されました。

ネットワーク共有VPC

cap01.PNG

分かりづらいですが、「test-transit-vpc-network」がインターネットゲートウェイで、
「test-transit-vpc-network-ap-northeast-1a」がNATゲートウェイです。

良い感じに作成できてます。

ネットワーク使用VPC

cap02.PNG

インターネットゲートウェイへのルートを持たない2つのプライベートサブネットが作成されていることが作成できています。

EC2の確認

cap03.PNG

ネットワーク使用VPCのプライベートサブネット上に作成されています。

cap04.PNG

SSMアクセスを試しますが、SSMエンドポイントに到達できないと表示されます。
VPCにはNATゲートウェイもインターネットゲートウェイも存在しないため、予想通りです。
良い感じですね!

では、Transitゲートウェイを作成していきます!

Transitゲートウェイを作成する

リソース一覧画面へ移動する

cap05.PNG

VPC > Transit Gateway と移動します。

作成画面へ移動する

cap05_1.PNG

Transit Gateway を作成 をクリックします。

名前を設定する

cap06.PNG

適当に「network-share-tgw」とします。

Transit Gatewayの挙動を設定する

cap07.PNG

「デフォルトルートテーブルの関連付け」と「デフォルトルートテーブル伝播」はこの後の手作業を一部自動で行ってくれる設定です。チェックしておきます。

その他、マルチキャストなどTransit Gatewayにはいろいろな機能が存在します。
今回のテストでは必要な機能のみチェックしておきます。

Transit Gatewayを作成する

cap08.PNG

その他項目はデフォルトのまま、「Transit Gatewayを作成」をクリックします。

ちょっと待つ

cap09.PNG

一分ほどpendingします。

作成されたことを確認する

cap10.PNG

きました!!

Transitゲートウェイアタッチメントを作成する

Transitゲートウェイを作成しただけでは、まだVPC同士は統合されていません。
Transitゲートウェイアタッチメントというリソースを作成する必要があります。

Transitゲートウェイアタッチメントをネットワーク共有VPCとネットワーク使用VPCにに設定し、Transitゲートウェイと接続させます。

リソース一覧画面へ移動する

cap11.PNG

VPC > Transit Gateway アタッチメント と移動します。

作成画面へ移動する

cap11_1.PNG

Transit Gateway アタッチメントを作成 をクリックします。

名前、接続先Transit Gatewayを設定する

cap13.PNG

名前を適当につけます。
ネットワーク共有用のprivateサブネットを接続するアタッチメントのため、「network-vpc-attachment」とします。

Transit Gatewayは先ほど作成したものを指定します。

アタッチメントの設定を行う

cap14.PNG

今回は不要なので、チェックを外しておきます。

VPCを設定する

cap15.PNG

VPCを選択します。ネットワーク共有VPCを選択します。
(もうひとつ作るので、その時はネットワーク使用VPCを選択)

サブネットを設定する

cap16.PNG

アタッチメントを作成するサブネットを選択します。
アタッチメントもプライベートIPを1つ使うリソースなのでCIDRを細かく設計している場合は注意です。

cap17.PNG

アベイラビリティーゾーンごとに選択できるサブネットは 1 つだけですが、そのアベイラビリティーゾーンのすべてのサブネットが Transit Gateway にトラフィックを送信できます。

とあるので、今回は適当にプライベートサブネットにアタッチメントを作成します。

アタッチメントを作成する

cap18.PNG

「Transit Gateway アタッチメントを作成」をクリックし、アタッチメントを作成します。

ネットワーク使用VPC用のアタッチメントを作成する

同様に、ネットワーク使用VPC用のアタッチメントを作成します。

設定は同じなのでスキップします。

cap19_1.PNG

最終的にはこんな感じになりました。

Transit Gateway ルートテーブルを準備する

もう少しだけ作業します。

Transit Gateway自体もルートテーブルを持っています。
このルートテーブルの設定も確認します。

Transit Gateway ルートテーブルを表示する

cap19.PNG

Transit Gateway画面から、「関連付けルートテーブルID」をクリックし、ルートテーブル画面に移動します。

ルートテーブルの設定を確認する

cap20.PNG

「関連付け」タブに2つのアタッチメントがあることが確認できます。
Transit Gatewayを作成したときにチェックした「デフォルトルートテーブルの関連付け」のおかげで、
先ほど作成したアタッチメントが自動で関連付けられています。

cap21.PNG

「ルート」タブに2つのルートがあることが確認できます。
Transit Gatewayを作成したときにチェックした「デフォルトルートテーブル伝播」のおかげで、
先ほど作成したアタッチメントが存在するVPCへのルートが自動で関連付けられています。

動作イメージの確認

ここまでの設定を見て、Transit Gatewayの動きをイメージしてみます。
現在のVPC、TransitゲートウェイのRouteを図にするとこんな感じです。

arch2_7.png

それぞれ確認します。

ネットワークを使用するVPCのプライベートサブネットのルート

arch2_1.png

ネットワークを使用するVPCのプライベートサブネットのルートです。
ネットワーク共有VPCへは、Transitゲートウェイ経由でアクセスしますが、
Transitゲートウェイへのルートが存在しないため、追加する必要があります。

arch2_4.png

インターネットへのアウトバウンドは全てネットワーク共有VPCに回したいので、
「0.0.0.0/0 → ネットワーク使用VPC内のTransitゲートウェイアタッチメント」のルートが必要です。

Transitゲートウェイのルート

arch2_2.png

Transitゲートウェイのルートです。
アウトバウンドは全てネットワーク共有VPCに回したいので、ルートを追加する必要があります。

arch2_5.png

「0.0.0.0/0 → ネットワーク共有VPC内のTransitゲートウェイアタッチメント」のルートが必要です。

ネットワークを共有するVPCのパブリックサブネットのルート

arch2_3.png

ネットワークを使用するVPCのパブリックサブネットのルートです。
ここまでの設定で、インターネットへ出れるようにはなったのですが、戻りのトラフィックのためのルートを用意する必要があります。

行きのトラフィックでは、EC2インスタンスのトラフィックはTransitゲートウェイを経由し、ネットワーク共有VPCでルートを探します。

その場合、「0.0.0.0/0」はNATゲートウェイにルートされるため、トラフィックはNATによってパブリックIPを与えられた後、インターネットに出ていきます。

戻りのトラフィックでは、パブリックサブネット内の「10.0.1.0/24 → local」ルートにより、トラフィックはNATへ転送されます。

NAT内でパブリックIPが元のプライベートIPへ変換されます。

この時、このプライベートIPをネットワーク使用VPCに返却するルートがパブリックサブネットのルートテーブルに必要になるわけです。

arch2_6.png

よって、ネットワーク使用VPC内のプライベートIPを全てTransitゲートウェイに投げ返す「10.0.2.0/24 → ネットワーク共有VPC内のTransitゲートウェイアタッチメント」のルートが必要です。

めっちゃ複雑なのですが、うまく伝わったでしょうか?
claudeに推敲させれば良いんだけどフリープラン使い切った。

各ルートの設定

TransitゲートウェイのRouteに「0.0.0.0/0」を追加する

cap22.PNG

ルートタブから「静的ルートを作成」をクリックします。

cap23.PNG

「0.0.0.0/0」を入力し、ネットワーク共有VPCへのアタッチメントを選択します。
外部インターネットへのトラフィックを、ネットワーク共有VPCに向けるためですね。

cap23.PNG

設定ができたら、「静的ルートを作成」をクリックします。

cap24.PNG

良い感じですね。

ネットワーク使用VPCのプライベートサブネットのRouteに「0.0.0.0/0」を追加する

ルートテーブル画面から編集します。

cap25.PNG

「ルートを編集」をクリックします。

cap26.PNG

「0.0.0.0/0」を追加し、ターゲットからTransit Gatewayを選択します。

cap27.PNG

リソースIDを求められるので、VPC内に作成されたアタッチメントを指定します。
「変更を保存」をクリックします。

cap28.PNG

ルートが追加されました!

これで、プライベートサブネットからインターネットへの通信が、トランジットゲートウェイアタッチメントを経過し、
トランジットゲートウェイのルートテーブルで処理されるようになりました。

トランジットゲートウェイのルートテーブルでは、「0.0.0.0/0」はネットワーク共有VPCへルートさせるので、晴れてインターネットへ接続できるようになりました!!

ただ、まだ設定が必要です。次が最後です。

ネットワーク共有VPCのパブリックサブネットのRouteに「10.0.2.0/24」を追加する

ネットワーク共有VPCのパブリックサブネットのRouteに「10.0.2.0/24」を追加します。
上記した通り、戻りトラフィックをネットワーク使用VPCにルートするためですね。

ルートテーブル画面から編集します。手順は同様ですので省略します。

cap29.PNG

ルートが追加されました!

SSMアクセスしてみる

ここまで長かった・・・。
EC2にSSMアクセスできるようになっているはずなので、コンソールからを確認します。

cap30.PNG

一応再起動させます。

cap32.PNG

インスタンス画面から「接続」を選択します。
接続画面はキャッシュが強烈なので、スーパーリロードします。

cap31.PNG

接続ボタンが活性化されました!!!!
SSMアクセスしてみましょう!

cap33.PNG

うおおおインターネットにつながってますね!

ということで、上述した
①NATゲートウェイを持つネットワーク共有用VPCを作成し、
②複数のVPCとこの共有VPCを統合するアーキテクチャを作成することができました。

NATゲートウェイだけではなく、VPCエンドポイントなども同じ要領で1つのVPCに集約できるため、色々はかどりそうです。

claudeが通信帯域のひっ迫やセキュリティについて注意しなさいと言っていたので、
しっかり運用する際はそこらへんも考慮すると良さそうです。

おわりに

SAPで何回も聞かれるTransit Gatewayの挙動を簡単な範囲で検証してみました。
戻りトラフィックのことをClaudeもGPTも私もすっかり忘れており土曜が消し飛びましたが、
良い感じに解決できてよかったです!!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?