SSH през релей на поток NGINX без да го счупите
Заглавката PROXY е съобщение за получател, който я очаква, а проксиран запис в DNS не е TCP релей. Оправете ръба и източника поотделно.
Публичният 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. HTTPS адрес на Git не го проверява и типичният адрес на отдалечено хранилище трябва да съответства на транспорта, който действително сте осигурили.
Това, което не бива да правите, е да изключите проверката на ключа на хоста, за да заглушите предупреждението. Това премахва защита, която поправката на препращането никога не е искала да бъде докосвана, и превръща козметично неудобство в истинско излагане.
Проверявайте всяка стъпка поотделно
Тествайте публичния слушател самостоятелно, след това връзката от релея към бекенда от хоста на релея и само след това клиента от край до край. Всеки от тези три теста изключва различен слой. Пропускането на един означава, че останалите два резултата не могат да бъдат тълкувани. Три наблюдения, три места, където може да живее провал.
Пазете адреса на местоназначението, порта и първите байтове на протокола с всеки резултат. Тази тройка различава грешка на ръба от проблем с VPN маршрутизацията от провал на SSH автентикацията и това е разликата между поправка и предположение.
Накрая документирайте предвиденото излагане. TCP релей, който пренася SSH до частен бекенд, е умишлено отваряне в публичния периметър и заслужава същия преглед като всяка друга входяща услуга.