OpenSSH を使って簡易拠点間 VPN
概要
少し業務とは違うところで、NAT配下のマシン同士で、拠点間のVPNもどきが必要になる場面がありました。
単純な Dynamic Port Forwarding で、 SOCKS プロキシを使う手もあったのですが、やはり、ローカルアクセス相当がしたいと。
調べてみると、 OpenSSH 4.3 から、 tun/tap デバイスを使ったレイヤー2およびレイヤー3のトンリングがサポートされていることがわかりました。
OpenSSH を使った簡易 VPN の構築
そこで、実際にやってみたので、メモ代わりに残しておいてみることにしました。
なお、今回はレイヤー2のトンネリングを行うことにしました。
クライアント側での準備
鍵生成
鍵認証を行うため、専用の鍵を生成します。
今回は、ブランクパスフレーズの鍵を生成しました。
また、あえて 1024 ビットの鍵を作っています。
(2048ビットだとトンネリングの負荷が少し高くなりそうだなあと思ったのと、そもそも、要件的に暗号強度は求められていないため)
[root@vpn-client ~]# ssh-keygen -t rsa -b 1024 Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: ee:ae:76:b8:e5:d1:ca:ac:ea:a5:a7:e1:62:ca:55:3d root@vpn-client
鍵をサーバに転送
作った鍵の公開鍵を、サーバ側に転送します。
[root@vpn-client ~]# scp -p ~/.ssh/id_rsa.pub user@vpn-server:/tmp
サーバ側の設定
OpenSSH で tun/tap デバイスによるトンネリングを行うためには、いくつか下準備が必要です。
/etc/ssh/sshd_config を修正
## レイヤー2、およびレイヤー3 の両方のトンネリングを許可する場合 #PermitTunnel yes ## レイヤー2 のみを許可する場合(今回はこれを使用) PermitTunnel ethernet ## レイヤー3 のみを許可する場合 # PermitTunnel point-to-point ## トンネリングには root ログインが必要なため、 ## authorized_keys で記述したコマンドのみ実行できるように制限する PermitRootLogin forced-commands-only
tun/tap デバイスを使えるように
- /etc/modprobe.d/tun.conf を作る
[root@vpn-server ~]# cat /etc/modprobe.d/tun.conf alias netdev-tun0 tun alias netdev-tap0 tun
- # modprobe tun
[root@vpn-server ~]# lsmod | grep tun tun 17127 0
クライアント側の公開鍵を登録
転送しておいた root ログイン用の公開鍵を登録します。
[root@vpn-server ~]# mkdir ~/.ssh [root@vpn-server ~]# chmod 0700 ~/.ssh [root@vpn-server ~]# echo -n 'tunnel="0",command="ifup tap0" ' > ~/.ssh/authorized_keys [root@vpn-server ~]# cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys [root@vpn-server ~]# chmod 0600 ~/.ssh/authorized_keys [root@vpn-server ~]# rm -f /tmp/id_rsa.pub [root@vpn-server ~]# cat ~/.ssh/authorized_keys tunnel="0",command="ifup tap0" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvM58cRnLjQQf+MniEtflzj4oAQNBCxeYv/NW0lsj/UnwYaX0H1z6kWpCWv/jI79zENVsJZ8VQUEa533tEBYZHLGh6xbKSpefFzWCUIEcxTT2Tm18ZJafnyrL36z1kWbnTzATxPkYrsaFeBQoVdmL9PGrTYiUwnoAyBqcLPwpErE= root@vpn-client
ifcfg-tap0 を作成
authorized_keys に記述している通り、 tap0 を ifup できるようにするため、
/etc/sysconfig/network-scripts/ifcfg-tap0 を作成します。
[root@vpn-server ~]# cat /etc/sysconfig/network-scripts/ifcfg-tap0 DEVICE="tap0" BOOTPROTO="none" MTU="1500" NM_CONTROLLED="no" ONBOOT="no" TYPE="Ethernet" IPADDR="192.168.11.254" NETMASK="255.255.255.0"
route-tap0 を作成
さらに、サーバ側 → クライアント側の通信を可能とするため、ルーティングを追加する必要があります。
ifup tap0 時に自動的にルーティングが追加されるように /etc/sysconfig/network-scripts/route-tap0 を作成します。
[root@vpn-server ~]# cat /etc/sysconfig/network-scripts/route-tap0 192.168.12.0/24 via 192.168.11.253 dev tap0
パケット転送を有効化
CentOS のデフォルトでは、パケット転送が無効化されています。
トンネリングされたパケットは tap0 を通して送受信されますが、配下のネットワークに接続されているホストとは ethN を通して通信するため、パケット転送を有効化する必要があります*1。
- /etc/sysctl.conf を編集し、net.ipv4.ip_forward を 1 にする
--- /etc/sysctl.conf.org 2012-02-22 23:47:27.000000000 +0900 +++ /etc/sysctl.conf 2012-11-03 18:54:26.000000000 +0900 @@ -4,7 +4,7 @@ # sysctl.conf(5) for more details. # Controls IP packet forwarding -net.ipv4.ip_forward = 0 +net.ipv4.ip_forward = 1 # Controls source route verification net.ipv4.conf.default.rp_filter = 1
- # sysctl -p で設定を再読み込み
クライアント側の設定
クライアント側でも、おおよそ同じことを設定します。
tun/tap デバイスを使えるように
- /etc/modprobe.d/tun.conf を作る
OpenSSH を使った簡易 VPN の構築 の解説では、
alias tun0 tun alias tap0 tun
という設定例が掲載されていますが、CentOS6.3 で設定し、 /etc/init.d/network restart したところ、
Loading kernel module for a network device with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-tap0 instead
といわれてしまったため、下記のように設定しました。
[root@vpn-client ~]# cat /etc/modprobe.d/tun.conf alias netdev-tun0 tun alias netdev-tap0 tun
- # modprobe tun
[root@vpn-client ~]# lsmod | grep tun tun 22849 0
ifcfg-tap0 を作成
サーバと違うのは、IPADDR。
[root@vpn-client ~]# cat /etc/sysconfig/network-scripts/ifcfg-tap0 DEVICE="tap0" BOOTPROTO="none" MTU="1500" NM_CONTROLLED="no" ONBOOT="no" TYPE="Ethernet" IPADDR="192.168.11.253" NETMASK="255.255.255.0"
route-tap0 を作成
クライアント側 → サーバ側のルーティングを設定
# cat /etc/sysconfig/network-scripts/route-tap0 192.168.10.0/24 via 192.168.11.254 dev tap0
パケット転送を有効化
同様にパケット転送を有効化します*2。
- /etc/sysctl.conf を編集し、net.ipv4.ip_forward を 1 にする
--- /etc/sysctl.conf.org 2012-02-22 23:47:27.000000000 +0900 +++ /etc/sysctl.conf 2012-11-03 18:54:26.000000000 +0900 @@ -4,7 +4,7 @@ # sysctl.conf(5) for more details. # Controls IP packet forwarding -net.ipv4.ip_forward = 0 +net.ipv4.ip_forward = 1 # Controls source route verification net.ipv4.conf.default.rp_filter = 1
- [root@vpn-client ~]# sysctl -p
接続設定を作成
/root/.ssh/config に接続設定を記述します。
[root@vpn-client ~]# cat ~/.ssh/config Host vpn-server HostName server.global Port 12345 User root IdentityFile ~/.ssh/id_rsa Tunnel ethernet TunnelDevice 0:0 PermitLocalCommand yes LocalCommand (echo "Waiting for 10 seconds..."; sleep 10; ifup tap0; ifconfig tap0; route; ping -c3 192.168.10.254; echo; if [ $? -eq 0 ]; then echo "Connect to 192.168.254: SUCCESS"; else echo "Connect to 192.168.10.254: FAILURE"; fi; echo; echo "Press Control-C to exit") &
OpenSSH を使った簡易 VPN の構築 で解説されているとおり、
クライアント側の tap0 は LocalCommand 実行後に作成されます。
そのため、LocalCommand はバックグランドで実行し、スリープを挟むようにします。
リンク先では、3秒にされていますが、一度接続すればコネクションが切れない限りは放っておくものであることを鑑みて、安全側に倒して10秒にしています。
実際に接続してトンネリングを確認する
あとは ssh コマンドで接続するだけです。
上記のように設定した場合、ローカル側で ifup tap0 まで自動で行われます。
[root@vpn-client ~]# ssh vpn-server Waiting for 10 seconds... tap0 Link encap:Ethernet HWaddr 5E:63:33:30:1E:AA inet addr:192.168.11.253 Bcast:192.168.11.255 Mask:255.255.255.0 inet6 addr: fe80::5c63:33ff:fe30:1eaa/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:11 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500 RX bytes:678 (678.0 b) TX bytes:448 (448.0 b) Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.12.0 * 255.255.255.0 U 0 0 0 eth1 192.168.10.0 192.168.11.254 255.255.255.0 UG 0 0 0 tap0 192.168.11.0 * 255.255.255.0 U 0 0 0 tap0 192.168.1.0 * 255.255.255.0 U 0 0 0 eth0 link-local * 255.255.0.0 U 1002 0 0 eth0 link-local * 255.255.0.0 U 1003 0 0 eth1 link-local * 255.255.0.0 U 1008 0 0 tap0 default 192.168.1.254 0.0.0.0 UG 0 0 0 eth0 PING 192.168.10.254 (192.168.10.254) 56(84) bytes of data. 64 bytes from 192.168.10.254: icmp_seq=1 ttl=64 time=4.06 ms 64 bytes from 192.168.10.254: icmp_seq=2 ttl=64 time=2.16 ms 64 bytes from 192.168.10.254: icmp_seq=3 ttl=64 time=2.23 ms --- 192.168.10.254 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 2.168/2.823/4.067/0.880 ms Connect to 192.168.10.254: SUCCESS Press Control-C to exit
サーバマシンの ifconfig, route の結果
[root@vpn-server ~]# ifconfig eth0 Link encap:Ethernet HWaddr 00:0C:29:C1:3B:3D inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fec1:3b3d/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1370 errors:0 dropped:0 overruns:0 frame:0 TX packets:1179 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:157592 (153.8 KiB) TX bytes:169069 (165.1 KiB) eth1 Link encap:Ethernet HWaddr 00:0C:29:C1:3B:47 inet addr:192.168.10.254 Bcast:192.168.10.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fec1:3b47/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:117 errors:0 dropped:0 overruns:0 frame:0 TX packets:152 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:12439 (12.1 KiB) TX bytes:13373 (13.0 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:14 errors:0 dropped:0 overruns:0 frame:0 TX packets:14 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:819 (819.0 b) TX bytes:819 (819.0 b) tap0 Link encap:Ethernet HWaddr 7E:C4:3C:1A:B9:A3 inet addr:192.168.11.254 Bcast:192.168.11.255 Mask:255.255.255.0 inet6 addr: fe80::7cc4:3cff:fe1a:b9a3/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:32 errors:0 dropped:0 overruns:0 frame:0 TX packets:31 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500 RX bytes:2456 (2.3 KiB) TX bytes:2414 (2.3 KiB) [root@vpn-server ~]# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 * 255.255.255.0 U 0 0 0 eth0 192.168.12.0 192.168.11.253 255.255.255.0 UG 0 0 0 tap0 192.168.10.0 * 255.255.255.0 U 0 0 0 eth1 192.168.11.0 * 255.255.255.0 U 0 0 0 tap0 link-local * 255.255.0.0 U 1002 0 0 eth0 link-local * 255.255.0.0 U 1003 0 0 eth1 link-local * 255.255.0.0 U 1008 0 0 tap0 default 192.168.1.254 0.0.0.0 UG 0 0 0 eth0
クライアントマシンの ifconfig, route の結果
[root@vpn-client ~]# ifconfig eth0 Link encap:Ethernet HWaddr 00:1E:C9:6B:5A:C2 inet addr:192.168.1.100 Bcast:192.168.10.255 Mask:255.255.255.0 inet6 addr: fe80::21e:c9ff:fe6b:5ac2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:4626 errors:0 dropped:0 overruns:0 frame:0 TX packets:3220 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:506625 (494.7 KiB) TX bytes:413131 (403.4 KiB) Interrupt:21 Memory:fe9e0000-fea00000 eth1 Link encap:Ethernet HWaddr 00:A0:B0:A5:84:A4 inet addr:192.168.12.254 Bcast:192.168.12.255 Mask:255.255.255.0 inet6 addr: fe80::2a0:b0ff:fea5:84a4/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:22 errors:0 dropped:0 overruns:0 frame:0 TX packets:12 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:7454 (7.2 KiB) TX bytes:828 (828.0 b) Interrupt:16 Base address:0x6f00 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b) tap0 Link encap:Ethernet HWaddr 5A:F1:0D:F0:93:27 inet addr:192.168.11.253 Bcast:192.168.11.255 Mask:255.255.255.0 inet6 addr: fe80::58f1:dff:fef0:9327/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:31 errors:0 dropped:0 overruns:0 frame:0 TX packets:32 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500 RX bytes:2414 (2.3 KiB) TX bytes:2456 (2.3 KiB) [root@vpn-client ~]# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.12.0 * 255.255.255.0 U 0 0 0 eth1 192.168.10.0 192.168.11.254 255.255.255.0 UG 0 0 0 tap0 192.168.11.0 * 255.255.255.0 U 0 0 0 tap0 192.168.1.0 * 255.255.255.0 U 0 0 0 eth0 link-local * 255.255.0.0 U 1002 0 0 eth0 link-local * 255.255.0.0 U 1003 0 0 eth1 link-local * 255.255.0.0 U 1009 0 0 tap0 default 192.168.1.254 0.0.0.0 UG 0 0 0 eth0
クライアント側ネットワークのホスト (192.168.12.100) から、サーバ側ネットワークのホスト (192.168.10.100) に tracert してみる
C:\Documents and Settings\user>tracert 192.168.10.100 Tracing route to 192.168.10.100 over a maximum of 30 hops 1 <1 ms <1 ms <1 ms 192.168.12.254 2 2 ms 2 ms 2 ms 192.168.11.254 3 2 ms 2 ms 2 ms 192.168.10.100 Trace complete.
サーバ側ネットワークのホスト (192.168.10.100) から、クライアント側ネットワークのホスト(192.168.12.100) に traceroute してみる
[root@server-host ~]# traceroute -T 192.168.12.100 traceroute to 192.168.12.10 (192.168.12.10), 30 hops max, 60 byte packets 1 192.168.10.254 (192.168.10.254) 0.212 ms 0.135 ms 0.104 ms 2 192.168.11.253 (192.168.11.253) 5.481 ms 6.058 ms 6.755 ms 3 192.168.12.100 (192.168.12.100) 7.385 ms 8.171 ms 8.408 ms
トンネリングを終了するには
入力待ちとなっているコンソールで、 Control-C を入力することで終了します。
tap0 デバイスは自動的に削除されるので、特に後始末をする必要はありません。
Connect to 192.168.10.254: SUCCESS Press Control-C to exit ^CKilled by signal 2.