Чи існує віртуальний SSH-проксі-сервер на основі імені?


36

Я дуже захопився зворотними проксі-серверами HTTP в нашому середовищі розробки і вважав, що віртуальний зворотний проксі-сервер на основі DNS є досить корисним. Якщо на брандмауері відкритий лише один порт (і стандартний), це значно полегшує управління.

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

Чи може це зробити HAProxy?


Чи призначена вами програма передачі файлів чи фактичний доступ SSH до хостів?
Кайл Ходжсон

Мета прямого доступу SSH до хоста. Ця потреба випливає з бажання запустити власний сервер Mercurial, але наш сервер знаходиться за брандмауером. Зараз я працюю над простою налаштуванням HTTP-версії, але мені хотілося, щоб комітети використовували SSH замість HTTP. Прямий доступ SSH до інших серверів був би бонусом, якби це було можливо.
ahanson

Це така дратівлива проблема.
упередженість

Я розумію, що HAProxy тепер підтримує це через SNI. Хоча мені ще не вдалося це втілити.
Карел

Відповіді:


24

Я не вірю, що SSH на основі імен - це те, що стане можливим, враховуючи, як працює протокол.

Ось кілька альтернатив.

  • Ви можете зробити це налаштувати хост, який відповідає на порт 22, щоб діяти як шлюз. Тоді ви можете налаштувати ssh-сервер для переадресації запитів всередину на основі ключа. Приклад шлюзу SSH з ключами

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

  • Ви також можете встановити простий проксі-сервер http на краю. Потім використовуйте це, щоб дозволити вхідні з'єднання. SSH через HTTP-проксі .

Очевидно, що з усього вищесказаного, переконатися, що ви правильно налаштували та заблокували шлюз, є досить важливим.


18

Я шукав рішення цієї проблеми ввімкнення та вимкнення протягом останніх 16 місяців. Але кожен раз, коли я дивлюся, здається, що це неможливо зробити за допомогою протоколу SSH, як зазначено у відповідних RFC та реалізованих основними реалізаціями.

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

Чому це неможливо

Клієнт не надсилає ім'я хоста в рамках протоколу SSH.

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

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

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

Висновок для мене досить чіткий, треба щось змінити на стороні клієнта, щоб цей зв’язок працював.

Більшість обхідних шляхів є інкапсуляцією трафіку SSH всередині іншого протоколу. Можна також уявити додаток до самого протоколу SSH, в якому банер версій, що надсилається клієнтом, включає ім'я хоста. Це може залишатися сумісним з існуючими серверами, оскільки частина банера в даний час вказана як поле ідентифікації вільної форми, і хоча клієнти, як правило, чекають банера версії з сервера, перш ніж надсилати свій власний, протокол дозволяє клієнту надсилати свій банер спочатку. Деякі останні версії ssh-клієнта (наприклад, версія Ubuntu 14.04) дійсно надсилають банер, не чекаючи банера сервера.

Я не знаю жодного клієнта, який вжив заходів для включення імені хоста сервера в цей банер. Я надсилаю виправлення до списку розсилки OpenSSH, щоб додати таку функцію. Але його було відхилено на основі бажання нікому не розкривати ім'я хоста, котра переслідує трафік SSH. Оскільки таємне ім’я хоста принципово не сумісне з функцією проксі-сервера, не очікуйте, що незабаром з’явиться офіційне розширення SNI для протоколу SSH.

Реальне рішення

Найкраще для мене вирішило використання IPv6.

За допомогою IPv6 у мене може бути окрема IP-адреса, призначена кожному серверу, тому шлюз може використовувати IP-адресу призначення, щоб дізнатися, на який сервер надіслати пакет. Клієнти SSH іноді можуть працювати в мережах, де єдиним способом отримати адресу IPv6 було б за допомогою Teredo. Відомо, що Teredo є ненадійним, але лише тоді, коли в корінному з'єднанні IPv6 використовується загальнодоступне реле Teredo. Можна просто поставити реле Тередо на шлюз, де ви запустили б проксі. Miredo можна встановити і налаштувати як реле менш ніж за п’ять хвилин.

