OpenBlocks のおと

vtun

初代OpenBlockSでvtunを利用した設定については昔のOpenBlocksのおと参照。 OpenBlockSSでも構築していてバイナリも置いてありますが、設定方法については詳しく述べられていません。 vtunのencryptオプションによる暗号化は弱いので定常的なVPNとして利用するには別途暗号化に関して工夫をする必要があります。

OpenVPN

OpenVPN公式サイトをまず訪れて下さい。
以下の例では、OpenBlockSSにつながったネットワークのグローバルIPが1.2.3.4であるとし、
FreeBSDにつながったネットワークのグローバルIPが5.6.7.8、DMZでのIPが10.20.30.40という環境であるとします。

OpenSSLを使ったCAの構築

セキュア Web サーバ構築(+SSL)googleでの検索結果 を参照して下さい。
セキュリティの観点から言うと、認証局の秘密鍵が奪われるとその認証局で発行された全ての証明書の信頼性がなくなってしまうので 認証局(CA)自体はVPNを張るマシンとは別になっていて、可能であればnetworkから到達できないぐらい方が望ましいです。 が、双方固定IPという環境であれば証明書を認証手段として使うのではなくIPアドレスを信じるという手もあります。その辺は一口で語れないのでとりあえず省略します。

認証局の証明書はcacert.pemとして作成されますが、他のメジャーな認証局証明書のかたまり ca-bundle.crt に同じフォーマットで埋め込むための ファイルをついでに作ります。ca.hoge.com.pemという感じのファイル名にした後、以下のシェルスクリプトを実行すると ca.hoge.com.crtの出来上がりです。

#!/bin/sh
HOST=ca.hoge.com

cp /dev/null ${HOST}.crt
echo  >> ${HOST}.crt
echo Hoge CA >> ${HOST}.crt
echo ========================================= >> ${HOST}.crt
openssl x509 -fingerprint -noout -in ${HOST}.pem >> ${HOST}.crt
echo PEM Data: >> ${HOST}.crt
cat ${HOST}.pem >> ${HOST}.crt
openssl x509 -noout -text -in ${HOST}.pem >> ${HOST}.crt

FreeBSD側でのOpenVPNサーバ構築

証明書の作成

OpenVPNで利用する証明書は大雑把に言ってapache用の証明書と同じものです。 うちでは通常以下のようなMakefileを作成して、env HOST=vpn.hoge.com make csrとやってCSR(証明書要求)を作成し、 秘密鍵ファイルをvpn.hoge.com.keyCAにて署名。 してもらった証明書をvpn.hoge.com.pemとして保存しています。
CSRの作成途中色々パラメーターを聞かれますが、OpenVPNで利用する限りどんな文字列でもかまいません。

csr::
  openssl req -new -nodes -newkey rsa:1024 -sha1 -keyform PEM -keyout ${HOST}.key -outform PEM -out ${HOST}.csr
  chmod 600 ${HOST}.key

dertopem::
  openssl x509 -inform der -outform pem -in ${HOST}.cer -out ${HOST}.pem

CSRをCAで署名してもらった結果がDERフォーマットのvpn.hoge.com.cerファイルの場合は、env HOST=vpn.hoge.com make dertopem として変換することもありますが、この作業は多分不要です。

OpenVPN(TLSサーバモード)の起動

以下のような感じのスクリプトを /usr/local/etc/rc.d/ に置きます。ログはsyslogに書き込まれますが、daemon facilityを取るようにしていないとダメかもしれません。

  /usr/local/sbin/openvpn --remote 1.2.3.4 --dev tun1 \
  --ifconfig 192.168.255.1 192.168.255.2 \
  --tls-server --dh /etc/ssl/certs/dh1024.pem --ca /etc/ssl/certs/ca.hoge.com.crt \
  --cert /usr/local/etc/openvpn/vpn.hoge.com.cer --key /usr/local/etc/openvpn/vpn.hoge.com.key \
  --reneg-sec 3600 --udp-mtu 1400 \
  --verb 3 \
  --up /usr/local/etc/openvpn/zebrarestart.sh \
  --down /usr/local/etc/openvpn/zebrarestart.sh \
  --daemon --writepid /var/run/openvpn.pid

dh1024.pemはopenssl dhparam -out dh1024.pem 1024で作成したファイルです。
/usr/local/etc/openvpn/zebrarestart.shの中身は/usr/local/sbin/zebractl restartです。

ファイアウォールの設定

OpenVPNを動かしているサーバがファイアウォールの後ろにある場合、UDPのポート5000に対するパケットを転送する必要があります。 ipfilterを使っている場合はipnat.confに以下のような感じのエントリになります。

rdr tun0 5.6.7.8/32 port 5000 -> 10.20.30.40 port 5000 udp

OpenVPNの--chrootオプションを使うよう変更

上記の設定でも利用可能ですが、 --chrootを使うと、chrootしたディレクトリ以下しかアクセスできなくなるため、万一openvpnにセキュリティホールがあっても問題が起きにくくなります。 以下のコマンドを使って、chroot後のディレクトリ構成を作成。

