この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
データアナリティクス事業本部の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で行っていこうと思います。
最後まで読んで頂いてありがとうございました。