Публічний SSH через релей ламається на двох не пов'язаних границях, і виправлення однієї зазвичай виявляє іншу. Або край повертає відповідь HTTP замість передавання потоку, або релей додає спереду заголовок, який бекенд ніколи не погоджувався читати. Три умови визначають, що саме ви бачите: на що насправді вказує публічний запис, що блок потоку надсилає вгору і яке ім'я перевіряє клієнт SSH. Працюйте з ними в цьому порядку.

Дві границі, два симптоми

Збій на краю виглядає як сторінка стану HTTP, що приходить туди, де має бути банер SSH. З'єднання встановлюється на рівні TCP, а перші байти — це текст, що належить веб-серверу. Це невідповідність протоколу, а не втрачений пакет. Він також каже вам, що край навмисно обслуговує для цього імені щось інше.

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

Ці два легко переплутати, бо обидва дають клієнт, який підключається і потім збоїть. Саме перша відповідь протоколу розрізняє їх, тому вона й має потрапити до тікета.

Заголовок PROXY — це повідомлення, а не перемикач

У модулі потоку proxy_protocol on наказує NGINX записати заголовок протоколу PROXY у бік висхідної системи перед корисним навантаженням. Це не вмикає проксіювання TCP і не має нічого спільного з шифруванням SSH. Це записка, адресована отримувачу. Якщо отримувач не може її прочитати, вона стає сміттям на початку потоку.

Сервіс, що приймає, повинен свідомо споживати цей заголовок. Звичайний sshd очікує обмін ідентифікацією SSH як перші байти з'єднання, тому неочікувана преамбула ламає рукостискання так, що це виглядає як пошкоджений сервер.

stream {
    server {
        listen 2222;
        proxy_pass 10.77.0.20:22;
    }
}

Цей фрагмент — увесь робочий релей для бекенду, доступного через VPN. Директива PROXY не з'являється, бо отримувач не говорить цим протоколом, і ця відсутність є рішенням, а не пропуском.

Розділяйте й обидва напрямки. Встановлення proxy_protocol у рядку listen означає, що NGINX очікує, що його власний клієнт надішле заголовок першим; увімкнення цього для звичайного клієнта SSH дає рівно протилежне тій проблемі, яку люди зазвичай намагаються вирішити.

Чого насправді досягає публічне ім'я хоста

Сторінка HTTP 400 у сеансі SSH — це доказ про край. Щось на шляху говорить HTTP, і жодна робота з ключем чи обліковим записом на бекенді цього не змінить. Перестаньте змінювати бекенд, доки край не буде залагоджено.

Звичайний проксійований запис Cloudflare передає підтримуваний трафік HTTP і HTTPS на заданих портах. Увімкнення проксі для імені хоста не створює загальний релей TCP, а перенесення SSH на порт 443 не робить його HTTPS.

Існують два робочі напрямки. Запис лише з DNS може вказувати на ваш власний релей TCP, що залишає рішення про розкриття у ваших руках. Або використовуйте продукт, який явно документує передавання SSH, з власною конфігурацією джерела, клієнта та доступу.

Що б ви не обрали, релею все ще потрібен маршрут VPN до бекенду, дозволене з'єднання і зворотний шлях. Маршрут не стає необов'язковим від того, що публічний бік працює.

Тримайте ідентичність SSH стабільною за допомогою псевдоніма

Користувачі зазвичай хочуть продовжувати вводити наявне ім'я хоста. Псевдонім у конфігурації SSH може це зробити, нічого не змінюючи в релеї, і залишає зміну на боці клієнта, де їй місце.

Host git.example.com
    HostName ssh-entry.example.net
    Port 2222
    User git
    HostKeyAlias git.example.com

Без HostKeyAlias OpenSSH шукає ключ хоста під тим іменем, до якого підключається, тому запис зміщується, і кожен користувач під час першого використання бачить попередження про змінений ключ. Встановлення псевдоніма зберігає записи known-hosts стабільними, поки з'єднання все ще йде до релею.

Цей псевдонім стосується лише віддалених сховищ на основі SSH. URL Git через HTTPS його не враховує, і типовий віддалений URL має відповідати транспорту, який ви справді підготували.

Чого робити не можна, так це вимикати перевірку ключа хоста, щоб попередження зникло. Це прибирає захист, який ремонт переспрямування ніколи не просив чіпати, і перетворює косметичну незручність на реальне розкриття.

Перевіряйте кожен крок окремо

Перевірте публічний слухач окремо, потім з'єднання від релею до бекенду з хоста релею і лише потім клієнт від початку до кінця. Кожна з цих трьох перевірок виключає свій шар. Пропуск однієї означає, що два результати, які залишилися, неможливо витлумачити. Три спостереження, три місця, де може жити збій.

Зберігайте адресу призначення, порт і перші байти протоколу разом із кожним результатом. Ця трійка відрізняє помилку краю від проблеми маршрутизації VPN і від збою автентифікації SSH, і в цьому різниця між виправленням і здогадкою.

Нарешті, задокументуйте передбачуване розкриття. Релей TCP, який передає SSH до приватного бекенду, — це навмисно відчинені двері в публічному периметрі, і він заслуговує на такий самий розгляд, як будь-який інший вхідний сервіс.

Схожі статті