OpenVPN(ブリッジ)
20150110

確認環境
 CentOS6.x
 CentOS5.x
⇒CentOS7xの場合はOpenVPN(ブリッジ)ページにて。
 Fedora8-10
 OpenVPN2.0.9
 OpenVPN2.2.2
 OpenVPN2.3.0
 OpenVPN2.3.2

概要
 1.SSL/TLS-VPNのサーバーを構築する。
 2.L2レベルでの通信が可能なブリッジモードを使用する。
 3.通信スループット20mbps以上を目指す。
 →暗号化処理の問題で、サーバーのハードウェアスペック(特にCPU)によって大幅に変わってきます。
 →当環境では、地デジ放送のデータ程度(15-18mbps)であればリアルタイムに転送出来る事を確認。
  CPU「A-10 5700(AES-NI未使用)」/メモリ「DDR3-2000-4096MB」/仮想環境OS /

トンネルモード(L3)VPNを構築する場合は「OpenVPN」を参考
 ※iphoneやandroidで接続する場合は上記トンネルモードで構築すること

OpenVPNブリッジモードによるメリット
 ルーティング設定が不要
 TCP/IP以外のプロトコルを使用可能
 →通常の内部ネットワークと同様に、NetBIOSによるファイル転送やDLNAが使えます。

OpenVPNブリッジモードによるデメリット
 アクセス制御の実装が面倒
 →基本的には「client-to-client」のコメントアウトをしない限り、VPNサーバ側内部ネットワークに属する
  システム全てと通信が可能な為、アクセス制限の方法が限られてしまう。
 →内部ネットワーク用NICが増えたと認識する(ようなもの)という点でトンネルモードと大きな違いがあります。
以下の仕様に基づいて設定をしています。

 VPNサーバ環境(Linux/ネットワークインターフェース/IPアドレス)
  IPアドレス : 192.168.0.3
  サブネットマスク  : 255.255.255.0(/24)
  ネットワークアドレス  : 192.168.0.0
  ブロードキャストアドレス : 192.168.0.255
  物理ネットワークインターフェース名 : eth0
  ブリッジ用ネットワークインターフェース名 : br0
  TAPインターフェース名 : tap0

 VPNサーバ仕様
  サーバーアドレス : ry.tl
  ポート : UDP 1194
  VPNクライアントIPアドレスプール : 192.168.0.64 〜 192.168.0.127

 VPNクライアント
  OS : Windows
  ブリッジインターフェース名 : tap
  →「ローカルエリア2」 とかになっているアダプター名

 鍵強度
  RSA鍵 : 4096bit
  →パフォーマンスへの影響は限定的です。
  →各種鍵作成時間の増加。(最初のお星様作成時間の増加が著しい)
  →1時間に1回のSSL/TLSの再ネゴシエーションの時間の増加。
  対称鍵 : AES(256bit)
  →サーバースペックによりますが、パフォーマンスに直結します。
  →対応CPUであれば「AES-NI」を実装すると劇的な向上が見込めます。
◆インストール
 [root@Server ~]# yum -y install openvpn
openvpnとlzoがインストールされる。

Centosの場合はFedoraと違い、標準ではyumインストール出来ません。
サードパーティのリポジトリの追加と、標準リポジトリの共存を図る為のプラグインを追加する必要があります。
 RPMforgeリポジトリ(CentOS5.x)
 EPELリポジトリ(CentOS6.x)
 yum-priorities

詳しくはぐーぐる先生にて。
◆CA証明書作成
 [root@Server ~]# cp -pr /usr/share/doc/openvpn-2.0.9/easy-rsa/2.0/ /etc/openvpn/easy-rsa

Centos6.xの場合は以下
 [root@Server ~]# cp -pr /usr/share/openvpn/easy-rsa/2.0/ /etc/openvpn/easy-rsa

 [root@Server ~]# cd /etc/openvpn/easy-rsa/
 [root@Server easy-rsa]# chmod +x *
 [root@Server easy-rsa]# vi vars

