UMGUM.COM (лучше) 

Linux Debian + L2TP + IPsec ( Налаживаем подключение linux-системы к L2TP-серверу, с обязательным шифрованием VPN-трафика. )

26 августа 2020  (обновлено 30 марта 2021)

OS: "Linux Debian 8/9/10", "Linux Ubuntu Server 16/18/20 LTS".
Apps: "strongswan", "xl2tpd", "ip", "netplan".

Задача: наладить подключение linux-системы к L2TP-серверу, с обязательным шифрованием VPN-трафика.

Для справки: L2TP ("Layer 2 Tunneling Protocol") представляет собой сетевой протокол туннелирования канального уровня, сочетающий в себе протокол L2F ("Layer 2 Forwarding"), разработанный компанией "Cisco", и протокол PPTP корпорации "Microsoft". Позволяет организовывать VPN с заданными приоритетами доступа, однако не содержит в себе средств шифрования и механизмов аутентификации - потому для создания защищённой VPN его используют совместно с IPSec.

Для управления L2TP-соединениями воспользуемся подсистемой "xl2tpd", а для шифрования - "strongSwan".

Последовательность действий такова:

1. Конфигурирование подсистемы IPsec-шифрования;
2. Конфигурирование подсистемы L2TP-подключений;
3. Автоматизация добавления сетевых маршрутов;
4. Ручное управление VPN-соединениями;
5. Автоматизация инициализации VPN-соединений.


Конфигурирование подсистемы IPsec-шифрования.

Инсталлируем необходимые приложения и утилиты:

# apt-get -y install strongswan

У проекта "strongSwan" хорошая документация, из которой для решения нашей простой задачи вполне достаточно чтения пары страниц: "ConnSection" и "IpsecCommand".

В основном конфигурационном файле подсистемы IPsec-шифрования "strongSwan" описываем общие параметры и правила шифрования трафика от IP до IP (пример связи с L2TP/типовым IPsec-шлюзом на базе "RouterOS"):

# vi /etc/ipsec.conf

# ipsec.conf - strongSwan IPsec configuration file

# Basic configuration
config setup
  # strictcrlpolicy=yes
  # uniqueids = no
  # nat_traversal = yes
  # protostack = netkey

# Default options for encryption of connections
conn %default
  ikelifetime = 60m
  keylife = 20m
  rekeymargin = 3m
  keyingtries = 1
  keyexchange = ikev1
  authby = secret
  ike = aes128-sha1-modp2048!
  esp = aes128-sha1-modp2048!

# Encryption of traffic to the "l2tp.example.net"
conn ipsec-gate.example.net
  # Automatic start of encryption at system startup
  auto = start
  # Restarting encryption if negotiation fails
  dpdaction = restart
  # Restart encryption on unexpected close
  closeaction = restart
  # Reconnect unlimited number of times
  keyingtries = %forever
  keyexchange = ikev1
  pfs = no
  authby = secret
  type = transport
  left = %defaultroute
  leftprotoport = 17/1701
  right = 100.200.250.21
  rightprotoport = 17/1701

include /var/lib/strongswan/ipsec.conf.inc

Секретный ключ шифрования PSK ("Pre-Shared Key"), используемый для предварительной клиент-серверной аутентификации, выносится в отдельный файл, где указывается, в каких условиях таковой должен применяться:

# vi /etc/ipsec.secrets

# <GATEWAY IP ADDRESS> <SERVER ADDRESS> : PSK "<PRE-SHARED KEY>"
%any 100.200.250.21 : PSK "strongSecretKey"

Защищаем файл с паролями от доступа посторонних:

# chown root /etc/ipsec.secrets
# chmod 600 /etc/ipsec.secrets

Для применения изменений в конфигурации перезапускаем сервис подсистемы IPSec-шифрования:

# systemctl restart strongswan
# systemctl status strongswan

