Google Cloud VPNとCiscoルータの接続（BGP経路）

# Google Cloud VPN

外部のネットワークをGoogle Cloud Platform(GCP)に接続する方法として、以下の4つのオプションがあります。ハイブリッドクラウド的な観点からオンプレミスのインフラを接続するとなると、前の2つのどちらかになります。

- 相互接続
    - Dedicated Interconnect
    - IPsec VPN
- ピアリング
    - ダイレクトピアリング
    - キャリアピアリング

Google Cloud VPNを使うと、オンプレミスのインフラとGCP Virtual Private Cloud(VPC)ネットワークをIPsec VPN接続経由でパブリックインターネット上でトラフィックを暗号化してセキュアに接続することができます。

その他の接続方式については、以下のGoogle Cloudオフィシャルのドキュメント参考にしてください。

**CLOUD INTERCONNECT**
https://cloud.google.com/interconnect/?hl=ja

# Google Cloud VPN構成

Google Cloud VPNでGCPとオンプレミスを接続する構成には2つのオプションがあります。

一つは、GCPのVPNゲートウェイとオンプレミスのピアゲートウェイをIPsec接続する方法です。この場合、経路情報は静的に設定されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/176968/846c8a60-213e-44cf-04c2-c20bfb31e78c.png)

もう一つは、上記のゲートウェイ間のIPsec接続に加え、GCPのCloud Routerと顧客のピアゲートウェイの間でBGPにより動的に経路情報を交換する方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/176968/74bc9979-331b-4747-a7b8-07c737bf252d.png)

このドキュメントでは、後者のBGP経路を用いる方法を解説します。

静的経路を用いる方法については以下の投稿を参照ください。

**Google Cloud VPNとCiscoルータの接続（静的経路）**
https://qiita.com/tetsusat/items/c82d2b3bba748c80d1d4

# 環境

このドキュメントを作成するにあたっては、以下の環境で試験してます。

- デバイス: Cisco ISR4321
- IOS XE Version: 16.8.1

他のCisco IOS XEルータ（ASR1000シリーズ、ISR4000シリーズ）でも同様の動作が期待されます。Google Cloud VPNはパブリックインターネットを通る場合は最大1.5Gbpsの転送速度で処理できるらしいので、実際はより上位のプラットフォームを選択するのがよいでしょう。

# おことわり

IKEv2およびIPsecのパラメータはGoogle Cloudのサイトに掲載されてある以下のコミュニティチュートリアルを参考にしました。

**How to Set Up VPN between Cisco ASR and Cloud VPN**
https://cloud.google.com/community/tutorials/using-cloud-vpn-with-cisco-asr

Google Cloud VPNではこの資料で設定したもの以外の各種アルゴリズムもサポートします。詳細は以下のGoogle Cloudオフィシャルのドキュメント参考にしてください。

https://cloud.google.com/compute/docs/vpn/advanced?hl=ja

# GCP側の設定

オンプレミス側の設定にはGCP側の設定時に取得するグローバルスタティックIPが必要になるので、GCP側から設定します。

VPCのネットワークを作成します。

```
gcloud compute networks create my-network \
    --subnet-mode custom
```

VPCのサブネットを作成します。
今回はGCP側のネットワークを`10.0.1.0/24`としました。

```
gcloud compute networks subnets create subnet-1 \
    --network my-network \
    --region asia-northeast1 \
    --range 10.0.1.0/24
```

ターゲットVPNゲートウェイを作成します。

```
gcloud compute target-vpn-gateways create my-vpn \
    --network my-network \
    --region asia-northeast1
```

VPNゲートウェイに使用するグローバルスタティックIPアドレスを予約します。

```
gcloud compute addresses create vpn-static-ip \
    --region asia-northeast1 
```

実際に予約されたIPアドレスは以下のコマンドの出力から分かります。

```
gcloud compute addresses describe vpn-static-ip \
    --region asia-northeast1
```

ESP、UDPポート500、UDPポート4500をVPNゲートウェイに転送する転送ルールを作成します。
`[VPN_STATIC_IP_ADDRESS]`には、前の手順で予約したスタティックIPアドレスを指定します。

