AWSとGCPのVPN接続をTerraformでまとめる
はじめに
データアナリティクス事業本部のkobayashiです。
AWSとGCPをセキュアな環境で接続してそれぞれのサービスを相互に利用できないか検証するためそれぞれのVPC間をVPNで接続してみました。
前回、前々回とでAWSとGCPの接続方法である「Classic VPN」「高可用性(HA)VPN」接続の方法をまとめましたが、AWSとGCPのリソースを扱うならTerraformで構成管理した方が便利なのでは?と考えたことと、今までTerraformは興味がありましたがなかなか触る機会がなかったのでその勉強も兼ねて簡単にリソースの構築と削除を行えるようにTerraformテンプレートを作成しましたのでその内容をまとめます。
- Cloud VPN の概要 | Google Cloud
- Provider: Google Cloud Platform - Terraform by HashiCorp
- Provider: AWS - Terraform by HashiCorp
前回、前々回の記事
環境
- Terraform v0.12.24
接続パターン
Classic VPN接続
AWSでAWS VPN connectionを作成すると2つのIPSec tunnelが利用できます。 上のパターン(以降パターン1)ではそのうちの1本を利用するパターン、下のパターン(以降パターン2)は2本とも利用してフェイルオーバーに対応するパターンになります。
高可用性(HA)VPN接続
HA VPNの接続パターンになります。 上のパターン(以降パターン3)ではAWS、GCPのVPN connectionを冗長化しています。下のパターン(以降パターン4)ではパターン3で冗長化した上でさらにAWS VPN connectionのIPSec tunnelを全て利用しています。GCPが推奨する高可用性(HA)VPN接続方法となります。
パターン1とパターン4をTerraformテンプレートにしましたのでその説明をします。
Classic VPN接続(パターン1)のTerraformテンプレート
テンプレートファイルの構成
以下のようなファイルの構成となります。
gcp_credentioal.json
はGCPのコンソール内のIAMと管理
よりサービスアカウントを作成し、サービスアカウントの詳細より作成した秘密鍵のファイルになります。それ以外の*.tf
ファイルの説明を以降の項で説明します。
├── aws_vpn.tf ├── gcp_credentioal.json ├── gcp_vpn.tf ├── provider.tf └── variables.tf
variables.tfの内容
AWS、GCPともにVPCの構築が終わっていてそれぞれのVPC間をVPNで接続する想定ですので、variables.tf
にvpc_id
などの値をまとめます。
variable "gcp_credential_filename" { default = "gcp_credentioal.json" } variable "gcp_project" { default = "{GCPのプロジェクト名}" } variable "gcp_network" { default = "{VPCネットワークの名前}" } variable "aws_access_key" { default = "{IAMユーザーのaccess_key}" } variable "aws_secret_key" { default = "{IAMユーザーのsecret_key}" } variable "aws_resname_prefix" { default = "{AWSのリソース名につけるPrefix:適当で}" } variable "aws_vpc_id" { default = "{VPC ID}" } variable "aws_vpc_route_table_id" { default = "{ルートテーブルID}" }
provider.tfの内容
先に説明したvariables.tf
の変数を利用してプロバイダー情報をまとめます。regionはAWS、GCPとも東京リージョンを指定してあります。
provider "google" { credentials = file(var.gcp_credential_filename) project = var.gcp_project region = "asia-northeast1" } provider "aws" { access_key = var.aws_access_key secret_key = var.aws_secret_key region = "ap-northeast-1" }
gcp_vpn.tfの内容
GCPのリソースを定義して
- 外部IPアドレスの作成
- クラウドルーターの作成
- VPNゲートウェイの作成
- VPNトンネルの作成
を行います。
// 外部IPアドレスの設定 resource "google_compute_address" "cmk_vgw_address" { name = "aws-gcp-vgw" } // クラウドルーターの設定 resource "google_compute_router" "cmk_cloud_router" { name = "connect-aws-router" network = var.gcp_network bgp { asn = 65000 } } // VPNゲートウェイの設定 resource "google_compute_vpn_gateway" "cmk_vgw" { name = "aws-gcp-vgw" network = var.gcp_network } // パケット転送ルールの設定(espパケット) resource "google_compute_forwarding_rule" "fr_esp" { name = "aws-gcp-vgw-esp" ip_protocol = "ESP" ip_address = google_compute_address.cmk_vgw_address.address target = google_compute_vpn_gateway.cmk_vgw.self_link } // パケット転送ルールの設定(IKEパケット(UDP 500番)) resource "google_compute_forwarding_rule" "fr_udp500" { name = "aws-gcp-vgw-udp500" ip_protocol = "UDP" port_range = "500" ip_address = google_compute_address.cmk_vgw_address.address target = google_compute_vpn_gateway.cmk_vgw.self_link } // パケット転送ルールの設定(NAT-Tパケット(UDP 4500番)) resource "google_compute_forwarding_rule" "fr_udp4500" { name = "aws-gcp-vgw-udp4500" ip_protocol = "UDP" port_range = "4500" ip_address = google_compute_address.cmk_vgw_address.address target = google_compute_vpn_gateway.cmk_vgw.self_link } // VPNトンネルの設定 resource "google_compute_vpn_tunnel" "cmk_vpn_tunnel1" { name = "aws-gcp-tunnel1" peer_ip = aws_vpn_connection.cmk_vpnc.tunnel1_address shared_secret = aws_vpn_connection.cmk_vpnc.tunnel1_preshared_key target_vpn_gateway = google_compute_vpn_gateway.cmk_vgw.self_link router = google_compute_router.cmk_cloud_router.self_link ike_version = 1 depends_on = [ google_compute_forwarding_rule.fr_udp500, google_compute_forwarding_rule.fr_esp, google_compute_forwarding_rule.fr_udp4500, ] } // Cloud Routerインターフェースの設定 resource "google_compute_router_interface" "cmk_interface" { name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel1.name}-interface" router = google_compute_router.cmk_cloud_router.name ip_range = "${aws_vpn_connection.cmk_vpnc.tunnel1_cgw_inside_address}/30" vpn_tunnel = google_compute_vpn_tunnel.cmk_vpn_tunnel1.name } // BGPピアリング用のBGP情報の設定 resource "google_compute_router_peer" "cmk_peer" { name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel1.name}-peer" router = google_compute_router.cmk_cloud_router.name peer_ip_address = aws_vpn_connection.cmk_vpnc.tunnel1_vgw_inside_address peer_asn = aws_vpn_connection.cmk_vpnc.tunnel1_bgp_asn interface = google_compute_router_interface.cmk_interface.name }
aws_vpn.tfの内容
AWSのリソースを定義して
- 仮想プライベートゲートウェイの作成
- クラウドルーターの作成
- カスタマーゲートウェイの作成
- サイト間のVPN接続の作成
を行います。
// 仮想プライベートゲートウェイの設定 resource "aws_vpn_gateway" "cmk_vgw" { vpc_id = var.aws_vpc_id tags = { Name = "${var.aws_resname_prefix}vgw" } } // 仮想プライベートゲートウェイのルート伝播の設定 resource "aws_vpn_gateway_route_propagation" "cmk_vgw_rp" { vpn_gateway_id = aws_vpn_gateway.cmk_vgw.id route_table_id = var.aws_vpc_route_table_id } // カスタマーゲートウェイの設定 resource "aws_customer_gateway" "cmk_cgw" { bgp_asn = 65000 ip_address = google_compute_address.cmk_vgw_address.address type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}cgw" } } // サイト間のVPN接続の設定 resource "aws_vpn_connection" "cmk_vpnc" { vpn_gateway_id = aws_vpn_gateway.cmk_vgw.id customer_gateway_id = aws_customer_gateway.cmk_cgw.id type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}vpn-connection" } }
これでテンプレートファイルの作成は終わったので後は
terraform plan
で内容を確認して問題がなければ、
terraform apply
でリソースを作成します。サイト間のVPN接続の作成に時間がかかる場合がありますが、おおよそ5分ほどで作成完了します。
高可用性(HA)VPN接続(パターン4)のTerraformテンプレート
テンプレートファイルの構成
Classic VPN接続(パターン1)のTerraformテンプレートと同じファイル構成で、variables.tf
はパターン1と同じ内容なので割愛します。
provider.tfの内容
先に説明したvariables.tf
の変数を利用してプロバイダー情報をまとめます。regionはAWS、GCPとも東京リージョンを指定してあります。
パターン1と唯一異なるのがprovider
で、GCPのリソースを記述する際にgoogle-beta
プロバイダーで記述する必要があるため、provider "google"
の部分をprovider "google-beta"
に書き換えます。
provider "google-beta" { credentials = file(var.gcp_credential_filename) project = var.gcp_project region = "asia-northeast1" } provider "aws" { access_key = var.aws_access_key secret_key = var.aws_secret_key region = "ap-northeast-1" }
gcp_vpn.tfの内容
GCPのリソースを定義して
- 高可用性(HA)VPN用のゲートウェイの作成
- クラウドルーターの作成
- 4つのインターフェースを持つVPNゲートウェイの作成
- 4つのVPNトンネルの作成
を行います。
// 高可用性(HA)VPN用のゲートウェイの設定 resource "google_compute_ha_vpn_gateway" "cmk_ha_gateway" { provider = google-beta name = "ha-vpn-1" network = "https://www.googleapis.com/compute/v1/projects/${var.gcp_project}/global/networks/${var.gcp_network}" } // クラウドルーターの設定 resource "google_compute_router" "cmk_cloud_router" { provider = google-beta name = "ha-vpn-router1" network = var.gcp_network bgp { asn = 65000 } } // 対AWS用のVPNゲートウェイの設定 // 4つのVPNトンネルを作成するのでinterfaceを4つ定義する resource "google_compute_external_vpn_gateway" "cmk_external_vgw" { provider = google-beta name = "aws-gateway" redundancy_type = "FOUR_IPS_REDUNDANCY" interface { id = 0 ip_address = aws_vpn_connection.cmk_vpnc1.tunnel1_address } interface { id = 1 ip_address = aws_vpn_connection.cmk_vpnc1.tunnel2_address } interface { id = 2 ip_address = aws_vpn_connection.cmk_vpnc2.tunnel1_address } interface { id = 3 ip_address = aws_vpn_connection.cmk_vpnc2.tunnel2_address } } // VPNトンネル1の設定 // VPNトンネルの接続設定(トンネル1用) resource "google_compute_vpn_tunnel" "cmk_vpn_tunnel1" { provider = google-beta name = "ha-vpn-tunnel1" shared_secret = aws_vpn_connection.cmk_vpnc1.tunnel1_preshared_key vpn_gateway = google_compute_ha_vpn_gateway.cmk_ha_gateway.self_link vpn_gateway_interface = 0 peer_external_gateway = google_compute_external_vpn_gateway.cmk_external_vgw.self_link peer_external_gateway_interface = 0 router = google_compute_router.cmk_cloud_router.name ike_version = 1 } // Cloud Routerインターフェースの設定(トンネル1用) resource "google_compute_router_interface" "cmk_interface1" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel1.name}-interface1" router = google_compute_router.cmk_cloud_router.name ip_range = "${aws_vpn_connection.cmk_vpnc1.tunnel1_cgw_inside_address}/30" vpn_tunnel = google_compute_vpn_tunnel.cmk_vpn_tunnel1.name } // BGPピアリング用のBGP情報の設定(トンネル1用) resource "google_compute_router_peer" "cmk_peer1" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel1.name}-peer1" router = google_compute_router.cmk_cloud_router.name peer_ip_address = aws_vpn_connection.cmk_vpnc1.tunnel1_vgw_inside_address peer_asn = aws_vpn_connection.cmk_vpnc1.tunnel1_bgp_asn interface = google_compute_router_interface.cmk_interface1.name } // VPNトンネル2の設定 // VPNトンネルの接続設定(トンネル2用) resource "google_compute_vpn_tunnel" "cmk_vpn_tunnel2" { provider = google-beta name = "ha-vpn-tunnel2" shared_secret = aws_vpn_connection.cmk_vpnc1.tunnel2_preshared_key vpn_gateway = google_compute_ha_vpn_gateway.cmk_ha_gateway.self_link vpn_gateway_interface = 0 peer_external_gateway = google_compute_external_vpn_gateway.cmk_external_vgw.self_link peer_external_gateway_interface = 1 router = google_compute_router.cmk_cloud_router.name ike_version = 1 } // Cloud Routerインターフェースの設定(トンネル2用) resource "google_compute_router_interface" "cmk_interface2" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel2.name}-interface2" router = google_compute_router.cmk_cloud_router.name ip_range = "${aws_vpn_connection.cmk_vpnc1.tunnel2_cgw_inside_address}/30" vpn_tunnel = google_compute_vpn_tunnel.cmk_vpn_tunnel2.name } // BGPピアリング用のBGP情報の設定(トンネル2用) resource "google_compute_router_peer" "cmk_peer2" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel2.name}-peer2" router = google_compute_router.cmk_cloud_router.name peer_ip_address = aws_vpn_connection.cmk_vpnc1.tunnel2_vgw_inside_address peer_asn = aws_vpn_connection.cmk_vpnc1.tunnel2_bgp_asn interface = google_compute_router_interface.cmk_interface2.name } // VPNトンネル3の設定 // VPNトンネルの接続設定(トンネル3用) resource "google_compute_vpn_tunnel" "cmk_vpn_tunnel3" { provider = google-beta name = "ha-vpn-tunnel3" shared_secret = aws_vpn_connection.cmk_vpnc2.tunnel1_preshared_key vpn_gateway = google_compute_ha_vpn_gateway.cmk_ha_gateway.self_link vpn_gateway_interface = 1 peer_external_gateway = google_compute_external_vpn_gateway.cmk_external_vgw.self_link peer_external_gateway_interface = 2 router = google_compute_router.cmk_cloud_router.name ike_version = 1 } // Cloud Routerインターフェースの設定(トンネル3用) resource "google_compute_router_interface" "cmk_interface3" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel3.name}-interface3" router = google_compute_router.cmk_cloud_router.name ip_range = "${aws_vpn_connection.cmk_vpnc2.tunnel1_cgw_inside_address}/30" vpn_tunnel = google_compute_vpn_tunnel.cmk_vpn_tunnel3.name } // BGPピアリング用のBGP情報の設定(トンネル3用) resource "google_compute_router_peer" "cmk_peer3" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel3.name}-peer3" router = google_compute_router.cmk_cloud_router.name peer_ip_address = aws_vpn_connection.cmk_vpnc2.tunnel1_vgw_inside_address peer_asn = aws_vpn_connection.cmk_vpnc2.tunnel1_bgp_asn interface = google_compute_router_interface.cmk_interface3.name } // VPNトンネル4の設定 // VPNトンネルの接続設定(トンネル4用) resource "google_compute_vpn_tunnel" "cmk_vpn_tunnel4" { provider = google-beta name = "ha-vpn-tunnel4" shared_secret = aws_vpn_connection.cmk_vpnc2.tunnel2_preshared_key vpn_gateway = google_compute_ha_vpn_gateway.cmk_ha_gateway.self_link vpn_gateway_interface = 1 peer_external_gateway = google_compute_external_vpn_gateway.cmk_external_vgw.self_link peer_external_gateway_interface = 3 router = google_compute_router.cmk_cloud_router.name ike_version = 1 } // Cloud Routerインターフェースの設定(トンネル4用) resource "google_compute_router_interface" "cmk_interface4" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel4.name}-interface4" router = google_compute_router.cmk_cloud_router.name ip_range = "${aws_vpn_connection.cmk_vpnc2.tunnel2_cgw_inside_address}/30" vpn_tunnel = google_compute_vpn_tunnel.cmk_vpn_tunnel4.name } // BGPピアリング用のBGP情報の設定(トンネル4用) resource "google_compute_router_peer" "cmk_peer4" { provider = google-beta name = "${google_compute_vpn_tunnel.cmk_vpn_tunnel4.name}-peer4" router = google_compute_router.cmk_cloud_router.name peer_ip_address = aws_vpn_connection.cmk_vpnc2.tunnel2_vgw_inside_address peer_asn = aws_vpn_connection.cmk_vpnc2.tunnel2_bgp_asn interface = google_compute_router_interface.cmk_interface4.name }
aws_vpn.tfの内容
AWSのリソースを定義して
- 仮想プライベートゲートウェイの作成
- クラウドルーターの作成
- 2つのカスタマーゲートウェイの作成
- 2つのサイト間のVPN接続の作成
を行います。
// 仮想プライベートゲートウェイの設定 resource "aws_vpn_gateway" "cmk_vgw" { vpc_id = var.aws_vpc_id tags = { Name = "${var.aws_resname_prefix}vgw" } } // 仮想プライベートゲートウェイのルート伝播の設定 resource "aws_vpn_gateway_route_propagation" "cmk_vgw_rp" { vpn_gateway_id = aws_vpn_gateway.cmk_vgw.id route_table_id = var.aws_vpc_route_table_id } // 1つ目のカスタマーゲートウェイの設定 resource "aws_customer_gateway" "cmk_cgw1" { bgp_asn = 65000 ip_address = google_compute_ha_vpn_gateway.cmk_ha_gateway.vpn_interfaces[0].ip_address type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}cgw" } } // 1つ目のサイト間のVPN接続の設定 resource "aws_vpn_connection" "cmk_vpnc1" { vpn_gateway_id = aws_vpn_gateway.cmk_vgw.id customer_gateway_id = aws_customer_gateway.cmk_cgw1.id type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}vpn-connection" } } // 2つ目のカスタマーゲートウェイの設定 resource "aws_customer_gateway" "cmk_cgw2" { bgp_asn = 65000 ip_address = google_compute_ha_vpn_gateway.cmk_ha_gateway.vpn_interfaces[1].ip_address type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}cgw" } } // 2つ目のサイト間のVPN接続の設定 resource "aws_vpn_connection" "cmk_vpnc2" { vpn_gateway_id = aws_vpn_gateway.cmk_vgw.id customer_gateway_id = aws_customer_gateway.cmk_cgw2.id type = "ipsec.1" tags = { Name = "${var.aws_resname_prefix}vpn-connection" } }
以上でテンプレートファイル群の作成は終わりです。
こちらもリソースの作成まで5分ほどかかります。
まとめ
当初の目的はAWS/GCPリソースの構成管理を簡単にして手軽にAWS-GCPの環境を作ることでしたが、Terraformテンプレートファイルを作成するにあたりTerraformをイチから調べてテンプレートファイルを作成しました。Terraformは記述方法もそれほど難しくなくマルチクラウドに対応できるので今後はリソース管理をTerrarormで行っていこうと思います。
最後まで読んで頂いてありがとうございました。