5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

外部ネットワークとAWSのVPCをSite-to-Site VPNとトランジェントゲートウェイで疎通する

Last updated at Posted at 2023-12-18

初めに

CYBIRD Advent Calendar 2023」 の19日目の記事を担当する@gongon282828です。

18日目の記事は、@cy-yuka-WPさんの「Google Apps Scriptを利用したスケジュール管理」でした。

この記事では、外部ネットワークとAWSをSite-to-Site VPNで疎通し、AWS側では複数のVPNに対して疎通をフレキシブルにとれるように、トランジェントゲートウェイを利用した構築方法を説明します。

前提

サイバードでは、AWSの開発にはIaC(Infrastructure as Code)の実用として、Terraformを利用して構築しているため、その方法について記載します。

その他、諸条件については以下になります。

  • Site-to-Site VPNと疎通をとる対象となる外部ネットワーク(オンプレミス環境や他パブリッククラウド等)のIPアドレスやネットワークは事前に用意してあるものとし、割愛します。
  • AWS側のVPCは記事の冗長化を避ける目的で、2つのVPCのみ構築する内容で記載し、クロスアカウントでのVPCでのネットワーク疎通については記載しません。
  • VPC内のサブネットは、プライベートサブネットの指定のみとします。
  • 実際に疎通するAWSリソース(EC2やRDS等)へのセキュリティグループの設定の許可については割愛し、各ネットワークのルートテーブルまでの構築方法について記載します。

ネットワーク構成

以下、ネットワーク構成を示します。

ネットワーク構成.png

Site-to-Site VPNで外部ネットワークと疎通させ、AWS側はトランジェントゲートウェイで疎通をとっています。

TerraformでのAWSリソースの構築

ここではTerraformで構築する方法を示します。

トランジェントゲートウェイとカスタムゲートウェイの生成

ここでは、トランジェントゲートウェイとカスタムゲートウェイを生成します。

terraform
locals{
 external_network_public_ip = "x.x.x.x/32"
}

resource "aws_ec2_transit_gateway" "main" {
  vpn_ecmp_support                = "enable"
  default_route_table_association = "disable"
  default_route_table_propagation = "disable"
  auto_accept_shared_attachments  = "disable"
  tags = { Name = "tgw" }
}

resource "aws_customer_gateway" "main" {
  ip_address = local.external_network_public_ip
  bgp_asn = "65000"
  type = "ipsec.1"
  tags = { "cgw" }
}

今回は、VPNとトランジェントゲートウェイの疎通をとるので、aws_ec2_transit_gatewayvpn_ecmp_supportenableにし、それ以外はdisableにします。

aws_customer_gateway(実質的には、これがSite-to-Site VPNのリソース)では、外部ネットワーク内のIPアドレスを指定します。

トランジェントゲートウェイとカスタムゲートウェイの疎通

terraform
resource "aws_vpn_connection" "main" {
  transit_gateway_id  = aws_ec2_transit_gateway.main.id
  customer_gateway_id = aws_customer_gateway.main.id
  type = "ipsec.1"
  static_routes_only = true
  tags = { Name = "tgw-cgw-connection" }
}

resource "aws_ec2_transit_gateway_route_table" "main" {
  transit_gateway_id = aws_ec2_transit_gateway.main.id
  tags               = { Name = "tgw-route-table" }
}

data "aws_ec2_transit_gateway_vpn_attachment" "main" {
  transit_gateway_id = aws_ec2_transit_gateway.main.id 
  vpn_connection_id  = aws_vpn_connection.main.id
  tags = { Name = "twg-vpn-attachment" }
}

resource "aws_ec2_transit_gateway_route_table_association" "vpn" {
  transit_gateway_attachment_id  = data.aws_ec2_transit_gateway_vpn_attachment.main.id
  transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}

resource "aws_ec2_transit_gateway_route_table_propagation" "vpn" {
  transit_gateway_attachment_id  = data.aws_ec2_transit_gateway_vpn_attachment.main.id
  transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}

Site-to-Site VPN側では、aws_vpn_connectionでトランジェントゲートウェイと紐づけるのですが、外部IPは事前に作成している前提になるので、static_routes_onlytrueにします。