以下を設定
 # Increase this to 2048 if you
 # are paranoid. This will slow
 # down TLS negotiation performance
 # as well as the one-time DH parms
 # generation process.
  export KEY_SIZE=4096

 # These are the default values for fields
 # which will be placed in the certificate.
 # Don't leave any of these fields blank.
  export KEY_COUNTRY="JP(国名)"
  export KEY_PROVINCE="OSAKA(都道府県)"
  export KEY_CITY="OSAKA(市町村)"
  export KEY_ORG="ry.tl(サーバーアドレス)"
  export KEY_EMAIL="root@ry.tl(管理人メールアドレス)"

 [root@Server easy-rsa]# source vars
 [root@Server easy-rsa]# ./clean-all  
 [root@Server easy-rsa]# ./build-ca
色々出てくるけどエンター連打

 [root@Server easy-rsa]# cp -pr keys/ca.crt /etc/openvpn/
所定の位置へとコピーします。

◆サーバー証明書作成
 [root@Server easy-rsa]# ./build-key-server server
以下が出てくるまでエンター。

  Sign the certificate? [y/n]:y
  1 out of 1 certificate requests certified, commit? [y/n]y

[root@Server easy-rsa]# cp -pr keys/server.crt keys/server.key /etc/openvpn/
所定の位置へコピーします。

◆DHパラメータ作成
 [root@Server easy-rsa]# ./build-dh
お星様がいっぱい出てくるので終わるのを待つ。

 [root@Server easy-rsa]# cp -pr keys/dh4096.pem /etc/openvpn/
所定の位置へコピーします。

◆共有鍵作成
 [root@Server easy-rsa]# openvpn --genkey --secret keys/ta.key

 [root@Server easy-rsa]# cp -pr keys/ta.key /etc/openvpn/
所定の位置へコピーします。

◆クライアント証明書(「test」アカウント用)
 [root@Server easy-rsa]# ./build-key test
以下が出てくるまでエンター

  Sign the certificate? [y/n]:y
  1 out of 1 certificate requests certified, commit? [y/n]y

〜パス付きを作る場合〜
[root@Server easy-rsa]# ./build-key-pass test
 Enter PEM pass phrase: パスワード
 Verifying - Enter PEM pass phrase:パスワード

◆最後にもろもろをコピー(とりあえず1個ずつ「/root」にでも。)
 [root@Server easy-rsa]# mkdir /root/key

 [root@Server easy-rsa]# cp -pr /etc/openvpn/ca.crt /root/key/
 [root@Server easy-rsa]# cp -pr /etc/openvpn/easy-rsa/keys/test.crt /root/key/
 [root@Server easy-rsa]# cp -pr /etc/openvpn/easy-rsa/keys/test.key /root/key/
 [root@Server easy-rsa]# cp -pr /etc/openvpn/ta.key /root/key/
◆サーバーコンフィグを編集
 [root@Server ~]# vi /etc/openvpn/server.conf
→サンプルConfigのパス「/usr/share/doc/openvpn-*/sample-config-files/server.conf」

----------------------------------------------------------------------------------------------------
# サーバー用コンフィグ
# Ver 20130114

# 使用するポートの指定(必須)
port 1194

# プロトコルの指定。TCPかUDP(必須)
proto udp

# TAPインターフェース指定(必須)
dev tap0

# 認証用鍵ファイルのパス(必須)
ca ca.crt
cert server.crt
key server.key
tls-auth ta.key 0

# 鍵強度
dh dh4096.pem
cipher AES-256-CBC

# 配布するIPアドレスのテーブル(任意)
# 固定化する際に用いる
ifconfig-pool-persist ipp.txt

# VPNサーバーのアドレスと、VPNクライアントのアドレスの幅指定(必須)
server-bridge 192.168.0.3 255.255.255.0 192.168.0.64 192.168.0.127

# 以下のローカルネットワークにアクセスする場合、VPNサーバーを経由する。(推奨)
push "route 192.168.0.0 255.255.255.0"

# DNSサーバー/WINSサーバーの設定(任意)
push "dhcp-option DNS 192.168.0.3"
push "dhcp-option DNS 192.168.0.1"
push "dhcp-option WINS 192.168.0.3"

# クライアント同士の通信を許可(推奨)
client-to-client

# キープアライブの設定(推奨)
keepalive 10 120