```
gcloud compute forwarding-rules create fr-esp \
    --region asia-northeast1 \
    --address [VPN_STATIC_IP_ADDRESS] \
    --target-vpn-gateway my-vpn \
    --ip-protocol ESP
```

```
gcloud compute forwarding-rules create fr-udp500 \
    --region asia-northeast1 \
    --address [VPN_STATIC_IP_ADDRESS] \
    --target-vpn-gateway my-vpn \
    --ip-protocol UDP \
    --ports 500
```

```
gcloud compute forwarding-rules create fr-udp4500 \
     --region asia-northeast1 \
     --address [VPN_STATIC_IP_ADDRESS] \
     --target-vpn-gateway my-vpn \
     --ip-protocol UDP \
     --ports 4500
```

Cloud Routerを作成します。
AS番号には任意のプライベートASを使えますが、このドキュメントではGCP側に65001、オンプレミス側に65002を使います。

```
gcloud compute routers create my-router \
    --region asia-northeast1 \
    --network my-network \
    --asn 65001
```

VPNトンネルを作成します。
`[CISCO_GW_EXT_IP]`には、オンプレミス側のピアゲートウェイに設定する外部IPアドレスを指定します。
`[SHARED_SECRET]`には、IKEv2認証用の共有秘密鍵を指定します。
静的経路との違いは、トラフィックセレクタを指定する代わりにCloud Routerを指定します。

```
gcloud compute vpn-tunnels create tunnel1 \
    --region asia-northeast1 \
    --ike-version 2 \
    --target-vpn-gateway my-vpn \
    --peer-address [CISCO_GW_EXT_IP] \
    --shared-secret [SHARED_SECRET] \
    --router my-router
```

BGPの仮想インターフェイスを作成します。
BGPピアリング用のIPアドレスにはリンクローカルアドレス用途に予約されている`169.254.0.0/16`の範囲のものが使えますが、ここではGCP側に169.254.0.1、オンプレミス側に169.254.0.2を使うことにします。

```
gcloud compute routers add-interface my-router \
    --interface-name if-1 \
    --ip-address 169.254.0.1 \
    --mask-length 30 \
    --vpn-tunnel tunnel1 \
    --region asia-northeast1
```

BGPピアの設定をします。
前述のとおり、オンプレミス側にはAS番号として65002、BGPピアリング用のIPアドレスとして169.254.0.2を使用します。

```
gcloud compute routers add-bgp-peer my-router \
    --peer-name bgp-peer1 \
    --interface if-1 \
    --peer-ip-address 169.254.0.2 \
    --peer-asn 65002 \
    --region asia-northeast1
```

# オンプレミス側の設定

ここからはCiscoルータの設定をします。
Cisco固有の解説は割愛しますので、適宜Ciscoが提供するドキュメント等をご参照ください。

WANインターフェイスの設定をします。
`[CISCO_GW_EXT_IP]`には、パブリックインターネットに接続するためのグローバルIPアドレスを指定します。
`[CISCO_GW_EXT_MASK]`には、上記グローバルIPアドレスに対応するマスクを指定します。

```
interface GigabitEthernet0/0/0
 ip address [CISCO_GW_EXT_IP] [CISCO_GW_EXT_MASK]
```

LANインターフェイスの設定をします。
今回はオンプレミス側のネットワークを`192.168.1.0/24`としました。

```
interface GigabitEthernet0/0/1
 ip address 192.168.1.254 255.255.255.0
```

IKEv2プロポーザルの設定をします。

```
crypto ikev2 proposal IKEV2_PROPOSAL
 encryption aes-cbc-256 aes-cbc-192 aes-cbc-128
 integrity sha256
 group 16
```

IKEv2プロファイルの設定をします。

```
crypto ikev2 policy IKEV2_POLICY
 proposal IKEV2_PROPOSAL
```

IKEv2の秘密鍵を管理するKeyringを作成します。
`[VPN_STATIC_IP_ADDRESS]`には、GCP側でVPNゲートウェイ用に用意したスタティックIPを指定します。
`[SHARED_SECRET]`には、GCP側で使用したものと同じIKEv2認証用の共有秘密鍵を指定します。

