クライアントの1人が、企業サービスへの安全なアクセスを組織するためのフォールトトレラントソリューションの開発を依頼しました。 解決策は次のとおりです。
- 耐障害性と冗長性を提供します。
- スケーリングが簡単。
- VPNユーザーの追加とブロックの問題を簡単かつ迅速に解決します。
- 入力ノード間で負荷を分散します。
- GNU / Linux、Mac OS X、およびWindowsのクライアントでも同様に機能します。
- NATの背後にあるクライアントをサポートします。
設定されたすべての条件を満足する既製のソリューションは見つかりませんでした。 そのため、人気のあるオープンソース製品に基づいて収集し、この記事で結果を共有できるようになりました。
コンセプト開発
クライアント側の基本的なVPNテクノロジーとしてOpenVPNを選択しました。NATを介してうまく機能し、必要なすべてのプラットフォームをサポートします。
OpenVPNをTLSサーバーモードでデプロイし、 easy-rsaパッケージを使用してユーザーを追加およびブロックします。これにより、キーと証明書を作成し、必要に応じてそれらを取り消すことができます。
解決が最も難しいのは、スケーリング、冗長性、フォールトトレランスの問題でした。
最終的な解決策はシンプルでエレガントなものでした。 ラウンドロビンDNSを使用してクライアントにアドレスが発行されるN個の入力ノードを使用することにしました。 カスタマーサービスのすべてのノードとノードは、1つのTinc VPN L2スペースに含まれています 。 クライアント接続(またL2)は、tincインターフェイスと組み合わされてブリッジになります。 したがって、OpenVPNを介して接続すると、クライアントはランダムノードに到達し、他のすべてのクライアント、ノード、およびクライアントサービスを持つ単一のL2ネットワークになります。
このスキームを実装するために、3つのVPSがさまざまなデータセンターに割り当てられ、ネットワークに「エントリポイント」を展開する必要がありました(
ep1
、
ep2
および
ep3
)。 さらに、クライアントサービス(
hpv1
)を備えたハイパーバイザーがネットワーク上に存在していました。 Ubuntu Server 16.04はすべてのマシンにインストールされました。
Tinc VPNを構築する
まず、パッケージをインストールします。
$ sudo apt-get update && sudo apt-get install tin
この段階で、ネットワークの名前を決定する必要があります
l2vpnnet
ます。 ディレクトリ構造を作成します。
$ sudo mkdir -p /etc/tinc/l2vpnnet/hosts
/etc/tinc/l2vpnnet
、
tinc.conf
ファイルを作成し、次の内容を入力します。
# Name = ep1 # , — L2 Mode = switch # , Interface = tap0 # UDP Port = 655 # , ConnectTo = ep2 ConnectTo = ep3 ConnectTo = hpv1
ファイル
/etc/tinc/l2vpnnet/ep1
を作成し
/etc/tinc/l2vpnnet/ep1
パラメーターを
/etc/tinc/l2vpnnet/ep1
ます。
# Address = 100.101.102.103 655 # Cipher = aes-128-cbc Digest = sha1 # Compression = 0
キーを生成します。 伝統的に、私たちは2キロビットの長さのキーを使用します。このキーの長さは、暗号化のオーバーヘッドのために、プライバシーレベルと待機時間のバランスをよくします。
$ cd /etc/tinc/l2vpnnet && sudo tincd -n l2vpnnet -K2048 Generating 2048 bits keys: ............................................+++ p .................................+++ q Done. Please enter a file to save private RSA key to [/etc/tinc/l2vpnnet/rsa_key.priv]: Please enter a file to save public RSA key to [/etc/tinc/l2vpnnet/hosts/ep1]:
残りのマシンでも同じことを行います。 公開キーと接続パラメーター(
/etc/tinc/l2vpnnet/hosts/ep1|ep2|ep3|hpv1
)を持つファイルは、すべてのネットワーク参加者とともに
/etc/tinc/l2vpnnet/hosts
配置する必要があります。
起動時にtincがネットワークへのVPNを自動的に開始する
/etc/tinc/nets.boot
に、ネットワーク名を
/etc/tinc/nets.boot
ファイルに入力する必要があります。
$ sudo cat nets.boot #This file contains all names of the networks to be started #on system startup. l2vpnnet
Tinc VPNとOpenVPNの両方を設定する場合、当社では標準的なUbuntuネットワーク管理メカニズムを使用するのが慣例となっています。
tap0
デバイスパラメータの説明を
/etc/network/interfaces
追加し
/etc/network/interfaces
。
# auto tap0 # manual, IP bridge iface tap0 inet manual # tinc pre-up ip tuntap add dev $IFACE mode tap # ... post-down ip tuntap del dev $IFACE mode tap # , tinc tinc-net l2vpnnet
このセットアップにより、ifup / ifdownスクリプトを使用してtincを制御できます。
単一のL2スペースの場合、L3スペースも選択する必要があります。 例として、ネットワーク
10.10.10.0/24
を使用します。 ブリッジインターフェースを設定し、それにIPを割り当てます。このため
/etc/network/interfaces
次の情報を
/etc/network/interfaces
。
auto br0 iface br0 inet static # , IP address 10.10.10.1 netmask 255.255.255.0 # , tinc vpn bridge_ports tap0 # spanning tree bridge- bridge_stp off # bridge_maxwait 5 # bridge_fd 0
その後、すべてのサーバーで両方のデバイスを順番に起動し、診断ツール(ping、mtrなど)で接続を確認します。
$ sudo ifup tap0 && sudo ifup br0 $ ping -c3 10.10.10.2 PING 10.10.10.2 (10.10.10.2) 56(84) bytes of data. 64 bytes from 10.10.10.2: icmp_seq=1 ttl=64 time=3.99 ms 64 bytes from 10.10.10.2: icmp_seq=2 ttl=64 time=1.19 ms 64 bytes from 10.10.10.2: icmp_seq=3 ttl=64 time=1.07 ms --- 10.10.10.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 1.075/2.087/3.994/1.349 ms
優れた:入力ノードとターゲットサーバー用のL2スペースが構築されています。 次に、リモートクライアントを追加する必要があります。
OpenVPNを構成する
まず、必要なパッケージをすべてのサーバーにインストールします。
$ sudo apt-get update && sudo apt-get install openvpn easy-rsa
DNSゾーンを構成し、VPNサービスと同じ名前の3つのAレコードを追加します。
vpn.compa.ny. IN A 100.101.102.103 vpn.compa.ny. IN A 50.51.52.53 vpn.compa.ny. IN A 1.1.1.1
DNSは、システムの最初のロードバランサーになります。 ドキュメントによると、OpenVPNは接続ポイントの名前を解決し、名前が解決されるすべてのIPへの接続を一貫して試行します。 DNSは、IPリストをランダムな順序で提供します。
負荷分散の2番目のメカニズムは、サーバーごとの最大接続数の制限です。 約50人のユーザーがいるとします。 冗長性を考慮して、サーバーに30ユーザーの制限を設け、次のようにIPアドレスプールを割り当てます。
Node 1 10.10.10.100-10.10.10.129 Node 2 10.10.10.130-10.10.10.159 Node 2 10.10.10.160-10.10.10.189
CAの環境を作成します。
$ cd /etc/openvpn $ sudo -s # make-cadir ca # mkdir keys # chmod 700 keys # exit
ここで、
vars
変数を使用してファイルを編集し、次の値を設定します。
# easy-rsa export EASY_RSA="`pwd`" # openssl, pkcs11-tool, grep export OPENSSL="openssl" export PKCS11TOOL="pkcs11-tool" export GREP="grep" # openssl export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA` # export KEY_DIR="$EASY_RSA/keys" export PKCS11_MODULE_PATH="dummy" export PKCS11_PIN="dummy" # export KEY_SIZE=2048 # CA- 10 export CA_EXPIRE=3650 # : , , # , , e-mail export KEY_COUNTRY="RU" export KEY_PROVINCE="Magadan region" export KEY_CITY="Susuman" export KEY_ORG="Company" export KEY_EMAIL="info@compa.ny" export KEY_OU="IT" export KEY_NAME="UnbreakableVPN"
キー生成を保存して開始します。
# . vars # ./clean-all # ./build-ca Generating a 2048 bit RSA private key ..........................+++ .+++ writing new private key to 'ca.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [RU]: State or Province Name (full name) [Magadan region]: Locality Name (eg, city) [Susuman]: Organization Name (eg, company) [Company]: Organizational Unit Name (eg, section) [IT]: Common Name (eg, your name or your server's hostname) [Company CA]: Name [UnbreakableVPN]: Email Address [info@compa.ny]: # ./build-dh Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time … # ./build-key-server server # openvpn --genkey --secret keys/ta.key
テストユーザーを作成し、すぐに証明書を失効してレビューリストを作成します。
# ./build-key testuser # ./revoke-full testuser
OpenVPNのキー情報を使用して、サーバーをディレクトリに設定するために必要なすべてのキーをコピーします。
# cd keys # mkdir /etc/openvpn/.keys # cp ca.crt server.crt server.key dh2048.pem ta.key crl.pem /etc/openvpn/.keys # exit
ファイル
/etc/openvpn/server.conf
を作成するOpenVPNサーバーの構成を準備します。
# verb 4 # port 1194 proto tcp-server # mode server tls-server # MTU tun-mtu 1500 # , dev ovpn-clients dev-type tap # , TA- key-direction 0 # cert /etc/openvpn/.keys/server.crt key /etc/openvpn/.keys/server.key dh /etc/openvpn/.keys/dh2048.pem tls-auth /etc/openvpn/.keys/ta.key crl-verify /etc/openvpn/.keys/crl.pem # auth sha1 cipher AES-128-CBC # , , # persist-tun # topology subnet server-bridge 10.10.10.1 255.255.255.0 10.10.10.100 10.10.10.129 # # DNS push "redirect-gateway autolocal" push "dhcp-option DNS 10.10.10.200" push "dhcp-option DNS 10.20.20.200" # 10 , # — 2 keepalive 10 120 # 30 max-clients 30 # openvpn user nobody group nogroup # IP float # log /var/log/openvpn-server.log
2番目と3番目のサーバーでは、同じキー情報セットを使用します。構成ファイルは、発行されたIPアドレスのプールのみが異なります。
tincと同様に、標準のifup / ifdownスクリプトを使用してOpenVPNコントロールを構成し、デバイスの説明を
/etc/network/interfaces
に追加し
/etc/network/interfaces
。
auto ovpn-clients iface ovpn-clients inet manual pre-up ip tuntap add dev $IFACE mode tap post-up systemctl start openvpn@server.service pre-down systemctl stop openvpn@server.service post-down ip tuntap del dev $IFACE mode tap
ブリッジのインターフェイスをtincとともに有効にし、br0インターフェイスの設定を変更します。
... netmask 255.255.255.0 bridge_ports tap0 bridge_ports ovpn_clients bridge_stp off ...
すべてを稼働状態にしましょう。
$ sudo ifup ovpn-clients && sudo ifdown br0 && sudo ifup br0
サーバー構成の準備ができました。 クライアントキーとovpnファイルを作成します。
$ sudo -s # cd /etc/openvpn/ca # ./build-key PetrovIvan # exit
使用を簡素化するために、インラインキー情報を含むクライアントovpnファイルを作成します。
$ vim PetrovInan.ovpn # , client dev tap proto tcp # MTU , tun-mtu 1500 # remote vpn.compa.ny 1194 # nobind # , persist-key persist-tun # MSS mssfix # , TA TLS- key-direction 1 ns-cert-type server remote-cert-tls server auth sha1 cipher AES-128-CBC verb 4 keepalive 10 40 <ca> ### ca.crt </ca> <tls-auth> ### ta.key </tls-auth> <cert> ### PetrovIvan.crt </cert> <key> ### PetrovIvan.key </key>
保存してクライアントに渡します。クライアントは、ovpnファイルを使用してVPNに接続するだけです。 これでOpenVPNの構成が完了しました。
クライアントロック
クライアントの1つがVPNに接続することを禁止する必要がある場合(たとえば、従業員が解雇された場合)、証明書を単に失効させます。
$ ./revoke-all PetrovIvan
レビュー後、すべての
crl.pem
サーバーで更新し、
crl.pem
を実行します。
$ sudo service openvpn reload
server.conf
persist-key
オプション
server.conf
ないことに注意して
server.conf
。 これにより、実行時にキー情報を更新できます;そうでない場合は、デーモンの再起動が必要になります。
Chefを使用して失効リストを配布し、OpenVPNの
reload
アクションを実行します。 明らかに、この目的のために、構成(Ansible、Puppetなど)の自動展開のその他の手段、または単純なシェルスクリプトでも実行できます。
さらに、ディレクトリをGitのCAに配置しました。これにより、私たちとクライアントは、衝突を避けるために重要な情報とともに作業することができました。
おわりに
もちろん、運用中に説明したソリューションが開発されます。 特に、キー生成中にクライアントovpnファイルを自動的に作成し、VPN監視システムで動作する単純なスクリプトを追加しました。
このソリューションの弱点についての考えや、構成のさらなる開発に関するアイデア/質問がある場合は、彼らのコメントを見てうれしいです!
PS
ブログもご覧ください。