# LZO(圧縮)の有効化(推奨)
comp-lzo

# ユーザー権限(必須)
user nobody
group nobody

# 読み込み関係(不明)
persist-key
persist-tun

# ログ関係(必須)
status /var/log/openvpn-status.log
log /var/log/openvpn.log
log-append /var/log/openvpn.log

# ログ取得レベル(必須。レベルは任意)
verb 3

# 下記設定については動作の保証は出来ません。
# うまく行けばスループット向上を見込めます。(当環境でNetBIOSを用いたファイル送信で20-25mbps前後)
# ※TAPアダプターが10Mbps接続となっている場合がありますが、実際にはそれ以上の速度で通信も可能です。

# 以下、通信最適化

# MTUを指定(VPN及びL2ヘッダを付与する必要がある為、データサイズを小さくするとオーバーヘッドが減ると予想)
link-mtu 1400
# MSSを指定(上記の通り)
mssfix 1300
# UDPのみ。断片化を防止する為に変更(MTU-28の値を指定)
fragment 1372

# AES-NI対応CPUであれば下記設定を有効にして下さい。
#engine aesni

# エラーが出る場合の対処
replay-window 128
----------------------------------------------------------------------------------------------------

※環境によって変更する事。

◆クライアントに対するIPアドレス配布を固定にする場合(一部のみでも可)
 [root@Server ~]# vi /etc/openvpn/ipp.txt
test,192.168.0.64
test2,192.168.0.120
◆サーバー用ブリッジのインストール
 [root@Server ~]# yum -y install bridge-utils

◆サーバー用ブリッジの設定(起動用スクリプトの作成)
 [root@Server ~]# vi /etc/openvpn/bridge-start

#!/bin/bash

# 20150110

# ブリッジインターフェース名
br="br0"

# TAPアダプター(インターフェース)名
tap="tap0"

# 物理ネットワークインターフェース名
eth="eth0"
# ひとつ上の物理ネットワークインターフェースのIPアドレス
eth_ip="192.168.0.3"
# サブネットマスク
eth_netmask="255.255.255.0"
# ブロードキャストアドレス
eth_broadcast="192.168.0.255"
# デフォルトゲートウェイアドレス
eth_gw="192.168.0.1"

# 以降設定不要
for t in $tap; do
openvpn --mktun --dev $t
done

brctl addbr $br
brctl addif $br $eth

for t in $tap; do
brctl addif $br $t
done

for t in $tap; do
ifconfig $t 0.0.0.0 promisc up
done

ifconfig $eth 0.0.0.0 promisc up

ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast

route add default gw $eth_gw

※IPアドレス部分を環境に合わせて設定する事。
※書き換える際はインターフェース名に注意

 [root@Server ~]# chmod +x /etc/openvpn/bridge-start
→実行権限を付与

◆サーバー用ブリッジの設定A(停止用のスクリプトの作成)
 [root@Server ~]# vi /etc/openvpn/bridge-stop

#!/bin/bash

# 20110129

# ブリッジインターフェース名(ifconfig等で要確認)
br="br0"

# TAPアダプター(インターフェース)名
tap="tap0"

# 以降設定不要
ifconfig $br down
brctl delbr $br

for t in $tap; do
openvpn --rmtun --dev $t
done

※環境に合わせて設定する事。
※書き換える際はインターフェース名に注意

 [root@Server ~]# chmod +x /etc/openvpn/bridge-stop
→実行権限を付与
◆ネットワークとOpenVPNの起動と終了の設定
起動順としては「ネットワークの起動→ブリッジ起動→OpenVPNの起動」
終了順としては「OpenVPNの終了→ブリッジ終了→ネットワークの終了」
これらを実装するために設定を行う。

 [root@Server ~]# vi /etc/rc.d/init.d/network
----------------------------------------------------------------------------------------------------

びふぉー
  touch /var/lock/subsys/network
  [ -n "${NETWORKDELAY}" ] && /bin/sleep ${NETWORKDELAY}
  ;;
  stop)
  # Don't shut the network down if root is on NFS or a network
  # block device.
  rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/" && $3 != "rootfs") { print $3; }}' /proc/mounts)
  rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)

  if [[ "$rootfs" =~ "^nfs" ]] || [[ "$rootopts" =~ "_netdev|_rnetdev" ]] ; then
  exit 1
  fi
