Пользователь
0,0
рейтинг
27 апреля 2012 в 09:16

Администрирование → SysAdmin Anywhere: Используем UDP Hole Punching для реализации удаленного рабочего стола

Введение


Системные администраторы по своей природе — люди ленивые. Не любят они по сто раз одно и то же делать. Хотят все автоматизировать, чтобы работало с минимальным вмешательством. И я такой.

Дабы облегчить жизнь себе и мне подобным, была создана программа, которая объединила разрозненные средства администрирования в один продукт с простым названием SysAdmin. Он включает поддержку мультидоменной сети, отчеты, инвентаризацию и много других полезных вещей, которые разбросаны по разным MMC или входят в сторонние продукты. Работать стало значительно удобней. Данная программа уже доросла до версии 5.3, сменила интерфейс на Metro-style. Но, к сожалению, в ней нет возможности администрировать компьютеры, не включенные в домен.

Однако, хотелось большего:

  • Полноценно администрировать удаленные компьютеры;
  • Настроить доступ без личного присутствия на удаленной стороне и без наличия квалифицированного сотрудника с удаленной стороны;
  • Не открывать порты на маршрутизаторе;
  • При невозможности личного присутствия не открывать доступ к маршрутизатору из интернета;
  • Не усложнять техническое решение, если необходимо иметь доступ не к одному компьютеру в удаленной сети:
  • Не открывать порты на маршрутизаторе для каждого компьютера;
  • Не открывать доступ на маршрутизаторе к серверу, а с него к компьютерам (Не всегда есть необходимость в сервере, а введение его в качестве средства для удаленного доступа – экономически нецелесообразно);
  • Не открывать один порт и каждый раз не перенастраивать маршрутизатор для доступа к другому компьютеру;
  • Не поднимать VPN.




Из опыта:
По работе надо было создать VPN-сеть с региональными отделениями, расположенными по всей стране. В центральном отделении было установлено мощное VPN-оборудование, а на местах планировалось оборудование той же компании, но проще. Необходимо было выяснить все про их интернет — соединение, локальную сеть, установленное оборудование и т.д. Подготовить VPN-оборудование и отправить им, чтобы они его подключили и все заработало. Пикантность ситуации заключалась в том, что это предстояло сделать фактически мне одному, командировки не предусматривались и уровень пользователей на местах был очень разнообразен. Конечно, все было реализовано, но это отняло массу времени на переписку и телефонные разговоры.


Из-за перечисленных ранее ограничений для реализации был необходим посредник. На удаленный компьютер устанавливается клиентская часть, которая создает соединение с посредником, не блокируемое файерволами, т.к. оно инициировано самой удаленной машиной. Администратору достаточно знать только адрес посредника, чтобы, подключившись к нему, получить доступ к удаленным компьютерам. Благодаря такому посреднику, мы получаем ряд преимуществ:

  • Нет необходимости открывать порты на маршрутизаторе. Повышается безопасность, снижается уровень необходимой квалификации пользователя;
  • Администратор имеет доступ к панели управления, расположенной в облаке, через браузер, поддерживающий Microsoft Silverlight посредством защищенного соединения;
  • Команды от администратора при помощи облачного сервиса отправляются на удаленный компьютер. Ответ передается администратору аналогичным образом;
  • Удаленный компьютер находится в режиме онлайн, поэтому нет необходимости в присутствии пользователя;
  • Дополнительные сервисы (инвентаризация, сервис-деск, отчеты, учет лицензий, архивация, мониторинг и т.д.) с хранением данных в облаке и доступа к ним, даже если удаленный компьютер не подключен к интернету;
  • Удаленный рабочий стол (VNC);
  • Доступ с мобильного телефона на Windows Phone.




Платформу для посредника долго искать не пришлось. Microsoft Azure, как нельзя кстати, подходила для этого. Тем более была возможность получить 30-ти дневный доступ для экспериментов.

Так сложилось, что к этому времени я сменил сферу деятельности с системного администрирования на программирование., поэтому решил создать сервис самостоятельно.
Ко мне присоединился мой коллега, и мы вместе приступили к разработке прототипа сервиса. Перед нами стояла задача за время тестового периода создать работоспособную модель взаимодействия удаленного клиента с облачным сервисом. Дальнейшие разработки можно было продолжить, используя Azure SDK.



