Raspberry Pi(ラズパイ)上にVPNサーバ(StrongSwan)を導入する手順

IT

Coderの構築により、どこにいてもどのPCでも同じ開発環境を利用することができるようになりました。

しかしながら、Dockerでマイクロサービスを作成して、立ち上げた後の動作確認はLAN内から実施する必要があります。

こんな時に便利なのが、VPNサーバです。

こういった用途で、筆者は、大昔にVPNサーバをラズパイ上に構築していましたが、少し前にAndroid12のスマホから接続できなくなっていて、そのまま放置していました。

今回、そろそろ直そうと思い立ち、ラズパイ上にVPNサーバを再構築しました。

ラズパイは、消費電力が少ないため、個人のVPNサーバの様な常設の基盤サービスを動作させるのに打ってつけです。

一方で、いつ壊れてもおかしくないリーズナブルなサーバなので、構築手順をここに残すことにしました。

前提

  • Raspberry Pi(Raspbian)にSSH接続できる状態である。
  • インターネット側からアクセス可能なFQDNを持っていること。※以降の手順では[サーバのFQDN]と表記する

システム、ネットワーク構成と構築手順の流れ

再構築前のVPNサーバでは、SoftEtherという超簡単にVPNサーバを構築できるソフトウェアを利用していましたが、Android12のIKEv2というプロトコルに対応しておらず、仕方なくStrongSwanというソフトウェアに変更しました。結構手順が多くて大変です。

システム構成図です。

Raspberry PiにVPNソフトウェア「StrongSwan」を構築、設定します。

続いて、ネットワーク構成図です。

手順は下記流れになります。

①StrongSwan導入

何はともあれ、ソフトウェアをインストールします。

②認証用の自己証明書作成

パスワード認証も可能ですが、クライアント証明書認証にするため作成します。

③StrongSwanの設定

作成した証明書の紐付け、プロトコルの設定、VPNセグメントの設定などを行います。

④ルータのポートフォワード設定

ルータで外からのVPN接続をラズパイに転送する設定を行います。

⑤Raspberry Piのネットワーク設定

ラズパイをルータ化する設定です。VPNセグメントからの通信をLAN内にルーティングします。

⑥Androidからの接続確認

AndroidにStrongSwanアプリとクライアント証明書を導入し、LAN内のファイルサーバなどに接続してみます。

VPNサーバ構成手順

①StrongSwan導入

まずはインストールです。ラズパイにrootログインし、下記コマンドを流し込みます。

apt-get update
apt-get upgrade
apt install strongswan
apt install strongswan-pki
apt install libstrongswan-extra-plugins

②認証用の自己証明書作成

次に、自己証明書類を作成します。下記コマンドを流し込みますが、[サーバのFQDN][メールアドレス]は置き換えてください。なお、証明書の有効期限は10年とします。

cd /etc/ipsec.d/
ipsec pki --gen --type rsa --size 4096 \
	   --outform pem \
	   > private/strongswanKey.pem
chmod 600 private/strongswanKey.pem
ipsec pki --self --ca --lifetime 3650 \
	   --in private/strongswanKey.pem --type rsa \
	   --dn "C=CH, O=strongSwan, CN=strongSwan Root CA" \
	   --outform pem \
    > cacerts/strongswanCert.pem
ipsec pki --print --in cacerts/strongswanCert.pem
ipsec pki --gen --type rsa --size 2048 --outform pem > private/vpnHostKey.pem
chmod 600 private/vpnHostKey.pem
ipsec pki --pub --in private/vpnHostKey.pem --type rsa | \
      ipsec pki --issue --lifetime 3650 --outform pem \
                --cacert cacerts/strongswanCert.pem \
                --cakey private/strongswanKey.pem \
                --dn "C=CH, O=strongSwan, CN=[サーバのFQDN]" \
                --san [サーバのFQDN] \
                --flag serverAuth --flag ikeIntermediate \
          > certs/vpnHostCert.pem
ipsec pki --print --in certs/vpnHostCert.pem
ipsec pki --gen --type rsa --size 2048 --outform pem > private/ClientKey.pem
chmod 600 private/ClientKey.pem
ipsec pki --pub --in private/ClientKey.pem --type rsa | \
      ipsec pki --issue --lifetime 3650 --outform pem \
                --cacert cacerts/strongswanCert.pem \
                --cakey private/strongswanKey.pem \
                --dn "C=CH, O=strongSwan, CN=[メールアドレス]" \
                --san [メールアドレス] \
          > certs/ClientCert.pem

作成したクライアント証明書をPKCS#12形式に変換します。下記コマンドを流し込むと、パスワード設定を求められますので、任意のパスワードを設定してください。