# CHROOT=/local/chroot/vpn
# mkdir -p $CHROOT
# mkdir -p $CHROOT/etc
# mkdir -p $CHROOT/var/run
# (cd /; ls -1 bin/sh sbin/ifconfig dev/null dev/random dev/tun0 dev/tun1 dev/tun2 dev/tun3 dev/tun4 dev/urandom dev/zero | cpio -pdm $CHROOT)
# echo 'openvpn:*:122:' > $CHROOT/etc/group
# echo 'openvpn:*:122:122::0:0:OpenVPN:/:/nonexistent' > $CHROOT/etc/master.passwd
# /usr/sbin/pwd_mkdb -p -d $CHROOT/etc $CHROOT/etc/master.passwd
# mkdir -p $CHROOT/certs

syslogdの起動時に-l /local/chroot/vpn/var/run/log オプションを追加して、chroot後に /var/run/log となる位置にソケットを作っておきます。 また、以下のopenvpn起動時に指定する証明書等のファイルを $CHROOT/certs に移動します。

  /usr/local/sbin/openvpn --remote 1.2.3.4 --dev tun1 \
  --port 5000 \
  --ifconfig 192.168.255.1 192.168.255.2 \
  --chroot /local/chroot/vpn \
  --tls-server --dh /certs/dh1024.pem --ca /certs/ca.hoge.com.crt \
  --cert /certs/vpn.hoge.com.cer --key /certs/vpn.hoge.com.key \
  --reneg-sec 3600 --udp-mtu 1400 \
  --verb 3 \
  --daemon --writepid /var/run/openvpn.pid \
  --ping 30 --ping-restart 90 \
  --single-session \
  --user openvpn --group openvpn \
  --persist-key --persist-tun --persist-local-ip --persist-remote-ip

--user, --group を指定した場合は --persist-??? を指定しないとセッションの再接続がうまくいかないようです。 また、--single-session を指定した場合は、--ping, --ping-restart を指定して自動的にセッションの再接続をするようにしないと、 クライアント側からのセッションの再接続の要求に応じられなくなります。

OpenVPNの--tls-verifyオプションを使うよう変更

OpenSSL付属の verify-cn はperlですが、shだけで動いてくれないとchroot環境の整備が大変なので $CHROOT/sbin/verify-cn として以下のようなスクリプトを作成しました。

#!/bin/sh

# Verify X509 Common Name
#
# Return 0 if cn matches the common name component of X509_NAME_oneline,
# 1 otherwise.
#
# For example in openvpn, you could use the option:
#  --tls-verify "./verify-cn Test-Client"

# check number of arguments
case $# in
  3)
    ;;
  *)
    exit 1;
    ;;
esac

cn=$1
depth=$2
x509="$3/"

