さくらのクラウドとGCPでサイト間VPNをコマンド一発構築

[Terraform](https://terraform.io) + [Terraform for さくらのクラウド](https://github.com/sacloud/terraform-provider-sakuracloud)でGCP <=> さくらのクラウドでサイト間VPNを一発構築する例です。

## 今回のネットワーク構成

以下のような構成をterraformで構築します。

![s2s_sacloud_gcp.png](https://qiita-image-store.s3.amazonaws.com/0/20668/96e40117-2a1c-d91a-7055-325a37e77fca.png)


## さくらのクラウド側

さくらのクラウド側でVPCを構築するにはVPCルータアプライアンスを利用します。

参考: [さくらのクラウド VPCルータとは](https://manual.sakura.ad.jp/cloud/network/vpc-router/about.html)

VPCルータアプライアンスは非常に以下のような機能を持つ多機能な仮想アプライアンスです。

- NAT機能
  - IPマスカレード(Forward NAT) 
  - ポートフォワーディング(Reverse NAT)
-VPN機能
  - L2TP/IPsec 
  - PPTP
- サイト間VPN機能 
- その他	
  - DHCPサーバ機能(スタティックマッピング設定可) 
  - 7個のVPCネットワーク(プライベート)側インターフェース 
  - トラフィックモニタ機能(Inbound/Outbound) 
  - ファイアウォール機能
  - ファイアウォールルールによって許可／遮断された通信ログの表示 
  - サイト間VPN／リモートアクセスVPNに関するログの表示
  - syslog転送機能

今回はこの中のサイト間VPN機能を用いてGCPとの間でIPSec VPN接続を行います。

## GCP側

GCP側は[Cloud VPN](https://cloud.google.com/compute/docs/vpn/overview?hl=ja)を利用します。
tfファイルは以下の記事を参考に作成しました。

参考: [Terraform で GCE と AWS VPC を VPN で接続する](https://qiita.com/quickguard/items/aff024221a3ab162b9d1)

## 準備

さくらのクラウドAPIキーやGCP認証ファイルの取得などが必要です。
Terraform入門記事などを参考に準備しておいてください。

## terraform定義ファイル(tfファイル)

tfファイルは以下の通りです。
変数についてはコマンドラインやterraform.tfvarsファイルなどで設定してください。

```hcl:さくらのクラウド_GCP_サイト間VPN.tf
variable "gcp_region" {} // GCP側リージョン
variable "gcp_project" {} // GCPプロジェクトID
variable "gcp_credential_file" {} // GCP認証情報(JSONファイルパス)
variable "sacloud_zone" {} // さくらのクラウド ゾーン

/**********************************************************
 * さくらのクラウド側設定
 *********************************************************/
provider sakuracloud {
  zone = "${var.sacloud_zone}"
}

# スイッチ
resource "sakuracloud_switch" "default" {
  name = "default"
}

# VPCルータ(スタンダードプラン)
resource "sakuracloud_vpc_router" "router" {
  name      = "sacloud-to-gcp"

  # スタンダードプランの場合はWAN側グローバルIPが1つ付与される
}

# VPCルータのプライベート側ネットワーク定義
resource "sakuracloud_vpc_router_interface" "eth1" {
  vpc_router_id = "${sakuracloud_vpc_router.router.id}"
  index         = 1
  switch_id     = "${sakuracloud_switch.default.id}"
  ipaddress     = ["192.168.21.1"]
  nw_mask_len   = 24
}

# VPCルータのサイト間VPN設定
resource "sakuracloud_vpc_router_site_to_site_vpn" "s2s" {
  vpc_router_id = "${sakuracloud_vpc_router.router.id}"

  # 対向IPアドレスにはGCP側で割り当てたグローバルIPを指定
  peer              = "${google_compute_address.vpn.address}"
  remote_id         = "${google_compute_address.vpn.address}"
  pre_shared_secret = "presharedsecret"

  # GCP側のIPアドレス範囲
  routes = ["${google_compute_subnetwork.subnet1.ip_cidr_range}"]

  # ローカル側(さくらのクラウド側)のIPアドレス範囲
  local_prefix = ["192.168.21.0/24"]
}

/**********************************************************
 * GCP側設定
 *********************************************************/
provider "google" {
  credentials = "${file(var.gcp_credential_file)}"
  project     = "${var.gcp_project}"
  region      = "${var.gcp_region}"
}

# VPCネットワーク作成
resource "google_compute_network" "default" {
  name                    = "sacloud-to-gcp"
  auto_create_subnetworks = "false"          #サブネット自動作成を行わない
}

# VPCネットワーク サブネット
resource "google_compute_subnetwork" "subnet1" {
  name          = "subnet1"
  network       = "${google_compute_network.default.self_link}"
  ip_cidr_range = "10.120.0.0/16"
  region        = "${var.gcp_region}"
}

# グローバルIP
resource "google_compute_address" "vpn" {
  name   = "gateway-to-sacloud"
  region = "${var.gcp_region}"
}

# VPNゲートウェイ
resource "google_compute_vpn_gateway" "default" {
  name    = "vpn-to-sacloud"
  network = "${google_compute_network.default.self_link}"
  region  = "${var.gcp_region}"
}

/*
 * google_compute_addressで確保したグローバルIP向けトラフィックを
 * VPNゲートウェイへフォワードするためのルールを3つ定義(ESP,IKE,IPsec Natトラバーサル)
 */
# フォワーディングルール(ESP用)
resource "google_compute_forwarding_rule" "esp" {
  name        = "vpn-to-sacloud-rule-esp"
  region      = "${var.gcp_region}"
  ip_protocol = "ESP"
  ip_address  = "${google_compute_address.vpn.address}"
  target      = "${google_compute_vpn_gateway.default.self_link}"
}

# フォワーディングルール(IKE: UDP500番)
resource "google_compute_forwarding_rule" "udp500" {
  name        = "vpn-to-sacloud-rule-udp500"
  region      = "${var.gcp_region}"
  ip_protocol = "UDP"
  port_range  = "500"
  ip_address  = "${google_compute_address.vpn.address}"
  target      = "${google_compute_vpn_gateway.default.self_link}"
}

# フォワーディングルール(IPsec NATトラバーサル: UDP4500番)
resource "google_compute_forwarding_rule" "udp4500" {
  name        = "vpn-to-aws-rule-udp4500"
  region      = "${var.gcp_region}"
  ip_protocol = "UDP"
  port_range  = "4500"
  ip_address  = "${google_compute_address.vpn.address}"
  target      = "${google_compute_vpn_gateway.default.self_link}"
}

# VPNトンネル
resource "google_compute_vpn_tunnel" "tunnel1" {
  name                   = "vpn-to-sacloud-tunnel-1"
  region                 = "${var.gcp_region}"
  peer_ip                = "${sakuracloud_vpc_router.router.global_address}"
  shared_secret          = "${sakuracloud_vpc_router_site_to_site_vpn.s2s.pre_shared_secret}"
  ike_version            = "1"
  target_vpn_gateway     = "${google_compute_vpn_gateway.default.self_link}"
  local_traffic_selector = ["${google_compute_subnetwork.subnet1.ip_cidr_range}"]

  depends_on = [
    "google_compute_forwarding_rule.esp",
    "google_compute_forwarding_rule.udp500",
    "google_compute_forwarding_rule.udp4500",
  ]
}

# ルーティング定義(さくらのクラウド向けトラフィック)
resource "google_compute_route" "vpn" {
  name                = "gce-to-sacloud"
  network             = "${google_compute_network.default.name}"
  next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.self_link}"
  dest_range          = "${sakuracloud_vpc_router_site_to_site_vpn.s2s.local_prefix[0]}" #複数ある場合はcount構文などでgoogle_compute_routeの定義を複数行うこと
  priority            = 1000
}

# ファイアウォール(さくらのクラウド間トラフィックを許可)
resource "google_compute_firewall" "vpn" {
  name          = "allow-sacloud"
  network       = "${google_compute_network.default.name}"
  source_ranges = ["${sakuracloud_vpc_router_site_to_site_vpn.s2s.local_prefix}"]

  allow {
    protocol = "tcp"
    ports    = ["0-65535"]
  }

  allow {
    protocol = "udp"
    ports    = ["0-65535"]
  }

  allow {
    protocol = "icmp"
  }
}
```

## 構築!!

あとは`terraform apply`するだけです。
terraformだとマルチクラウドな環境構築も楽チンですよね。

(10/18)追記  
GCP側のファイアウォール定義は最低限のものだけしか記載していません。
動作確認の際はdefaultネットワークのファイアウォール定義などを参考に適宜追加してください。

以上です。