Здравствуйте!
Данная статья рассматривает пример реализации удаленного доступа для предприятия на основе связки Libreswan/GRE/Quagga + MikroTik.
Предполагается наличие предустановленного Linux дистрибутива, стека iproute2+NetFilter+IPTABLES и поддержки автозагрузки скриптов Runlevel Local.
Почему Linux ? Почему MikroTik ? Здесь все просто - реализовать можно на чем угодно.
Возьмем Palo Alto, Check Point, FortiGate (Все это - отличные NGFW). Прикрутим с Вами и Site to Site, и Hub and Spoke. Настроим полноценную аутентификацию. Маршрутизацию. Возможно копнем в фильтрацию и инспекцию трафика. Разберем сигнатуры. Все это возможно и широко используется в энтерпрайзе.
Главные вопросы здесь вот в чем - какой процент новичков имеет доступ к таким технологиям ? А каков процент организаций с подходящим бюджетом ?
Старался подобрать что-то доступное и рассмотреть несколько вариантов за один заход, ведь если человек разберется на OpenSource, он вам потом и на "Срусле" реализует :) Там вопрос лишь расположения кнопок. Ядро технологий - одно и то же.
Впрочем кого я обманываю ! :) Изначально писалось как заметка в первую очередь для себя, под задачу которая вероятно появится в будущем. Переросло в нечто большее и результат мне нравится больше.
Приступим !
Техническое задание
Вводные:
Есть некая организация в России. У нее есть сотрудники и офисы разбросанные по соседним городам и странам.
Есть некие внутренние ресурсы опубликованные в публичном облаке (почта, документооборот, unified comms)
Доступ к этим ресурсам разрешен только с публичных адресов этой компании
Проблема:
Удаленные сотрудники не получат доступа к этим ресурсам, не смотря на то, что смогут резолвить их FQDNs
Решение:
Реализация удаленного доступа для сотрудников и маршрутизация их трафика через периметр нашей компании
Проблема:
У компании ограниченная полоса пропускания на внешних каналах и забивать их лишним трафиком не хотелось бы. К тому же, гонять трафик, скажем, из Казахстана в Россию и обратно в Казахстан - дело такое себе (вопросы комплаенса оставим за рамками)
Решение:
Реализовать Split Tunneling и, как следствие, разрешить выход в Интернет как через локального ISP, так и через туннель
Топология
В первой части данной статьи, мы построим Site to Site топологию между головным офисом и филиалом. Во второй - объясним зачем нам понадобился GRE. В третьей - построим Hub and Spoke топологию для доступа с сотовых телефонов и домашних пользователей с динамической адресацией.

Топология представлена двумя зонами: Zone1 (Филиал) и Zone2 (Головной офис)
Каждая из зон имеет подключение к сети Интернет со статическими публичными адресами
Клиентский доступ предполагает возможность выхода в сеть как через ISP1, так и через ISP2
Mikrotik представлен как FW1 и расположен в Zone1, Linux как FW2 и расположен в Zone2
GRE под первую часть статьи - абсолютно избыточен (Но мы его все-таки настроим. Хуже от этого не будет) Так же учтите, что если Ваш провайдер блокирует GRE, то первая группа тестов у вас проходить не будет (Ничего страшного здесь нет, просто продолжайте дальше и как только закончите с IPSec, GRE будет инкапсулирован в IPSec ESP и связь появится)
Забегу вперед и покажу где и зачем GRE может пригодиться (Реализация динамической маршрутизации в Linux базируется на Quagga)

Предположим у вас два офиса и нужно обеспечить связность
Предположим каждый из офисов имеет по два аплинка через разных ISP
Предположим каждый из офисов использует PA (Provider Aggregatable) адреса
Предположим вам необходимо обеспечить отказоустойчивость линков с минимальной сходимостью
Вот здесь GRE и пригодится чтобы обеспечить установку соседства OSPF
Подбор оборудования
Требования Zone1:
Обеспечить динамическую конфигурацию CE интерфейса средствами PPP/DHCP opt. 82
Обеспечить связь в локальной сети средствами IEEE 802.11
Поддержка GRE, IPSec, OSPF, PBR, NAT, Traffic Filtering
Удобство администрирования предполагает наличие GUI
Минимальные финансовые вложения
Требования Zone2:
Поддержка GRE, IPSec, OSPF, NAT, Traffic Filtering
Минимальные финансовые вложения
Выводы:
Исходя из требований выбор "железа" пал на MikroTik RouterOS и стек iproute2/Libreswan/Quagga/IPTABLES. MikroTik и IPTABLES объяснять, думаю, излишне, альтернатив Quaggа насколько я помню нет, а вот выбор Libreswan основывался на сравнении характеристик Libreswan/strongSwan