Сложнее всего было организовать постоянное соединение удаленного компьютера с облачным сервисом. В результате долгих и нудных экспериментов (деплой в облако занимает ощутимое время) появилось рабочее решение, которое дало уверенность в достижении поставленной цели.

Мы смогли соединить удаленный компьютер с облаком, при этом ничего не настраивая из сетевого оборудования. Для нас это стало прорывом.

Теперь стояла задача передать команду от администратора в облако, а далее на компьютер и получить от него ответ. Мы остановились на том, что универсальным решением было бы использовать WMI. Причем, облачный сервис не должен знать ничего про WMI. Его задача — пересылка. Это задумывалось для того, чтобы как можно реже приходилось обновлять сам облачный сервис и клиентское ПО на удаленных компьютерах (сейчас обновляется до последней версии нажатием кнопки в консоли).

Пример:
От администратора передается запрос на получение списка установленных служб (Select * From Win32_Service) плюс набор полей, значения которых нам нужны. Все это сериализуется JSON, пакуется, шифруется и передается в облако. В облаке данные записываются в очередь и затем забираются из нее экземпляром службы, к которому подключен удаленный компьютер.
Клиент, получив запрос, выполняет его. Полученный результат сериализуется JSON, пакуется, шифруется и передается в обратном порядке администратору.


Использование WMI не ограничивается только запросом, реализован вызов функций и процедур. Например, любую из служб можно остановить.



Казалось бы, все просто, но не стоит забывать, что если мы планируем сделать масштабируемое решение — без работы с несколькими экземплярами нашего сервиса в облаке не обойтись. Работа с ними требует некоторого пересмотра своего опыта в разработке. Всегда надо держать в голове, что существует не один экземпляр, а несколько, и работают они параллельно. Желаете что-то сделать монопольно — не забывайте оповестить об этом остальные экземпляры. Например, биллинг. Будет крайне неприятно, когда каждый экземпляр пройдется по базе и пересчитает баланс клиента, каждый раз уменьшая его. Такой вариант показан в качестве примера того, что может произойти, хотя в настоящее время мы работаем над тем, чтобы исключить эту проблему в будущем.



Создавая сервис, мы исходили из того, что в большинстве случаев не обязательно иметь доступ к удаленному рабочему столу. Достаточно прямого управления процессами, службами и т.п. Это быстрее и проще сделать через веб-интерфейс.



Все же удаленный рабочий стол очень востребован и для его реализации требуется прямое соединение между компьютерами. Передавать такой объем информации через облако нерационально, так как задержка в обновлении экрана может достигать несколько секунд.

Реализация UDP Hole Punching


Наиболее интересной задачей оказалась реализация системы удаленного доступа к рабочему столу. Для экономии времени было решено взять уже готовую реализацию VNC что, однако, порождало свои проблемы: соединить напрямую клиент и сервер VNC невозможно. Единственным решением явилось создание посредников, задача которых — ретрансляция трафика. Таким образом, VNC клиент и сервер будут “думать”, что работают локально, когда на самом деле весь трафик между ними мы будем передавать через Интернет.



NAT Travesal

Остался открытым вопрос: каким образом передавать информацию между посредниками? Первый приходящий на ум вариант – гонять все через облако – является сколь дорогим столь и неэффективным способом. Гораздо лучше соединить все напрямую. Тут мы и наталкиваемся на стандартную проблему NAT Traversal.



Преобразование сетевых адресов (NAT) не дает возможности устанавливать прямое соединение между клиентами. NAT – это процесс трансляции локальных адресов, недоступных из Интернета, во внешние. Для обхода NAT существует несколько стандартных способов: открыть порт, поднять VPN.

К сожалению, ни один из них нам не подходит, т.к. сразу усложняет установку всех необходимых компонентов (а ведь мы хотим, чтобы установка клиента на рабочей машине была доступна наименее продвинутым пользователям без помощи админа). Поэтому воспользуемся механизмом UDP Hole Punching.

UDP Hole Punching

UDP hole punching — метод для прямого соединения двух компьютеров, которые находятся за NAT-ами. Для инициации соединения требуется третья сторона – сервер, который виден обоим компьютерам. Обычно используются публичные STUN-серверы.

