前の記事はこちら → 1 : Easy-RSA による証明書等の準備
2 : サーバの設定
以上で、必要な証明書や鍵などのファイルの準備が整いました。
いよいよ、サーバの設定ファイルなど、サーバ本体を構築していきます。
サーバのホストで作業します。
2-1 OpenVPNサーバの設定ファイルを作成
サーバの基本的な 設定ファイル server.conf
(/etc/openvpn/server.conf
)を作ります。
実際には、 /etc/openvpn/server/
に ファイル server.conf
を作って保持し、それへのシンボリックリンクを /etc/openvpn/
に置きました。
root<serverhost/etc/openvpn> % cd server
root<serverhost/etc/openvpn/server> % cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf .
root<serverhost/etc/openvpn/server> % vim server.conf
下敷きにしたサンプルファイルの中には詳しい説明(コメント)が含まれているので、読めば参考にもなります。
ここでは、最終的な設定内容だけを示しておきます。
port 1194
proto udp
dev tap0
ca /etc/openvpn/ca.crt
cert /etc/openvpn/serverhost.crt
key /etc/openvpn/serverhost.key # This file should be kept secret
dh /etc/openvpn/dh.pem
topology subnet
server-bridge
client-to-client
keepalive 10 120
tls-auth /etc/openvpn/ta.key 0 # This file is secret
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3
explicit-exit-notify 1
management localhost 7505
crl-verify /etc/openvpn/crl.pem
ファイルを保存したらシンボリックリンクを作ります。
root<serverhost/etc/openvpn/server> % cd ..
root<serverhost/etc/openvpn> % ln -s server/server.conf
server.conf
の内容に関するメモ
参考 : man openvpn
参考 : Deprecated Options in OpenVPN
設定内容 | メモ |
---|---|
port 1194 と proto udp
|
ポートは UDP 1194 を使うようにしました。 |
dev tap0 |
OpenVPN の tap接続 は、 OS からはネットワークインタフェースとして扱われ、インタフェース名が tapX (X は数字)となるようです。ここでは、 tap0 と指定しました。 |
topology subnet |
いまでは subnet にするのが当たり前らしいですが、 バージョン 2.0.9 以前の古い Windows クライアントと通信するには net30 にしなければならず、そのために用意されているオプションのようです。デフォルトが net30 のため、このオプションは入れておいたほうがいいようです。デフォルトの変更が検討されているとのことで、急にデフォルト挙動が変わったとき焦らないためにも、入れておくほうがよいとのこと。 |
server-bridge |
server-bridge の後に何も書かないこのオプションは、 mode server tls-server push "route-gateway dhcp" の3つを指定するのと同等とのこと。要するに、接続してきたクライアントがローカルネットワーク内の DHCPサーバ を使うようになるということです。なお、 server-bridge の後に色々つける形のオプションは、これと異なり OpenVPNサーバ が DHCP に相当する役割もする設定になります。 |
user nobody と group nogroup
|
起動時の必要な設定が終わったらサーバの権限を降格させてセキュリティを向上させます。指定する ユーザ名 nobody と グループ名 nogroup が実際に存在しないと駄目だそうなので、システムに合わせて変える必要があります。 |
persist-key と persist-tun
|
上のオプションを使って権限を降格させるとサーバのリロード時に権限が足りずたとえば秘密鍵ファイルを読めないなどでエラーになるらしいのですが、それを防ぐ動作をさせるオプションです。 persist-key のほうは、「指定しなくてもつねに有効になるので不要」との情報を見つけたのですが、試しに消してみたところ接続できなくなりました。どうやら「今後そうする方向で検討中」ということのようです。 |
cipher AES-256-CBC | いまのバージョンの OpenVPN では、サーバとクライアントが相談して利用可能な中から最適なサイファを決めるようになっているそうで、オプションでの指定は必要ないようです。 バージョン 2.3 以前のクライアントと通信する場合は互換性のために入れてもよいとの情報がありますが、しないと思うので省きました。 |
comp lzo | ネット上の情報ではこれを入れるべきという説明が多いのですが、最新の情報では「圧縮は推奨しないしユーザが使うのを避けるべき機能の1つである」だそうです。なので入れませんでした。 |
management localhost 7505 |
稼働中のサーバをネットワークからアクセスしてコントロールできる 管理インタフェース を有効にします。 7505 は使うポートです。このポートに telnet でアクセスすることで利用できます。 |
2-2 証明書や鍵のファイルを適切な場所に置く
1 : Easy-RSA による証明書等の準備 で用意した証明書や鍵のファイルのうち OpenVPN のサーバに必要なものを、コピーしてきて適切な場所(/etc/openvpn
)に置きます。
OpenVPN のサーバが必要とするファイルは以下です。
必要なもの | ファイル名 |
---|---|
サーバの証明書 | serverhost.crt |
サーバの秘密鍵 | serverhost.key |
CAの証明書 | ca.crt |
証明書失効リスト | crl.pem |
DHパラメータ | dh.pem |
TLS認証鍵 | ta.key |
2-2-1 CA証明書
CAの証明書 はサーバ・クライアントともに持つ必要があります。
サーバの分として、 ca.crt
を /etc/openvpn/
にコピーします。
root<serverhost/etc/openvpn> % cp /etc/openvpn/easy-rsa/pki/ca.crt .
CAの秘密鍵 は CA として証明書を発行するためのもので、 VPNサーバ や VPNクライアント には必要ないものです。
CA から絶対に漏洩してはならないものなので、ディレクトリのパーミッションに注意してそのまま保管します。
2-2-2 サーバ証明書・サーバ秘密鍵
(1) 適切な場所にコピーする
サーバの証明書 と サーバの秘密鍵 はサーバが持つ必要があります。
serverhost.crt
と serverhost.key
を /etc/openvpn/
にコピーします。
実際には、2つのファイルを /etc/openvpn/server/
にコピーして保持し、それらへのシンボリックリンクを /etc/openvpn/
に置きました。
root<serverhost/etc/openvpn> % cp /etc/openvpn/easy-rsa/pki/issued/serverhost.crt ./server/
root<serverhost/etc/openvpn> % cp /etc/openvpn/easy-rsa/pki/private/serverhost.key ./server/
root<serverhost/etc/openvpn> % ln -s server/serverhost.crt
root<serverhost/etc/openvpn> % ln -s server/serverhost.key
(2) 秘密鍵からパスフレーズを取り除く
サーバの秘密鍵 にはパスフレーズがついています。
試してみたところ、このままでは、パスフレーズを入力しない限りこれらを利用できないため、 VPN接続 ができないように思えました(実はあまりちゃんと確かめてませんが…)。
そこで、 サーバの秘密鍵 からパスフレーズを取り除きます。
openssl
コマンドで行います。具体的には、 openssl rsa -in 元の秘密鍵ファイル -out パスフレーズの取り除かれた秘密鍵を格納するファイル名
とします。
Enter pass phrase for serverhost.key.BACKUP:
でそのパスフレーズを入力します。
root<serverhost/etc/openvpn> % cd server/
root<serverhost/etc/openvpn/server> % mv serverhost.key serverhost.key.BACKUP
root<serverhost/etc/openvpn/server> % openssl rsa -in serverhost.key.BACKUP -out serverhost.key
Enter pass phrase for serverhost.key.BACKUP:
writing RSA key
なお、 サーバの秘密鍵 は決して漏れたり盗まれたりしてはならないものなわけですが、そこからパスフレーズを取り除いてしまうのはセキュリティ上の危険性をだいぶ上げてしまうことと言えます。ですから、このファイルが盗まれたら(パスフレーズがあれば秘密鍵は漏洩しない可能性があったところ、パスフレーズを取り除いてしまったので)一巻の終わり、と考え、ファイルとディレクトリのパーミッションに細心の注意を払っておく必要があります。
このファイルの オーナー は root:root にし、 パーミッション は 600 にしました。
2-2-3 DHパラメータ
DHパラメータ はサーバが使います。
dh.pem
を /etc/openvpn/
にコピーします。
実際には、ファイルを /etc/openvpn/server/
にコピーして保持し、それへのシンボリックリンクを /etc/openvpn/
に置きました。
root<serverhost/etc/openvpn> % cp /etc/openvpn/easy-rsa/pki/dh.pem ./server/
root<serverhost/etc/openvpn> % ln -s server/dh.pem
2-2-4 CRL
CRL はサーバが持ちます。
crl.pem
を /etc/openvpn/
にコピーします。
実際には、ファイルを /etc/openvpn/server/
にコピーして保持し、それへのシンボリックリンクを /etc/openvpn/
に置きました。
root<serverhost/etc/openvpn> % cp /etc/openvpn/easy-rsa/pki/crl.pem ./server/
root<serverhost/etc/openvpn> % ln -s server/crl.pem
CRL は、今後、何らかの証明書が失効するたびに直ちに作り直され、サーバに渡されなければなりません。
つまり、 OpenVPNサーバ が持つ CRL は、つねに 手動で 置き換えて最新のものに保たれ続けなければならないということです。
2-2-5 TLS認証鍵
TLS認証鍵 はサーバ・クライアントともに持つ必要があります。
ta.key
ですが、サーバのホストでは、すでに適切な場所(/etc/openvpn
)に置いてあります。
TLS認証鍵 は漏洩してはならないものですから、パーミッションに注意します。
オーナー は root:root にし、 パーミッション は 600 にしました。
2-3 ブリッジインタフェースを操作するスクリプトを用意
仮想インタフェースである tap0
と 物理インタフェース(eno1
とします) の間で自由にパケットを行き来させることにより、外部から接続しているクライアントにとって内部と全く同等な環境を実現することができます。
この、2つのインタフェースを繋ぐ機能は、 ブリッジインタフェース という仮想インタフェースの形で提供されます。
ブリッジインタフェース という仕組みを提供するのは、 OpenVPN ではなく、 OS です。
それを操作するためのツールが bridge-utils
というパッケージで与えられているわけです。
ブリッジインタフェース を作ったり削除したりするツールは brctl
です。
それを使い OpenVPN の tap接続 に必要な ブリッジインタフェース を起動/停止するシェルスクリプトを作ります。起動するほうを bridge-start
、停止するほうを bridge-stop
とします。
これらは、 /etc/openvpn/
に置くことにします。
下敷きにするサンプルファイルをコピーしてくる
root<serverhost/etc/openvpn> % cp /usr/share/doc/openvpn/examples/sample-scripts/bridge-start .
root<serverhost/etc/openvpn> % cp /usr/share/doc/openvpn/examples/sample-scripts/bridge-stop .
起動用のスクリプト
root<serverhost/etc/openvpn> % vim bridge-start
書き換える箇所を diff で示します。
左が元の(サンプル)ファイル、右が書き換え後。
17,18c17,18
< eth="eth0"
< eth_ip="192.168.8.4"
---
> eth="eno1"
> eth_ip="192.168.0.2"
20c20,21
< eth_broadcast="192.168.8.255"
---
> eth_broadcast="192.168.0.255"
> gw="192.168.0.1"
32a34,35
> sleep 1
>
36a40,41
> sleep 1
>
39a45,47
>
> route add default gw $gw
>
ファイル全体はこうです。
#!/bin/sh
#################################
# Set up Ethernet bridge on Linux
# Requires: bridge-utils
#################################
# Define Bridge Interface
br="br0"
# Define list of TAP interfaces to be bridged,
# for example tap="tap0 tap1 tap2".
tap="tap0"
# Define physical ethernet interface to be bridged
# with TAP interface(s) above.
eth="eno1"
eth_ip="192.168.0.2"
eth_netmask="255.255.255.0"
eth_broadcast="192.168.0.255"
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
sleep 1
for t in $tap; do
ifconfig $t 0.0.0.0 promisc up
done
sleep 1
ifconfig $eth 0.0.0.0 promisc up
ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast
route add default gw $gw
停止用のスクリプト
bridge-stop
はサンプルファイルのまま、どこも書き換えずに使うことができました。
ファイル全体はこうです。
#!/bin/sh
####################################
# Tear Down Ethernet bridge on Linux
####################################
# Define Bridge Interface
br="br0"
# Define list of TAP interfaces to be bridged together
tap="tap0"
ifconfig $br down
brctl delbr $br
for t in $tap; do
openvpn --rmtun --dev $t
done
実行権限をつける
これら2つのスクリプトに実行パーミッションを与えます。
root<serverhost/etc/openvpn> % chmod a+x bridge-start bridge-stop
2-4 systemd のサービスの設定
システム起動時に OpenVPN のサーバを起動しブリッジインタフェースを起動するように systemd に指示するため、ユニットファイルを用意し、サービスの設定をします。
OpenVPNサーバ を起動するユニットファイルは openvpn.service
など用意されているようなのですが、ブリッジインタフェースを起動/停止するユニットファイルはないようなので、作ります。
2-4-1 ブリッジインタフェースを起動/停止するユニットファイルを作る
openvpn-bridge.service
(/usr/lib/systemd/system/openvpn-bridge.service
)として作りました。
root<serverhost/etc/openvpn> % cd /usr/lib/systemd/system/
root<serverhost/usr/lib/systemd/system> % ls o*
open-iscsi.service openvpn-client@.service openvpn.service
open-vm-tools.service openvpn-server@.service openvpn@.service
root<serverhost/usr/lib/systemd/system> % vim openvpn-bridge.service
openvpn-bridge.service
は、 bridge-start
と bridge-stop
を呼び出してブリッジインタフェースを起動したり停止したりする内容です。
ファイル全体は次のとおり。
[Unit]
Description=Openvpn bridge service
Requires=openvpn@server.service
After=openvpn@server.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/openvpn/bridge-start
ExecReload=/bin/true
ExecStop=/etc/openvpn/bridge-stop
[Install]
WantedBy=multi-user.target
2-4-2 systemd で必要なサービスを有効化する
あとは、 systemd で適切なサービスを有効化しておけば、システム起動時に OpenVPN のサーバが自動的に起動します。
有効化するのは、いま作ったブリッジインタフェースを起動する openvpn-bridge
と、 server.conf
の設定に従うサーバを起動する openvpn@server
です。
最初から有効化されている openvpn
は必要ないので、無効化してしまいます。
サービス openvpn
の無効化
root<serverhost/usr/lib/systemd/system> % cd
root<serverhost~> % systemctl disable openvpn
Synchronizing state of openvpn.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable openvpn
Removed "/etc/systemd/system/multi-user.target.wants/openvpn.service".
サービス openvpn-bridge
の有効化
root<serverhost~> % systemctl enable openvpn-bridge
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn-bridge.service → /usr/lib/systemd/system/openvpn-bridge.service.
サービス openvpn@server
の有効化
root<serverhost~> % systemctl enable openvpn@server
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn@server.service → /usr/lib/systemd/system/openvpn@.service.
なお、 openvpn@server
は openvpn@.service
というユニットファイルが実体です。 @
の後ろの server
は サーバの設定ファイルの名前 で、今回は server.conf
なので server
をつけているのです。
2-5 ファイアウォールの設定
ゲートウェイ(ブロードバンドルータ)の設定を変え、ホスト 192.168.0.2 の udp 1194 ポート を WAN に開放します。
2-6 ブリッジインタフェースに関わるリゾルバの設定
いろいろ試してみて気づいたのですが、サーバのホストでブリッジインタフェースを起動すると、なぜかサーバのホストから DNS にアクセスできなくなることがわかりました。 DNSサーバ は同じホストで稼働しています。他のホストからは問題なく DNS を使えているので、ブリッジインタフェースの起動によってサーバのホストのリゾルバの設定がおかしくなってしまうのだと考えられます。
さらにいろいろ試した結果、リゾルバ設定が ネットワークインターフェース eno1
に関連づけられているためだとわかりました。
リゾルバ設定は NetworkManager によって管理されているので、 NetworkManager の設定を編集して、 ブリッジインタフェース br0
に関連づけたリゾルバ設定を加えます。
恥ずかしながら NetworkManager もあまりよく理解していないので、ちょっと苦戦しました。
/etc/netplan/50-cloud-init.yaml
を編集します。
root<serverhost~> % cd /etc/netplan/
root<serverhost/etc/netplan> % vim 50-cloud-init.yaml
network:
の下の ethernets:
の下に br0:
エントリを追加します。
最終的にファイル全体はこうなりました。
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
eno1:
addresses:
- 192.168.0.2/24
nameservers:
addresses:
- 192.168.0.2
search:
- my.domain
routes:
- to: default
via: 192.168.0.1
br0:
nameservers:
addresses:
- 192.168.0.2
search:
- my.domain
version: 2
書き換えを反映させるために次のコマンドを実行します。
root<serverhost/etc/netplan> % netplan apply
これで、 DNS の問題は解決しました。
2-7 DHCPサーバが正しく機能するようにする
受け売りになりますが、 VPNサーバ を DHCPサーバ と同じホスト上で動かした場合、 DHCPサーバ の起動より先にブリッジインタフェースが作られていないと、 DHCPサーバ がブリッジインタフェースを listen しないことがあるそうです。
参考 : OpenVPNのtapブリッジングでDHCPを使う場合のTips
そうなると、 VPNクライアント が接続してきたとき、 VPN として接続できたとしてもIPアドレスなどが割り振られず、結局、機能しないことになってしまいます。
実際に、試してみると、そのとおりだと思えるようなことが起こりました。
この問題を解決するために、システムを起動するときの isc-dhcp-server
の起動が openvpn-bridge
の起動よりも後になるようにします。
systemd の ユニットファイル isc-dhcp-server.service
を書き換えます。
root<serverhost/etc/netplan> % cd /usr/lib/systemd/system/
root<serverhost/usr/lib/systemd/system> % vim isc-dhcp-server.service
[Unit]
セクションに次の1行を加えます。
After=openvpn-bridge.service
ファイル全体はこうなります。
[Unit]
Description=ISC DHCP IPv4 server
Documentation=man:dhcpd(8)
Wants=network-online.target
After=network-online.target
After=time-sync.target
After=openvpn-bridge.service
ConditionPathExists=/etc/default/isc-dhcp-server
ConditionPathExists=|/etc/ltsp/dhcpd.conf
ConditionPathExists=|/etc/dhcp/dhcpd.conf
[Service]
EnvironmentFile=/etc/default/isc-dhcp-server
RuntimeDirectory=dhcp-server
# The leases files need to be root:dhcpd even when dropping privileges
ExecStart=/bin/sh -ec '\
CONFIG_FILE=/etc/dhcp/dhcpd.conf; \
if [ -f /etc/ltsp/dhcpd.conf ]; then CONFIG_FILE=/etc/ltsp/dhcpd.conf; fi; \
[ -e /var/lib/dhcp/dhcpd.leases ] || touch /var/lib/dhcp/dhcpd.leases; \
chown root:dhcpd /var/lib/dhcp /var/lib/dhcp/dhcpd.leases; \
chmod 775 /var/lib/dhcp ; chmod 664 /var/lib/dhcp/dhcpd.leases; \
exec dhcpd -user dhcpd -group dhcpd -f -4 -pf /run/dhcp-server/dhcpd.pid -cf $CONFIG_FILE $INTERFACESv4'
[Install]
WantedBy=multi-user.target
isc-dhcp-server6.service
も同様にしておきます。
root<serverhost/usr/lib/systemd/system> % vim isc-dhcp-server6.service
これで、 DHCP の問題は解決しました。
次の記事はこちら → 3 : クライアントの設定