strongSwan を使って AWS VPC 間で Site-to-Site VPN を構築してみた
いわさです。
先日ですが Site-to-Site VPN の検証をしたい時がありました。
オンプレミス環境が用意できない時などはこれまで私は Azure と AWS の間で Site-to-Site VPN を構築したりしていました。
ただ、最近 Azure サブスクリプションと連携させるのも若干面倒になってきたので検証環境であれば AWS 内だけで簡潔させたいところです。
VPC と VPC で Site-to-Site VPN を構築したいところですが、カスタマーゲートウェイデバイスを AWS Site-to-Site VPN に指定することはできないので、カスタマーゲートウェイ用の環境が必要になります。
VyOS を使った記事が過去にはあります。
今回私は strongSwan を使って同じようなことをやる機会がありました。なんで strongSwan を使ったかというと AWS 公式でも紹介されていたからです。
せっかくなのでその様子を紹介します。
やろうとしていること
今回は東京リージョンに VPC を2つ用意します。片方を AWS 側(10.0.0.0/16)、もう片方をオンプレ側(10.100.0.0/16)想定とします。
オンプレ側のパブリックサブネットに strongSwan を入れた EC2 を置き、Elastic IP を付けます。この EIP をカスタマーゲートウェイの IP として登録します。
オンプレ側にもう1台、strongSwan EC2 の奥にいる「拠点ホスト役」の EC2 を置きます。

strongSwan はオープンソースで、VPN ソフト側の追加費用はありません。
構築してみる
最初 Amazon Linux 2023 で組もうとしたのですが、strongSwan が標準リポジトリに入っていませんでした。
$ dnf list --available strongswan
Error: No matching Packages to list
EPEL を足せば入りそうなのですが、面倒だったので今回は Ubuntu 24.04 の EC2 にしました。こちらは apt で一発でした。
$ apt-get install -y strongswan strongswan-swanctl
$ swanctl --version
strongSwan swanctl 5.9.13
そして strongSwan EC2 は、単なるトンネルの終端ではなく「拠点ルーター」として振る舞わせたいので、IP フォワーディングを有効化しておきます。
$ sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
オンプレ側のルートテーブルには、オンプレ EC2 が AWS(10.0.0.0/16)宛のパケットを strongSwan EC2 へ向けるよう、10.0.0.0/16 のターゲットを strongSwan EC2 の ENI にしたルートを追加します。これでオンプレ EC2 から AWS 側に流れてくれるはず。

AWS 側は仮想プライベートゲートウェイ(VGW)を VPC にアタッチし、カスタマーゲートウェイには strongSwan EC2 の EIP を指定します。
そして VPN 接続は静的ルーティングで作り、リモート側 CIDR にオンプレ CIDR の 10.100.0.0/16 を登録しました。

VPN 接続を作ると、AWS 側トンネルの外部 IP と事前共有鍵(PSK)が払い出されるので、続いてこちらを strongSwan の設定に反映させる必要があります。
今回インストールされた strongSwan は v5.9.13 でした。最新は 6.1.0 みたいなのですが、Ubuntu 24.04 だとデフォルトでこれがインストールされました。まぁ今日はなんでも良いです。
strongSwan 5.9 系は swanctl.conf で設定します。
connections {
aws1 {
version = 2
local_addrs = 10.100.1.220
remote_addrs = 198.51.100.20
local {
auth = psk
id = 203.0.113.10
}
remote {
auth = psk
id = 198.51.100.20
}
children {
net {
local_ts = 10.100.0.0/16
remote_ts = 10.0.0.0/16
start_action = start
dpd_action = restart
esp_proposals = aes128-sha1-modp1024
}
}
proposals = aes128-sha1-modp1024
dpd_delay = 10s
}
}
secrets {
ike-aws1 {
id = 198.51.100.20
secret = "..."
}
}
暗号化する範囲を決める local_ts / remote_ts は、片方の IP ではなくサブネット全体(10.100.0.0/16 と 10.0.0.0/16)にしています。
最初local_addrs に EIP(203.0.113.10)を書いたところ、トンネルが上がらず、ログに Network is unreachable のエラーが出てました。
[NET] sending packet: from 203.0.113.10[500] to 198.51.100.20[500] (336 bytes)
[NET] error writing to socket: Network is unreachable
OS が確認できるのはプライベート IP の 10.100.1.220 なので EIP だと存在しない送信元 IP でバインドしようとしていたみたいです。
local_addrs をプライベート IP に直して、id だけ EIP のままにしたところいけました。
その後設定をロードして確認してみます。
$ swanctl --list-sas
aws1: #2, ESTABLISHED, IKEv2
local '203.0.113.10' @ 10.100.1.220[4500]
remote '198.51.100.20' @ 198.51.100.20[4500]
AES_CBC-128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
net: #1, reqid 1, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-128/HMAC_SHA1_96
local 10.100.0.0/16
remote 10.0.0.0/16
ESTABLISHED になり INSTALLED になってますね。
AWS 側のトンネルステータスも確認してみましょう。

トンネル1が「アップ」になりました。
今回 strongSwan 側でトンネル1しか設定していないのでトンネル2がダウンしています。これは期待どおりなので OK です。
トンネルがアップになったので相互に疎通確認してみます。
オンプレ EC2(10.100.1.50)から AWS 側 EC2(10.0.1.12)へ ping してみます。
$ ping -c 4 10.0.1.12
64 bytes from 10.0.1.12: icmp_seq=1 ttl=126 time=3.42 ms
64 bytes from 10.0.1.12: icmp_seq=2 ttl=126 time=3.34 ms
--- 10.0.1.12 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss
いけましたね。
今度は逆に、AWS 側 EC2(10.0.1.12)からオンプレ EC2(10.100.1.50)へ ping してみます。
$ ping -c 4 10.100.1.50
64 bytes from 10.100.1.50: icmp_seq=1 ttl=63 time=3.45 ms
64 bytes from 10.100.1.50: icmp_seq=2 ttl=63 time=3.46 ms
--- 10.100.1.50 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss
こちらもいけました。
さいごに
本日は strongSwan を使って AWS VPC 間で Site-to-Site VPN を構築してみました。
オンプレハイブリッドなマルチテナント SaaS の検証のために AWS PrivateLink とかリソースゲートウェイを使いたくて、その流れでオンプレ相当の環境を用意したかったのですが、これでいけそうです。
また、カスタマーゲートウェイの設定を行うことってあまり無かったのですが良い経験になりました。