Итак, наша задача состоит в том, чтобы напрямую связать клиента на удаленной машине и консоль. Для этого необходимо сделать несколько шагов:

  • Узнать внешний IP и порт удаленной машины. Для этого воспользуемся STUN – сетевым протоколом, который позволяет определить внешний IP-адрес.
  • Передать эту информацию нашему приложению
  • Установить соединение и использовать его далее для обмена данными




Как это выглядит в коде?

В теории все просто. Как все это выглядит на практике?



Как видно из изображения выше, немногим сложнее. Сначала мы отправляем запрос на соединение от нашего приложения, который через облако передается приложению на клиентской машине (шаги 1 и 2). Клиентская машина запрашивает свой внешний адрес и порт у STUN-сервера (шаги 3 и 4). В сети можно найти множество реализаций STUN протокола.

string address = String.Empty;
udpClient = new UdpClient();
udpClient.AllowNatTraversal(true);
ResultSTUN result = ClientSTUN.Query("stun.ekiga.net", 3478, udpClient.Client);
if (result.NetType == UDP_BLOCKED) { /* обработка ошибки */ }
else { address = result.PublicEndPoint.ToString(); }


Т.к. в нашем решении используется UDP, мы можем, используя тот же сокет, подключиться к клиенту (что выгодно отличает его от TCP).

После этих нехитрых манипуляций address будет содержать внешний адрес и порт клиентской машины (или сообщение об ошибке). Эта ценная информация передается консоли управления через облако (шаги 5 и 6). Создать соединение, зная порт и адрес – уже дело техники. Теперь мы можем передавать всю необходимую нам информацию.

Задача NAT Traversal решается просто и изящно при использовании UDP, но что если мы при этом хотим все преимущества TCP: гарантированную доставку пакетов, целостность данных, отсутствие дублирования и т.д.? Первая мысль, которая приходит в голову – написать свой протокол поверх UDP. Естественно, мы далеко не первые, кто столкнулся с этой проблемой. Поэтому после недолгого поиска можно найти такое решение, как Lindgren.Network, которое в итоге используется в нашем приложении.