Обхідний шлях

Можна використовувати хост стрибків / бастіон. Цей підхід призначений для тих випадків, коли ви не хочете виставляти SSH-порт окремих серверів безпосередньо у загальнодоступному Інтернеті. Це має додаткову перевагу щодо зменшення кількості IP-адреси, яка стоїть зовні, необхідної для SSH, і тому вона може бути використана в цьому сценарії. Той факт, що це рішення, призначене для додання іншого рівня захисту з міркувань безпеки, не заважає вам використовувати його, коли вам не потрібна додаткова безпека.

ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target

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

Хак, який я збираюся описати, повинен використовуватися лише в крайньому випадку. Перш ніж навіть подумати про використання цього хаку, я настійно рекомендую отримати IPv6 адресу для кожного із серверів, до яких ви хочете бути доступними зовні через SSH. Використовуйте IPv6 як свій основний метод доступу до ваших серверів SSH, і цей хак використовуйте лише тоді, коли вам потрібно запустити SSH-клієнт із мережі, що використовується лише для IPv4, де ви не маєте ніякого впливу на розгортання IPv6.

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

І HTTP, і HTTPS дозволяють клієнту надіслати ім'я хоста до того, як сервер надішле будь-які дані. Тепер питання полягає в тому, чи можна побудувати потік байтів, який одночасно дійсний як трафік SSH і як HTTP, так і HTTPS. HTTP - це майже нестартер, але HTTP можливий (для досить ліберальних визначень HTTP).

SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$: 
Host: example.com

Це вам схоже на SSH чи HTTP? Це SSH і повністю сумісний з RFC (за винятком того, що деякі бінарні символи трохи заплуталися SF-рендерінгом).

Рядок версії SSH включає поле коментаря, яке у вищезазначеному має значення / HTTP/1.1. Після нового рядка SSH має деякі двійкові пакетні дані. Перший пакет - це MSG_SSH_IGNOREповідомлення, надіслане клієнтом і ігнорування сервера. Корисне навантаження, яке слід ігнорувати:

: 
Host: example.com

Якщо проксі-сервер HTTP є достатньо ліберальним у тому, що він приймає, то та сама послідовність байтів буде інтерпретуватися як метод HTTP, який називається SSH-2.0-OpenSSH_6.6.1 і двійкові дані на початку повідомлення про ігнорування будуть інтерпретуватися як ім'я заголовка HTTP.

Проксі-сервер не розумів ні методу HTTP, ні першого заголовка. Але це міг зрозумітиHost заголовок, що все, що йому потрібно для того, щоб знайти підсилку.

Для того, щоб це працювало, проксі повинен бути розроблений за принципом, що йому потрібно лише зрозуміти достатню кількість HTTP, щоб знайти бекенд, і після того, як бекенд знайдений, проксі просто передасть необмежений потік байтів і залишить справжнє завершення HTTP-з'єднання, яке повинно бути виконано бекендером.

Це може здатися трохи розтягнутим, щоб зробити так багато припущень щодо HTTP-проксі. Але якщо ви були готові встановити нову частину програмного забезпечення, розробленого з метою підтримки SSH, то вимоги до HTTP-проксі не здаються занадто поганими.

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

Доказ концепції клієнта та проксі . (Відмовтеся від того, що проксі - це послуга, якою я керую. Не соромтеся замінювати посилання після підтвердження будь-якого іншого проксі для підтримки цього використання.)

Печери цього хака

  • Не використовуйте його. Краще скористатися реальним рішенням, яким є IPv6.
  • Якщо проксі намагається зрозуміти трафік HTTP, він, безумовно, перерветься.
  • Покладатися на модифікований клієнт SSH - це не приємно.

Чи можете ви пояснити, що ви маєте на увазі під the gateway can use the destination IP address to find out which server to send the packet toрішенням IPv6?
Джейкоб Форд

