Несмотря на обилие статей про IPsec на linux, каждый раз, когда мне нужно было слушать multicast на виртуальной машине в облаке (на примере AWS), который нужно было там получать через IPSec тоннель, я, сталкиваясь с какими-то проблемами в настройке, жалел, что не сделал никаких заметок в прошлый раз. В этот раз я решил записать пример конфигурации с небольшими пояснениями и поделиться им с общественностью, в надежде, что это кому-то может быть полезным.

Итак, обычно перед началом конфигурации вы должны договориться с другой стороной (в этой статье это будет условный DataCenter) о конфигурации IKE (фаза1) и IPSec (фаза2), в частности, согласовать PSK (pre-shared key) фразу, способы и алгоритмы аутентификации и шифрования, используется ли PFS (perfect forward secrecy), ваши публичные IP адреса (peer VPN gateway), ваши локальные подсети, которые вы связываете (interesting traffic), а также адресацию для GRE тоннеля. Обычно это делается совместным заполнением таблички, которую вы пересылаете по почте, в итоге собирается табличка такого вида:

сборная табличка утвержденных параметров (все адреса вымышлены)
сборная табличка утвержденных параметров (все адреса вымышлены)

Дальнейшая конфигурация будет производиться на AWS виртуальной машине с Ubuntu 20.04.3 LTS и Linux strongSwan U5.8.2/K5.13.0-1028-aws.

Конфигурация ipsec.conf:

ipsec.conf с комментариями
ipsec.conf с комментариями

Для того, чтобы жестко закрепить только один профиль безопасности (аутентификации и шифрования) phase1 или phase2, стоит указать восклицательный знак (!) после строки с заданной конфигурацией, например так:

ike=aes256-sha256-modp2048! # параметры аутентификации и шифрования IKE esp=aes256-sha256-modp2048! # параметры аутентификации и шифрования ESP

Для включения возможности маршрутизировать ipv4 трафик, необходимо включить:

sysctl net.ipv4.ip_forward=1

Необходимо также настроить iptables, чтобы весь трафик (interesting traffic) к DataCenter Remote Address (100.15.30.0/24) выходил с source IP 10.45.8.17 и , как следствие, упаковывался в IPSec туннель службой strongswan:

iptables -t nat -A POSTROUTING -d 100.15.30.0/24 -j SNAT --to-source 10.45.8.17

Также, чтобы весь трафик к лупбэку GRE Tunnel source DataCenter (10.44.7.1) выходил с source IP 10.44.6.1:

iptables -t nat -A POSTROUTING -d 10.44.7.1/32 -j SNAT --to-source 10.44.6.1

Для перезапуска strongswan используйте команду ipsec restart.

Теперь создадим GRE туннель c MTU 1476 и лупбэк:

ip tunnel add gre1 local 10.44.6.1 remote 10.44.7.1 mode gre ttl 255
ip link set gre1 up
ip addr add 10.44.4.6/30 dev gre1
ip link set dev gre1 mtu 1476
ip link set gre1 multicast on
// должно быть по умолчанию включено, но пусть будет
ifconfig gre1 pointopoint 10.44.4.5

Схема GRE тоннеля
Схема GRE тоннеля

Для того, чтобы linux мог отвечать на GRE keepalive, нужно либо разрешить следующие параметры:

sysctl net.ipv4.conf.default.accept_local=1

sysctl net.ipv4.conf.all.accept_local=1

Либо воспользоваться более безопасным reply-only решением для ответа на GRE keepalive.

В результате, мы должны видеть на локальном сетевом интерфейсе приходящий пакет GRE keepalive от 10.44.7.1 к нашему адресу 10.44.6.1 , содержащий в себе инкапсулированный обратный пакет от 10.44.6.1 к 10.44.7.1:

tcpdump -n -vv -i eth0 proto 47
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:53:20.976489 IP (tos 0xc0, ttl 255, id 38364, offset 0, flags [none], proto GRE (47), length 48)
10.44.7.1 > 10.44.6.1: GREv0, Flags [none], length 28
IP (tos 0xc0, ttl 255, id 34625, offset 0, flags [none], proto GRE (47), length 24)
10.44.6.1 > 10.44.7.1: GREv0, Flags [none], length 4
gre-proto-0x0

Также мы должны видеть деинкапсулированный исходящий пакет в дампе трафика на интерфейсе gre1:

tcpdump -i gre1 -n
13:01:30.985542 IP 10.44.6.1 > 10.44.7.1: GREv0, length 4: gre-proto-0x0

Кроме того, стоит проверить, что в разделе Security Associations вывода статуса демона strongswan счетчики входящего и исходящего трафика растут:

ipsec statusall - команда проверки статуса ipsec

...