GRE
MikroTik
Поднимаем GRE интерфейс (Interfaces >> GRE Tunnel)

Назначаем IP адрес (IP >> Addresses)

Прописываем правила фильтрации (IP >> Firewall)

Debian
Подгружаем GRE модуль в ядро
modprobe ip_gre
Проверяем
lsmod | grep gre
Поднимаем GRE интерфейс
ip tunnel add gre1 mode gre local PubIP2 remote PubIP1 ttl 255
ip addr add 10.254.254.254/30 dev gre1
ip link set gre1 up
Выставляем MTU с учетом размера заголовков IP (20 байт), GRE (4 байта), IPSec (64 байта)
ip link set dev gre1 mtu 1412
Проверяем
ifconfig gre1
gre1: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1412
inet 10.254.254.254 netmask 255.255.255.252 destination 10.254.254.254
Добавляем в автозагрузку (см здесь)
nano -w /etc/rc.local
# GRE
modprobe ip_gre
ip tunnel add gre1 mode gre local PubIP2 remote PubIP1 ttl 255
ip addr add 10.254.254.254/30 dev gre1
ip link set dev gre1 mtu 1412
ip link set gre1 up
Прописываем правила фильтрации (см здесь)
nano -w /etc/iptables/rc.firewall
# GRE
gre_iface="gre1"
remote_peer="PubIP1"
$ipt -A INPUT -i $iface -p 47 -m state --state NEW -s $remote_peer -j ACCEPT
$ipt -A OUTPUT -o $iface -p 47 -m state --state NEW -d $remote_peer -j ACCEPT
$ipt -A INPUT -i $gre_iface -p icmp --icmp-type echo-request -m state --state NEW -j ACCEPT
Проверяем
/etc/iptables/rc.firewall
iptables -nvL
Тестируем
Проверяем (потеря первого пакета ожидаема, поскольку туннелю необходимо время для инициализации)
[username@fw1] > ping address=10.254.254.254 src-address=10.254.254.253 size=1500
SEQ HOST SIZE TTL TIME STATUS
0 10.254.254.254 timeout
1 10.254.254.254 1500 64 2ms488us
2 10.254.254.254 1500 64 1ms829us
3 10.254.254.254 1500 64 1ms883us
4 10.254.254.254 1500 64 1ms931us
5 10.254.254.254 1500 64 1ms953us
sent=6 received=5 packet-loss=16% min-rtt=1ms829us avg-rtt=2ms16us max-rtt=2ms488us
IPSec
MikroTik
Задаем параметры криптографии Phase 1 (IP >> IPSec >> Profiles)

Задаем параметры пира (IP >> IPSec >> Peers)

Генерим сертификаты для IKEv2 аутентификации
> /certificate/
/certificate> add name=root_ca common-name=root_ca key-size=2048 key-usage=key-cert-sign,crl-sign days-valid=3650
/certificate> print
/certificate> sign 0
/certificate> add name=fw1_ike common-name=fw1_ike key-size=2048 days-valid=3650
/certificate> add name=fw2_ike common-name=fw2_ike key-size=2048 days-valid=3650
/certificate> print
/certificate> sign 1 ca=root_ca
/certificate> sign 2 ca=root_ca
Задаем параметры аутентификации для нашего пира (IP >> IPSec >> Identities)

Несколько слов о Notrack Chain:
Все дело в том, что у MikroTik (впрочем у меня есть подозрение что это проблема netfilter) есть серьезные проблемы с трекингом IPSec (желающие попробовать вернуться в Dial-Up эру могут прогнать через FastTrack :) ) Поэтому будем отключать в дальнейшем.
Задаем параметры криптографии Phase 2 (IP >> IPSec >> Proposals)

Описываем SAs (IP >> IPSec >> Policies)


Описываем правила фильтрации IPSec (IP >> Firewall)