トランジェントゲートウェイ側では、トランジェントゲートウェイ用のルートテーブルを作成した上で、Site-to-Site VPNをアタッチさせます。その上で、トランジェントゲートウェイのルートテーブルの関連付け(association)と伝番(propagation)の設定を入れています。

トランジェントゲートウェイとVPCの疎通

トランジェントゲートウェイと各VPCを疎通させます。
ここでは、AWSのVPCの各リソースについては、localで変数化したものを参照させています。実際に構築する際には、他moduleで生成し参照させる方法が一般的かと思います。

terraform
locals{
 external_network = "x.x.x.x/16"

 aws_network = {
   env_1 = {
     env                     = "env_1"
    vpc_id                  = "x.x.x.x/16"
    private_subnet_ids      = ["x.x.0.x/24","x.x.1.x/24"]
     private_route_table_ids = "rtb-xxxxxxxxxx"
   }
   env_2 = {
     env                     = "env_2"
    vpc_id                  = "x.x.x.x/16"
    private_subnet_ids      = ["x.x.0.x/24","x.x.1.x/24"]
     private_route_table_ids = "rtb-xxxxxxxxxx"
   }
 }
}

resource "aws_ec2_transit_gateway_vpc_attachment" "main" {
 count = length(local.aws_network[*])

  transit_gateway_id = aws_ec2_transit_gateway.main.id
  vpc_id             = local.aws_network[count.index].vpc_id
  subnet_ids         = local.aws_network[count.index].private_subnet_ids

  transit_gateway_default_route_table_association = false
  transit_gateway_default_route_table_propagation = false

  tags = {
    Name = "${local.aws_network[count.index].env}-twg-vpc-attachment"
  }
}

resource "aws_ec2_transit_gateway_route_table_association" "aws" {
  count = length(aws_ec2_transit_gateway_vpc_attachment.main[*]) 
  
  transit_gateway_attachment_id  = element(aws_ec2_transit_gateway_vpc_attachment.main, count.index)
  transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}

resource "aws_route" "main" {
  count = length(local.aws_network[*])
   
  route_table_id         = local.aws_network[count.index].private_route_table_ids
  transit_gateway_id     = aws_ec2_transit_gateway.main.id
  destination_cidr_block = locals.external_network
}

まず、aws_ec2_transit_gateway_vpc_attachmentでトランジェントゲートウェイと各VPCの紐づけを、サブネット単位で行います。

次に、トランジェントゲートウェイ側のルートテーブルに関連付けと伝番を設定します。

最後に、各VPCのルートテーブル側で、外部ネットワークのciderを登録します。

以上が、Terraformでの構築方法になります。

補足

実践の場では、外部ネットワーク側のルーティングについては仮想ルーターでOSSとなるVyOSを活用して外部ネットワークの疎通リソースを構築しました。

また、VyOS側の作業として、AWSコンソール上で出力される設定情報を流し込む必要があります。

なお、VyOSはLTSバージョンは有償にはなるのですが、isoイメージをビルドするソースは公開されているので、isoイメージについても別途作成する必要があります。

最後に

トランジェントゲートウェイを利用することで、例えば環境の部分移管やAWS側の一部VPCを廃止させたい時など、稼働しているネットワークに影響を与えずに、ネットワーク構成をフレキシブルに変更することができ、便利に活用しています。

また、実はいうとこの記事は本当は書く予定はなかったのですが、アドベントカレンダーの記事はQiita内で重複参照できないことを前日朝に気づき(絶望...)、急遽、本記事を用意しました。

AWS for Games Advent Calendar 2023」 の19日目の記事「ECS Fargateでのx86_64とarmのマルチアーキテクチャ実装概略とTerraformでの構築」も担当しているので、ぜひそちらもチェックいただければ嬉しいです!

CYBIRD Advent Calendar 2023」 、20日目は@ice_matcha3さんの「ロードバランサの流量調整を動的にやってみた!」です。

サイバードのアドベントカレンダーは明日も引き続きインフラトピックになります!
乞うご期待!!

5
1
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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?