Security Associations (2 up, 0 connecting):
dc-tun[2]: ESTABLISHED 2 hours ago, 10.1.1.246[222.45.67.1]...177.54.214.20[177.54.214.20]
dc-tun[2]: IKEv2 SPIs: a62a46f88ff6e9c2_i* 50d27be1188d653d_r, pre-shared key reauthentication in 104 minutes
dc-tun[2]: IKE proposal: AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048
dc-tun-gre{9}: INSTALLED, TUNNEL, reqid 3, ESP in UDP SPIs: c9788976_i 0e1488b7_o
dc-tun-gre{9}: AES_CBC_256/HMAC_SHA2_256_128/MODP_2048, 13872 bytes_i (221 pkts, 8s ago), 3072 bytes_o (121 pkts, 10s ago), rekeying in 34 minutes
dc-tun-gre{9}: 10.44.6.1/32 === 10.44.7.1/32
dc-tun-tcp{10}: INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: cb28899e_i ace88e01_o
dc-tun-tcp{10}: AES_CBC_256/HMAC_SHA2_256_128/MODP_2048, 16800 bytes_i (200 pkts, 30s ago), 16800 bytes_o (200 pkts, 30s ago), rekeying in 34 minutes
dc-tun-tcp{10}: 10.45.8.17/28 === 100.15.30.0/24

В результате мы имеем рабочий GRE over IPSec тоннель по которому мы сможем получать multicast сообщения.

Для подписки на мультикаст с помощью PIM, я использовал python скрипт, в основу которого я взял скрипт из этого замечательного ответа на стаковерфлоу.

Для функции send_dummy_join(group, rp_addr, neighbor_ip) для этого примера:

group - это адрес мультикаст группы на которую вы хотите подписаться

rp_addr - адрес Multicast Rendezvous point 100.15.30.253, данный нам стороной ДЦ

neighbor_ip - адрес соседа (пира) по GRE тоннелю 10.44.4.5

Для маршрутизации мультикаста можно использовать pimd, но его настройка уже не будет описана в этой статье.

Если вы хотите почитать на русском о PIM, то советую эту статью (Сети для самых маленьких. Часть 9.3. Мультикаст. Протокол PIM).

Комментарии (4)


  1. viktort_t
    03.04.2023 07:31
    +1

    Приветствую!

    Расскажите чуть подробнее, с чем связан именно такой дизайн ipsec? Несколько ipsec политик и NAT выглядят как попытка "потушить пожар" :)

    Если со стороны "customer VM" есть публичный айпи, то тогда можно же сделать классический gre-over-ipsec. Будет более прозрачно. Имеем одну политику для ipsec и отсутствие НАТа.

    Если со стороны "customer VM" нет публичного айпи, то тогда можно сделать site2site для /32 адресов, поверх которых уже построить GRE. Опять таки, повышается прозрачность конфигурации, отсутствие НАТа. (Не забываем про МТУ).

    Если сервер и клиент - тачки на линукс, то тогда можно посмотреть в сторону ipsec VTI, или XFRM интерфейсов (зависит от версии ядра и версии iproute2). Насколько помнится, они поддерживают mcast.

    Ну и в целом, рассмотреть переход от deprecated stroke-based scenarios (ipsec.conf и ipsec команды) к swanctl :)


    1. Petrufel Автор
      03.04.2023 07:31

      Виктор, спасибо за комментарий.

      Наверное я зря не пояснил в статье, что:

      1. На AWS виртуальные машины имеют локально только приватные адреса, NAT которых выполняет Internet Gateway. (Но конечно можно привязать выделенный публичный Elsatic IP для каждого приватного адреса).

      1. Несколько политик скорее обусловлено дизайном подключения со стороны "DataCenter". Они отдельно дают классический IPsec для TCP коммуникации (настроен в conn dc-tun-tcp), и отдельно дают IPsec для построения GRE внутри (настроен в conn dc-tun-gre), как вы и предположили "site2site для /32 адресов, поверх которых уже построить GRE". По сути так и сделано. По GRE уже разрешены только кипэлайвы и мультикаст (политика с той стороны).

      2. Со стороны "DataCenter" точно Cisco, но не скажу модель.

      Спасибо что обратили внимание на swanctl, действительно, стоит переезжать.


      1. viktort_t
        03.04.2023 07:31
        +1

        Стало чуть яснее.

        Но НАТ кажется лишним. Так как в GRE уже указаны source ip и dst ip, с которого и куда он будет строиться (который и попадает под политику). И касаемо site2site сетей, сервисы, насколько я понимаю, будут жить в сети 10.45.8.16/28 и обращаться к сети 10.15.30.0/24 (что также попадает под политику).

        И мту на gre1 интерфейсе не 1476 будет. Там же у вас не чистый gre, а плюсом ipsec в туннельном режиме.


        1. Petrufel Автор
          03.04.2023 07:31

          NAT для tcp был нужен, так как клиенты по tcp обращаются в 10.15.30.0/24, но source IP из многих подсетей, а та сторона (условный “DataCenter”) принимает в конфиг только одну подсеть с моей стороны.

          Для GRE же NAT в принципе не нужен, но он не мешает, и облегчал отладку скрипта который слал PIM join в сторону 10.44.4.5. Я мог это делать тоже из другой подсети.