AWSのVPCにはVPN機能がついているので、利用すると社内など任意のサブネットとVPCの間を、Privateアドレスで暗号化通信できるようになります。
通常このVPC VPNは、ハードウェアルーターを用いて接続するべく、一般的なルータの設定ファイルを配布してくれる至れり尽くせりな環境なのですが、ウチは貧乏でLinuxが大好きなので、
Debian Wheezyで接続を試みるのでした。
2つの方法
Linuxでは私が最初に構想した、綺麗で完全な冗長化構成はできないことがわかり、妥協案として2つの構成案ができたため、2つのエントリに分けて書くことにします。その2つの案とは、で、まずは概要と、前者の構築手順を紹介し、
後者は2つ目のエントリとします。
全体図
まずはVPNに必要な登場人物とネットワーク情報です。Customer側は人によって異なるところなので簡単に説明しておくと、
Customer VPN自体の冗長化は今回は省略します。
必要ならLVSとmonitなどの組み合わせで実現可能なはずです。
使用するソフトウェア
最初はOpenSWANでやろうとしたのですが、どうやっても最終形態に届きそうになかったのですぐ諦めました。例によってネットワーク知識が非常に乏しいなりに、簡単に役割を説明をしてみます。
(※それぞれの詳細はググってね!)
setkey (ipsec-tools)
IPsecを利用する通信を、セキュリティポリシーという名目で指定します。
詳しくはSPAやSPDでググるとよいですが、簡潔にはsrc/dstの組の許可という感じです。
Tunnelを掘るためにも必要ですし、VPN確立後に通るClient間のFORWARDパケットも関係します。
racoon
VPC G/WとTunnelの情報、鍵、暗号化方式などを指定してVPN接続を確立します。OpenVPNと違って、Tunnel Addressは自動的に割り当ててくれないので、eth0 などのaliasとして自分で割り当てる必要があります。
setkeyとracoonの設定が正しければ、両方を有効にした時点で
VPC側の2つのTunnel AddressにPingを飛ばすことができます。
quagga
routeやip rで見える、通常のルーティングを動的に設定します。目的は、EC2サブネットへのG/Wを2つのTunnelどちらかに設定することで、両方とも生きていればどちらかを選び、利用中のTunnelが落ちれば、自動的にもう片方に切り替えてくれます。
VPC Management Consoleでやっておくこと
VPCでVPN付きPrivateNetworkを作成して、そこにEC2を作成する、までは済んでいるとします。それ以降で注意すべき点がいくつかあるので、上手くいかない時はこの辺を点検してみてください。VPNのCustomerGateway
このCustomerGatewayとは、VPC G/Wから見たCustomer側のSourceAddressになります。上の全体図で言えばNATしてWANに出ていく 1.2.3.4 になります。CustomerVPNサーバがGlobalAddressを持っていれば、それになります。最初にracoonがTunnelを掘る時、VPC G/W に UDP:500 とかで繋ぐのですが、CustomerGatewayに登録したSourceAddressでないと、そのレスポンスを返してくれないようになっています。
VPN Routing
quaggaにより動的ルーティングにするので、staticではなくUse dynamic routing (requires BGP) を選択してください。
staticにしておくと、ダウンロードする設定ファイルにBGP関連が載りません。
Security Group
接続したいEC2インスタンスが所属するSecurityGroupを編集し、INPUTのICMP, SSH辺りを通しておいてください。
最初は src 0.0.0.0/0 にしておいて、ひと通り成功してから制限すればよいです。
VPN設定のダウンロード
VPN Connections => Download Configuration でGenericの設定をダウンロードしておきます。
この中の設定値を用いて、各種設定をしていきます。
(※後述する構築スクリプトに使うことで全自動で構築できます)
Customerの環境でやっておくこと
CustomerVPNからVPC G/Wに対して、以下の通信が通れる必要があります。CustomerVPNがGlobalAddressを持っていればOUTPUTの許可になりますが、今回は他サーバにFORWARDしてもらってるので、途中のG/Wでこのように許可しました。
1 2 3 |
iptables -A FORWARD -p udp --dport 500 -j ACCEPT iptables -A FORWARD -p tcp --dport 500 -j ACCEPT iptables -A FORWARD -p esp -j ACCEPT |
CustomerVPNの構築
では1つ目である、綺麗な冗長化+VPNサーバでのNAT 構成でいきます。各設定の設定名:値は、ダウンロードした Generic設定を参照してください。
sysctlの設定
他クライアントのG/Wとなるので、FORWARDを許可しておきます。/etc/sysctl.d/vpn.conf
1 2 3 4 5 6 7 8 9 10 11 |
net.ipv4.ip_forward = 1 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.conf.eth0.send_redirects = 0 net.ipv4.conf.lo.send_redirects = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.eth0.accept_redirects = 0 net.ipv4.conf.lo.accept_redirects = 0 |
反映します。
1 |
service procps restart |
Clientのルーティング異常対策
send_redirects を 0 に設定している理由は、1 のままだとquaggaによりルーティングが書き換えられた時に、Clientのルーティングキャッシュが勝手に書き換わって通信できなくなることがあり、それを防ぐためです。例えばこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 |
# Clientに Customer => VPC のrouteを設定しておく route add -net 10.100.1.0/24 gw 172.30.4.11 # 正常なルーティングキャッシュはこの状態 netstat -nrC | grep 10.100 (正) 172.30.4.20 10.100.1.50 172.30.4.11 1500 0 0 eth0 # quaggaによりVPNサーバのルーティングが切り替わった後のClientのルーティングキャッシュ # 行き先がVPNじゃなくDefaultG/Wになったり (誤) 172.30.4.20 10.100.1.50 172.30.4.1 1500 0 0 eth0 # ClientではありえないTunnelAddressになる (誤) 172.30.4.20 10.100.1.50 169.254.252.5 1500 0 0 eth0 |
パッケージのインストール
入れます。
1 |
apt-get install ipsec-tools racoon quagga |
racoonのログ設定
ログディレクトリを作成します。
1 |
mkdir /var/log/racoon |
デーモンにオプションをくっつけます。
/etc/default/racoon
1 |
RACOON_ARGS="-l /var/log/racoon/racoon.log" |
ログローテートの設定をしておきます。(めんどくて copytruncate)
/etc/logrotate.d/racoon
1 2 3 4 5 6 7 8 |
/var/log/racoon/racoon.log { rotate 10 daily compress missingok notifempty copytruncate } |
鍵の設定
VPC G/WのアドレスとPre-Shared Key の組を2つ書いておきます。/etc/racoon/aws-vpc.txt
1 2 |
27.0.1.16 BaerPBBt.ZkyPL.zgAyqkogX94Upprwm 27.0.1.144 yBv.gqPa0EcTsA9HSTcNfpnwePKtoxdn |
racoonの設定
racoonの設定は色々あるように見えて、相手がVPCである以上はほぼ固定です。リージョンが変わると、G/WやTunnelSubnetが若干変わるみたいです。
/etc/racoon/racoon.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
log notify; path pre_shared_key "/etc/racoon/aws-vpc.txt"; remote 27.0.1.16 { exchange_mode main; lifetime time 28800 seconds; generate_policy off; proposal { encryption_algorithm aes128; hash_algorithm sha1; authentication_method pre_shared_key; dh_group 2; } } remote 27.0.1.144 { exchange_mode main; lifetime time 28800 seconds; generate_policy off; proposal { encryption_algorithm aes128; hash_algorithm sha1; authentication_method pre_shared_key; dh_group 2; } } sainfo address 169.254.252.2/30 any address 169.254.252.1/30 any { pfs_group 2; lifetime time 3600 seconds; encryption_algorithm aes128; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 169.254.252.6/30 any address 169.254.252.5/30 any { pfs_group 2; lifetime time 3600 seconds; encryption_algorithm aes128; authentication_algorithm hmac_sha1; compression_algorithm deflate; } |
ipsec-tools の設定
ipsec-tools はデーモンはなく、initスクリプトで setkey を実行しているだけです。Tunnel同士の通信と、CustomerVPN<=>EC2間の、2Tunnel分を許可しています。
/etc/ipsec-tools.d/vpc.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/sbin/setkey -f flush; spdflush; # Tunnel1 spdadd 169.254.252.2/30 169.254.252.1/30 any -P out ipsec esp/tunnel/172.30.4.11-27.0.1.16/require; spdadd 169.254.252.1/30 169.254.252.2/30 any -P in ipsec esp/tunnel/27.0.1.16-172.30.4.11/require; spdadd 169.254.252.2/30 10.100.0.0/16 any -P out ipsec esp/tunnel/172.30.4.11-27.0.1.16/require; spdadd 10.100.0.0/16 169.254.252.2/30 any -P in ipsec esp/tunnel/27.0.1.16-172.30.4.11/require; # Tunnel2 spdadd 169.254.252.6/30 169.254.252.5/30 any -P out ipsec esp/tunnel/172.30.4.11-27.0.1.144/require; spdadd 169.254.252.5/30 169.254.252.6/30 any -P in ipsec esp/tunnel/27.0.1.144-172.30.4.11/require; spdadd 169.254.252.6/30 10.100.0.0/16 any -P out ipsec esp/tunnel/172.30.4.11-27.0.1.144/require; spdadd 10.100.0.0/16 169.254.252.6/30 any -P in ipsec esp/tunnel/27.0.1.144-172.30.4.11/require; |
quaggaの設定
色々あるけど bgpd と zebra さんを有効にします。/etc/quagga/daemons
1 2 |
zebra=yes bgpd=yes |
Quaggaの前身がZebraだとかかんとか。で基本設定になります。
/etc/quagga/zebra.conf
1 2 3 4 5 6 7 8 9 |
hostname gedowfather-debian7-01 password QuaggaPassword enable password QuaggaPassword ! ! list interfaces interface eth0 interface lo ! line vty |
BGPの設定をします。
/etc/quagga/bgpd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
hostname gedowfather-debian7-01 password QuaggaPassword enable password QuaggaPassword ! log file /var/log/quagga/bgpd.log !debug bgp events !debug bgp zebra debug bgp updates ! router bgp 65000 bgp router-id 172.30.4.11 network 169.254.252.2/30 network 169.254.252.6/30 ! Routing for VPC to CUSTOMER (see Route Tables on VPC Console) ! if CustomerVPN forward using NAT, this is unnecessary. ! network 172.30.4.11/22 ! ! aws tunnel #1 neighbor neighbor 169.254.252.1 remote-as 10124 ! aws tunnel #2 neighbor neighbor 169.254.252.5 remote-as 10124 ! line vty |
Tunnelアドレスの設定
Tunnelアドレスは自主的にエイリアスとして設定します。
1 2 |
ip addr add 169.254.252.2/30 dev eth0 ip addr add 169.254.252.6/30 dev eth0 |
OS起動時にも設定されるようにします。
OpenStackのVMなのでDHCPですが気にしないでください。
/etc/network/interfaces
1 2 3 4 5 |
allow-hotplug eth0 iface eth0 inet dhcp pre-up ifconfig eth0 mtu 9000 post-up ip addr add 169.254.252.2/30 dev eth0 post-up ip addr add 169.254.252.6/30 dev eth0 |
VPN開始
まずsetkey, racoonを開始します。起動後はTunnelの接続チェックします。
1 2 3 4 5 6 7 8 9 10 11 12 |
service setkey restart service racoon restart # VPC側のTunnelへPing ping 169.254.252.1 ping 169.254.252.5 # 失敗したら setkey の確認やログ確認 setkey -D setkey -D -P racoonctl show-sa ipsec less /var/log/racoon/racoon.log |
Tunnelが通れば、quaggaを起動してEC2へのルーティングを確保します。
少し時間がかかる場合がありますが、成功すればCustomerVPNサーバからEC2へPingが飛ぶはずです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
service quagga restart # 確認 # - EC2へPing # - ルーティングにEC2 Subnetゆきで VPC Tunnel 1 or 2 が追加されていること # ex) 10.100.0.0/16 via 169.254.252.5 dev eth0 proto zebra # - > show bgp neighbors で BGP state = Established になること # なっていれば、VPC ConsoleのVPN Connectionsで緑になっているはずです ping 10.100.1.50 ip r route -n nc localhost 2605 Password: QuaggaPassword > show ip bgp > show bgp neighbors |
from Client to EC2 with NAT
ここからさらに、Customer ClientからEC2へ接続できるようにします。CustomerVPNのiptables
G/WとなるのでFORWARDを許可し、NATして出て行くようにします。これにより、EC2側ではSrcが 169.254.252.2 or 169.254.252.6 に見えます。
1 2 |
iptables -t nat -A POSTROUTING -d 10.100.0.0/16 -j MASQUERADE iptables -A FORWARD -d 10.100.0.0/16 -j ACCEPT |
Customer Clientのルーティング
EC2ゆきの接続を、VPNサーバに転送をお願いするように設定します。起動時にも有効にする場合は /etc/network/if-up.d/ のどこかに書いておいてください。
1 |
route add -net 10.100.0.0/16 gw 172.30.4.11 |
これで、ClientからEC2にPingできるようになります。
VPNやEC2上で tcpdump -i any -n icmp とか出しておくとよいです。
NAT構成の構築スクリプト
今回のNAT型の構築はスクリプトにしてあります。VPC Consoleから落としたGenericのVPN Configurationを指定して実行するだけで、VPC VPNとの接続ができます。こんな感じです。
1 2 3 4 5 |
./aws_vpn_between_vpcgw_and_debian_with_nat.sh General.txt ping 169.254.252.1 ping 169.254.252.5 ping 10.100.1.50 |
これでPrivate上のEC2にSSHするという目的は達成していますが、NATするとEC2側から見た時のSrcアドレスがCustomerVPNのTunnelアドレスになってよろしくないので、ここからNATを外して利用する方法を次のエントリとします。