仮構築・WireGuardとFreeBSD 13.0Rを使用したandroidスマートホン自宅アクセス環境

OpenVPNで作っていた自宅アクセス用VPN回線がうまく通らなくなった(*1)ので再構築しようかと考えていた矢先、WireGuardなるものがあるのを知ったので、とりあえず試験がてら構築のメモ。
昨今コロナ禍でリモートワークが叫ばれる中、自宅にいることを証明するのが大変めんどくさいのでとりあえず自宅経由で会社に接続するというのが本当の狙い。外出先からFreeBSDとxfreerdp使ってWindowsに接続し、そこから会社内へアクセスできればラッキーかな、と。もちろん勤め先の資材と自宅のネットワークは分離し、会社とWindowsとの間は監視して余計なパケットが流れていないかは確認する。(要は会社が余計なことしでかしてないか監視するためにマジックミラーの中を歩かせたい)


まずは、利便性の観点から自宅のFreeBSDとAndroidスマートホンの接続を考える。

[1. 考え方]
 ・Peer to Peer、Point to point、End to end、表現はなんでもいいんだが、サーバとクライアントという関係より1対1で接続する関係。ここでは考え方を簡単にする意味合いと常時起動中のFreeBSDを境目にしてインターネット回線へ向かうため、FreeBSDをサーバ・Androidスマホをクライアントという呼び方でこの記事は統一する。(*2)
 ・WireGuardは秘密鍵と公開鍵の二つの鍵を使用した暗号化通信を行う。この秘密鍵(受信者が持つ)と公開鍵(発信者が持つ)の組合せにより、Peerを識別する。つまり一つのPeerは自身宛の暗号化通信を解読するためマスターキーたる秘密鍵を持ち、また相手方Peerのマスターキーだけが解読しうる暗号化を施すため相手方Peerの公開鍵を持つ。家の鍵で考えれば閉じる鍵と開く鍵は全く別で、開く鍵たる秘密鍵を元に閉じる鍵たる公開鍵を作ることができる。つまり公開鍵は複数本作ることが可能でそのための秘密鍵が管理外に持ち出されるとあとは秘密鍵の所持者宛となる通信を傍受さえできれば復号化し放題となる。
 ・LAN内のハード/ソフト資源にアクセスできるようにする。リモートワークだけで使うのはもったいないし、写真のデータサイズを考えるとデータの転送はすぐにでも行いたい。


[2. 必要な対処]
・WireGuardでできることはPeer to Peerなので、通常クライアント同士をただ直結した構成になってしまう。(WiFiやスイッチハブ経由ではなく、1:1のケーブル接続相当となるためこのままでは使いにくい)
なので、FreeBSDサーバより先のネットワークへアクセスできるようにしないといけない。そこでFreeBSDにデフォルトでインストールさているnatdは使用するが、Firewallによる防衛措置は今の所講じない(*3)。FreeBSDでデフォルトインストールされているFirewallとして、候補にPFやIPNWが考えられる。


[3. 準備]
・WireGuardのインストール。
本来wireguardだけでよいのだが、libqrencodeはstdinからQRコード生成が可能ということで便利なものは使っていきましょう。(*4)
root# pkg install wireguard libqrencode


[4.鍵の生成]
中身はbase64に化かした鍵。わりかし短い。
後ほど、この内容をコンフィグファイルに記載する。
server.privateはFreeBSD(サーバ)側の秘密鍵として、逆にpublicは公開鍵として。
smartphone.privateはAndroid(クライアント)側の秘密鍵として、逆にpublicは公開鍵として。
ファイル名自体は決めの話なので、とりあえず保存できればどうでもよい。
root# wg genkey > server.private
root# wg pubkey < server.private > server.public
root# wg genkey > smartphone.private
root# wg pubkey < smartphone.private > smartphone.public


[5.コンフィグの記載:サーバサイド]
まず、[Interface]の方。
Address は、VPNを設立(WireGuardを起動し1つ以上のPeerと接続)したときに使用する、サーバ側のIPアドレスを示す。(OpenVPNみたいにDHCP相当はない)
PrivateKey は Peerが送付してきたパケットを翻訳するために使用する鍵。(Public aka 公開鍵と取り違えないように)
ListenPort は、サービスの待受ポートを指定する。インターネット回線からHGWやBBルーターなどを使用してポートフォワードを行う場合はポート番号/UDPをFreeBSDへ転送する設定を忘れないこと。

続けて[Peer]の方。
PublicKey は、PeerとのVPNを設立したときにパケットを暗号化するために使用する鍵。(Private aka 秘密鍵と取り違えないように)
AllowedIP は、特にサーバサイドの場合は、接続先のPeerのIPアドレスを示す。(デフォルトルート相当の考え方に近い。ある秘密鍵を持つクライアントは1台なのでSubnetmaskは32)
ちなみに、1ファイル中[Peer]セクションは1つ以上あっても良い。その場合は使用する仮想インタフェースを共用する形になるし、[Peer]ごとにコンフィグを書き分けても良い。


root# cat __END__ > /usr/local/etc/wireguard/wg0.conf
[Interface]
Address = 192.168.254.254/32
PrivateKey = "server.private の内容"
ListenPort = 12345

[Peer]
PublicKey = "smartphone.public の内容"
AllowedIP = 192.168.254.253/32

__END__



