Управление файрволлом из браузера или решение нетривиальной задачи

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

Задача

На ряде компьютеров нужно осуществить подключение к сети Интернет, а также подключение к некоторым базам данных, находящихся в другой интра-сети. Причём есть ряд требований.

  1. Доступ не должен быть одновременно и к сети Интернет и к базе данных, т.к. создаются предпосылки для нецелевого использования – доступа удалённых злоумышленников посредством TeamViewer и прочих RAdmin-ов. Такого не надо :)
  2. Доступ к базам осуществляется с использованием средств криптографической защиты ViPNet 3-ей и 4-ой версии (к разным базам – через разные клиенты) посредством той же сети Интернет.

Решение

Придумал вот что.

  1. Завёл две виртуальные машины под ViPNet Client-ы. На каждую – соответствующий клиент и дистрибутив ключей. Первая виртуалка может обращаться на защищённые узлы 1.1.1.1, 2.2.2.2, 3.3.3.3, вторая – на 4.4.4.4, 5.5.5.5 соответственно. (адреса завуалированы, там, соответственно, ещё и порты различные).
  2. На каждую из виртуальных машины поставил Nginx под Windows. В настройках прописал типа такого:
    server {
    listen 80;
    server_name baza1.localdomain;
    location / {
    proxy_pass http://1.1.1.1;
    }
    }

    И так для каждого удалённого узла. Если используются нестандартные порты – всё указывается как есть.
  3. Для одной из машин создаём также сервер с server_name базы, доступной из другой виртуалки и проксируем запросы на вторую. Цель – каскадная передача информации, чтобы с одного веб-сервера были доступны вообще все базы.
  4. Настраиваем межсетевой экран в ViPNet Client таким образом, чтобы разрешались нужные порты для соответствующих узлов. Если что – лезть в “Фильтры открытой сети”. Если что – смотреть журнал IP-пакетов, какие пакеты отбрасываются и на каком фильтре.
    Доступ на первую виртуалку делаем только с IP-адреса нашего шлюза (GW – в п.5), чтобы нельзя было пойти в обход.
  5. Теперь самое интересное – как сделать, чтобы одновременно работал либо Интернет, либо эти самые базы.
    Создаём следующие правила в iptables:
    #адрес первой виртуалки, с которой доступно всё
    virtual1=192.168.1.ZZ
    #адрес шлюза Интернет
    GW=192.168.1.XX
    $iptables -t nat -A PREROUTING -m set --match-set baza src -d $GW -p t cp -m tcp --dport 80 --j DNAT --to-destination $virtual1:80
    $iptables -t nat -A PREROUTING -m set --match-set baza src -d $GW -p t cp -m tcp --dport 5000 --j DNAT --to-destination $virtual1:5000
    $iptables -I FORWARD -d $virtual1 -m set --match-set baza src -j ACCEPT
    $iptables -I FORWARD -s $virtual1 -m set --match-set baza dst -j ACCEPT
    $iptables -I FORWARD -m set --match-set baza dst -i $WAN -j DROP

    #да, у меня одна из баз на 5000-ом порту – приходится мириться.
  6. Создаём список ipset типа hash:ip с именем baza. Таким образом IP-адреса, находящиеся в этом списке могут получать доступ к базам, используя шлюз как ретранслятор, а не находящиеся – могут ходить в Интернет. Осталось только либо помещать IP абонента в список, либо извлекать из него, в зависимости от желания пользователя. Решено было сделать это при помощи связки PHP+AJAX. См. следующий пункт.
  7. Создаём скриптец примерно такого вида:
    <?php
    header('Access-Control-Allow-Origin: *');
    $IP = $_SERVER['REMOTE_ADDR'];
    switch ($_POST['mode']){
    case 'inet':
    exec("/bin/ipset -D baza $IP");
    break;
    case 'base':
    exec("/bin/ipset -A baza $IP");
    break;
    }
    echo json_encode($output);
    ?>

    Да-да, пришлось вынести ipset в /bin и назначить SUID ему… Маленькая хитрость. Но по другому не смог – не запускать же весь веб-сервер с правами рута?.
    Осталось сделать веб-страничку с переключателем (на каком-нибудь красивом UI-фреймворке и влепить передачу параметра ‘mode’ = “inet” или “base” в зависимости от того, что мы хотим получить.
  8. Ну и осталось поднять зону DNS, которая будет обслуживать адреса вида *.localdomain и посылать всех на адрес шлюза.

Теперь всё выглядит так. Клиент открывает браузер – у него прописана домашняя страничка – заглушка с переключателем и краткой инструкцией. Выставляет переключатель в нужное положение в зависимости от того, что ему нужно получить – Интернет или Базы. При этом на скрипт посылается соответствующий параметр. Скрипт добавляет/удаляет IP-адрес клиента в ipset list “baza”. При выборе доступа к базам отображается перечень всех баз с доменными именами (DNS посылает всех на шлюз). И шлюз редиректит все обращения на свой 80 порт дальше, на первую виртуальную машину.

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

P.S. Я ещё реализовал примочку запроса текущего состояния, чтобы при закрытии и открытии браузера ползунок оставался в последнем заданном положении.

P.P.S. Пока не поборол проблему проксирования https.

 

Интересно? Поделись с другом
Litl-Admin.ru

Comments:

Leave a Reply