Игорь Маркин @RIAMedia
карма
9,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

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

  • 0
    Выглядит очень круто!

    Пожелания:
    1. В хроме при логине не сохраняется пароль, мне лично это неудобно.
    2. Хорошо бы сделать возможность давать клиенту ссылку на скачивание уже персонализированного иснталлера с зашитым регайди (генерировать новую каждый раз, в админке указывая имя компьютера, описание и прочее), + возможность скачивать универсальный инсталлер из админки с зашитым регайди, для массового развертывания (автоматом брать имя компьютера).
    • 0
      3. Эвентлог лучше подсасывать сразу, в фоновом режиме, а не после клика на events в админке.
      • 0
        Соответсвенно в дальнейшем напрашивается развитие фичи в автоматическом пуше эвентлога в облако, да и вообще пуше всех важных вещей и реалиазация системы мониторинга с возможностью отправки оповещений на почту (и смс за денежку :) ). Если такое есть в планах, могу помочь советами что и как нужно мониторить.
        • 0
          События сохраняются в мониторинге. Правда все ограничено ошибками и хранится не более суток. Но зато можно видеть эвенты сразу по всем компьютерам.
    • 0
      4. Киллер-фичей была бы возможность удаления приложений из админки.
    • 0
      3. Нужно причесать раздел хардваре:
      гораздо полезнее показывать «человеческий конфиг» — процессор, объем памяти, диски и место на них, видеокарта, сетевые карты (только физические), айпи и мак адреса + возможность добавления своих полей и кастомизации существующих.
      • 0
        + очень круто было бы добавить «экспертный режим», то есть возможность добавить кастомное поле и задать WQL запрос что именно дергать.
        • 0
          Простой ввод запроса в текстовое поле реализовать не сложно. Гораздо сложнее сделать мастер по составлению запросов. Но пожелание очень интересное, постараемся реализовать.
          • 0
            Ну мастер в принципе не нужен, достаточно ссылку на справку, кому реально нужно, сам разберется, там ничего сложного нету.
      • 0
        Про «человеческий конфиг» — каемся, пока руки не дошли. По поводу "… возможность добавления своих полей и кастомизации существующих..." можно поподробнее?
        • 0
          Ну то есть например возможность добавить поле «Монитор» и вписать туда модель и серийник. Или когда вы проапгрейдите раздел и добавите поле серийник, нужна возможность ручками его поменять, в WMI не всегда то что нужно лежит. Нужна возможность добавить поле «Компьютер» (или как-то иначе реализововать трекинг компьютера как цельной единицы), нужна возможность добавить поле серийник, инвентарный номер, дату покупки, гарантию, примечание, ссылку на дрова например и т.д.), то есть нужна волшебная кнопка «я знаю что я делаю», которая меняет интерфейс для домохозяек на мощный инструмент инветаризации.

          Еще надо подумать, нужно ли железо перечислять в двух местах, наверное логичнее держать в базе единую информацию о железе компьютера, и выдавать одно и тоже на в разделе хардваре и в инвентори.
          • 0
            В Inventory хранится не последняя конфигурация, а все ее изменения. Последняя конфигурация генерируется автоматически. Позже мы добавим возможность отслеживать во времени изменения. В хардваре показывается конфигурация в «реальном времени».
            • 0
              Да, это понятно. Я про то, что в саммари инвентори и в хардваре компьютера должны быть одинаковые данные, то есть в хардваре по сути показывать тоже самое, что в инвентори, иначе возникает путаница. А сейчас в харваре последние данные из лист инвентори.
    • 0
      1. К сожалению, пароль пока нигде не сохраняется.
      2. Думаем над реализацией.
    • 0
      Ну про то что кнопка NEW в инцидентах ничего не делает, вы наверное и так в курсе.
      • 0
        А это не кнопка — это фильтр. Инциденты создаются пользователями на удаленных компьютерах. В консоли нельзя завести новый инцидент. У нас в планах реализовать дополнительную фичу с полноценным сервис-деском.
    • 0
      С инвентаризацией лицензий вообще все плохо, но это не ваша вина, я уже месяц думаю, как это реализовать, и пока ничего стоящего не придумал.

      1. Не интуитивное добавление лицензии через клик на ПО. (я с ходу не понял что нужно забивать в количество, потом добавил одну и ту же софтину два раза — она и пощиталась два раза.



      2. Как считать лицензию на винду?
      3. Ну поле «серийник» так и просится, помимо примечания.
      4. Дата окончания лицензии с нотификацией за n дней — отличная фича на будущее.
      5. Я сейчас раздумываю над формированием списка популярного ПО, и механизмом вычленения из установленного ПО конкретных наименований по паттерну, а то один msoffice добавляет в «программы» порядка 15 пунктов, а продукт по сути один. Можем подумать вместе.
      • 0
        У нас сравнивает лицензии по части названия, например, Office — считает все название со словом Office. Мы открыты для обсуждений. Насчет одинаковых названия — наш косяк. Поправим.
        • 0
          Не совсем понял. Можно как-то добавить лицензию не кликом на софте? По части названия сейчас не сравнивает:



          На самом деле стоит Kaspersky Endpoint Security 8 для Windows

          Наверное удобно будет дать возможность ввести вручную ПО, количество и название, а также маску поиска, типа (*Office 2010*)/(*Офис 2010*) или Windows 7 Professional/Профессиональная.
          • 0
            В Inventory внизу кнопка Add
            • 0
              Позор мне. Вообще не заметил эту синюю полоску :)
              • 0
                Как бы в стиле Metro 8 :-)
        • 0
          Дату установки ПО тоже полезно вытаскивать.
          • 0
            Там же есть в таблице. Может где-то еще надо?
            • 0
              Действительно есть, проглядел. Смотрел на ласт ченжес — там нету, не знаю насколько там нужно.
    • 0
      Ну и русская версия нужна наверное? В профиле выбор языка.
      • 0
        Планируется
    • 0
      Также хочется проверку установленных обновлений и состояния типа «комп обновлен», «ожидает перезагрузки для установки» и т.д.
  • 0
    Выглядит действительно стильно, в духе Win 8 и метро.
    Но вот что-то со скоростью работы программы совсем не порядок… карточка пользователя открывается 15-30 секунд, прожорливость ресурсов… на скриншоте: habrastorage.org/storage2/f4a/9fe/f04/f4a9fef0499d06d9746078c4aa7c28e8.png"
    • 0
      Вообще-то в статье идет рассказ не про SysAdmin, а про SysAdmin Anywhere. Но замечания принимаем по всем. Посмотрим что не так со скоростью. А прожорливость от дот нета.
      • 0
        Да, прошу прощения, просто смотрю и то, и другое.
  • +1
    Либо вы с темой NATa разобрались не до конца, либо недописАли статью.

    1. STUN-серверы используются прежде всего для того, чтобы опеределить тип NAT (простой ликбез по NAT здесь: aoz.com.ua/2009/01/26/nat-types/ ), а только после этого решается требуется ли использовать релей для соединения.
    2. UDP-punching не панацея, при Symmetric Cone NAT работать не будет. Лучше сделать нормальное определение типа NAT и при попадании в SC NAT делать соединение через релей.
    3. Из первых двух пунктов вывод, что логически UDP Hole punching и STUN вещи разные. Просто STUN сервера обычно используют также как рандеву-сервера
    3. Если я все правильно понимаю, схему после слов «В теории все просто. Как все это выглядит на практике?» можно упростить, если работать через TCP и держать коннект к облаку с keep-alive и а в базе сохранять тип ната у клиента и его «внешний» ip на каждую сессию — тогда не надо будет каждый раз делать операции 3 и 4.
    Еще один RTFM, как раз про STUN, UDP hole punching и TCP hole punching: www.brynosaurus.com/pub/net/p2pnat/

    • 0
      1. Не только тип NATAа, но и адрес + порт
      2. Не панацея. В примере кода показано, что мы не можем соединиться если данный тип соединения невозможен.
      3. Мы пока используем STUN сервера, т.к. в Azure пока нет возможности работать с UDP протоколом.
      4. Мы и так держим коннект к облаку по TCP, но реализация TCP hole punching сложна. Главная фишка UDP hole punching в том, что к открытому соединению можно подключиться с другого адреса.
      • 0
        Тип NATa как раз таки определяется (не)возможностью соединения с портом и/или адресом. Это вместе и называется «тип NATa».
        А алгоритм работы TCP hole punching — не сильно сложнее такового для udp. Он как раз есть по второй ссылке.
        Кроме того, можно попробовать реализовать соединение через закрытие соединения, когда бинды к клиенту за натом еще должны быть открыты в течение пары минут. Бонус будет в упрощении логики работы системы.
        • 0
          Спасибо за предложение. Делали то, что было проще реализовать. Все упростится, когда в Azure появится поддержка UDP. Тогда STUN-сервера нам не понадобятся.
          • 0
            Да вам и сейчас udp имхо не сильно нужен. Надо только сделать tcp hole punching или протестить соединение с клиентом после закрытия коннекции.
            А в облако заведите модуль, который будет выполнять роль stun сервера (ну или полноценный стороннюю реализацию stun) — возврат клиенту его global routable ip и определения типа nat и дополните его TURN сервером, который будет релеем, когда у клиентов symmetric NAT.
            Будет все канонично, как это принято.
            У меня по поводу udp hole punching вообще такое мнение, что он нужен только для быстрого пиринга на предопределенные порты с минимальным задействованием рандеву сервера.
            • 0
              Если речь идет о TCP hole punching, то тогда STUNT-сервер.
            • 0
              Когда искали как нам все реализовать попадались решения для TCP hole punching, но они были либо давно заброшены, либо не продвинулись далее статей с красивыми картинками.
  • 0
    Кнопка edit на pending компьютере не нажимается.
    • 0
      сервис деску не помешает функционал снятия скриншотов.

      также было бы неплохо сделать Solution обязательным для заполнения полем, и без него не давать закрывать тикет.
    • 0
      Есть такое дело, поправим.
    • 0
      еще бы группировку компьютеров добавить.
      • 0
        В этом вопросе у нас есть две задумки:
        1. Папки
        2. Тэги
        Склоняемся к тэгам.
        • 0
          Одно другому не мешает
          папки — физические отделы/кабинеты/оргструктура
          теги — например «менеджмент», «бухи», «слабое железо», «админские права у пользователя»
          • 0
            Может быть и такой вариант. Будем тестировать
  • 0
    Вы будто читаете мысли.
    Только вчера обнаружил у себя в закладках ваш сайт и кинул знакомому в скайп:
    [26.04.2012 21:03:52] Valery Solovjeff: wtf? ria-media.net/products.aspx
    • 0
      И? Все прояснилось? :-)
  • 0
    И вот ещё один сервис-деск…
    Ребята, лучше посмотрите в сторону интеграции с Смарт-натом, это будет лучше, чем с нуля писать свой СД.
    • 0
      К сожалению, не увидел у них поддержки языков отличных от русского.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.