[6.コンフィグの記載:クライアントサイド]
[Interface]の方は自身の情報を書く。ほとんどサーバサイドと変わらない。
サーバサイドと違うのはListenPortの記述は行わないことぐらい。
[Peer]のほうはサーバサイドの情報を書く。
PublicKey もサーバサイドと同じ考え方。(誤ってもさすがにクライアントサイドの鍵を書くことはないと思うが…[1敗])
AllowedIPs はデフォルトルート相当なのも変わらない。s付きなので、半角空白で複数書ける。smartphoneの場合は全てをVPN経由にするとネットワークパフォーマンスがほぼ落ちるので自宅のネットワーク範囲に合わせた設定が使いやすい。全ての通信をVPN経由にするなら0.0.0.0/0の指定にしておく。
EndPoint は例えばサーバサイドに接続するときインターネット回線経由であれば、グローバルIPアドレスとポート番号になるだろう。ポートフォワーディングが不安なうちは正直やらないほうが良いかもしれない。
ちなみに、このsmartphone.confのファイルは後でQRコード化する。

root# cat __END__ > /usr/local/etc/wireguard/smartphone.conf
[Interface]
Address = 192.168.254.253/32
PrivateKey = "smartphone.private の内容"

[Peer]
PublibKey = "server.public の内容"
AllowedIPs = 192.168.254.254/32
EndPoint = server.side.url:PORT-NUM

__END__


[・サーバサイドの設定 /etc/sysctl.conf]
net.inet.tcp.tso=0 → パケットに関する何らかの支援をCPUが行っているらしいのだが、それをOFFにする(逆かもしれない)。その処理を挟まない分速度向上が見込めるとのこと。
net.inet.ip.forwarding=1 → 必須。ネットワークゲートウェイとして動作するために必要な設定。/etc/rc.confにgateway_enable="YES"を記述しても良い。
いずれも再起動しないと有効にならないが、sysctlコマンドを使用することで、即時適用が可能。

root# vi /etc/sysctl.conf
net.inet.tcp.tso=0
net.inet.ip.forwarding=1
[EOT]


[・サーバサイドの設定 /etc/rc.conf]
具体的な説明は割愛。

root# vi /etc/rc.conf
natd_enable="YES"
natd_interface="インターネット側のNICデバイス名"
netd_flags="-dynamic"
firewall_enable="YES"
firewall_type="OPEN"
gateway_enable="YES"
wireguard_enable="YES"
wireguard_interfaces="wg0"
[EOT]


[・サービス起動]
具体的な説明は割愛。

root# service routing restart
root# service wireguard restart


[・Androidスマホへ適用]
表示されたQRコードをWireGuardアプリで読み取る。
先ほど作成したコンフィグではterminalで230列程度必要だったのでpng形式にして別の形で表示したほうが良いかもしれない。

root# qrencode -t ansiutf8 < smartphone.conf




疲れたのでここまで。
LinuxやWindowsであれば情報が腐るほどあるのでなんとかなるんじゃないかな。
暇があれば調べて追記するし、ダメそうならそのままだしみたいなヤツ。
そのうちラズパイに移設したいなあ…




[注釈]
*1: WireGuardは基本的にPoint to Point、End to End、1:1でのVPNにしか対応しない。かつL3接続が前提となる(やり方次第でL2接続相当にもできる)。OpenVPNはL2接続からL3接続をサポートし、OpenSSL等による秘密鍵/公開鍵型の暗号化をサポートする。要はVPNを維持する上で考慮しなければならない事項が多くなり、かつ証明書のデフォルトの期限が1年程度を見落としていたために一旦崩壊。最小限度で証明書を再発行し直しても最長10年のサポートにしかならない。(しかもその頃にはやり方を一切忘れているだろう、というオチ)

*2: 読み進めていけば分かるが、ただVPNを1:1で繋げるだけならそれほど難しいことはしていない。AndroidではなくFreeBSDやWindowsであったとしても対応するクライアントがあれば起動の仕方はともかくそれ以外は大して変わらないと思う。

*3: ファイアウォールは少なくともホストサイドとなるFreeBSDに設定するもののだが、①VPNを受け入れるための通常ネットワークインタフェース、②クライアントサイドへの通信ゲートとなる仮想ネットワークインタフェース、③その他別のネットワークへ接続するためのインタフェース との疎通を考えた上でファイアウォールを構築する必要があると言える。本文中では書かなかったが動的IPアドレス配下のNAT/NAPT(通常、HGWやブロードバンドルータと呼ばれるもの)配下にNAT/NAPT構成を作るからというのもあるのだが、玄関口だけは頑丈にして秘密の勝手口が疎かというのは目も当てられない。

*4: 実は参考サイトから知った。libqrencodeはQRコード化するものだが、逆にQRコードを読み取る(デコード)する同様のソフトウェアとしてzbarがある。FreeBSD 13.0-Releaseでは両方共Ports CollectionやPKGに登録がある。



☆参考サイト
FreeBSDにWireGuardをインストールしてVPN接続
https://webprog.spg-games.net/2021-03-31/freebsd%E3%81%ABwireguard%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6vpn%E6%8E%A5%E7%B6%9A/


WireGuard on FreeBSD Quick Look Part 2: Android Remote Access
https://genneko.github.io/playing-with-bsd/networking/freebsd-wireguard-android/


WireGuard で Android スマートフォンと自宅の間で VPN 回線を構築する - eggshell blue
https://robinegg.hatenadiary.jp/entry/20180813/p1#fn-f5fe5a5e

コメント