@JacobFord Ключовим моментом для розуміння цього речення є те, що я використовую шлюз слова, а не проксі . За допомогою IPv6 ви отримуєте достатню кількість IP-адрес, щоб призначити їх кожному хосту, а ще запасні адреси. Усі машини, які ви поставили за проксі, мали б власну IP-адресу, для чого імена вирішують. Отже, вам більше не потрібен проксі, клієнти направляють свій трафік на IP-адресу потрібного хоста, і ви можете направляти трафік прямо туди.
kasperd

для обхідної частини існує відносно новий перемикач команд для ssh -J, тому ви можете використовувати: ssh -J user1 @ front user2 @ target
PMN

3

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

Крім того, у вас виникнуть проблеми з підтвердженням ключа хоста. Клієнти SSH перевірять ключі на основі IP-адреси, а також імені хоста. У вас було б кілька імен хостів з різними ключами, але той самий IP-адресу, з яким ви підключаєтесь.

Можливим рішенням буде мати хост "бастіону", де клієнти можуть вторгнутись у цю машину, отримати нормальну (або обмежену за бажанням) оболонку, а потім звідти змогу потрапити у внутрішні хости.


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

Дуже прикро, що ssh не надсилає fqdn і обробляє DNS на стороні клієнта. Я думаю, що люди не турбувались про публічне роздуття IP та NAT, коли було створено більшість протоколів рівня TCP / IP. Тому що, серйозно, вам слід мати змогу робити NAT на основі FQDN з iptables (тобто фільтрами ядра).
упередженість

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

@bias Ви не можете робити NAT на основі імені хоста, навіть якщо протокол вищого рівня дійсно надсилає ім'я хоста. Причина цього неможливо зробити в тому, що вибір бекенда потрібно робити, коли приймається пакет SYN, але ім'я хоста надсилається лише після обробки SYN та повернення SYN-ACK. Однак ви можете використовувати дуже тонкий проксі-програму проксі для протоколів, які надсилають ім'я хоста, таких як http та https.
kasperd

3

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

SSh piper на github

Мої перші тести підтверджені, і SSH, і SFTP працюють.


Це фактично MITM-атака. Я очікую, що він порушиться у всіх налаштуваннях, захищених від MITM-атак.
kasperd

1
Насправді приймаюча сторона - це і обидва, і господар, і людина в середині, тому лише ті двоє беруть участь.
Király István

@ KirályIstván це дивовижний проект, який підтверджує, що інші відповіді не на 100% вірні. Я створив подібний інструмент на основі github.com/gliderlabs/sshfront та деякого bash / python (я не можу відкрити його, але це не так цікаво - bash запускає ssh-клієнт, а python використовується як обробник auth). Але в мене є одне питання з поточним рішенням. Він не підтримує sftp (scp працює). Він висить, намагаючись запустити підсистему debug1: Sending subsystem: sftp. Виявляється, сорочка спереду не підтримує підсистеми. Чи підтримуєте ви подолу в SSh piper?
Maciek Sawicki

1
@MaciekSawicki Я не автор. Я просто використовую це у своєму проекті. .)
Кіралі Іштван

2

Мені цікаво, чи не вдасться змінити Honeytrap (медовий лот із низькою взаємодією), який має проксі-режим, щоб досягти цього.

Цей медовий горщик здатний переслати будь-який протокол на інший комп'ютер. Додавання vhost-системи на основі імені (як реалізовано Apache) може зробити її ідеальним зворотним проксі-сервером для будь-якого протоколу ні?

Я не маю навичок цього досягти, але, можливо, це може бути чудовий проект.


відмінна ідея!
упередженість

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

1

Зі збільшенням кількості портів / хостів, до яких потрібно отримати доступ за брандмауером, збільшується зручність VPN.

Мені не подобаються VPN.


1

через те, як працює ssh, я думаю, що це неможливо. Подібно до https, вам доведеться мати різні (зовнішні) IP-адреси для різних хостів, оскільки шлюз не знає, до якого ви хочете підключитися, оскільки все в ssh зашифровано

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.