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 = 0mss = 1280 # MTU to set on installed routes, 0 to disable.# mtu = 0mtu = 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
に準拠しています。
これで起動するようになります。
おわりに
書きかけです。