Задача:
- Linux-машина (назовем ее router) подключается к strongswan-серверу (IPSec IKEv2)
- Некоторые другие машины прописывают ip router как default route и работают через VPN (прозрачно для них)
Как сервер настроить – ничего особенного, например по этой статье: . Как соединить 2 сети тоже понятно: https://selectel.ru/blog/tutorials/how-to-set-up-vpn-ipsec/ (но нам не нужно, чтобы с vpn-сервера была видна вся внутренняя сеть, нам бы nat и правила доступа).
Если использовать обычный клиент (требуется доступ с локального компьютера, а не предоставляется доступ с локальной сети), то можно включить https://docs.strongswan.org/docs/5.9/plugins/bypass-lan.html плагин, чтобы при включенном VPN эта машинка продолжала видеть локальную сеть.
Есть еще один вариант – на router запустить proxy-сервер (squid) и через это раздавать VPN-соединение, но не хочется нагружать слабую машинку.
В заметке описывается как настроить XFRM-клиент (Route-based VPN) и все что нужно вокруг. Изначально планировалось VTI-клиент, но там больше магии, чем в XFRM (вроде как XFRM предпочтительнее).
Настраиваем для SUSE MicroOS. Для других дистрибьютивов в деталях может быть по другому. Например, здесь включен ip forward по умолчанию, не нужно менять эту настройку.
Отключаем SELinux для начала (в принципе, можно еще помучаться и включить, но не сейчас):
cat >/etc/selinux/config <<EOF
SELINUX=permissive
SELINUXTYPE=targeted
EOF
# да, оно просто так не отключается, нужно еще grub править
vim /etc/default/grub
# изменить: enforcing=1 -> enforcing=0
transactional-update grub.cfg
reboot
Ставим пакеты:
transactional-update pkg in strongswan nftables
reboot
Кладем сертификат с сервера в /etc/ipsec.d/cacerts/ca-cert.pem
.
/etc/ipsec.conf устарел и не содержит новые параметры (if_id_in). Поэтому используем swan-файлы настройки. 192.168.3.0/24 – внутренняя сеть в примерах. 10.10.10.0/24 – сеть для vpn, настроенная на vpn-сервере (rightsourceip=10.10.10.0/24).
Настраиваем vpn:
vim /etc/strongswan.conf
# add 2 params inside charon to disable automatic routes (our script will do job):
# install_routes = no
# install_virtual_ip = no
# (может быть можно через какие-то параметры настроить, чтобы оно само правильно формировалось, но мне удалось это решить ручными скриптами)
cat >/etc/swanctl/conf.d/ikev2-do.conf <<EOF
connections {
ikev2-myconn {
include /etc/swanctl/conf.d/ike_sa_default.conf
version = 2
if_id_in = %unique
if_id_out = %unique
# it can be any IP, sever can provide another but it's required to have some IP here
vips = 10.10.10.4
remote_addrs = myremote.example.com
children {
ikev2-do {
include /etc/swanctl/conf.d/child_sa_default.conf
start_action = start
local_ts = dynamic
remote_ts = 0.0.0.0/0
updown = /usr/local/bin/rw-updown.sh
}
}
local-0 {
auth = eap-mschapv2
id = mi-vpn-client
}
remote-0 {
auth = pubkey
id = @myremote.example.com
}
}
}
secrets {
eap-mi-vpn-client {
secret = "myPassword!"
id-0 = myUser1
}
}
EOF
cat >/usr/local/bin/rw-updown.sh <<EOF
#!/bin/bash
set -eEuo pipefail
XFRM_IF="xfrm${PLUTO_UNIQUEID}"
case "${PLUTO_VERB}" in
up-client)
echo "vpn rw-updown" ${PLUTO_VERB} ${PLUTO_UNIQUEID} ${XFRM_IF} ${PLUTO_ME} ${PLUTO_PEER} ${PLUTO_IF_ID_IN} ${PLUTO_IF_ID_OUT}
ip link add ${XFRM_IF} type xfrm dev lo if_id ${PLUTO_IF_ID_IN}
ip link set dev ${XFRM_IF} mtu 1418
ip addr add ${PLUTO_MY_CLIENT} dev ${XFRM_IF}
ip link set ${XFRM_IF} up
ip route add default dev ${XFRM_IF}
nft add rule nat postrouting ip saddr 192.168.3.0/24 oifname "${XFRM_IF}" masquerade
;;
down-client)
echo down
# NOTE: folling command is planned but not supported yet by nft
# nft delete rule nat postrouting ip saddr 192.168.3.0/24 oifname "xfrm1" masquerade
nft flush chain nat postrouting
ip route delete default
ip link del ${XFRM_IF}
;;
esac
EOF
chmod +x /usr/local/bin/rw-updown.sh
И роутинг (отключаем дефолтный роут – он будет от vpn и настраиваем прямой доступ к vpn-серверу):
nmcli connection modify ens18 ipv4.never-default true
nmcli connection modify ens18 +ipv4.routes "<ip address of myremote.example.com> 192.168.3.1"
Немного firewall (для vpn только nat (пустая цепочка), остальное можно не настраивать):
cat >/etc/nftables.conf <<EOF
#!/usr/sbin/nft -f
flush ruleset
# ipv4 + ipv6
table inet filter {
set wanted_tcp_ports {
type inet_service
flags interval
elements = { 22 }
}
chain base_checks {
## another set, this time for connection tracking states.
# allow established/related connections
ct state {established, related} accept;
# early drop of invalid connections
ct state invalid drop;
}
chain input {
type filter hook input priority 0; policy drop;
# allow from loopback
iif "lo" accept;
jump base_checks;
# allow icmp and igmp
ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply, packet-too-big, time-exceeded, parameter-problem, destination-unreachable, packet-too-big, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept;
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept;
ip protocol igmp accept;
tcp dport @wanted_tcp_ports accept
# for testing reject with logging
counter log prefix "[nftables] input reject " reject;
}
chain forward {
type filter hook forward priority 0; policy accept;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
}
}
EOF
chmod +x /etc/nftables.conf
Стартуем (да, встроенного стартера nftables нет):
cat >/etc/systemd/system/nftables.service <<EOF
[Unit]
Description=Initialises nftab rules
[Service]
Type=oneshot
ExecStart=/etc/nftables.conf
[Install]
WantedBy=default.target
EOF
systemctl daemon-reload
systemctl enable --now nftables.service
systemctl enable --now strongswan
reboot
И разные команды, чтобы проверить как все настроилось:
swanctl -l
swanctl -L
ip a l
ip -s link show xfrm1
ip -d link show xfrm1
ip rule ls
ip r l table 0
ip route show table lan
ip route show table vpn
nft list ruleset
nmcli connection show ens18
curl https://myip.ru/index_small.php
Как-то слишком много настроек и знаний для этих настроек нужно, но проще не получилось.