----------------------------------------------------------------------------------------------------

あふたー
  touch /var/lock/subsys/network

  /bin/bash /etc/openvpn/bridge-start
  /bin/bash /etc/rc.d/init.d/openvpn start


  [ -n "${NETWORKDELAY}" ] && /bin/sleep ${NETWORKDELAY}
  ;;
  stop)
  # Don't shut the network down if root is on NFS or a network
  # block device.

  /bin/bash /etc/rc.d/init.d/openvpn stop
  /bin/bash /etc/openvpn/bridge-stop


  rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/" && $3 != "rootfs") { print $3; }}' /proc/mounts)
  rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)

  if [[ "$rootfs" =~ "^nfs" ]] || [[ "$rootopts" =~ "_netdev|_rnetdev" ]] ; then
  exit 1
  fi

※システムのアップデートで本ファイルの内容が初期化される場合があります。
 その場合の症状としては、起動時に自動でopenvpnが立ち上がらなくなり、
 openvpnデーモンを起動しても接続は出来るがホストとの通信が出来ないといった不具合が発生します。
 この症状が見られた場合は本ファイルを一度見直して下さい。

◆上記対策の為、一日一回本ファイルの中身を調査するスクリプトを作成(任意)
 [root@Server ~]# vi /etc/cron.daily/openvpn_network.sh

#!/bin/sh
export LANG=ja_JP.UTF-8

# Ver 20111214

# ネットワークスクリプトファイル
FILE="/etc/rc.d/init.d/network"

# 検索キーワード
KEY="openvpn"

# メール送信先アドレス。(デフォルトroot宛)
MAILADDRESS="root"

# 以降設定不要
if grep $KEY $FILE > /dev/null 2>&1 ; then
:
else echo -e "「$FILE」内にて、「$KEY」の文言を確認出来ません。\nOpenVPNの動作に支障が出る可能性がありますので、確認して下さい。\n参考「http://ry.tl/openvpn.html」"| mail -s "ネットワークスクリプト内容の変更を確認" $MAILADDRESS
fi

 [root@Server ~]# chmod +x /etc/cron.daily/openvpn_network.sh
→実行権限を付与

→cronにて実行され、問題があればメールにて通知されてきます。
◆IPフォワードの設定その1
 [root@Server ~]# echo 1 > /proc/sys/net/ipv4/ip_forward

◆IPフォワードの設定その2
 [root@Server ~]# vi /etc/sysctl.conf
  # Controls IP packet forwarding
  net.ipv4.ip_forward =0

 これを以下に変更する。

  # Controls IP packet forwarding
  net.ipv4.ip_forward =1
◆iptablesの設定を変更
 [root@Server ~]# iptables -A FORWARD -s 192.168.0.0/255.255.255.0 -j ACCEPT
内部アドレスからの通過を許可する。

 [root@Server ~]# iptables -A INPUT -p udp --dport 1194 -j ACCEPT
VPNに使用するポートへのアクセスを許可する。(ルータでも行う事)
----------------------------------------------------------------------------------------------------

インターフェース名からIPアドレスを取得して設定している場合は「eth0」から「br0」に変更する必要があります。
 →CentOSで自宅サーバー構築様のiptables設定を用いている場合を想定して記します。

文字は変更/文字は追記。試していないので動作の保証は出来ません。

# インタフェース名定義
LAN=br0

# 外部からのUDP1194番ポート(OpenVPN)へのアクセスを日本からのみ許可
# ※OpenVPNサーバーを公開する場合のみ
iptables -A INPUT -p udp --dport 1194 -j ACCEPT_COUNTRY

# 内部からの通過をすべて許可
iptables -A FORWARD -s $LOCALNET -j ACCEPT


どうしても構築がうまく行かない場合はFW(iptables)で引っかかっている場合が多いので、一度無効化して問題の切り分けしてみて下さい。
◆OpenVPNの起動
 [root@Server ~]# /etc/rc.d/init.d/network restart