case $depth in
  0)
    case $x509 in
      */CN=$cn/* )
        exit 0;
        ;;
      *)
        exit 1;
        ;;
    esac
    ;;
  *)
    exit 0;
    ;;
esac
exit 0;

openvpnの起動は以下のようになります。--tls-verifyの引数で、カンマの後に続ける文字列はクライアント用証明書作成の時に指定したCommonNameです。

  /usr/local/sbin/openvpn --remote 1.2.3.4 --dev tun1 \
  --port 5000 \
  --ifconfig 192.168.255.1 192.168.255.2 \
  --chroot /local/chroot/vpn \
  --tls-server --dh /certs/dh1024.pem --ca /certs/ca.hoge.com.crt \
  --cert /certs/vpn.hoge.com.cer --key /certs/vpn.hoge.com.key \
  --tls-verify /sbin/verify-cn,openblockss.hoge.com \
  --reneg-sec 3600 --udp-mtu 1400 \
  --verb 3 \
  --daemon --writepid /var/run/openvpn.pid \
  --ping 30 --ping-restart 90 \
  --single-session \
  --user openvpn --group openvpn \
  --persist-key --persist-tun --persist-local-ip --persist-remote-ip

OpenBlockSS側でのOpenVPNクライアント構築

カーネルへのtunデバイスの組み込み

昔のOpenBlocksのおと参照。ファームウェア自体も置いてあります。
将来的にはopenvpnをramdiskに置いたバージョンを作ってここに置きたいところ。そうなればCFカードも不要になるので。

OpenVPNバイナリの設置

バイナリをそのまま置いておきます。圧縮もしていません。コンパイルはHDD付OpenBlockSSで行いました。(2002.8.13: OpenSSL 0.9.6g に更新)
openvpn 1.2.1 実行ファイル本体 MD5 (openvpn) = b8ebdbfdc1bcf74b487d887c7661cdc5
libcrypto.so.0.9.6 OpenSSL ダイナミックリンクライブラリ MD5 (libcrypto.so.0.9.6) = 31940a2f74064b78dd615923363220f2
libssl.so.0.9.6 OpenSSL ダイナミックリンクライブラリ MD5 (libssl.so.0.9.6) = 05dc6cbd21c100eb7e3a6c42372494d8
openssl-0.9.6g-openblocks.tar.gz ソース+コンパイル結果 MD5 (openssl-0.9.6g-openblocks.tar.gz) = a36b72e006a90ef77acea3a0ede272d0
ldconfig ダイナミックリンクライブラリ設定ツール MD5 (ldconfig) = dfc2ccb02bc1f115a9661f486e09b1da
うちの openvpn でlddを取った結果は以下の通りです。

[root@openblocks sbin]# ldd openvpn
        libssl.so.0.9.6 => /local/lib/libssl.so.0.9.6 (0x0ffad000)
        libcrypto.so.0.9.6 => /local/lib/libcrypto.so.0.9.6 (0x0fe99000)
        libc.so.6 => /lib/libc.so.6 (0x0fd81000)
        libdl.so.2 => /lib/libdl.so.2 (0x0fd5e000)
        /lib/ld.so.1 => /lib/ld.so.1 (0x30000000)

/local/lib においてシンボリックリンクを作成します。リンク作成後の状態は以下の通りです。

[root@openblocks sbin]# ls -l /local/lib
total 1569
lrwxrwxrwx   1 root     root           14 Dec 26  2001 libcrypto.so -> libcrypto.so.0
lrwxrwxrwx   1 root     root           18 Dec 26  2001 libcrypto.so.0 -> libcrypto.so.0.9.6
-r-xr-xr-x   1 root     root      1111432 Dec 25  2001 libcrypto.so.0.9.6
lrwxrwxrwx   1 root     root           11 Dec 26  2001 libssl.so -> libssl.so.0
lrwxrwxrwx   1 root     root           15 Dec 26  2001 libssl.so.0 -> libssl.so.0.9.6
-r-xr-xr-x   1 root     root       230800 Dec 25  2001 libssl.so.0.9.6

ld.so.confを以下のようにした後、起動時にldconfig /etc/ld.so.confが実行されるようにします。

/usr/lib
/lib
/local/lib
/usr/local/lib

証明書の作成

FreeBSDのサーバ用証明書とほぼ同様ですが、パラメータのうちCN(=CommonName)と生成されるファイル名だけ変えたものを作成します。 サーバ側の--tls-verifyの引数で指定するCN(=CommonName)はここで指定した文字列ですなので、必要な場合はメモを取って下さい。
env HOST=openblockss.hoge.com make csrとやってCSR(証明書要求)を作成して、 CAにて署名
出来上がった秘密鍵ファイルopenblockss.hoge.com.keyと証明書openblockss.hoge.com.pemをOpenBlockSSに転送しますが、 特に秘密鍵ファイルについては盗聴されないことが確実な環境で行って下さい。普通はscpを利用することになるでしょう。 また、CA証明書ca.hoge.com.crtも同様に転送して下さい。

OpenVPN(TLSクライアントモード)の起動

以下のような感じのスクリプトを /etc/rc.d/rc.local に追加します。うちのOpenBlockSSはsyslogを動かしていないためログは取っていません。 --mktunでtun0を作成していますが、実際に利用しているのはtun1のため不要かもしれません。

/local/sbin/openvpn --mktun --dev tun0
/local/sbin/openvpn --dev tun --remote 5.6.7.8 \
  --ifconfig 192.168.255.2 192.168.255.1 --tls-client \
  --ca /local/etc/openvpn/ca.hoge.com.crt \
  --cert /local/etc/openvpn/openblockss.hoge.com.cer \
  --key /local/etc/openvpn/openblockss.hoge.com.key \
  --udp-mtu 1400 \
  --reneg-sec 3600 \
  --up /local/etc/zebraall.sh \
  --down /local/etc/zebrakill.sh \
  --daemon

/local/etc/zebraall.shは以下のようにzebraを起動するスクリプトです。

#!/bin/sh
/local/sbin/zebra -k -d -f /local/etc/zebra.conf
/local/sbin/ospfd -d -f /local/etc/ospfd.conf
/local/sbin/ripd -d -f /local/etc/ripd.conf

/local/etc/zebrakill.shは以下のようにzebraを終了するスクリプトです。

#!/bin/sh
kill `cat /var/run/ripd.pid /var/run/ospfd.pid /var/run/zebra.pid`

zebra (動的ルーティング)

/local/etc/zebra.conf, /local/etc/ospfd.conf, /local/etc/ripd.confについては昔のOpenBlocksのおとを参照して下さい。 OpenBlockS初代と同じです。

ファイアウォールの設定

OpenBlockSSがブロードバンドルータの後ろにある場合、UDPのポート5000に対するパケットを転送する必要があります。 静的NATの設定を行って下さい。

おわりに

OpenVPNのオプションについて詳しい説明は、マニュアルを日本語訳するべきなんでしょうけど…現在発展途上なのでちと悩ましいです。