Libreswan
Устанавливаем пакет
apt install libreswan
Инициализируем NSS и устанавливаем пароль на доступ к базе
ipsec initnss
certutil -W -d sql:/var/lib/ipsec/nss
Несколько слов о NSS:
NSS есть ничто иное как пользовательская библиотека используемая Libreswan IKE демоном pluto. NSS не обрабатывает IPSec криптографию внутри ядра; за это отвечают NETKEY или KLIPS модули.
Основной плюс использования NSS в том, что для pluto нет необходимости знать о том как работает криптографический шлюз. Pluto не требует доступа к ключам или данным, вместо этого используя PK11 wrapper API независимо от криптографического шлюза. Вся обработка осуществляется через доступ к NSS средствами PK11 интерфейса, тем самым избегая необходимости прямого доступа к ключам шифрования. Все IKE операции осуществляются с использованием NSS. RSA ключи (как чистые RSA, так и X.509 ключи) хранятся внутри NSS и не упоминаются напрямую в /etc/ipsec.secrets. X.509 ключи и сертификаты описываются при помощи их "никнеймов" (вместо их реальных имен) в /etc/ipsec.conf
Задаем пароль подключения к NSS для pluto
touch /etc/ipsec.d/nsspassword
nano -w /etc/ipsec.d/nsspassword
NSS Certificate DB:secret
Включаем Libreswan
systemctl enable ipsec
systemctl status ipsec
Выгружаем сертификаты из MikroTik (System >> Certificates) На выходе получатся 3 PEM пары с защищенными паролем ключами
Загружаем на Libreswan сервер и снимаем защиту
openssl rsa -in root_ca.key_encr -out root_ca.key
openssl rsa -in fw1_ike.key_encr -out fw1_ike.key
openssl rsa -in fw2_ike.key_encr -out fw2_ike.key
Создаем PKCS#12 архивы
openssl pkcs12 -export -in fw1_ike.crt -inkey fw1_ike.key -certfile root_ca.crt -out fw1_ike.p12 -name fw1_ike
openssl pkcs12 -export -in fw2_ike.crt -inkey fw2_ike.key -certfile root_ca.crt -out fw2_ike.p12 -name fw2_ike
Импортируем сертификаты аутентификации IKE в NSS (подробнее можно прочитать здесь)
certutil -A -a -i /home/username/certs/root_ca.crt -d sql:/var/lib/ipsec/nss -n "RootCA" -t 'CT,,'
ipsec import /home/username/certs/fw1_ike.p12
ipsec import /home/username/certs/fw2_ike.p12
Настраиваем IPSec (подробнее здесь)
touch /etc/ipsec.d/fw1-fw2.conf
nano -w /etc/ipsec.d/fw1-fw2.conf
conn fw1-fw2
# Peers
left=PubIP2
right=PubIP1
# Phase 1 Settings
keyexchange=ike
ikev2=insist
ike=aes256-sha256;dh21
ikelifetime=24h
dpddelay=8s
dpdtimeout=32s
dpdaction=clear
fragmentation=yes
# IKEv2 Auth
authby=rsasig
leftcert=fw2_ike
leftid=%fromcert
leftsendcert=always
leftrsasigkey=%cert
rightcert=fw1_ike
rightid=%fromcert
rightca=%same
rightrsasigkey=%cert
# Phase 2 Settings
type=tunnel
phase2=esp
phase2alg=aes256-sha256;dh21
salifetime=12h
rekey=yes
pfs=yes
# SAs
leftsourceip=PubIP2
leftprotoport=gre
rightsourceip=PubIP1
rightprotoport=gre
# Auto Start During Bootup
auto=start
Указываем интерфейс на котором будем слушать трафик (аргумент interfaces оказался устаревшим, работаем через listen) В том же файле при необходимости можно включить дебаги.
nano -w /etc/ipsec.conf
listen=PubIP2
Рестартим сервис
systemctl restart ipsec
systemctl status ipsec
Задаем правила фильтрации
nano -w /etc/iptables/rc.firewall
# IPSec
$ipt -A INPUT -i $iface -p udp -m state --state NEW -s $remote_peer --dport 500 -j ACCEPT
$ipt -A OUTPUT -o $iface -p udp -m state --state NEW -d $remote_peer --dport 500 -j ACCEPT
$ipt -A INPUT -i $iface -p 50 -m state --state NEW -s $remote_peer -j ACCEPT
$ipt -A OUTPUT -o $iface -p 50 -m state --state NEW -d $remote_peer -j ACCEPT
Проверяем
/etc/iptables/rc.firewall
iptables -nvL
Тестируем
Проверяем (та же самая ситуация с первым пакетом)
[username@fw1] > ping address=10.254.254.254 src-address=10.254.254.253 size=1500
SEQ HOST SIZE TTL TIME STATUS
0 10.254.254.254 timeout
1 10.254.254.254 1500 64 3ms69us
2 10.254.254.254 1500 64 2ms865us
3 10.254.254.254 1500 64 2ms861us
4 10.254.254.254 1500 64 2ms918us
5 10.254.254.254 1500 64 2ms944us
sent=6 received=5 packet-loss=16% min-rtt=2ms861us avg-rtt=2ms931us max-rtt=3ms69us
ipsec whack --trafficstatus
Маршрутизация и NAT
MikroTik
Создаем новую таблицу маршрутизации (Routing >> Tables)

