OpenSSHでVPNを構築する(tap編)

sshさえ通ればなんでもできる、とはよく言われることです。勤務先などで、ネットワークの制限が厳しくて、困っている方もいるのではないでしょうか。
最近のOpenSSHは、OSのtun/tapデバイスを利用して、VPNを構築することができます。tunを利用したVPNは解説がいくつかあったのですが、tapを利用してVPNを構築する方法(特に日本語)の解説がみつからなかったので、自分で行った設定をまとめてみます。前提条件は、以下の通りです。

  1. クライアント/サーバの双方がUNIX系である
    • 調べてないのでわかりませんが、tun/tapデバイスを作成する都合上、cygwinおよびcolinuxでは難しいのではないかと思っています。
  2. クライアント/サーバの双方にrootでアクセスできる
    • クライアント側はともかく、サーバ側に必要というのが厳しい条件です。OSと設定によっては非特権ユーザでもtun/tapデバイスを作成することができるようですが、詳しくは調べていません。
    • たとえrootアクセスが可能でも、tun/tapデバイスの作成が許可されない設定になっているVPSなどの仮想環境では不可能なこともあるようです。
  3. サーバ側でiptablesの設定が可能
    • サーバ側のネットワークへのアクセスが必要でないなら不要
    • ブリッジネットワークの設定が可能な人なら不要

さて、tapでは仮想ネットワークが構成されます。ここでは、次のようなネットワーク設定を用いることにします。また、クライアントからサーバを経由してのネットワーク接続ができるような設定にもします。

マシン インターフェース名 IPアドレス ネットマスク
server tap0 192.168.100.1 255.255.255.0
client tap0 192.168.100.2 255.255.255.0

さて、実際にVPN接続の設定に移ります。特権アカウントでの手動ネットワーク設定がかかわるところなので、Debian系列とRedHat系列で設定ファイルが異なります。以下はすべてDebian GNU/Linux (squeeze以降)を仮定します。

rootでのssh接続を可能にする

サーバ側の/etc/ssh/sshd_configの設定変更

最低セキュリティを次の設定まで緩めないといけません。tapだけでなく、tunなVPNも利用する予定があるならPermitTunnelをyesにしましょう。

PermitRootLogin forced-commands-only
PermitTunnel ethernet
サーバ側の/root/.ssh/authorized_keysへ公開鍵の登録

さすがにrootでのパスワード認証を常にOKするのはまずいので、クライアント側でVPN用の鍵を作ります。この鍵は、VPN構築専用で、自動化するためにパスフレーズを空にします。なお、パスフレーズが空でも、秘密鍵さえちゃんと安全に管理しておけば、パスワード認証よりも安全です。今回の事例では、tapvpnという名前にします。

client$ sudo -H ssh-keygen -t rsa -f tapvpn
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/tapvpn):
Enter file in which to save the key (/root/.ssh/tapvpn):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/tapvpn.
Your public key has been saved in /root/.ssh/tapvpn.pub.
The key fingerprint is:
dc:f1:54:b9:1c:21:9d:3a:70:59:b2:50:55:ad:3f:ec root@client
The key's randomart image is:
+--[ RSA 2048]----+
|          ..+===o|
|          ..o== .|
|          .ooo + |
|       . . +o +  |
|        S . .... |
|               o.|
|              . .|
|               E |
|                 |
+-----------------+

公開鍵の内容を一般ユーザ環境にコピーして、tapデバイスの設定と制限を行います。

client$ sudo cp /root/.ssh/tapvpn.pub .
...
client$ cat tapvpn.pub
no-X11-forwarding,no-agent-forwarding,no-pty,tunnel="0",command="/sbin/ifdown tap0; /sbin/ifup tap0" ssh-rsa AAAA....== root@client

次に、上記のように作ったVPN用の公開鍵(/root/.ssh/tapvpn.pub)をサーバにコピーします。一般ユーザならssh-copy-idコマンドで一発なのですが、サーバにrootで直にログインすることはできないですし、一般ユーザでserverにログインします。なお、server上のアカウントではsudoでなんでもできることを仮定します。

client$ scp tapvpn.pub server:
client$ ssh server
server$ echo tapvpn.pub | sudo tee -a /root/.ssh/authorized_keys

なお、authorized_keysにオプションを指定するのもよいでしょう。この段階で、クライアントからrootで認証が成功するかどうかを試しておきましょう。シェルのコンソールはでなくとも、認証が通っていれば成功です。Ctrl-Cで終了してください。

client$ sudo -H ssh -v -i /root/.ssh/tapvpn server

クライアント側での/root/.ssh/configの編集

tapの設定をコマンドラインで行うのは面倒なので、一発接続ができるように設定を行います。/root/.ssh/configを編集します。

client$ sudo cat /root/.ssh/config
...
Host server-vpn
  HostName server
  IdentityFile %d/.ssh/tapvpn
  Tunnel ethernet
  TunnelDevice 0

サーバ側でのネットワーク設定の編集

ここまでで、仮想ネットワークデバイスの準備はできているのですが、IPなどの設定が一切していません。今回は、クライアントからはサーバ側のネットワークにサーバマシンによるiptablesによるNATを使って接続する設定にします。変更するのは/etc/network/interfacesです。

server$ cat /etc/network/interfaces
...
auto eth0
iface eth0 inet static
        address XXX.XXX.XXX.XXX
        netmask YYY.YYY.YYY.YYY
        pre-up echo 1 > /proc/sys/net/ipv4/ip_forward
        pre-up iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j MASQUERADE
...
iface tap0 inet static
        address 192.168.100.1
        netmask 255.255.255.0

クライアント側のネットワーク設定

今回は、ドラスティックに、クライアントマシンからの通信は、すべてサーバ側を経由するようにします。なお、autosshパッケージを利用します。また、やはり/etc/network/interfacesを編集します。サーバの実IPアドレスがXXX.XXX.XXX.XXX、クライアントの(VPN接続前の)ゲートウェイのアドレスをZZZ.ZZZ.ZZZ.ZZZとします。

client$ cat /etc/network/interfaces
...
iface tap0 inet static
        pre-up autossh -f server-vpn
        pre-up sleep 5
        address 192.168.100.2
        netmask 255.255.255.0
        up route add XXX.XXX.XXX.XXX gw ZZZ.ZZZ.ZZZ.ZZZ eth0
        up route add default gw 192.168.100.1 tap0
        up route del default gw ZZZ.ZZZ.ZZZ.ZZZ eth0
        down route add default gw ZZZ.ZZZ.ZZZ.ZZZ eth0
        down route del default gw 192.168.100.1 tap0
        down route del XXX.XXX.XXX.XXX gw ZZZ.ZZZ.ZZZ.ZZZ eth0
        post-down killall autossh

接続のOn/Offの確認とDNSの設定

ここまでの設定で、VPN接続が可能になっているはずです。

client$ sudo ifup tap0
client$ sudo ifdown tap0

設定の確認は、ifconfigや、netstatを利用します。

client$ /sbin/ifconfig -a
client$ /bin/netstat -rn

(追記予定: 2010/09/04) 運用時にroot権限を用いない方法があるので、改定します。