初回は終了する際に、存在しないブリッジインターフェースを終了させようとしてエラーが発生しますが、問題はありません。
以下のようにインターフェースの起動、ブリッジの起動、OpenVPNの起動がされればOK

 インターフェース eth0 を終了中: [ OK ]
 ループバックインターフェースを終了中 [ OK ]
 ループバックインターフェイスを呼び込み中 [ OK ]
 インターフェース eth0 を活性化中:
 eth0 のIP情報を検出中... 完了。
 Wed Jul 22 22:01:24 2009 TUN/TAP device tap0 opened
 Wed Jul 22 22:01:24 2009 Persist state set to: ON
 openvpn を起動中: [ OK ]
◆クライアント作業
先ほど「/root/key」にコピーした鍵一式と「client.ovpn」をC:\Program Files\OpenVPN\config\に保存。
◆クライアント作業(Windows64bitの場合)
先ほど「/root/key」にコピーした鍵一式と「client.ovpn」をC:\Program Files (x86)\OpenVPN\config\に保存。

補足として鍵一式
 ca.crt
 test.crt
 test.key
 ta.key
◆クライアント作業(「client.ovpn」をメモ帳などで開きます。)
# クライアント用コンフィグ
# Ver 20130114

# モード
client

# ネットワーク接続のデバイス名(コントロールパネルなりから確認設定をしてから変更)
dev-node tap

# プロトコル(サーバー側と合わせる。)
proto udp

# サーバーアドレス+ポート番号
remote ry.tl 1194

# 名前解決関係
resolv-retry infinite

# 特定のローカルポートを確保しない。
nobind

# Man-in-the-Middle攻撃対策
ns-cert-type server

# 読み込み関係
persist-key
persist-tun

# キーとかのパス(クライアント毎にファイル名などの変更が必須)
ca ca.crt
cert test.crt
key test.key
tls-auth ta.key 1

# 鍵強度
cipher AES-256-CBC

# LZO(圧縮)の有効化。サーバー側とあわせる必要がある。
comp-lzo

# ログ取得レベル
verb 3

# OpenVPNサーバからパラメータを受け取るための設定らしい。
pull

# OpenVPNサーバからIPアドレスを受け取るための設定らしい。
float

# 下記設定については動作の保証は出来ません。
# うまく行けばスループット向上を見込めます。(当環境でNetBIOSを用いたファイル送信で20-25mbps前後)
# ※TAPアダプターが10Mbps接続となっている場合がありますが、実際にはそれ以上の速度で通信も可能です。

# 以下、通信最適化

# MTUを指定(VPN及びL2ヘッダを付与する必要がある為、データサイズを小さくするとオーバーヘッドが減ると予想)
link-mtu 1400
# MSSを指定(上記の通り)
mssfix 1300
# UDPのみ。断片化を防止する為に変更(MTU-28の値を指定)
fragment 1372

# AES-NI対応CPUであれば下記設定を有効にして下さい。
#engine aesni

# エラーが出る場合の対処
replay-window 128
----------------------------------------------------------------------------------------------------

※環境によって変更する事。
〜運用後の操作〜
◆追加で使用するクライアント用の認証鍵を作成する場合。
 [root@Server ~]# cd /etc/openvpn/easy-rsa/
 [root@Server easy-rsa]# source vars

 [root@Server easy-rsa]# ./build-key test2
以下が出てくるまでエンター
  Sign the certificate? [y/n]:y
  1 out of 1 certificate requests certified, commit? [y/n]y

〜パス付きを作る場合〜
 [root@Server easy-rsa]# ./build-key-pass test2
  Enter PEM pass phrase: パスワード
  Verifying - Enter PEM pass phrase:パスワード
最後に
 OpenVPNは下記のように「conf」ファイルを複数用意する事によって、同一サーバー上にて複数のVPNサーバーを立てる事が出来ます。
 ブリッジモードとトンネルモードの両方を同一サーバー上で構築する事も可能です。
  /etc/openvpn/server.conf
  /etc/openvpn/server2.conf

 使用するポート番号の重複は出来ませんので、注意して下さい。

 また、クライアントについても同様の設定で複数サーバーへの接続が可能です。
 この場合、トンネル用インターフェースの増設が必須となる点に注意(パッチが用意されています。)

以上