ブリッジ接続のDockerコンテナ環境にした際、従来からインストールされていたOpenVPN(tap)と競合し、Dockerサービスのリブート後にOpenVPNも再起動する必要が生じました。
また、OpenVPN導入手順の棚卸のため、OpenVPN環境をコンテナ内に移植することにしました。
構成
以下のような構成にしてみます。
従来、OpenVPNはブリッジ(tap)モードで動作していましたが、モバイルデバイス(iPhone/Android)からの接続も行いたいため、今回はルーティング(tun)モードで動作させることとします。
証明書の作成
OpenVPNの動作に必要な証明書などを作成します。
easyRSAのインストール
# yum install epel-release # yum --enablerepo=epel install easy-rsa
esayRSA設定
# cd /usr/share/easy-rsa/2.0/ # cp -p vars vars.org # vi vars
以下のように組織名等を記載します。
-------鍵の基本情報(デフォルトから変更せず) export KEY_SIZE=2048 ※鍵の長さ2048bit export CA_EXPIRE=3650 ※有効期限10年 export KEY_EXPIRE=3650 -------組織名等を変更 export KEY_COUNTRY="JP" export KEY_PROVINCE="Tokyo" export KEY_CITY="Tama-city" export KEY_ORG="kizawa.info" export KEY_EMAIL="xxxxx@kizawa.info" export KEY_OU="Development Studio"
設定変更を反映
# source vars NOTE: If you run ./clean-all, I will be doing a rm -rf on /usr/share/easy-rsa/2.0/keys # ./clean-all ←⼀応実⾏
自己認証局証明書の作成
認証局の証明書、秘密鍵の作成を行う。
# ./build-ca
対話式に情報を求められますが、全てEnterで問題ありません。
サーバ証明書・鍵の作成
OpenVPNサーバの証明書、秘密鍵の作成を行う。
# ./build-key-server server
DH暗号パラメータの生成
DH(ディフィー・ヘルマン)暗号パラメータの作成を行う。
# ./build-dh
TLS認証鍵の作成
TLS認証鍵の生成にはOpenVPNが必要
# openvpn --genkey --secret /etc/openvpn/keys/ta.key
設定ファイルの準備
証明書の準備
作成した以下の証明書や鍵ファイルを同一ディレクトリにコピーしておきます。
ca.crt | 認証局の証明書 |
---|---|
server.key | このOpenVPNサーバの秘密鍵 |
server.crt | このOpenVPNサーバの証明書 |
dh2048.pem | dh(ディフィー・ヘルマン)鍵 2048bit |
ta.key | TLS認証鍵 |
OpenVPN設定ファイル(openvpn.conf)
OpenVPNサーバの設定ファイルを以下のように準備します。
# 動作モード&ポート proto udp dev tun0 port 1194 # クライアント接続制御 server 192.168.101.0 255.255.255.0 ifconfig-pool-persist ipp.txt max-clients 5 keepalive 10 120 comp-lzo cipher AES-256-CBC # 鍵情報 ca keys/ca.crt key keys/server.key cert keys/server.crt dh keys/dh2048.pem tls-auth keys/ta.key 0 persist-key persist-tun # クライアントへのpush情報 push "route 192.168.100.0 255.255.255.0" push "dhcp-option DNS 192.168.100.2" push "dhcp-option DOMAIN kizawa.info" # クライアント同士の通信を許可する client-to-client # ログ出力 verb 3 status openvpn-status.log log /var/log/openvpn.log log-append /var/log/openvpn.log
ログローテーション設定(openvpn-logrotate.conf)
ついでにログローテーションの設定も。
/var/log/openvpn.log { missingok rotate 53 compress postrotate systemctl restart openvpn 2>&1 > /dev/null || true endscript }
イメージ生成&コンテナ起動
Dockerfile
以下のような内容となりました。
なお、SSHログイン可能としたコンテナをベースとしています。
FROM centos:sshdenable MAINTAINER Tomotaka Kizawa # epel有効化 RUN yum install -y epel-release && yum clean all # インストール RUN yum --enablerepo=epel -y install openvpn logrotate cronie && yum clean all RUN yum update -y && yum clean all # 設定ファイルの埋め込み ADD openvpn.conf /etc/openvpn/openvpn.conf # 鍵ファイルの埋め込み RUN mkdir /etc/openvpn/keys ADD ca.crt /etc/openvpn/keys/ ADD server.key /etc/openvpn/keys/ ADD server.crt /etc/openvpn/keys/ ADD dh2048.pem /etc/openvpn/keys/ ADD ta.key /etc/openvpn/keys/ RUN chmod 600 /etc/openvpn/keys/*.key # 起動スクリプト変更 RUN cp -p /usr/lib/systemd/system/openvpn@.service /usr/lib/systemd/system/openvpn.service RUN sed -ri '/ExecStart/i ExecStartPre=/bin/echo 1 > /proc/sys/net/ipv4/ip_forward' /usr/lib/systemd/system/openvpn.service RUN sed -ri '/ExecStart/a ExecStopPost=/bin/echo 0 > /proc/sys/net/ipv4/ip_forward' /usr/lib/systemd/system/openvpn.service RUN sed -ri '/PIDFile/s/%i.pid/openvpn.pid/g' /usr/lib/systemd/system/openvpn.service RUN sed -ri '/ExecStart/s/%i.pid/openvpn.pid/g' /usr/lib/systemd/system/openvpn.service RUN sed -ri '/ExecStart/s/%i.conf/openvpn.conf/g' /usr/lib/systemd/system/openvpn.service RUN systemctl enable openvpn # logrotate設定 ADD openvpn-logrotate.conf /etc/logrotate.d/openvpn RUN logrotate /etc/logrotate.conf RUN systemctl enable crond
ビルド
以下のコマンドでイメージを生成しました。
上記で準備した各種ファイルは同一ディレクトリに保存しておいてください。
# docker build -f ./openvpn.dockerfile -t centos:openvpn --no-cache=true .
コンテナ起動
生成したイメージからコンテナを起動します。
# docker run --privileged -d --name openvpn --hostname openvpn --net shared_nw --ip 192.168.100.3 --restart=always centos:openvpn /sbin/init
結果
上位ルータでのポートフォワード先、及びルーティング設定の追加を行い無事に移植が完了しました。
構築手順を棚卸する意味でも、Dockerfileを書いてみるのは良いことですね。
サーバ秘密鍵を埋め込むのか、ホストOSから見せるのか判断に悩んだのですが、可搬性(管理性)を高める意味から埋め込むことにしました。
またCRL鍵失効リストの管理ができていないことが課題になりますね。
別場所(ホストOSあるいは別のコンテナ)で生成されている失効リストを定期的に参照し、取り込むシェルを組み込む必要があるかと思います。
補足 2017/5
ホスト側のシステムアップデート後にopenvpnデーモンが起動しなくなりました。
詳細な原因は不明ですが、pidファイル設置場所が存在しなくなっていましたので/usr/lib/systemd/system/openvpn.serviceを以下の通り修正し-serviceを追加ことで解決しました。
[Unit] Description=OpenVPN Robust And Highly Flexible Tunneling Application On %I After=network.target [Service] PrivateTmp=true Type=forking PIDFile=/var/run/openvpn-server/openvpn.pid ExecStartPre=/bin/echo 1 > /proc/sys/net/ipv4/ip_forward ExecStopPost=/bin/echo 0 > /proc/sys/net/ipv4/ip_forward ExecStart=/usr/sbin/openvpn --daemon --writepid /var/run/openvpn-server/openvpn.pid --cd /etc/openvpn/ --config openvpn.conf ExecStopPost=/bin/echo 0 > /proc/sys/net/ipv4/ip_forward [Install] WantedBy=multi-user.target
コメント