openssl pkcs12 -export -name "My own VPN client certificate" \
                 -inkey private/ClientKey.pem \
                 -in certs/ClientCert.pem  \
                 -certfile cacerts/strongswanCert.pem \
                 -caname "strongSwan Root CA" \
                 -out Client.p12

Android端末にクライアント証明書をインストールするときに、設定したパスワードを入力する必要があります。パスワードを知っている人だけが、クライアント端末へ証明書導入できるため、万が一ファイルが外部に漏れても安全ということです。

出力されたClient.p12をそのままAndroid端末に読み込めないので、base64に変換し、sswanファイルを作成します。

base64 Client.p12

→クライアント証明書が文字列で表示されます。

PCの適当な場所に「Client.sswan」というファイルを作成し、下記入力します。

※[base64文字列]を上記コマンドの結果に置き換えます。[サーバのFQDN]も置き換えてください。

{
  "uuid": "a79d0628-cb3c-416a-814a-6f953603deb0",
  "name": "My own VPN client certificate",
  "type": "ikev2-cert",
  "remote": {
    "addr": "[サーバのFQDN]"
  },
  "local": {
    "p12": "[base64文字列]"
  }
}

③StrongSwanの設定

続いて、StrongSwanの設定ファイルを作成します。

任意のエディタで/etc/ipsec.confを開きます。

元々の文字列はすべて削除し、下記文字列を入力します。

VPNのセグメントは、rightsourceip=192.168.20.0/24で設定しています。LANのセグメントと重複していなければ、そのままでよいです。重複している場合は、第3オクテットの20を21などに変更しましょう。

/etc/ipsec.conf

config setup
  charondebug="cfg 2, dmn 2, ike 2, net 2"
conn %default
  keyexchange=ikev2
  ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024!
  esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1!
  dpdaction=clear
  dpddelay=300s
  rekey=no
  left=%any
  leftsubnet=0.0.0.0/0
  leftcert=vpnHostCert.pem
  right=%any
  rightdns=8.8.8.8,8.8.4.4
  rightsourceip=192.168.20.0/24
conn IPSec-IKEv2
  keyexchange=ikev2
  auto=add
conn IPSec-IKEv2-EAP
  also="IPSec-IKEv2"
  rightauth=eap-mschapv2
  rightsendcert=never
  eap_identity=%any
conn CiscoIPSec
  keyexchange=ikev1
  # forceencaps=yes
  rightauth=pubkey
  rightauth2=xauth
  auto=add

次に、/etc/ipsec.secretsを任意のエディタで開いて、元々の文字列を削除し、下記文字列に置き換えます。

/etc/ipsec.secrets

: RSA vpnHostKey.pem

設定ファイルを反映させます。

ipsec restart
ipsec status

現状、下記のように表示されるはずです。

Security Associations (0 up, 0 connecting):
  none

まだ何もつながっていません。

VPNサーバの起動を確認しておきます。

ss -uapn

udp/500と4500が受付開始されていればオッケーです。

④ルータのポートフォワード設定

ルータの種類は、メーカー毎に多種多様のため、設定の抽象的な意味のみ記載します。

下記2設定を行います。

  • インターネットからルータに届いたudp/500をラズパイ(VPNサーバ)のudp/500に転送
  • インターネットからルータに届いたudp/4500をラズパイ(VPNサーバ)のudp/4500に転送

⑤Raspberry Piのネットワーク設定

最後に、VPNセグメントからの通信をLANにルーティングする設定です。

まずは、カーネル設定です。下記コマンドを流し込みます。

echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf
echo net.ipv6.conf.all.forwarding = 1 >> /etc/sysctl.conf
echo net.ipv4.conf.all.accept_redirects = 0 >> /etc/sysctl.conf
echo net.ipv4.conf.all.send_redirects = 0 >> /etc/sysctl.conf
sysctl -p

次に、ルーティング設定です。下記コマンドを流し込んで設定は完了です。

apt install iptables-persistent
iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -j MASQUERADE
iptables-save > /etc/iptables/rules.v4
【参考】
実は、ラズパイで構築する前に、WindowsのWSLでVPNサーバを構築しようと企んでいましたが、このルーティングがどうしてもできず断念した経緯があります。
WSLの場合は、ホストのWindowsに来たUDP通信をWSLにフォワードする設定も必要となりますが、そちらについては、下記ソフトを使用することで実現できました。

GitHub - matthid/UdpPortForwarder: Simple utility tool to forward udp ports, Supports multiple clients.
Simple utility tool to forward udp ports, Supports multiple clients. - matthid/UdpPortForwarder

⑥Androidからの接続確認

Android端末にStrongSwanアプリを導入します。

strongSwan VPN Client - Apps on Google Play
An easy to use IKEv2/IPsec-based VPN client.

