Router OS API : smartROS

В общем возникла идея автоматической блокировки ip при “прощупывании” nextCloud сервера – заметил, что каждый день регулярно кто-то таки пытается подобрать пароли. Fail2ban на самом сервере, естественно, стоит, но он ловит не все попытки + как правило “прощупывальщики” тыкают не только в этот сервер, а во все сервисы, что смотрят в глобальный Интернет.

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

Предисловие

На немой вопрос – “а есть же скрипты автоматической блокировки прямо на Микротике” – да, есть. Но они используются в случае, когда сканируют/тыкаются в известные порты типа 22, 25, 80 и т.д., которые по факту закрыты. Они не помогут (ну или почти не помогут), если у вас есть http/https сервер, который реально смотрит в мир и доступ к которому нужно обеспечить с любого внешнего ip-адреса. Тут уже нужно анализировать запросы и если кто-то подбирает пароли или пытается открыть закрытые ресурсы – блочить такие ip. Для этого можно использовать тот же fail2ban. Но он контролирует только тот хост, на котором установлен.

Учитывая, что fail2ban – opensource, можно адаптировать его (и думаю, если хорошо поискать – кто-то и где-то это уже делал).

Но хотелось бы:

  1. Сделать это централизовано, то есть если какой-то из сервисов “замечает”, что его пытаются взломать – сообщает центральному узлу, и тот глобально заносит такой ip в общий черный список;
  2. Иметь общую картинку о том, что и где происходит – централизовано собирать логи и иметь возможность с одного места видеть все такие инциденты (таки да – будет скоро и про ELK+Mikrotik %)
  3. Сделать всё максимально универсально и гибко, чтобы не настраивать с нуля или значительно адаптировать решение каждый раз под каждый сервер. В идеале максимально использовать готовые и хорошо зарекомендовавшие себя решения.
  4. Не скрою, хотелось потыкать ELK на практике %)

В итоге в голове сложилась такая схема:

  1. Центральное хранилище логов: ELK (точнее Elasticsearch – “E”). По сути под все более-менее известные сервисы/сервера существуют плагины, которые позволяют передавать логи в ELK. Супер.
  2. С помощью filebean будем забирать логи с NextCloud, с помощью logstash (“L” в ELK ) обрабатывать и выделять нужные моменты (то есть, к примеру, выделять характерные для попыток взлома сообщения в логах).
  3. С помощью Kibana (“K”) – будем наблюдать/визуализировать (или же та же Grafana – кому что больше нравится).
  4. Каким-то образом решать – блокировать или нет (на тот момент в голове конкретного решения не было, но бегло просмотрев документацию по logstash понял – вариантов есть и не один %)
  5. Иметь возможность на основе принятия решения обновлять blacklist на всех необходимых роутерах.
  6. Учитывая, что система получится распределенная, нужно подумать, как хоть номинально обеспечить длительную работоспособность %)

Начнем с конца. С роутеров %)

1. ROS API : что это

Итак, кто не знает – роутеры Микротик имеют возможность управления не только посредством Winbox/www/ssh/telnet, но и через низкоуровневый сетевой API. Последний удобен именно в случае, когда необходимо выполнять команды удаленно и – получать/обрабатывать результаты в удобном для программы, а не для человека, виде.

По умолчанию RouterOS API выключен. Для удаленного подключения его необходимо включить. Но сделать это надо очень аккуратно дабы не отдать ваш роутер в руки хакеров:

  • api или api-ssl – вот в чем вопрос. Только api-ssl, без вариантов! Почему – начиная с версии 6.43 логин/пароль передается в plain (то есть открытом) виде, то есть очень легко перехватить. Даже если вы открыли этот порт только для доступа из локальной сети и только для избранных ip адресов – можете ли вы гарантировать, что в локальной сети у вас ни на одном ПК нет трояна, которые подслушывает локальный трафик? Можно, конечно, завернуть это всё в VLAN (внимание – имеется в виду физически-выделенный, а не логический, VLAN!), и даже было бы правильно все каналы управления сетевым железом держать в отдельной физической подсети … но обычно делают как проще %) Потому только ssl.
  • обязательно в настройках api-ssl (Available From)) указать список разрешенных для подключения адресов (то же самое, кстати, и для www/ssh/winbox, если пользуетесь. А telnet вообще вырубить сразу и навсегда).
  • делаем дублирующие правила доступа и в фаерволе.  В данном случае лучше перестраховаться, чем потом кусать локти.
  • желательно (и иногда единственный вариант) – используем сертификаты. Как сгенерировать правильно – распишу потом отдельно (ибо сертификаты полезны не только для API, но и для того же VPN). Кто не хочет ждать – смотрит/пользует скрипты для “ленивых”.
  • для api-ssl создаем своих пользователей. Я использую два – один только для чтения (права read), второй имеет права write. Ни в коем случае ни админский логин, ни любой другой с правами full. В настройках учёток тоже можно (нужно) прописать разрешенные ip. В режиме “параноя” создаем отдельную учётку для каждого конкретного удаленного сервера/сервиса, который должен иметь доступ к API роутера, даем только необходимые права read или write, и привязываем каждую такую учётку к определенному ip.  И логируем на внешний сервер все попытки подключения %)
  • аккуратно храним логины/пароли данных учёток – так, чтобы они никуда не “утекли”. Никаких стикеров с паролями на рабочем месте. Пароль – рандомно сгенерённый достаточной длины.

Сделали? Вот теперь можем переходить к следующему разделу.

