strongSwan で iOS 対応の VPN を作成する(charon-systemd 版)
strongSwan を使って iOS(もちろん macOS も)対応の VPN を作成します。strongSwan 5.8.0 で設定方法が大きく変わりましたので、新しい方(charon-systemd)で設定します。残念ながら、執筆時点で最新バージョンの strongSwan 5.9.10 は buggy なため、この記事の設定例では、ローカルで rpmbuild した strongswan-5.9.11-dr3.x86_64.rpm を使用しています。5.9.11 の正式リリースを待つか、自力でビルドしましょう。
全体像
モバイル端末から接続可能な VPN を作成する、リモートアクセススタイルです。
以下のような設定の VPS(IP アドレスは仮に 12.34.56.78 とします)に VPN サーバを建てます。VPN 用のプライベートネットワークとして、192.168.2.0/24 を作成します。それぞれ、firewalld のゾーンとして、public と trusted を割り当てます。VPS は 12.34.56.78 と 192.168.2.1 の 2つのアドレスを持ちます。
- eth0(public ゾーン, 12.34.56.78, 1234::5678)
- eth1(trusted ゾーン, 192.168.2.1, fd00:1234:5678::192:168:2:1)
ユニークローカルアドレスは RFC 4193 で規定された方式で、各自ランダムな値を生成してください。
モバイル端末からの通信は、全通信が VPN を経由する(外部サーバからは 12.34.56.78 からの通信に見える)方式か、trusted ゾーンの 192.168.2.0/24 宛の通信のみが VPN を経由する方式か、いずれかお好みの方法を選択できます。
前提
前提として、SSLサーバ証明書は取得済みとします。パスワード認証の場合は、Let's Encrypt のものでも OK です。クライアント証明書で認証する場合は、自前の認証局を建てて、サーバ証明書も発行しましょう。別の記事(strongSwan 用の証明書を作成する)も参照ください。
Let's Encryptでは、--key-type オプションで RSA と ECDSA から cipher を選べるようになりました(デフォルトは ECDSA ですが、一度 RSA で取得したものは更新しても RSA のままなので、ECDSA を使いたい場合は手動で取り直す必要があります)。
インストール
説明する間でもないですが、例によってこうです。
# dnf install strongswan strongswan-sqlite tpm2-abrmd
strongswan-sqlite は入れておかないと、swanctl コマンドで一部のオプションを指定した時にエラーになります。VPN サーバとして使うだけなら must ではないです。VPS には TPM(Trusted Platform Module)はないのですが、strongSwan が TPM を利用しようとするので、stub として tpm2-abrmd を入れておきます。
strongSwan の設定
/etc/strongswan/swanctl/conf.d/my-vpn-ikev2.conf を以下のように作成します(ファイル名は何でもいいです)。
一応、IPv6 対応です。
VPN にアクセスしたクライアントには、192.168.2.32-192.168.2.127 と fd00:1234:5678::192:168:2:32-fd00:1234:5678::192:168:2:127 の仮想アドレスを振ります。
DNS は VPN 用のローカル DNS サーバとして 192.168.2.1(fd00:1234:5678::192:168:2:1)と、グローバルな DNS サーバとして Google Public DNS を指定しています。適宜変更してください。
設定の一覧の詳細は、公式のドキュメントを参照してください。デフォルトで問題ない部分は触っていません。
/etc/strongswan/swanctl/ 以下にサーバ証明書を配置します。秘密鍵と公開鍵の両方が必要です。ここでは、Let's Encrtypt の証明書を使用する場合の配置例を挙げます。以下のように、シンボリックリンクを作るのが良いでしょう。
# tree /etc/strongswan/swanctl/
.
├── bliss
├── conf.d
│ └── my-vpn-ikev2.conf
├── ecdsa
├── pkcs12
├── pkcs8
├── private
│ └── example.com.key.pem -> /etc/letsencrypt/live/example.com/privkey.pem
├── pubkey
├── rsa
├── swanctl.conf
├── x509
│ └── example.com.cert.pem -> /etc/letsencrypt/live/example.com/fullchain.pem
├── x509aa
├── x509ac
├── x509ca
├── x509crl
└── x509ocsp
15 directories, 3 files
#
/etc/strongswan/swanctl/my-vpn-ikev2.conf は以下のように書きます。
connections {
my-vpn-ikev2 {
version = 2
unique = never
encap = yes
dpd_delay = 30s
send_cert = always
pools = pool-zone-trusted-ipv6, pool-zone-trusted-ipv4
local {
id = example.com
certs = example.com.cert.pem
}
remote {
auth = eap-mschapv2
eap_id = %any
}
children {
my-vpn-ikev2 {
local_ts = ::/0, 0.0.0.0/0
#local_ts = fd00:1234:5678::192:168:2:1/64, 192.168.2.0/24
}
}
}
}
pools {
pool-zone-trusted-ipv4 {
addrs = 192.168.2.32-192.168.2.127
dns = 192.168.16.1, 8.8.8.8, 8.8.4.4
}
pool-zone-trusted-ipv6 {
addrs = fd00:1234:5678::192:168:2:32-fd00:1234:5678::192:168:2:127
dns = fd00:1234:5678::192:168:2:1, 2001:4860:4860::8888, 2001:4860:4860::8844
}
}
secrets {
eap-alice {
id=alice
secret="********"
}
eap-bob {
id=bob
secret="********"
}
}
/etc/strongswan/swanctl/ 以下に証明書を配置します。サーバ証明書の秘密鍵と公開鍵、認証局の公開鍵は最低限必要です。CRL は必要な場合は配置しましょう。シンボリックリンクでも、実体のファイルでも、どちらでも構いません。クライアント証明書は、ここで登録した認証局から発行されているものであれば使えます。
# tree /etc/strongswan/swanctl/ . ├── bliss ├── conf.d │ └── my-vpn-ikev2.conf ├── ecdsa ├── pkcs12 ├── pkcs8 ├── private │ └── example.com.key.pem -> /etc/pki/myCA/servers/example.com.key.pem ├── pubkey ├── rsa ├── swanctl.conf ├── x509 │ └── example.com.cert.pem -> /etc/pki/myCA/servers/example.com.cert.pem ├── x509aa ├── x509ac ├── x509ca │ └── root.cert.pem -> /etc/pki/myCA/cacerts/root.cert.pem ├── x509crl │ └── crl.pem -> /etc/pki/myCA/crls/crl.pem └── x509ocsp 15 directories, 6 files #
各種証明書は /etc/strongswan/swanctl/x509 からの相対パスだったり、フルパスだったり、URI だったりして、全く統一感のない設定ファイルです。
connections {
my-vpn-ikev2 {
version = 2
unique = never
encap = yes
dpd_delay = 30s
send_cert = always
pools = pool-zone-trusted-ipv6, pool-zone-trusted-ipv4
local {
id = example.com
certs = example.com.cert.pem
}
remote {
auth = eap-tls
eap_id = %any
}
children {
my-vpn-ikev2 {
local_ts = ::/0, 0.0.0.0/0
#local_ts = fd00:1234:5678::192:168:2:1/64, 192.168.2.0/24
}
}
}
}
pools {
pool-zone-trusted-ipv4 {
addrs = 192.168.2.32-192.168.2.127
dns = 192.168.16.1, 8.8.8.8, 8.8.4.4
}
pool-zone-trusted-ipv6 {
addrs = fd00:1234:5678::192:168:2:32-fd00:1234:5678::192:168:2:127
dns = fd00:1234:5678::192:168:2:1, 2001:4860:4860::8888, 2001:4860:4860::8844
}
}
authorities {
my-root-ca {
file = /etc/pki/myCA/cacerts/root.cert.pem
crl_uris = file:///etc/pki/myCA/crls/crl.pem
}
}
firewalld の設定
strongSwan で使用するポートを開けます。500/UDP、4500/UDP、4500/TCP が開きます。
# firewall-cmd --permanent --zone=public --add-service=ipsec success # firewall-cmd --reload success #
すべてのパケットを VPN 経由にする場合は、NAT の設定をします。以下では、eth0 (ゾーン public)がインターネット側、eth1(ゾーン trusted) が VPN 側です。
# firewall-cmd --permanent --zone=trusted --change-interface=eth1 success # firewall-cmd --permanent --zone=trusted --add-masquerade success # firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -o eth0 -j MASQUERADE success # firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i eth1 -o eth0 -j ACCEPT success # firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT success # firewall-cmd --reload success #
MSS と MTU は /etc/strongswan/strongswan.d/charon/kernel-netlink.conf に設定があるので、適宜変更します。
# MSS to set on installed routes, 0 to disable.
# mss = 0
mss = 1280
# MTU to set on installed routes, 0 to disable.
# mtu = 0
mtu = 1280
とりあえず、上記の例では最低値の 1280 に設定していますが、VPN の疎通確認後、各自の環境に合わせて適宜増加させてください。
一度でも旧設定を使った場合
stringswan-starter.service を使うと、古い設定のままで動かすことができます。一旦、古い設定を使ってしばらく運用し、後から stringswan.service に移行しようとお考えの方! ハマりポイントがあります。
stringswan-starter.service と stringswan.service には、ディレクトリ /run/strongswan の扱いについて、以下の差異があります。
stringswan-starter.serviceは起動時に/run/strongswanを作成し、終了時に/run/strongswanを削除する。stringswan.serviceは起動時に/run/strongswanが存在することを前提としている。存在しない場合は、ソケットの作成に失敗し、エラーを吐いて起動しない。
このことからお分かりのように、一度でも旧設定で stringswan-starter.service を動かすと、stringswan.service が正常に動作するための前提が崩れてしまうのです。乱暴な仕様だなあ、という感じもします。
仕方がないので、stringswan.service に drop-in の仕組みを使って、パッチを充てることします。以下のように入力すると、エディタが起動します。
$ sudo systemctl edit strongswan.service
色が付いている部分を入力します。(2023-01-15 修正)
### Editing /etc/systemd/system/strongswan.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file [Service] RuntimeDirectory=strongswan RuntimeDirectoryMode=0755 ### Lines below this comment will be discarded
(2023-01-15 修正)systemd では、PID ファイルや UNIX ソケットの置き場所のディレクトリを作成する場合、RuntimeDirectory で指定することになりました。記事執筆時点では、この方法に移行していないパッケージも残っており、順次切り替わっていくものと思います。紹介している設定のパーミッションおよびオーナーは /usr/lib/tmpfiles.d/strongswan.conf に準拠しています。
これで起動するようになります。
おわりに
書きかけです。