リモートワーク用の会社VPNを常時接続するルーターを作った

Hey社のリモートワーク制度では、 必要が無くてもリモートワーク時にはVPNを繋ぐ という無意味な制度がある
ManjaroでAURの networkmanager-l2tp が不安定になってしまったので、VPN接続をNATするルーターをこしらえた話

必要なもの

  • NICを2枚挿した物理鯖かVM
  • Ubuntu 18.04

手順

1. パッケージを入れる

わざわざNetworkManagerを使っているのは、lx2tpd + strongswanだけでやったら10秒ごとに接続がハングして使い物にならなかったから
秘伝のタレに頼るのが一番ってことよ

sudo apt install -y strongswan xl2tpd network-manager network-manager-l2tp iptables-persistent

2. NetworkManagerでIPアドレスを固定する

設定値自体はお好みで
eth1 相当のNICはゲートウェイとか諸々無効にしておく

/etc/netplan/50-cloud-init.yaml

network:
  renderer: NetworkManager
  ethernets:
    eth0:
      dhcp4: false
      addresses:
        - 172.16.33.8/22
      gateway4: 172.16.35.254
      nameservers:
        addresses:
          - 1.1.1.1
          - 1.0.0.1
    eth1:
      dhcp4: false
      dhcp6: false
      addresses:
        - 172.16.34.254/22
      link-local: []
  version: 2
sudo systemctl enable --now NetworkManager
sudo netplan apply

3. NetworkManagerにVPNの設定をインポートする

事前に他のLinux機で network-manager-l2tp のVPN設定を作っておいて、エクスポートする
気合を入れて手書きしても良い(というか下記のサンプルを弄れば多分できる)

vpn.conf

#org.freedesktop.NetworkManager.l2tp

[connection]
id=vpn

[vpn]
gateway=接続先ホスト
user=ユーザー名
refuse-eap=true
refuse-pap=true
refuse-chap=false
refuse-mschap=true
refuse-mschapv2=true
lcp-echo-failure=5
lcp-echo-interval=30
mru=1200
mtu=1200
ipsec-enabled=true
ipsec-gateway-id=VPNサーバーがNAT配下(とされる)なら記入する
ipsec-psk=事前共有鍵
ipsec-ike=3des-sha1-modp1024 (ike-scanして調整)
ipsec-esp=aes128-sha1 (ike-scanして調整)

[ip4]
method=auto
ignore-auto-routes=false
ignore-auto-dns=false
dhcp-send-hostname=true
never-default=false

んで、インポート

sudo nmcli connection import type l2tp file ./vpn.conf

4. インポートした設定にパスワードを書き込む

インポート・エクスポートではVPNの認証パスワードが設定されていない
NetworkManagerのファイルに無理やり書き込む

/etc/NetworkManager/system-connections/vpn

[connection]
id=vpn
uuid=9e62ebf3-9a23-4326-bd6f-fecaac757933
type=vpn
permissions=
timestamp=1580888742

[vpn]
gateway=接続先ホスト
ipsec-enabled=yes
ipsec-esp=aes128-sha1 (ike-scanして調整)
ipsec-gateway-id=VPNサーバーがNAT配下(とされる)なら記入する
ipsec-ike=3des-sha1-modp1024 (ike-scanして調整)
ipsec-psk=事前共有鍵
lcp-echo-failure=5
lcp-echo-interval=30
mru=1200
mtu=1200
password-flags=0 (この行を追加)
refuse-chap=no
refuse-eap=yes
refuse-mschap=yes
refuse-mschapv2=yes
refuse-pap=yes
user=ユーザー名
service-type=org.freedesktop.NetworkManager.l2tp

(このセクションを追加)
[vpn-secrets]
password=パスワード

[ipv4]
dns-search=
method=auto
never-default=true

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

変えたらNetworkManagerを再起動する

sudo systemctl restart NetworkManager

5. 繋いでみる

繋がらなかったら咽び泣いて諦めろ

sudo nmcli connection up vpn
 ❯ ip addr show dev ppp0
4: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1200 qdisc fq_codel state UNKNOWN group default qlen 3
    link/ppp 
    inet 192.168.0.112 peer 192.168.1.1/32 scope global ppp0
       valid_lft forever preferred_lft forever

6. ネットワーク接続時にVPNを自動接続する

たぶんdispatcherでやるのが楽

/etc/NetworkManager/dispatcher.d/vpn-up

#!/bin/bash

ETH="netplan-eth0"
VPN="vpn"

eth_conn=$(nmcli connection show --active | grep "${ETH}")
vpn_conn=$(nmcli connection show --active | grep "${VPN}")
if [ "${eth_conn}" -a ! "${vpn_conn}" ]; then
    nmcli connection up "${vpn_conn}"
fi
sudo chmod a+x /etc/NetworkManager/dispatcher.d/vpn-up

7. iptablesを設定する

NATルーターに仕立てる

sudo iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
sudo iptables -A FORWARD -i eth1 -o ppp0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i ppp0 -o eth1 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4

ここまででサーバー側はOK

8. クライアント側で静的ルートを切る

NetworkManagerでもsystemd-networkdでも好きなものでOK
Arch系でNetworkManagerを使うのはバカっぽいのでsystemd-networkdの例

[Route] 以下を追加する

/etc/systemd/network/eth.network

[Match]
Name=bridge-eth

[Network]
Address=172.16.34.1/22
Gateway=172.16.35.254
DNS=1.1.1.1,1.0.0.1

[DHCP]
RouteMetric=10

[Route]
Gateway=172.16.34.254
Destination=192.168.0.0/22
GatewayOnlink=yes

もし手動でやるなら

sudo ip route add 192.168.0.0/22 via 172.16.34.254 dev bridge-eth

で、適当にping打ったりSSHしてみて繋がればOK

 ❯ ip route
default via 172.16.35.254 dev bridge-eth proto static 
172.16.32.0/22 dev bridge-eth proto kernel scope link src 172.16.34.1 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
172.18.0.0/16 dev br-4af6dd58c80e proto kernel scope link src 172.18.0.1 linkdown 
172.19.0.0/16 dev br-b670b9b70b09 proto kernel scope link src 172.19.0.1 linkdown 
172.22.0.0/16 dev br-a9dacf04ae97 proto kernel scope link src 172.22.0.1 linkdown 
172.23.0.0/16 dev br-819da9294f54 proto kernel scope link src 172.23.0.1 
192.168.0.0/22 via 172.16.34.254 dev bridge-eth 

 ❯ ping 192.168.1.220
PING 192.168.1.220 (192.168.1.220) 56(84) バイトのデータ
64 バイト応答 送信元 192.168.1.220: icmp_seq=1 ttl=62 時間=6.56ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=2 ttl=62 時間=6.88ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=3 ttl=62 時間=7.10ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=4 ttl=62 時間=6.61ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=5 ttl=62 時間=6.66ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=6 ttl=62 時間=6.76ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=7 ttl=62 時間=6.81ミリ秒
64 バイト応答 送信元 192.168.1.220: icmp_seq=8 ttl=62 時間=6.66ミリ秒
^C
--- 192.168.1.220 ping 統計 ---
送信パケット数 8, 受信パケット数 8, 0% packet loss, time 7010ms
rtt min/avg/max/mdev = 6.561/6.754/7.096/0.161 ms