LoginSignup
1
0

TerraformでVPCピアリングを実装してみた

Last updated at Posted at 2023-08-05

最近、特定のタスクを達成するために、VPC1内のプライベートサブネットに設置したLambdaアプリケーションを、同一VPC内のパブリックサブネットに存在するNAT Gatewayを介して、VPC2内のパブリックサブネットにあるALB(接続先はプライベートサブネットのECS)のパブリックURLを利用するように設定しました。

しかし、ALBへのトラフィックはLambdaからのものだけで、以下の非機能要求を満たすために、VPCピアリングを介したプライベートな接続に変更することにしました。

  • コスト: NAT Gatewayを利用するよりもデータ転送量が少なくて済み、コスト削減につながる。
  • パフォーマンス: VPC間のネットワーク遅延を最小化でき、大量のデータ転送や低レイテンシを要求するアプリケーションに有効。
  • セキュリティ: 通信がAWS内のプライベートなネットワーク接続で行われるため、通信がインターネットに出るリスクを排除できる。

この記事では、これらの要求を満たすためにTerraformを用いてVPCピアリングを実装する方法を記載します。

実装

今回は以下のようなディレクトリ構成を採用しています。
各環境(dev, stg, prod)に対応するディレクトリと、再利用可能なモジュール(route_table, security_group, vpc_peering)を用意しています。

-- terraform-project/
   -- environments/
      -- dev/
         -- backend.tf
         -- main.tf
      -- stg/
         -- backend.tf
         -- main.tf
      -- prod/
         -- backend.tf
         -- main.tf
   -- modules/
      -- route_table/
         -- main.tf
         -- variables.tf
         -- outputs.tf
         -- provider.tf
         -- README.md
      -- security_group/
         -- main.tf
         -- variables.tf
         -- outputs.tf
         -- provider.tf
         -- README.md
      -- vpc_peering/
         -- main.tf
         -- variables.tf
         -- outputs.tf
         -- provider.tf
         -- README.md

VPCピアリング

VPCピアリングはAWS内の2つのVPC間で直接的なネットワーク接続を作る機能です。
以下のvpc_peering/main.tfでは、SSMパラメータストアからVPCのIDを取得し、それらを用いてVPCピアリングを設定しています。

modules/vpc_peering/main.tf
data "aws_ssm_parameter" "lambda_vpc_id" {
  name = "/vpc/id/lambda"
}

data "aws_ssm_parameter" "ecs_vpc_id" {
  name = "/vpc/id/ecs"
}

// 同一アカウント内でのVPCピアリングのため、接続と承認を一度に行う
resource "aws_vpc_peering_connection" "vpc_peering" {
  vpc_id      = data.aws_ssm_parameter.lambda_vpc_id.value
  peer_vpc_id = data.aws_ssm_parameter.ecs_vpc_id.value
  auto_accept = true
}

さらに、VPCピアリングのIDを他のモジュールで利用できるようにoutputs.tfで出力しています。

modules/vpc_peering/outputs.tf
output "vpc_peering_connection_id" {
  description = "Connection Id of VPC Peering"
  value       = aws_vpc_peering_connection.vpc_peering.id
}

ルートテーブル

次に、VPC内のネットワークトラフィックのルートを設定するルートテーブルを作成します。
ここでは、各VPCのCIDRブロックとVPCピアリングのIDを用いて、ピアリング接続を経由するルートを設定しています。
Lambdaが配置されているサブネットのルートテーブルをlambda_local_nat、ALBが配置されているサブネットのルートテーブルをecs_localとしています。

data "aws_ssm_parameter" "lambda_vpc_cidr" {
  name = "/vpc/cidr/lambda"
}

data "aws_ssm_parameter" "ecs_vpc_cidr" {
  name = "/vpc/cidr/ecs"
}

resource "aws_route_table" "lambda_local_nat" {
  vpc_id = data.aws_ssm_parameter.lambda_vpc_id.value
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = data.aws_ssm_parameter.lambda_nat_gw_id.value
  }
  tags = {
    Name = "lambda-vpc-private-local-nat-rtb"
  }
}

// 既存ルートへの影響を考慮して分割
resource "aws_route" "peering_route" {
  route_table_id            = aws_route_table.lambda_local_nat.id
  destination_cidr_block    = data.aws_ssm_parameter.ecs_vpc_cidr.value
  vpc_peering_connection_id = var.vpc_peering_connection_id
}

resource "aws_route_table" "ecs_local" {
  vpc_id = data.aws_ssm_parameter.ecs_vpc_id.value

  tags = {
    Name = "ecs-vpc-private-local-rtb"
  }
}

// 既存ルートへの影響を考慮して分割
resource "aws_route" "ecs_peering_route" {
  route_table_id                = aws_route_table.ecs_local.id
  destination_cidr_block        = data.aws_ssm_parameter.lambda_vpc_cidr.value
  vpc_peering_connection_id     = var.vpc_peering_connection_id
}

ルートテーブルモジュールでは、VPCピアリングのIDを入力として受け取るために、variables.tfで変数を定義しています。

modules/route_table/variables.tf
variable "vpc_peering_connection_id" {
  description = "Connection Id of VPC Peering"
  type        = string
}

セキュリティグループ

最後に、ALBのセキュリティグループを設定します。
これにより、特定のIP範囲からの通信だけを許可するというルールを作ることができます。
今回、Lambdaは2つのプライベートサブネットに存在するので、各サブネットのCIDRブロックを指定しています。

modules/security_group/main.tf
data "aws_ssm_parameter" "lambda_private_subnet_cidr1" {
  name = "/subnet/private/cidr1/lambda"
}

data "aws_ssm_parameter" "lambda_private_subnet_cidr2" {
  name = "/subnet/private/cidr2/lambda"
}

resource "aws_security_group_rule" "elb_sg_ingress_443_lambda" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.elb_sg.id
  cidr_blocks       = [data.aws_ssm_parameter.lambda_private_subnet_cidr1.value, data.aws_ssm_parameter.lambda_private_subnet_cidr2.value]
}

プライベートDNSと証明書の設定

Terraformの実装は以上なのですが(あとはterraform applyするだけ)、VPCピアリングはプライベートな接続を扱うため、Lambdaのアプリケーション内でApplication Load Balancer(ALB)の接続先をパブリックURLからプライベートDNSに変更する必要があります。

加えて、HTTPS接続を行うためには、AWS Certificate Manager(ACM)のPrivate Certificate Authority(CA)を用いてプライベート証明書を作成し、その証明書をALBのリスナーに割り当てる作業が必要になります。

以下が設定手順です。

1.Private CAの作成

  • AWS Certificate Manager(ACM)のダッシュボードから「Private CAs」を選択し、「Create CA」をクリックします。
  • Root CAまたはSubordinate CAのタイプを選択し、CAの詳細を入力します。
  • その後、「Next」をクリックし、設定を確認します。
  • 問題がなければ、「Confirm and create」をクリックして、Private CAを作成します。

2.プライベート証明書の発行

  • Private CAが作成されたら、「Certificate Manager」ダッシュボードに戻り、「Get started」をクリックします。
  • 証明書の設定画面で、「Private」を選択し、「Request a certificate」をクリックします。
  • プライベートDNS名を含むドメイン名を入力し、詳細を設定します。
  • 設定が完了したら、「Confirm and request」をクリックします。

3.ALBのリスナーに証明書を割り当てる

  • ALBの設定画面に移動し、対象のリスナーを選択します。
  • 「Actions」ドロップダウンから「Change certificate」を選択し、作成したプライベート証明書を選択します。
1
0
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
1
0