```
crypto ikev2 keyring KEY
 peer GCP
  address [VPN_STATIC_IP_ADDRESS]
  pre-shared-key [SHARED_SECRET]
```

`[VPN_STATIC_IP_ADDRESS]`には、GCP側でVPNゲートウェイ用に用意したスタティックIPを指定します。

```
crypto ikev2 profile IKEV2_PROFILE
 match address local interface GigabitEthernet0/0/0
 match identity remote address [VPN_STATIC_IP_ADDRESS]
 authentication local pre-share 
 authentication remote pre-share 
 keyring local KEY
 lifetime 36000
 dpd 60 5 periodic
```

IPsecのSAライフタイムとリプレイウィンドウサイズを設定します。前者はデフォルト値なので、実際は設定する必要はないです。

```
crypto ipsec security-association lifetime seconds 3600 
crypto ipsec security-association replay window-size 1024
```

トランスフォームセットを設定します。

```
crypto ipsec transform-set TS esp-aes 256 esp-sha-hmac
 mode tunnel
```

IPsecプロファイルを設定します。

```
crypto ipsec profile IPSEC_PROFILE
 set security-association lifetime seconds 3600
 set transform-set TS
 set pfs group16
 set ikev2-profile IKEV2_PROFILE
```

トンネルインターフェイスを設定します。
前述のとおり、オンプレミス側ではBGPピアリング用のIPアドレスとして169.254.0.2を使用します。

```
interface Tunnel1
 ip address 169.254.0.2 255.255.255.252
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source GigabitEthernet0/0/0
 tunnel mode ipsec ipv4
 tunnel destination [VPN_STATIC_IP_ADDRESS]
 tunnel protection ipsec profile IPSEC_PROFILE
```

BGPの設定をします。
前述のとおり、オンプレミス側にはAS番号として65002、GCP側にはAS番号として65001、BGPピアリング用のIPアドレスとして169.254.0.1を使用します。

```
router bgp 65002
 bgp log-neighbor-changes
 neighbor 169.254.0.1 remote-as 65001
 neighbor 169.254.0.1 timers 20 60 60
!
 address-family ipv4
  network 192.168.1.0
  neighbor 169.254.0.1 activate
 exit-address-family
```

# 確認

オンプレミス側のネットワーク(`192.168.1.0/24`)からの通信を許容するファイアウォールルールを設定します。

```
gcloud compute firewall-rules create vpnrule1 \
    --network my-network \
    --allow tcp,udp,icmp \
    --source-ranges 192.168.1.0/24
```

Pingの宛先になるCompute Engineのインスタンスを立ち上げます。このインスタンスのプライベートアドレスは10.0.1.2となりました。

```
gcloud compute instances create "ping-test" \
    --zone "asia-northeast1-a" \
    --machine-type "f1-micro" \
    --subnet "subnet-1" 
```

CiscoルータからLAN側のインターフェイスを送信元として上記のインスタンスにPingして、応答があることを確認します。

```
Router#ping 10.0.1.2 source gi0/0/1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 10.0.1.2, timeout is 2 seconds:
Packet sent with a source address of 192.168.1.254
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 3/4/5 ms
```

暗号化されているかどうかは以下のコマンドで分かります。
Pingに前後してコマンドを実行すると、暗号(encrypt)と復号(decrypt)のカウンタが増えるはずです。

```
Router#sh crypto ipsec sa | inc pkts
    #pkts encaps: 298, #pkts encrypt: 298, #pkts digest: 298
    #pkts decaps: 304, #pkts decrypt: 304, #pkts verify: 304
    #pkts compressed: 0, #pkts decompressed: 0
    #pkts not compressed: 0, #pkts compr. failed: 0
    #pkts not decompressed: 0, #pkts decompress failed: 0
```

# 参考資料

**Cloud VPN の概要**
https://cloud.google.com/compute/docs/vpn/overview?hl=ja

**動的ルートを使用するトンネルの作成**
https://cloud.google.com/compute/docs/vpn/creating-vpn-dynamic-routes?hl=ja