IPsec L2TP VPN サーバ
IPsec/L2TP はレガシーな VPN プロトコルと見なされています。現代的なクライアント (Windows 7 以降の Windows、11 以降の Android、10.11 以降の macOS、9 以降の iOS) のためには、代わりに IPsec IKEv2 MSCHAPv2 VPN server を検討してください。両方をサポートする必要があるなら、strongSwan はレガシーな IKEv1/L2TP クライアントと現代的な純粋な IKEv2/MSCHAPv2 クライアントを同時に取り扱うことができます。
多くのオペレーティングシステムは、L2TP/IPSec による VPN 機能を実装しています。L2TP/IPSec は、IPsec (インターネットプロトコル セキュリティ) による機密保持および認証サービス、レイヤ2トンネルプロトコル(L2TP)によるネットワークトンネリング、pppdを通したユーザ認証を組み合わせたものです。管理者は、複数の異なるシステムをまたいでVPNネットワークを設定可能です。Android、Windows、GNU/Linux、macOSなどのオペレーティングシステム間で、商用ソフトウェアを一切追加することなしに、VPNを設定可能です。
はじめに
IPsec/L2TPは、Windowsなどのオペレーティングシステムで一般的に使用されているVPNプロトコルです。VPN クライアント側としては、Windows では 2000 以降のすべてのバージョンに組み込まれており、(OpenVPN などと異なり) 外部クライアントを要せずとても便利です。他方のサーバ側の Linux については、IPsec、L2TP および PPP の少なくとも3つのレイヤが関わってしまいますので、設定がずっと難しいです。
- IPsecの設定は、ネットワーク通信の機密性およびクライアント(システム)の認証を提供します
- L2TP でトンネルを設定することで、VPN トラフィックが透過的に IPsec を通過します
- PPP(ポイント・トゥ・ポイント プロトコル)の設定は、ユーザー認証を管理します
このガイドでは、DHCP や RADIUS、Samba、公開鍵インフラ(PKI)の設定を記載していません。Linuxをクライアントにする際の設定方法を記載していません(実際には、このガイドを読めば容易に判るはずですが)。そもそも、クライアント側の Windows の設定について記載しているのも、サーバ設定のトラブルシューティングに使うことを想定しているからにすぎません。
想定および設定例
このガイドでは、以下の状況を想定した設定例を記載しています(そのため実際の設定は、状況に応じて読み替えて行ってください):
- ドメイン名は example.com
- サーバ名は vpn.example.com
- CA(認証局) ファイル名は ca.crt
- サーバ側の認証ファイル名は vpn.example.com.crt
- サーバ側の鍵ファイル名は vpn.example.com.key
- クライアント側の認証ファイル名は client.example.com.crt
- クライアント側の鍵ファイル名は client.example.com.key
IPsec
最初にセットアップするレイヤが IPsec です。IPsec はピア・トゥ・ピア(1対1)なので、IPsec 用語としてはクライアントをイニシエータ、サーバをレスポンダと呼びます。
Portage にある IPsec の実装には、LibreSwan と strongswan の 2 種類の選択肢があります。どちらも NAT トラバーサルがデフォルトで有効化されていますが、VPN サーバが NAT の背後にあり、かつクライアントが Windows である場合、特別なクラアイント設定が必要になります。
次のセクションでは、それぞれ異なる設定が説明されています。それぞれの選択肢について以下を記載しています
- どうやって認証に PSK を用いるか
- どうやって認証に証明書を用いるか
PSK か証明書か、いずれか一つを選んでください。IKEv1 プロトコルにおいて、PSK をやりとりする手段はない、ということに注意してください。通信元と通信先の IP アドレスに基づいてどの鍵を選ぶかという情報が得られるのみです。多くの状況では、応答者は要求者の IP アドレスをあらかじめ知り得ないため、誰もが同じ事前共有鍵を使用するほかありません。よって、単一のユーザしかいない場合でさえも、事前共有鍵 (PSK) 方式よりも証明書 (PKI) 方式が推奨されます。しかし、証明書や PKI(公開鍵インフラストラクチャ)を作成するのは比較的複雑な作業ですので、この記事の対応範囲外ですが、app-crypt/easy-rsa パッケージを使うと楽になります。
このチュートリアルでは、証明書方式の認証を使用している場合、すでに必要な証明書が利用できることを前提としています。
選択肢 1: LibreSwan
LibreSwan は (FreeS/WAN のフォークである)OpenSwan のフォークです。実際には、もともとの OpenSwan の制作者達によるフォークですが、彼らが Xelerance を辞めたあとに "Openswan" の名称をめぐって紛争になり訴訟に至りました。その結果として、LibreSwan という名称が採用されました。
LibreSwan における、PSK 方式でのセットアップ
共通鍵を作成せねばなりません。鍵は、引用符で括られた文字列か、16進数字です。次の例では、PUT_VPN_SERVER_IP
を実際のサーバの IP アドレスに置き換えてください。ドメイン名を用いることも可能ですが、LibreSwan の制作者達は推奨していません。%any
という設定は、この PSK を用いるあらゆるクライアントを許可します。
PUT_VPN_SERVER_IP %any : PSK 0x87839cfdab5f74bc211de156d2902d128bec3243
# もしくは、16進数字の代わりに平文テキストを使用:
# PUT_VPN_SERVER_IP %any : PSK "password_pass"
そして、/etc/ipsec.d/vpn.example.com.conf を作成します:
conn vpnserver
type=transport
authby=secret
ikev2=no
pfs=no
rekey=no
keyingtries=1
left=%defaultroute
leftprotoport=udp/l2tp
leftid=@vpn.example.com
right=%any
rightprotoport=udp/%any
auto=add
LibreSwan における、証明書方式でのセットアップ
LibreSwan のためには、Network Security Services (NSS) を要し、適切に設定されていなければならず、証明書の管理に用います。容易にするためには、PKCS#12 バンドルには、サーバの秘密鍵と証明書、認証局(CA)の証明書がまとめておくべきです。
user $
openssl pkcs12 -export -certfile ca.crt -inkey vpn.example.com.key -in vpn.example.com.crt -out /etc/ipsec.d/vpn.example.com.p12 -passout pass:
このバンドルを、NSS データベースにインポートします:
root #
pk12util -i vpn.example.com.p12 -d /var/lib/ipsec/nss
LibreSwan の設定ファイルは、インポートされた内容物をニックネームで参照します。certutil -L -d /var/lib/ipsec/nss や certutil -K -d /var/lib/ipsec/nss を用いればニックネームがわかります。
上記の例では、vpn.example.com
がニックネームとして用いられており、certutil -K -d . コマンドで判ります。
conn vpnserver
type=transport
authby=rsasig
ikev2=no
pfs=no
rekey=no
keyingtries=1
left=%defaultroute
leftprotoport=udp/l2tp
leftcert=vpn.example.com
leftid=@vpn.example.com
right=%any
rightprotoport=udp/%any
rightrsasigkey=%cert
auto=add
ここでは、vpn.example.com
はcertutil -L -d . コマンドで判るニックネームです。
選択肢 2: strongSwan
strongSwan は、FreeS/WAN のフォークの一つです。(多くのコードが書き換えられていますが。)
strongSwan はレガシーな ipsec.conf 設定機構 (stroke) をサポートする一方で、新しいインターフェースのための新しい種類の設定ファイルも導入しています: the Versatile IKE Control Interface (VICI) です。
これを使用するには、いくつかディレクトリを定義する必要があります:
root #
( umask 007 ;\
mkdir /etc/swanctl/{bliss,conf.d,ecsda,pkcs12,pkcs8,private,pubkey,rsa};\
mkdir /etc/swanctl/x509{,aa,ac,ca,crl,ocsp};\
mkdir /etc/ipsec.d;\
mkdir /etc/ipsec.d/{private,certs,crls,ocspcerts,aacerts,acerts,reqs}; )
strongSwan における、PSK 方式でのセットアップ
共通鍵を作成せねばなりません。共通鍵は引用符で括られた文字列か、16進数字です。
connections {
linuxvpn {
version=1
proposals=aes128-sha1-modp1024,default
local-1 {
auth=psk
id = @vpn.example.com
}
remote-1 {
auth=psk
}
children {
only {
mode=transport
local_ts=dynamic[udp/l2tp]
rekey_time=0
}
}
}
}
pools {
}
secrets {
ike-1 {
secret = "password_pass"
}
}
authorities {
}
proposals=aes128-sha1-modp1024,default の部分は Windows 7 と Android のためのものです。これが無いと、これらのクライアントは接続できないでしょう。下のクライアントに関するメモも確認してください。
strongSwan における、証明書方式でのセットアップ
正しい場所にファイルをコピーする必要があります:
root #
cp ca.crt /etc/swanctl/x509ca
root #
cp server.example.com.crt /etc/swanctl/x509
root #
cp server.example.com.key /etc/swanctl/private
そして、/etc/swanctl/conf.d/vpn.example.com.conf を下記の通り更新します:
connections {
linuxvpn {
version=1
proposals=aes128-sha1-modp1024,default
local-1 {
auth = pubkey
certs = vpn.example.com.crt
id = @vpn.example.com
}
remote-1 {
auth = pubkey
}
children {
only {
mode=transport
local_ts=dynamic[udp/l2tp]
rekey_time=0
}
}
}
}
pools {
}
secrets {
}
authorities {
}
proposals=aes128-sha1-modp1024,default の部分は Windows 7 と Android のためのものです。これが無いと、これらのクライアントは接続できないでしょう。下のクライアントに関するメモも確認してください。
L2TP
2つ目の層である、第2層トンネリングプロトコル(L2TP)は、セットアップがずっと容易です。L2TP は IPsec と同様にピアツーピア(2端点間)プロトコルです。クライアント側は「L2TP アクセス集線装置」(L2TP Acccess Concentrator) すなわち LAC と呼ばれ、サーバ側は「L2TP ネットワークサーバ」(L2TP Network Server) すなわち LNS と呼ばれます。
L2TP を IPsec トンネルに制限する
L2TP は秘匿されていませんから、IPsec 接続の外ではアクセス可能にすべきではありません
iptables
iptables を使っているならば、IPsec レイヤ外の L2TP 接続をブロックするつぎのようなルールを用いましょう:
root #
iptables -t filter -A INPUT -p udp -m policy --dir in --pol ipsec -m udp --dport l2tp -j ACCEPT
root #
iptables -t filter -A INPUT -p udp -m udp --dport l2tp -j REJECT --reject-with icmp-port-unreachable
root #
iptables -t filter -A OUTPUT -p udp -m policy --dir out --pol ipsec -m udp --sport l2tp -j ACCEPT
root #
iptables -t filter -A OUTPUT -p udp -m udp --sport l2tp -j REJECT --reject-with icmp-port-unreachable
nftables
nftables を使っているならば、IPsec レイヤ外の L2TP 接続をブロックするつぎのようなスクリプトを用いましょう:
#!/sbin/nft -f
table ip l2tp-ipsec {
chain INPUT {
type filter hook input priority filter; policy accept;
meta ipsec exists udp dport 1701 counter accept
udp dport 1701 counter reject
}
chain OUTPUT {
type filter hook output priority filter; policy accept;
rt ipsec exists udp sport 1701 counter accept
udp sport 1701 counter reject
}
}
firewalld
firewalld は外部からの接続のみをブロックし、内部からの接続はブロックしません。さらに、「リッチ」ルールを使っても、外部からの接続に関して必要なものを記述できるほどの表現力はありません。しかしながら、firewalld は nftables のテーブルと共存できるように設計されているため、上の nftables を使った解決策が干渉せずに機能するでしょう。
xl2tpd を用いる
ほかの L2TP サーバと異なり、xl2tpd は、DHCP や RADIUS のサーバを用いなくとも、IP アドレスプールの管理が可能です。こうした機能はネットワーク階層構造を逸脱していますが、簡易なセットアップ時には極めて便利です:
[global]
port = 1701
access control = no
[lns default]
ip range = 172.21.118.2-172.21.118.254
local ip = 172.21.118.1
require authentication = yes
name = LinuxVPN
pppoptfile = /etc/ppp/options.xl2tpd
他方で RADIUS や DHCP のサーバを用いるならば、ip range
と local ip
の箇所は空欄にしてください。
オプション用のファイルもつくります:
require-mschap-v2
This line is for Windows's benefit. Without it, (at least as of Windows 10) Windows will send EAP probes, which pppd rejects, but Windows will insist, rather then fall back. Manual configuration of the VPN connection will be for Windows to use MSCHAPv2 instead of EAP. By limiting Windows's choice, it will work "out of the box".
If more flexibility is desired and Windows client configuration is not an issue, this line can be dropped.
PPP
最後の層は、ポイント・トゥ・ポイント プロトコル(PPP)層です。インストールすべきパッケージは net-dialup/pppd です。
root #
emerge --ask net-dialup/pppd
認証
PPP は認証に用いられます。PSK 認証による証明書と異なり、PPP 層は、エンドユーザが VPN にアクセスするのに必要な認証や権限付与のためにより多くのことを要します。
chap.secrets を通じた認証
小規模のユーザ(典型的には、ホームネットワークから外部に接続したいような状況)には、chap.secrets ファイルを用いた認証で達せられます:
# CHAP を用いた認証
# クライアント サーバ 合言葉 IP アドレス
avatar * unontainium *
ドメインで認証を行うときには、クライアント名は適切に切り出されていなければなりません。たとえばこの場合は
EXAMPLE\\avatar
/etc/ppp/chap-secrets 内のパスワードは暗号化されていませんから、root のみ読み書き可能な属性にしなければなりません
Samba を通じた認証
マシンが MS ドメインや AD(アクティブディレクトリ)フォレストの一部である(あるいはこれらをホスティングしている)のならば、クライアントは winbind を用いることも可能です。つまり、Samba を認証に用いることが可能です。plugin winbind.so
を ppp オプションに追加しましょう。なお、そのための Samba と pppd のセットアップに関しては、この記事の対応範囲外です。
RADIUS を通じた認証
pppd は RADIUS を利用できます。radius
USE フラグを有効にして net-dialup/ppp をインストールしましょう。PPP オプションに plugin radius.so
と plugin radattr.so
を追加します。なお、RADIUS のセットアップに関しては、この記事の対応範囲外です。
EAP-TLS を通じた認証
(マシンにではなく)ユーザ個人が証明書を保有していたら、pppd の認証に EAP-TLS を用いることも可能です。eap-tls
USE フラグを有効にして net-dialup/ppp をインストールしてください。require-eap
も、PPP のオプションファイルに追加する必要があるかもしれません。このような pppd のセットアップ方法に関しては、この記事の対応範囲外です。
サーバに関するメモ
NAT 裏のサーバ
サーバが NAT (Network Address Translation)裏にある場合、つまり多くはホームルータの裏にサーバがホスティングされている場合ですが、IPsec 接続を確実に動作させるには、特別な注意点があります。
ポートを開く
2 つのポートを開く必要があります:
- UDP ポート 500 (ISAKMP)
- UDP ポート 4500 (NAT トラバーサル)
VPN サーバに転送することも忘れないでください。
さらに、(ポートではなく)以下のインターネットプロトコルを許可する必要があります:
- 50 (ESP)
- 51 (AH)
こうした設定は、ルータがプロトコル別に設定されている(およそスルーでない)際に必要になることがあります。
クライアントに関するメモ
一般
PKCS12 ファイルを作成する
証明書は PKCS12 にパッケージングされていなければなりません。この処理は openssl か gnutls で行えます:
user $
openssl pkcs12 -export -certfile ca.crt -inkey client.example.com.key -in client.example.com.crt -out client.example.com.p12
user $
certtool --load-ca-certificate /home/salahx/easy-rsa/pki/ca.crt --load-certificate /home/salahx/easy-rsa/pki/issued/client.example.com.crt --load-privkey /home/salahx/easy-rsa/pki/private/client.example.com.key --to-p12 --p12-name=client.example.com.crt --outder --outfile client.example.com.p12
パスワードを確実に設定してください。クライアントによっては (例えば MacOS では) パスワードなしの p12 ファイルを開けません。一部のレガシーなクライアントには、DER エンコードされた p12 ファイルしか扱えないものもあります (openssl のデフォルトで、certtool のデフォルトは PEM になっています)。また、証明書はマシン/システムが所有するもので、ユーザが所有するものではないことを再確認してください。
Windows
RRAS エラー 809: リモート サーバーが応答していないため、お使いのコンピューターと VPN サーバーの間のネットワーク接続を確立できませんでした。...
When importing, it's important to choose "Local Machine" to import to, NOT "Current User". Otherwise, Windows can't find the certificate and just times out without ever contacting the IPSec server.
Weak proposals
Unlike other clients, Windows prefers the weakest proposal. So if 3des-sha1-modp1024 is offered, it will take it over a better option. On strongSwan, the added proposal aes128-sha1-modp1024 is added for the benefit of legacy clients (Windows 7 and earlier). Older version of Windows won't offer anything stronger than modp1024 by default. It is possible to allow or force Windows to accept a better proposal through a registry hack. Set DWORD HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Rasman\Parameters\NegotiateDH2048_AES256 to 1 to enable Windows to accept aes256-sha1-modp2048, set it to 2 to not allow anything weaker.
If there are no legacy clients (see Android section below), and all Windows clients are at least Windows 10 21H2 (might work with earlier versions) OR have the above registry hack applies, and the server is running strongSwan, the proposal=aes128-sha1-modp1024 may be removed or adjusted.
スプリットトンネリングを有効化する
デフォルトでは Windows はフルトンネルモード (すべての接続が VPN を経由する) で接続しますが、Windows 側でスプリットトンネルを有効化することもできます。
GUI からスプリットトンネリングを有効化する
「アダプターのオプションを変更する」から、アダプターを表示してください。VPN 接続を右クリックし、プロパティを選択して、ネットワーク、インターネット プロトコル バージョン 4 (TCP/IPv4)、プロパティ、詳細設定へと進み、「リモート ネットワークでデフォルト ゲートウェイを使う」のチェックを外してください。
PowerShell から
Set-VPNconnection -name vpn.example.com -SplitTunneling $true
vpn.example.com の部分は VPN 接続名で置き換えてください。
NAT 裏のサーバ
Windows does not automatically support IPsec/L2TP servers behind NAT. See Configure a L2TP/IPsec server behind a NAT-T device to enable support.
RRAS Error 835: The L2TP connection attempt failed because the security layer could not authenticate the remote computer...
The subjectAltName of the server certificate MUST match the server name being connected to. (When connecting by IP address, Windows skips this check).
Mac OS X
MacOS X client require several steps:
- The CA and client certificates must be imported into the System keychain, not the Login keychain.
- In the Keychain app, the new CA is untrusted by default, so it must be marked trusted
- Also note that if corrected after the VPN connection is created, it is necessary to re-select the certificate under Authentication Settings to clear the error.
The "Account Name" should be the PPP username.
Note that Mac OS also checks the subjectAltName vs DNS, if it does not match, it will refuse to connect.
Android
As of Android 12, Android no longer supports IPsec/L2TP. Like Windows, Android won't offer anything stronger than modp1024, so strongSwan config has an added proposal of aes128-sha1-modp1024. This works even on very old version of Android (at least 4.2). If there are no Android client or other legacy clients (see Windows above), the proposal=aes128-sha1-modp1024 may be removed or adjusted.
iOS
iOS は IPSec/L2TP では証明書方式の認証をサポートしておらず、事前共有鍵 (PSK) のみサポートしています。(しかしながら、IPSec/XAuth では証明書をサポートしています。)
外部の情報
- a Linux L2TP/IPsec VPN server Jacco de Leeuw による記事