2. ROS API – готовые библиотеки

Их много, часть из них можно увидеть тут, часть на форуме , есть много и разных на github .

Глаза разбегаются – что же выбрать?

В моем случае список сразу ограничивается следующими требованиями:

  • Python
  • поддержка SSL, в идеале с сертификатами
  • удобоваримое использование

Если глянуть все имеющиеся библиотеки – по сути они в основе все имеют код со страницы.

То есть так или иначе придется изучать язык запросов, описанный тут %) Не проблема, тем паче учитывая богатый опыт программирования (включая Форт – который имеет схожую логику), но я не уверен, что те, кто будет потом после меня поддерживать код – сможет или будет это делать. Да и почему бы сразу не сделать удобоваримо?

Поэтому так или иначе придется дописывать библиотеку – значит ищем ту, которая написана так, чтобы можно было легко:

  1. разобраться в ней;
  2. переписать-расширить.

И тут выбор пал по сути на одну библиотеку – librouteros . Изначально думал, обойдусь малой кровью (форкнул даже), но… мои планы несовместимы даже с этой библиотекой – пришлось практически на 90% переписать ее + сверху добавить свое.

Результат – smartROS .

3. SmartROS

Это практически на 90% написанный самостоятельно код, остальные 10% взяты с librouteros (ну и по сути часть с официальной страницы Микротик). На момент написания статьи – стадия “бета”, хоть код уже используется у меня (и даже работает %)

3.1. Особенности

  • поддерживаются три режима – plain, TLS+ADH, TLS+Certificate. Plain изначально задумывал даже не реализовывать, чтобы даже возможности не было подключиться небезопасно, но потом решил таки оставить (полезен для отладки-диагностики).
  • параметры подключения к роутерам хранятся теперь в отдельном конфиг-файле, по умолчанию в /etc/smartros/routers.json . Зачем – предполагается активное использование из сторонних систем, не хотелось бы “светить” паролями в чужом, порой мало изученном, мире. Полностью проблему скрытия логинов/паролей при взломе сайта не решает, но, по крайней мере, они не на виду. Ломают всё, вопрос только в затраченных ресурсах. Кроме того, упрощает администрирование скриптов. Теперь можно в одном месте прописать/обновить данные не меняя сами скрипты.
  • также вынесены в отдельный файл глобальные настройки – /etc/smartros/main.conf . Обычно их трогать не нужно, но иногда приходится – к примеру, при вызове скриптов smartROS из logstash удобно лог перенаправить в папку logstash (во-первых, логи в одном месте, во-вторых скрипты при вызове из logtsash вызываются от имени logstash – то есть скрипт по умолчанию уже будет иметь права на запись в папку /var/log/logstash ).
  • если почитать, как же при вызове команд RouterOS API указывать условия – окажется, что обратная польская запись не такая уж и прозрачная для понимания вещь ибо придумана она для железа, а не для людей %). Вместо того, чтобы думать, как же простое условие типа “a>=2 and a<c” правильно и без ошибок записать на языке низкоуровневого API , хотелось бы просто так и написать – “a>=2 and a<c”. Что и сделано в данной библиотеке – она переводит условия с “человеческого” на “машинный” язык.
  • реализовал консоль – удобна при отладке запросов.
  • тестирую как под Windows, так и под Ubuntu, Python 3 ( 3.6.x/3.7.x ).

3.2. Установка

Тут просто – написал скрипт установки, который делает почти всё сам:

cd ~
wget https://raw.githubusercontent.com/BlackVS/smartROS/master/install.sh -O - | bash

Библиотека по-умолчанию ставится в /opt/smartros, создаются умолчальные конфиги в /etc/smartros . После установки нужно как минимум прописать логин-пароли для роутера в /etc/smartros/main.conf и можно пробовать подключаться через скрипт-консоль:

cd /opt/smartros/src
./test_console.py

Естественно проделав предварительно всё то, что описано в п.1.

Если увидели приглашение – можете выполнять команды и наблюдать результат. Например, выдать список дефолтных шлюзов:

/ip/route/print where="dst-address=0.0.0.0/0"

Согласитесь, это приятнее писать-читать, чем что типа:

'/ip/route/print' 
'?=dst-address=0.0.0.0/0' 
EOS

Более детально о том, как пользоваться библиотекой – читаем тут.

Если не получилось подключиться или некоторые команды “почему-то” не выполняются – включаем режим debug в /etc/smartros/main.conf и внимательно изучаем лог.

Единственно, что отмечу – для подключения через TLS без сертификатов необходимо, чтобы система, на которой выполняется скрипт, поддерживала ADH-AES128-SHA256 – Микротик на данный момент поддерживаем только это кодирование при подключения без сертификатов. Но не все дистрибутивы Linux (точнее, openssl) с коробки поддерживают этот режим, из-за чего получаем при попытке подсоединиться ошибку:

error: CipherUnsupportedError: [SSL: NO_CIPHERS_AVAILABLE] no ciphers available

Это говорит о том, что сервер и роутер не смогли найти общий язык (кодировку).

Варианты – либо пытаться переустановить openssl (и возможно, пересобрать соответствующую библиотеку ssl для Python) на версию, которая поддерживает данный режим, либо найти дистрибутив Linux (или Python для Windows), который поддерживает его изначально, либо использовать сертификаты для подключения. Какой вариант выбрать – решать вам %)

А дальше начнем шаманить и собирать “сложившуюся в голове” схему, о чем будет написано потом…