作成した「Client.sswan」をAndroid端末に送り、StrongSwanアプリでClient.sswanを読み込んで、証明書をインストールします。

アプリを起動後、右上の「ADD VPN PROFILE」の横の3つの点をタップし、「Import VPN profile」をタップすると、ファイル選択画面が出ます。

そこで、「Client.sswan」を選択すると下記画面が出ます。

「IMPORT CERTIFICATE FROM VPN PROFILE」をタップすると、パスワード入力を求められます。

設定したパスワードを入力してOKをタップします。

下記画面が出ますので、そのままOKをタップします。

こちらもそのままOKをタップします。

下記画面が表示されます。「選択」をタップします。

最後に、右上の「IMPORT」をタップします。

これで設定は完了しました。

読み込んだプロファイルをタップし、VPN接続します。

下記のように「Status: Connected」となれば接続完了です。

あとは、LAN内の任意のサービス(ファイルサーバ等)に接続できることを確認します。

【追記】LinuxからのVPN接続

最近Linux Mint(Cinnamon)を使い始めました。

完成度が高くてWindowsのショートカットがそのまま使えたり、とても気に入っていますが、ラズパイのStrongSwanにVPN接続しようとして、VPNクライアントの設定に手こずったため、こちらに追記することにしました。

Ubuntuでも同じ手順で設定できると思います。

まず前提として、上記手順「②認証用の自己証明書作成」で作成しているクライアント証明書(p12ファイルやsswanファイル)は、Linuxではそのまま利用できません。

p12ファイルやsswanファイルには、サーバ証明書、クライアント証明書(秘密鍵、公開鍵)が含まれていて、クライアントへの導入が簡単にできるようになっています。

Linuxでは、p12ファイルにまとめる前の、それぞれの証明書をクライアントに導入する必要があります。

上記手順「②認証用の自己証明書作成」でラズパイに作成した下記ファイルを取得しておきます。

  • /etc/ipsec.d/cacerts/strongswanCert.pem
  • /etc/ipsec.d/certs/ClientCert.pem
  • /etc/ipsec.d/private/ClientKey.pem

では早速、クライアントのLinuxで必要なモジュールを導入します。

sudo apt-get install strongswan libcharon-extra-plugins

導入完了後、/etc/ipsec.dディレクトリができますので、VPNサーバから取得した3つのファイルを同じディレクトリに置きます。

  • /etc/ipsec.d/cacerts/strongswanCert.pem
  • /etc/ipsec.d/certs/ClientCert.pem
  • /etc/ipsec.d/private/ClientKey.pem

ファイルの所有者はすべてroot、権限は上2つの証明書が644、3つ目の秘密鍵が600です。

続いて、クライアント側のVPN設定ファイルを修正します。ファイルにデフォルト記載されている「#」から始まる行はコメント行のため、消してもそのままでも良いです。

/etc/ipsec.conf

config setup
conn ikev2-rw
    right=[サーバのFQDN]
    rightid=%any
    rightsubnet=0.0.0.0/0
    rightauth=pubkey
    leftcert=ClientCert.pem
    leftid="C=CH, O=strongSwan, CN=[メールアドレス]"
    leftsourceip=%config
    auto=add

/etc/ipsec.secrets

: RSA ClientKey.pem

最後に設定を再読込して設定完了です。

sudo ipsec restart
sudo ipsec reload

VPN接続コマンド

sudo ipsec up ikev2-rw

VPN切断コマンド

sudo ipsec down ikev2-rw

参考サイト

ポイント対サイトの証明書を生成してエクスポートする: Linux - strongSwan - Azure VPN Gateway
Linux (strongSwan) CLI を使用して、自己署名ルート証明書を作成し、公開キーをエクスポートし、クライアント証明書を生成する方法について説明します。
strongSwan - ArchWiki
strongSwanのモダンな方法を使ってVPN環境構築してみた
IKEv2、公開鍵認証、仮想IP使用、Roadwarriorシナリオ。 スマホはAndroid版アプリを使用し ...
WSL2で起動したサーバーに外部の端末からアクセスする
ぶっちゃけググれば、もっと詳細に説明してくれている記事がいくらでもみつかるのだけれど、一応自分用のメモとして書いておく。 概要 wsl2の中でサーバーを立ち上げて開発していると、外部の端末(例えば実機スマホなど)から動作確認のためにアクセス...

コメント

  1. […] 考になる記事がなくて断念してたのだが、以下の記事があった。Raspberry Pi(ラズパイ)上にVPNサーバ(StrongSwan)を導入する手順ここまでまとめられてるなら案外簡単そうだなって。中途半端に […]

タイトルとURLをコピーしました