Укладываем дефолт для вновь созданной таблицы маршрутизации в туннель (IP >> Routes)

Тегируем необходимый нам трафик для последующей переброски в GRE RT (IP >> Firewall >> Mangle) Здесь пока работаем c туннельным интерфейсом нашего GRE пира


Изолируем наши таблицы маршрутизации (Routing >> Rules)


Описываем трансляцию адресов (IP >> Firewall >> NAT) В данном случае чтобы не утруждаться контролем обратных маршрутов со стороны Libreswan используем NAT через GRE интерфейс MikroTik (Здесь возникнут проблемы с анализом логов, так как все пользователи филиала будут видны с одним сорс адресом. Если для Вас это важно - рекомендуется прибегнуть к маршрутизации)

Описываем фильтрацию (IP >> Firewall)

Тестируем
Проверяем со стороны клиента
ping 10.254.254.254 -l 1500
Pinging 10.254.254.254 with 1500 bytes of data:
Reply from 10.254.254.254: bytes=1500 time=2ms TTL=63
Reply from 10.254.254.254: bytes=1500 time=2ms TTL=63
Reply from 10.254.254.254: bytes=1500 time=3ms TTL=63
Reply from 10.254.254.254: bytes=1500 time=3ms TTL=63
Ping statistics for 10.254.254.254:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 2ms, Maximum = 3ms, Average = 2ms
Заключение
В принципе вот и получился у нас сплит-туннель. Закончить хотелось бы выходом "наружу" :) Тем более у нас с вами остался нерассмотренным вопрос проблемы FastTrack.
Приступим !
Включаем IPv4 форвардинг
nano -w /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p
Задаем правила фильтрации и трансляции адресов
# Stateful rules
$ipt -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#
# FORWARD
#
# GRE FWD
$ipt -A FORWARD -i $gre_iface -m state --state NEW -j ACCEPT
#
# NAT
#
# OB MASQUERADE
remote_peer_tu="10.254.254.253"
$ipt -t nat -A POSTROUTING -o $iface ! -p 47 -s $remote_peer_tu -j MASQUERADE
Проверяем
iptables -nvL
iptables -nvL -t nat
Тегируем трафик на внешний адрес (IP >> Firewall >> Mangle) Здесь работаем с FQDN null.somedomain.name и задаем две метки: первую - для маршрутизации через GRE RT и вторую - для байпаса FastTrack



Включаем байпас на FastTrack


Проверяем пути от клиента
tracert -d 8.8.8.8
Tracing route to 8.8.8.8 over a maximum of 30 hops
1 <1 ms <1 ms <1 ms 10.10.10.10
2 7 ms 2 ms 11 ms 58.162.26.204
3 1 ms 1 ms 1 ms 203.50.60.72
4 2 ms 2 ms 3 ms 203.50.61.144
5 2 ms 2 ms 1 ms 203.50.11.195
6 3 ms 2 ms 2 ms 142.250.162.28
7 2 ms 2 ms 2 ms 142.250.234.217
8 3 ms 3 ms 2 ms 216.239.59.109
9 2 ms 2 ms 1 ms 8.8.8.8
Trace complete.
tracert -d null.somedomain.name
Tracing route to null.somedomain.name [45.32.236.11]
over a maximum of 30 hops:
1 <1 ms <1 ms <1 ms 10.10.10.10
2 2 ms 2 ms 2 ms 10.254.254.254
3 * * * Request timed out.
4 2 ms 2 ms 2 ms 100.100.200.1
5 11 ms 10 ms 31 ms 10.91.0.1
6 2 ms 2 ms 2 ms 10.91.0.17
7 2 ms 2 ms 2 ms 10.91.0.1
8 80 ms 9 ms 7 ms 67.199.141.33
9 244 ms 244 ms 244 ms 141.136.106.174
10 * * * Request timed out.
На этом все :) Спасибо всем, кто дочитал до конца и по традиции ссылка на внешний ресурс <Project Null> - заглядывайте иногда.
Буду рад ответить на вопросы по теме.