Клієнт підключається до сервера OpenVPN на віртуальній машині Compute Engine, вікно стану повідомляє підключено, а ping до хоста всередині VPC усе одно нікуди не доходить. Перший порив — додати ще один рядок push, і це ніколи не допомагає. Compute Engine вирішує, куди йдуть пакети, за власною таблицею маршрутів і за адресами, які інтерфейс VM справді тримає, тому пул тунелю, яким VM не володіє, — це пул, до якого ніхто не доставляє.

Ідіть за пакетом, що падає, а не за файлом конфігурації, і відсутні частини з'являться по порядку.

Почніть з умираючого пакета

SYN залишає клієнта, потрапляє в тунель і досягає VM як інкапсульований пакет до адресата всередині VPC. OpenVPN розпаковує його і намагається передати через eth0, де fabric ставить одне запитання перед усім іншим: чи володіє цей інстанс адресою призначення. Пул тунелю, вирізаний з чужої підмережі, не проходить це запитання, і пакет відкидається ще до того, як буде перевірено бодай один маршрут чи правило firewall.

Отже, напрямок від клієнта до VPC має дві окремі вимоги, і жодна з них не є директивою push. VM потрібен діапазон alias, що покриває пул тунелю, і саме це робить її законним власником цих адрес. VPC потрібен маршрут, який називає VM наступним переходом для кожного захищеного префікса. Бракує одного — пакет умирає в іншому місці, а клієнт бачить ту саму тишу.

Читайте збій у цьому порядку, бо з боку клієнта обидві умови виглядають однаково. Тунель, який повідомляє про підключення, коли ніхто не відповідає, — ознака проблеми топології, а не поганого шифру.

Чи володіє інстанс пулом тунелю

Дайте VM вторинний діапазон усередині її власної підмережі, а потім змусьте OpenVPN видавати адреси рівно з цього діапазону. На інстансі, чия основна адреса — 10.156.0.10/20, alias /28 відокремлює пул від адрес, які вже тримають інші інстанси:

gcloud compute instances network-interfaces update openvpn-vm \
  --zone=europe-west1-b \
  --aliases=eth0:10.156.1.0/28

Тоді директива server має описувати той самий блок. Її перша адреса стає шлюзом тунелю, а решта адрес роздаються клієнтам. Тут два числа описують один блок, мережу й маску, і це той синтаксис пулу, якого OpenVPN досі чекає.

server 10.156.1.0 255.255.255.240

Переконайтеся, що адреса справді потрапила на інтерфейс, а не лише в конфігурацію OpenVPN. Fabric пересилає те, що повідомляє NIC, а не те, у що вірить демон. Одна команда це вирішує:

ip -4 addr show dev eth0

Вторинна адреса, яка так і не доходить до eth0, або пул, що перетинається з іншою підмережею, згодом проявляється як періодичні втрати, а не як помилка запуску. Демон стартує, клієнти підключаються, і лише частина призначень поводиться неправильно. Тримайте діапазон alias малим, щоб пул легко впізнавався в таблиці маршрутів. Ніколи не вирізайте його з підмережі, яку вже використовує інший інстанс.

Дайте зворотному трафіку наступний перехід

Відповідь від хоста у VPC адресована клієнтській адресі з пулу тунелю, яка не належить жодній відомій VPC підмережі. Без маршруту до цього пулу відповідь зупиняється на першому переході без збігу, а запит цілком міг успішно виконатися на далекому кінці.

gcloud compute routes create openvpn-return \
  --network=prod-vpc \
  --destination-range=192.168.127.0/24 \
  --next-hop-instance=openvpn-vm \
  --next-hop-instance-zone=europe-west1-b \
  --priority=800

Той самий маршрут потрібен для будь-якого префікса, що лежить за клієнтом, а не всередині VPC. Цим префіксам також потрібен запис iroute у ccd-файлі цього клієнта. Цей запис — облік на боці сервера: він каже серверу, який клієнт володіє префіксом, і нічого не встановлює на самому клієнті.

Залиште список push для клієнтського боку розмови, бо він лише додає маршрути на машину, що підключається. Рядок push для підмережі VPC і маршрут VPC назад до пулу — дві половини одного шляху, і будь-яка половина сама по собі дає тунель, який несе запити, але не відповіді.

Firewall, пересилання та проміжні переходи

Firewall VPC оцінює розпакований пакет, тому правило ingress має пропускати пул тунелю й будь-який префікс майданчика, що доходить до VM цим шляхом. Позиція default-deny тихо провалюється тут: пакет відкидається після розпакування, а журнал OpenVPN показує здорову сесію.

На будь-якому хості Linux, який пересилає, а не завершує, перевірте, чи ввімкнено net.ipv4.ip_forward. Правило володіння діє й там: машина, яка пересилає для підмережі, якої вона не має, відкидає пакет так само, як це зробила б VM. Прочитайте значення, перш ніж звинувачувати тунель.

Коли не працює рівно один префікс

Частковий збій читається найлегше, бо все інше на шляху вже доведено. Почніть зі списку маршрутів і прочитайте діапазон призначення та наступний перехід запису, який мав би покривати префікс, потім прочитайте опис інстансу й порівняйте його діапазон alias із пулом, який роздає сервер.

gcloud compute routes list --filter=destination-range~10.164.0.0
 gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)

Відсутній маршрут проявляється як відсутність наступного переходу для префікса, а відсутній alias — як пакет, відкинутий на інтерфейсі; з боку клієнта ці дві речі схожі, а в цих двох виводах зовсім різні. Якщо є і те й те, підозрюваний, що залишився, — iroute у ccd клієнта, який заявляє префікс.

Запишіть чотири значення поряд із тунелем: діапазон alias, пул сервера, запушені префікси, маршрути VPC. Застарілий alias ламає кожну адресу пулу, застарілий маршрут ламає один напрямок, відсутній push ховає префікс від клієнта, а хибний iroute надсилає префікс не тому peer. Наступній людині, яка додасть підмережу, потрібні всі чотири в одному місці, і ця нотатка дешевша за вечір.

Схожі статті