Если конфигурация IPsec выше подразумевает автоматическое включение шифрования, то сразу после перезапуска "strongSwan" мы уже должны получить желаемое.

Если режим запуска шифрования для какого-то направления выбран "ручной" (auto=add), то запускаем его соответствующей командой:

# ipsec up ipsec-gate.example.net

Соответственно, при необходимости, аналогичной ручному запуску командой можно шифрование в заданном направлении остановить:

# ipsec down ipsec-gate.example.net

Просматриваем статус IPsec-соединений:

# ipsec statusall
# ipsec status

Security Associations (1 up, 0 connecting):
ipsec-gate.example.net[1]: ESTABLISHED 43 seconds ago, 10.20.30.45...100.200.250.21
ipsec-gate.example.net{1}:  INSTALLED, TRANSPORT, reqid 1, ESP in UDP SPIs: c57b51bb_i 04fa2652_o
ipsec-gate.example.net{1}:   10.20.30.45/32[udp/l2f] === 100.200.250.21/32[udp/l2f]

Теперь весь трафик к целевому сетевому узлу инкапсулируется в IPsec.

Конфигурирование подсистемы L2TP-подключений.

Инсталлируем необходимые приложения и утилиты:

# apt-get -y install xl2tpd net-tools

Параметры для настройки L2TP-подключения посредством "xl2tpd" хорошо описаны во встроенном руководстве по эксплуатации, вызываемом командой "man xl2tpd.conf" (как вариант, можно посмотреть web-версию).

Описываем параметры VPN-канала, который должен быть установлен посредством "xl2tpd":

# vi /etc/xl2tpd/xl2tpd.conf

[lac l2tp-gate.example.net]
lns = 100.200.250.21
;ppp debug = yes
pppoptfile = /etc/ppp/options.l2tpd.client-gate.example.net
length bit = yes
autodial = yes
redial = yes
redial timeout = 30

Описываем параметры PPP-соединения, включая логин и пароль для аутентификации:

# vi /etc/ppp/options.l2tpd.client-gate.example.net

ipcp-accept-local
ipcp-accept-remote
refuse-eap
require-mschap-v2
noccp
noauth
mtu 1280
mru 1280
noipdefault
nodefaultroute
usepeerdns
connect-delay 5000
name vpn-node0-tunnel
password strongSecretPassword

Защищаем файл с паролем от доступа посторонних:

# chmod 600 /etc/ppp/options.l2tpd.client-gate.example.net

Для применения изменений в конфигурации перезапускаем сервис:

# systemctl restart xl2tpd
# systemctl status xl2tpd

Если конфигурация "xl2tpd" выше подразумевает автоматическое создание VPN-туннеля, то сразу после перезапуска "xl2tpd" мы уже должны получить желаемое.

Если режим запуска создания VPN-туннеля выбран "ручной" (autodial=no), то запускаем его соответствующей командой:

# xl2tpd-control connect l2tp-gate.example.net

Соответственно, при необходимости, аналогичной ручному режиму командой можно определённый VPN-туннель выключить и удалить виртуальный интерфейс:

# xl2tpd-control disconnect l2tp-gate.example.net
# xl2tpd-control remove l2tp-gate.example.net

После вышеприведённых действий в перечне сетевых интерфейсов должен появится новый виртуальный PPP-интерфейс, через который осуществляется передача трафика до целевого L2TP-сервера:

# ifconfig -a

....
ppp0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1280
  inet 10.172.255.2 netmask 255.255.255.255  destination 10.172.255.1
  ppp  txqueuelen 3 (Point-to-Point Protocol)
  ....

Простейшим способом проверяем доступность опорного IP-адреса на стороне L2TP-сервера:

# ping 10.172.255.1

Слегка напрягает, что сервисы, обеспечивающие работу IPsec и L2TP прослушивают ряд портов в ожидании входящих подключений тогда, как нам требуется от них только работа в роли клиентов - но, насколько я понимаю, это неотъемлемая особенность работы подсистем, обеспечивающих двухсторонние сетевые туннели:

# netstat -apn

Proto ... Local Address Foreign Address PID/Program name    
udp   ... 0.0.0.0:4500  0.0.0.0:*       .../charon        
udp   ... 0.0.0.0:500   0.0.0.0:*       .../charon        
udp   ... 0.0.0.0:1701  0.0.0.0:*       .../xl2tpd        
....

Разумеется, можно прикрыть сетевые сервисы защитным экраном "iptables", предписав предоставлять доступ к портам только для запросов со стороны L2TP-сервера.

Автоматизация добавления сетевых маршрутов.

В производственной среде VPN-туннели чаще предназначены для передачи только выделенного трафика - к тем сервисам, что нуждаются в изоляции внутри корпоративной сети. Соответственно, после установления VPN-соединения, необходимо активировать дополнительные сетевые маршруты, направляющие выделенный трафик не через "шлюз по умолчанию", а через L2TP-сервер. Такой функционал давно реализован через систему "хуков (hook)", запускающий произвольные скрипты при изменении состояния PPP-соединений.

Пишем простой bash-скрипт, автоматически запускаемый при инициализации PPP-соединения и добавляющий произвольный набор маршрутов с предварительной проверкой наличия опорной IP-адресации (в имени скрипта "ppp-hook" не допускается символов ".", так что для наглядности заменяем их "-"):

# vi /etc/ppp/ip-up.d/90-l2tp-gate-example-net

#!/bin/bash

if [[ "${PPP_LOCAL}" == "10.172.255.2" ]] ; then
  sleep 1
  ip route add 10.10.10.0/24 via 10.172.255.1
  ip route add 192.168.10.0/24 via 10.172.255.1
fi

exit $?

Не забываем сделать скрипт "исполняемым" (в противном случае подсистема PPP проигнорирует его):

# chmod +x /etc/ppp/ip-up.d/90-l2tp-gate-example-net

Ручное управление VPN-соединениями.

Учитывая то, что сервисы шифрования и поддержки PPP-туннеля реализованы в двух независимых подсистемах, ради обеспечения должного уровня безопасности важно не забывать об очерёдности их включения и выключения - чтобы в какой-то момент через недоверенные участки сети не пошёл незашифрованный трафик.

Последовательная инициализации IPsec-шифрования и L2TP-туннеля:

# ipsec up ipsec-gate.example.net && xl2tpd-control connect l2tp-gate.example.net

Последовательное выключение L2TP-туннеля и IPsec-шифрования:

# xl2tpd-control disconnect l2tp-gate.example.net && xl2tpd-control remove l2tp-gate.example.net && ipsec down ipsec-gate.example.net

Автоматизация запуска посредством "ifupdown".

При автоматическом запуске IPsec-шифрования и L2TP-туннеля нет необходимости отдельно стартовать эти сервисы. Но, в каких-то конфигурациях это может потребоваться:

# vi /etc/network/interfaces

....
iface eth0 inet dhcp
  ....
  sleep 5 && post-up ipsec up ipsec-gate.example.net && xl2tpd-control connect l2tp-gate.example.net &

Автоматизация запуска посредством "Netplan".

Новомодная подсистема управления сетевой конфигурацией "Netplan" не имеет встроенного обработчика изменения состояния, что странно. Придётся воспользоваться дополнительным инструментом "Network Dispatcher":

# apt-get install networkd-dispatcher

# vi /etc/networkd-dispatcher/routable.d/90-ifup-eth0-hooks

#!/bin/bash

if [[ "${IFACE}" == "eth0" ]] ; then
  sleep 5
  ipsec up ipsec-gate.example.net && xl2tpd-control connect l2tp-gate.example.net &
fi

exit $?

Добавляем скрипту статус "исполняемого" (иначе "networkd-dispatcher" проигнорирует его):

# chmod +x /etc/networkd-dispatcher/routable.d/90-ifup-eth0-hooks


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )