Русский
Русский
English
Статистика
Реклама

Freeradius

Из песочницы Как мы выбирали VPN-протокол и сервер настраивали

23.08.2020 18:21:00 | Автор: admin

Зачем всё это и для чего?


У нас было: 10 самых простых конфигураций серверов на DigitalOcean, мобильные устройства на базе iOS, сервер для сбора статистики, никакого опыта в настройке VPN-серверов, а также неукротимое желание сделать быстрый, надёжный и простой в использовании VPN-сервис, которым будет приятно пользоваться. Не то, чтобы всё это было категорически необходимо, но если уж начали, то к делу надо подходить серьёзно.


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


Я думаю, что в IT сфере уже не найти человека, который не знал бы, что такое VPN и зачем он нужен.


Но если тезисно объяснять, зачем нужен VPN современному человеку, то получится примерно следующее:


  • Если у вас есть какие-то внутренние (приватные) ресурсы, доступ к которым должен быть ограничен из глобальной сети интернет.
  • Если вам необходимо организовать защищенное соединение между двумя сетями.
  • Если вам нужно получить доступ к ресурсам, которые по тем или иным причинам недоступны из вашей страны (меняется ваше местоположение относительно вашего IP-адреса).

И не совсем очевидный момент: скорость интернет-соединения может быть выше через vpn, т.к. ваш провайдер может отправить ваш трафик по более короткому маршруту, а значит более оптимальному маршруту, из-за этого вы и можете получить прирост в скорости. Но это может сработать и в обратную сторону, если вы выберете не очень удачное расположение сервера относительно вас (об этом немного позже).


Как мы выбирали VPN-протокол


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


Мы выбрали самые известные реализации протоколов и отсеяли не подходящие по условиям исходной задачи.


А условия всего два, я напомню:


  • Стабильное и надёжное подключение.
  • Без установки стороннего программного обеспечения на устройство клиента.

Пробегусь по протоколам и кратко расскажу о них + расскажу причины, почему тот или иной протокол нам не подошёл.


PPTP (Point-To-Point Tunneling Protocol)


Один из самых старейших VPN протоколов, разработанный компанией Microsoft. Из-за солидного возраста протокол поддерживается большинством операционных систем, но в то же время не может обеспечить стабильное и надёжное соединение. Компания Microsoft советует использовать L2TP или SSTP на замену PPTP.


Этот протокол прост в настройке и не требователен к ресурсам сервера, но проблемы с безопасностью заставляют отказаться от его использования в наших целях.


L2TP/IPSec


Протокол во многом схож с PPTP, разрабатывался и принимался практически одновременном с ним. Этот протокол более требователен к вычислительным мощностям, часто используется интернет-провайдерами, т.к. считается более эффективным для построения виртуальных сетей.
L2TP/IPsec позволяет обеспечить высокую безопасность данных, поддерживается всеми современными операционными системами. Есть одно но: он инкапсулирует передаваемые данные дважды, что делает его менее эффективным и более медленным, чем другие VPN-протоколы.


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


IKEv2/IPSec


Был разработан Microsoft совместно с Cisco, существуют реализации протокола с открытым исходным кодом (например, OpenIKEv2, Openswan и strongSwan).


Поддерживает Mobility and Multi-homing Protocol (MOBIKE), что обеспечивает устойчивость к смене сетей.


IKEv2 очень хорошо подходит для использования на мобильных устройствах, которые чаще всего склонны к переключению между WiFI и мобильным интернетом.


IKEv2 имеет нативную поддержку в большинстве операционных систем.


Вот этот вариант нам уже больше подходит, т.к. поддержка Mobility and Multi-homing Protocol будет очень большим плюсом при использовании на мобильных устройствах.


OpenVPN


Разработан компанией OpenVPN Technologies.


Протокол с открытым исходным кодом, который прошёл все возможные проверки безопасности.
Протокол OpenVPN стабилен и может обеспечить хорошую скорость передачи данных. Ещё одно преимущество протокола в том, что он использует для работы стандартные протоколы TCP и UPD, а также может работать на любом из портов. Это усложняет блокировку VPN сервиса провайдерами.


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


Этот вариант нам бы тоже подошёл, но, к сожалению, из-за необходимости установки клиента, придётся отказаться от этого протокола.


Wireguard


На данный момент это самый свежий протокол VPN. Его часто сравнивают с IPSec и OpenVPN, и называют его их заменой, но он всё ещё слишком сырой, чтобы использовать его в больших масштабах.


Лучшие результаты этот протокол показывает на Unix системах, т.к. он реализован в виде модуля ядра Unix. Но эта высокая пропускная способность достигается за счёт замедления сетевой активности других приложений.


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


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


В итоге мы решили остановится на IKEv2/IPSeс, по следующим причинам:


  • Поддержка Mobility and Multi-homing Protocol (MOBIKE).
  • Нативная поддержка в большинстве операционных систем.
  • Обеспечивает высокую скорость соединения.
  • Не требователен к ресурсам сервера.

Перейдём от теории к практике.


Настраиваем VPN-сервер


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


Самый простой критерий выбора расположения сервера это удалённость от вас, т.е. если будет выбор между размещением сервера в Германии или в США, то своё предпочтение следует отдать Германии (если вы находитель в России), т.к., в теории, ваш трафик будет проходить через меньшее кол-во магистралей и будет идти по более короткому маршруту.


Для личного использования или небольшого кол-ва пользователей подойдёт самый простой вариант сервера, к примеру на digitalocean можно взять самую базовую конфигурацию сервера с одним ядром, 1 Gb оперативной памяти и 25 Gb дискового пространства.


От слов к практике, каких-то особых навыков и тайных знаний для настройки VPN-сервера не понадобится.


Для установки и настройки сервера будем использовать следующие инструменты:


  • Docker + docker-compose.
  • strongswan реализацию IPSec сервера.
  • Let's Encrypt для генерации сертификатов.
  • Radius для мониторинга и отправки статистических данных.

Начнём с Docker контейнера, в котором и будет запускаться vpn-сервер.


Docker.file (полная версия)


FROM alpine:latest #сервер будем собирать на основе образа alpine-linux...# strongSwan VersionARG SS_VERSION="http://personeltest.ru/aways/download.strongswan.org/strongswan-5.8.2.tar.gz" #версию можете выбрать сами, исходя из того когда вы читаете данную статью....COPY ./run.sh /run.shCOPY ./adduser.sh /adduser.shCOPY ./rmuser.sh /rmuser.shRUN chmod 755 /run.sh /adduser.sh /rmuser.shVOLUME ["/usr/local/etc/ipsec.secrets"]EXPOSE 500:500/udp 4500:4500/udpCMD ["/run.sh"]

Для управления пользователями мы создаём два скрипта adduser.sh, rmuser.sh для добавления и удаления пользователя соответственно.


adduser.sh


#!/bin/shVPN_USER="$1"if [ -z "$VPN_USER" ]; then  echo "Usage: $0 username" >&2  echo "Example: $0 jordi" >&2  exit 1ficase "$VPN_USER" in  *[\\\"\']*)    echo "VPN credentials must not contain any of these characters: \\ \" '" >&2    exit 1    ;;esacVPN_PASSWORD="$(openssl rand -base64 9)" #генерируем пароль для пользователяHOST="$(printenv VPNHOST)"echo "Password for user is: $VPN_PASSWORD"echo $VPN_USER : EAP \"$VPN_PASSWORD\">> /usr/local/etc/ipsec.secrets # сохраняем имя пользователя и пароль в файл /usr/local/etc/ipsec.secretsipsec rereadsecrets

rmuser.sh


#!/bin/shVPN_USER="$1"if [ -z "$VPN_USER" ]; then  echo "Usage: $0 username" >&2  echo "Example: $0 jordi" >&2  exit 1ficp /usr/local/etc/ipsec.secrets /usr/local/etc/ipsec.secrets.baksed "/$VPN_USER :/d" /usr/local/etc/ipsec.secrets.bak > /usr/local/etc/ipsec.secrets # удаляем строку и с пользователем из файла /usr/local/etc/ipsec.secretsipsec rereadsecrets

На сервере все пользователи будут храниться в файле ipsec.secrets.


Для запуска нашего сервера подготовим следующий скрипт:


run.sh полная версия


#!/bin/bashVPNIPPOOL="10.15.1.0/24" # указываем из какого диапазона будут выдаваться IP нашим клиентам, которые будут подключаться к VPN-серверу.LEFT_ID=${VPNHOST}       # домен нашего vpn-сервераsysctl net.ipv4.ip_forward=1sysctl net.ipv6.conf.all.forwarding=1sysctl net.ipv6.conf.eth0.proxy_ndp=1if [ ! -z "$DNS_SERVERS" ] ; then # можем указать свои DNS сервера, которые будут использоваться в vpn сервере.DNS=$DNS_SERVERSelseDNS="1.1.1.1,8.8.8.8"fiif [ ! -z "$SPEED_LIMIT" ] ; then # для того, чтобы один пользователь не "съел" весь канал, можем ограничить скорость пользователя до указанной величины.tc qdisc add dev eth0 handle 1: ingresstc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip src 0.0.0.0/0 police rate ${SPEED_LIMIT}mbit burst 10k drop flowid :1tc qdisc add dev eth0 root tbf rate ${SPEED_LIMIT}mbit latency 25ms burst 10kfiiptables -t nat -A POSTROUTING -s ${VPNIPPOOL} -o eth0 -m policy --dir out --pol ipsec -j ACCEPTiptables -t nat -A POSTROUTING -s ${VPNIPPOOL} -o eth0 -j MASQUERADEiptables -L# Здесь мы генерируем сертификат сервераif [[ ! -f "/usr/local/etc/ipsec.d/certs/fullchain.pem" && ! -f "/usr/local/etc/ipsec.d/private/privkey.pem" ]] ; then    certbot certonly --standalone --preferred-challenges http --agree-tos --no-eff-email --email ${LEEMAIL} -d ${VPNHOST}    cp /etc/letsencrypt/live/${VPNHOST}/fullchain.pem /usr/local/etc/ipsec.d/certs    cp /etc/letsencrypt/live/${VPNHOST}/privkey.pem /usr/local/etc/ipsec.d/private    cp /etc/letsencrypt/live/${VPNHOST}/chain.pem /usr/local/etc/ipsec.d/cacertsfirm -f /var/run/starter.charon.pid# Настройка непосредственно ipsec сервераif [ -f "/usr/local/etc/ipsec.conf" ]; thenrm /usr/local/etc/ipsec.confcat >> /usr/local/etc/ipsec.conf <<EOFconfig setup    charondebug="ike 1, knl 1, cfg 1"    uniqueids=never    conn ikev2-vpn    ...    eap_identity=%identityEOFfiif [ ! -f "/usr/local/etc/ipsec.secrets" ]; thencat > /usr/local/etc/ipsec.secrets <<EOF: RSA privkey.pemEOFfi.....EOFfisysctl -pipsec start --nofork

Чтобы было проще запустить весь сервер одной командой, завернём всё в docker-compose:


version: '3'services:  vpn:    build: .    container_name: ikev2-vpn-server    privileged: true    volumes:      - './data/certs/certs:/usr/local/etc/ipsec.d/certs'      - './data/certs/private:/usr/local/etc/ipsec.d/private'      - './data/certs/cacerts:/usr/local/etc/ipsec.d/cacerts'      - './data/etc/ipsec.d/ipsec.secrets:/usr/local/etc/ipsec.secrets'    env_file:      - .env    ports:      - '500:500/udp'      - '4500:4500/udp'      - '80:80'    depends_on:      - radius    links:      - radius    networks:      - backend  radius:    image: 'freeradius/freeradius-server:latest'    container_name: freeradius-server    volumes:      - './freeradius/clients.conf:/etc/raddb/clients.conf'      - './freeradius/mods-enabled/rest:/etc/raddb/mods-enabled/rest'      - './freeradius/sites-enabled/default:/etc/raddb/sites-enabled/default'    env_file:      - .env    command: radiusd -X    networks:      - backendnetworks:  backend:    ipam:      config:        - subnet: 10.0.0.0/24

Здесь мы сохраняем в volume ключи сертификата, чтобы при каждом перезапуске сервера не генерировать их снова.


Пробрасываем порты, необходимые для подключения к серверу, а также для генерации сертификатов через Let's Encrypt.


Перед запуском и сборкой контейнеров необходимо создать и заполнить .env файл, в который помещаем следующее:


VPNHOST=vpn.vpn.com # домен нашего vpn-сервераLEEMAIL=admin@admin.com # адрес почты, который будет использован для генерации сертификатов Let's EncryptSPEED_LIMIT=20 # если нужно, то указываем как лимит скорости в mbitDNS_SERVERS= # если нужно то указываем собственные DNS сервераRADIUS_SERVER= # адрес radius сервера, в нашем случае это будет radiusRADIUS_SERVER_SECRET= # секретный ключ, с помощью которого проходит авторизация на radius сервереREMOTE_SERVER= # в эту переменную вынесли endpoint, на который отправлялась статистика из radius сервера, об этом расскажу далее.

Выполняя команду docker-compose up -d, мы запускаем наш vpn-сервер, а также radius сервер (если он вам нужен).


Вот так выглядит весь проект в сборке


Сбор статистики с VPN-сервера


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


Испробовав разные варианты, решили остановиться и разобраться, как настроить FreeRadius сервер, который как раз и будет получать данные от ipsec и отправлять данные со статистикой нам.


FreeRadius сервер можно использовать и для авторизации пользователей, но мы остановились только на сборе статистики.
Для включения radius необходимо добавить следующее в конфигурацию ipsec:


FreeRADIUS сервер для мониторинга подключений к серверу и сбора статистики


if [[ ! -z "$RADIUS_SERVER" && ! -z "$RADIUS_SERVER_SECRET" ]]; thenrm /usr/local/etc/strongswan.d/charon/eap-radius.confcat >> /usr/local/etc/strongswan.d/charon/eap-radius.conf <<EOFeap-radius {    accounting = yes # включаем аккаунтинг, ipsec будет отправлять данные о том что пользователь подключился/отключился, а также отправлять данные о объёме используемого трафика    accounting_close_on_timeout = no    accounting_interval = 300 # интервал через который radius сервер будет отправлять данные нам.    close_all_on_timeout = no    load = yes    nas_identifier = $VPNHOST    # Section to specify multiple RADIUS servers.    servers {        primary {            address = $RADIUS_SERVER            secret = $RADIUS_SERVER_SECRET            auth_port = 1812   # default            acct_port = 1813   # default        }    }}

Чтобы наши данные уходили на наш endpoint, включаем модуль rest. Для этого в файле /etc/raddb/mods-enabled/rest настраиваем блок accounting, получится что-то вроде:


accounting {    uri = "${..connect_uri}/vpn_sessions/%{Acct-Session-Id}-%{Acct-Unique-Session-ID}"method = 'post'tls = ${..tls}body = jsondata = '{ "username": "%{User-Name}", "nas_port": "%{NAS-Port}", "nas_ip_address": "%{NAS-IP-Address}", "framed_ip_address": "%{Framed-IP-Address}", "framed_ipv6_prefix": "%{Framed-IPv6-Prefix}", "nas_identifier": "%{NAS-Identifier}", "airespace_wlan_id": "%{Airespace-Wlan-Id}", "acct_session_id": "%{Acct-Session-Id}", "nas_port_type": "%{NAS-Port-Type}", "cisco_avpair": "%{Cisco-AVPair}", "acct_authentic": "%{Acct-Authentic}", "tunnel_type": "%{Tunnel-Type}", "tunnel_medium_type": "%{Tunnel-Medium-Type}", "tunnel_private_group_id": "%{Tunnel-Private-Group-Id}", "event_timestamp": "%{Event-Timestamp}", "acct_status_type": "%{Acct-Status-Type}", "acct_input_octets": "%{Acct-Input-Octets}", "acct_input_gigawords": "%{Acct-Input-Gigawords}", "acct_output_octets": "%{Acct-Output-Octets}", "acct_output_gigawords": "%{Acct-Output-Gigawords}", "acct_input_packets": "%{Acct-Input-Packets}", "acct_output_packets": "%{Acct-Output-Packets}", "acct_terminate_cause": "%{Acct-Terminate-Cause}", "acct_session_time": "%{Acct-Session-Time}", "acct_delay_time": "%{Acct-Delay-Time}", "calling_station_id": "%{Calling-Station-Id}", "called_station_id": "%{Called-Station-Id}"}' }

Здесь мы можем как угодно комбинировать данные и отправлять на наш сервер.


При настройке VPN сервера столкнулись с некоторыми нюансами, вроде таких, что устройства Apple не могут подключить к серверу, если на нём будет самоподписанный сертификат, всё заработало только после того, как сертификат начали генерировать через Let's Encrypt.


Какие недостатки присутствуют в нашей сборке?


  • Если radius сервер не отвечает, то пользователь не сможет подключиться к VPN.
  • Если закончится срок действия сертификата, пользователь не сможет авторизоваться на VPN-сервере.

Что можно было бы добавить в следующих версиях VPN-сервера?


  • Авторизацию пользователей вынести в radius.
  • Добавить автоматическое обновление сертификата.
  • Провести рефакторинг скриптов, а также файлов конфигураций.
  • Добавить health-check для впн сервера.

Что же у нас получилось в итоге?


Методом проб и ошибок мы пришли к варианту, который описан в статье, прежде всего мы придерживались принципа "делай проще", не стали изобретать свои велосипеды и воспользовались уже готовыми инструментами типа Docker, FreeRadius. Да, скорее всего тут есть место для оптимизации, ужесточения политик безопасности, автоматизации. Но наш вариант отлично подойдёт для личного использования и для использования в небольших компаниях, если вам нужно организовать доступ к приватной (закрытой) информации.

Подробнее..

Freeradius Google Autheticator LDAP Fortigate

05.09.2020 02:04:29 | Автор: admin
Как быть, если двухфакторной аутентификации и хочется, и колется, а денег на аппаратные токены нет и вообще предлагают держаться и хорошего настроения.
Данное решение не является чем-то супероригинальным, скорее микс из разных решений, найденных на просторах интернета.

Итак, дано:


Домен Active Directory.
Пользователи домена, работающие через VPN, как многие нынче.
В роли шлюза VPN выступает Fortigate.
Сохранение пароля для VPN-клиента запрещено политикой безопасности.
Политику Fortinet в отношении собственных токенов менее чем жлобской не назовешь бесплатных токенов аж 10 единиц, остальные по очень некошерной цене. RSASecureID, Duo и им подобные не рассматривал, поскольку хочется опенсорса.

Предварительные требования: хост *nix с установленным freeradius, sssd введен в домен, доменные пользователи могут спокойно на нем аутентифицироваться.
Дополнительные пакеты: shellinabox, figlet, freeeradius-ldap, шрифт rebel.tlf с репозитория https://github.com/xero/figlet-fonts.

В моем примере CentOS 7.8.
Логика работы предполагается такая: при подключении к VPN пользователь должен ввести доменный логин и OTP вместо пароля.

Настройка сервисов:


В /etc/raddb/radiusd.conf меняется только пользователь и группа, от имени которых стартует freeradius, так как сервис radiusd должен уметь читать файлы во всех поддиректориях /home/.

user = rootgroup = root

Чтобы можно было использовать группы в настройках Fortigate, нужно передавать Vendor Specific Attribute. Для этого в директории raddb/policy.d создаю файл со следующим содержимым:

group_authorization {    if (&LDAP-Group[*] == "CN=vpn_admins,OU=vpn-groups,DC=domain,DC=local") {            update reply {                &Fortinet-Group-Name = "vpn_admins" }            update control {                &Auth-Type := PAM                &Reply-Message := "Welcome Admin"                }        }    else {        update reply {        &Reply-Message := "Not authorized for vpn"            }        reject        }}

После установки freeradius-ldap в директории raddb/mods-available создается файл ldap.
Нужно создать символьную ссылку в каталог raddb/mods-enabled.

ln -s /etc/raddb/mods-available/ldap /etc/raddb/mods-enabled/ldap

Привожу его содержимое к такому виду:

ldap {        server = 'domain.local'        identity = 'CN=freerad_user,OU=users,DC=domain,DC=local'        password = "SupeSecretP@ssword"        base_dn = 'dc=domain,dc=local'        sasl {        }        user {                base_dn = "${..base_dn}"                filter = "(sAMAccountname=%{%{Stripped-User-Name}:-%{User-Name}})"                sasl {                }                scope = 'sub'        }        group {                base_dn = "${..base_dn}"                filter = '(objectClass=Group)'                scope = 'sub'                name_attribute = cn                membership_filter = "(|(member=%{control:Ldap-UserDn})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"                membership_attribute = 'memberOf'        }}

В файлах raddb/sites-enabled/default и raddb/sites-enabled/inner-tunnel в секции authorize дописываю имя политики, которая будет использоваться group_authorization. Важный момент имя политики определяется не названием файла в директории policy.d, а директивой внутри файла перед фигурными скобками.
В секции authenticate в этих же файлах нужно раскомментировать строку pam.
В файле clients.conf прописываем параметры, с которыми будет подключаться Fortigate:

client fortigate {    ipaddr = 192.168.1.200    secret = testing123    require_message_authenticator = no    nas_type = other}

Конфигурация модуля pam.d/radiusd:

#%PAM-1.0auth       sufficient   pam_google_authenticator.soauth       include      password-authaccount    required     pam_nologin.soaccount    include      password-authpassword   include      password-authsession    include      password-auth

Дефолтные варианты внедрения связки freeradius с google authenticator предполагают ввод пользователем учетных данных в формате: username/password+OTP.

Представив количество проклятий, которое посыпется на голову, в случае использования дефолтной связки freeradius с Google Authenticator, было принято решение использовать конфигурацию модуля pam так, чтобы проверять только лишь токен Google Authenticator.
При подключении пользователя происходит следующее:

  • Freeradius проверяет наличие пользователя в домене и в определенной группе и, в случае успеха, производится проверка OTP токена.

Все выглядело достаточно удачно до момента, пока я не задумался А как же произвести регистрацию OTP для 300+ пользователей?
Пользователь должен залогиниться на сервер с freeradius и из-под своей учетной записи и запустить приложение Google authenticator, которое и сгенерирует для пользователя QR-код для приложения. Вот тут на помощь и приходит shellinabox в комбинации с .bash_profile.

[root@freeradius ~]# yum install -y shellinabox

Конфигурационный файл демона находится в /etc/sysconfig/shellinabox.
Указываю там порт 443 и можно указать свой сертификат.

[root@freeradius ~]#systemctl enable --now shellinaboxd

Пользователю остается лишь зайти по ссылке, ввести доменные креды и получить QR-код для приложения.

Алгоритм следующий:
  • Пользователь логинится на машину через браузер.
  • Проверяется доменный ли пользователь. Если нет, то никаких действий не предпринимается.
  • Если пользователь доменный, проверяется принадлежность к группе администраторов.
  • Если не админ, проверяется настроен ли Google Autheticator. Если нет, то генерируется QR-код и logout пользователя.
  • Если не админ и Google Authenticator настроен, то просто logout.
  • Если админ, то опять проверка Google Authenticator. Если не настроен, то генерируется QR-код.

Вся логика выполняется с использованием /etc/skel/.bash_profile.

cat /etc/skel/.bash_profile
# .bash_profile# Get the aliases and functionsif [ -f ~/.bashrc ]; then        . ~/.bashrcfi# User specific environment and startup programs# Make several commands available from user shellif [[ -z $(id $USER | grep "admins") || -z $(cat /etc/passwd | grep $USER) ]]  then    [[ ! -d $HOME/bin ]] && mkdir $HOME/bin    [[ ! -f $HOME/bin/id ]] && ln -s /usr/bin/id $HOME/bin/id    [[ ! -f $HOME/bin/google-auth ]] && ln -s /usr/bin/google-authenticator $HOME/bin/google-auth    [[ ! -f $HOME/bin/grep ]] && ln -s /usr/bin/grep $HOME/bin/grep    [[ ! -f $HOME/bin/figlet ]] && ln -s /usr/bin/figlet $HOME/bin/figlet    [[ ! -f $HOME/bin/rebel.tlf ]] && ln -s /usr/share/figlet/rebel.tlf $HOME/bin/rebel.tlf    [[ ! -f $HOME/bin/sleep ]] && ln -s /usr/bin/sleep $HOME/bin/sleep  # Set PATH env to <home user directory>/bin    PATH=$HOME/bin    export PATH  else    PATH=PATH=$PATH:$HOME/.local/bin:$HOME/bin    export PATHfiif [[ -n $(id $USER | grep "domain users") ]]  then    if [[ ! -e $HOME/.google_authenticator ]]      then        if [[ -n $(id $USER | grep "admins") ]]          then            figlet -t -f $HOME/bin/rebel.tlf "Welcome to Company GAuth setup portal"            sleep 1.5            echo "Please, run any of these software on your device, where you would like to setup OTP:Google Autheticator:AppStore - https://apps.apple.com/us/app/google-authenticator/id388497605Play Market - https://play.google.com/stor/apps/details?id=com.google.android.apps.authenticator2&hl=enFreeOTP:AppStore - https://apps.apple.com/us/app/freeotp-authenticator/id872559395Play Market - https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp&hl=enAnd prepare to scan QR code."            sleep 5            google-auth -f -t -w 3 -r 3 -R 30 -d -e 1            echo "Congratulations, now you can use an OTP token from application as a password connecting to VPN."          else            figlet -t -f $HOME/bin/rebel.tlf "Welcome to Company GAuth setup portal"            sleep 1.5            echo "Please, run any of these software on your device, where you would like to setup OTP:Google Autheticator:AppStore - https://apps.apple.com/us/app/google-authenticator/id388497605Play Market - https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=enFreeOTP:AppStore - https://apps.apple.com/us/app/freeotp-authenticator/id872559395Play Market - https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp&hl=enAnd prepare to scan QR code."            sleep 5            google-auth -f -t -w 3 -r 3 -R 30 -d -e 1            echo "Congratulations, now you can use an OTP token from application as a password to VPN."            logout        fi      else        echo "You have already setup a Google Authenticator"        if [[ -z $(id $USER | grep "admins") ]]          then          logout        fi    fi  else    echo "You don't need to set up a Google Authenticator"fi


Настройка Fortigate:


  • Создаем Radius-сервер

  • Создаем необходимые группы, в случае необходимости разграничения доступа по группам. Имя группы на Fortigate должно соответствовать группе, которая передается в Vendor Specific Attribute Fortinet-Group-Name.

  • Редактируем необходимые SSL-порталы.

  • Добавляем группы в политики.



Плюсы данного решения:
  • Есть возможность аутентификации по OTP на Fortigate опенсорс решением.
  • Исключается ввод доменного пароля пользователем при подключении по VPN, что несколько упрощает процесс подключения. 6-цифровой пароль ввести проще, чем тот, который предусмотрен политикой безопасности. Как следствие, уменьшается количество тикетов с темой: Не могу подключиться к VPN.


P.S. В планах докрутить это решение до полноценной 2-хфакторной авторизации с challenge-response.
Подробнее..

AD Freeradius Google Autheticator. Установка с нуля для Cisco Anyconnect и не только

24.02.2021 20:16:16 | Автор: admin
Итак, у нас встала задача включить двухфакторную аутентификацию для Cisco AnyconnectVPN и некоторых других пакетов. Общими у всех задач есть одно они умеют аутентифицироваться в Radius.
Есть масса платных решений (например Cisco DUO ), но платное не значит лучше и зачем платить больше?

Да, критики скажут это очередная статья как натянуть сову на глобус или как подружить FreeRadius, MS Acitve Directory и Google Authenticator. Но есть нюансы, которые я хочу показать.

Во-первых. Мне нужно несколько типов аутентификации. Я это реализую нестандартными настройками FreeRadius и получу на трех разных портах одного сервера три типа аутентификации:
  1. ADlogin, ADPasswordGoogleAuth (логин из AD, паролем выступает склееная фраза из пароля в AD и цифр от GoogleAuth )
  2. ADlogin, ADPassword (стандартный вариант логина и пароля от AD, по сути чисто технический вариант, но нужен для Anyconnect)
  3. ADLogin, GoogleAuth ( логин из AD, пароль цифры GoogleAuth. Так сказать GoogleAuthenticator в чистом виде)

Во-вторых. Используя модуль shellinabox предоставляем возможность клиенту создать себе GoogleAuth токен самостоятельно, при этом не понижая уровня безопасности системы. Возможно не самое красивое решение но 100% работающее.

И в-третьих. Мне так и не удалось победить проблему: когда истекает время жизни пароля в AD, FreeRadius перестает считать его валидным и пробрасывает дальше ошибку. Т.е перестает предлагать сменить пароль в такой ситуации. Решение shellinabox позволяет решить эту проблему, предлагая пользователю в такой ситуации зайти на URL shellinabox.

Все проверено на Centos7 но без особых изменений зайдет на любом RedHat дистрибутиве и с непринципиальными модификациями на Ubuntu и FreeBSD. Другие дистрибуты не проверял, но общий смысл обязан сохранится.

1) Включаем NTP если не включено. Можно заменить любой аналогичной службой, важно чтоб время было синхронизировано корректно.

a) Установка
#yum install ntp


b) Включение на старте и сразу запуск
#systemctl enable now ntpd


c) Проверка
#ntpq p


2) Включаем Linux в AD. Я предпочитаю SSSD.

a) Установка
#yum install y sssd realmd oddjob oddjob-mkhomedir adcli samba-common samba-common-tools krb5-workstation openldap-clients policycoreutils-python

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

b) собственно ввод в домен
#realm join pbu.icb --user=имя-пользователя-домена


c) проверка
#realm list


Должно вывести нечто подобное:
my.domen
type: kerberos
realm-name: MY.DOMEN
domain-name: my.domen
configured: kerberos-member
server-software: active-directory
client-software: sssd
required-package: oddjob
required-package: oddjob-mkhomedir
required-package: sssd
required-package: adcli
required-package: samba-common-tools
login-formats: %U
login-policy: allow-permitted-logins
permitted-logins:


d) редактируем /etc/sssd/sssd.conf для ограничения по AD группам, которым можно ходить на эту машину. Читай аутентифицироваться в AD с этой машины.
use_fully_qualified_names = False
simple_allow_groups = GroupLinuxAdmins@my.domen, GroupUseVPN@my.domen
ad_gpo_ignore_unreadable = True


первая группа GroupLinuxAdmins@my.domen, члены которой могут администрировать систему, вторая GroupUseVPN@my.domen это те кто потом будет ходить в VPN.

e) Запускаем sssd
#chown root.root /etc/sssd/sssd.conf&&chmod 600 /etc/sssd/sssd.conf#systemctl restart sssd

Убеждаемся что sssd работает корректно:
#id  имя-пользователя-домена

Должно вывести список групп AD в которые входит пользователь домена имя-пользователя-домена

f) Разрешаем админам sudo
#echo "%GroupLinuxAdmins@my.domen ALL=(ALL) ALL" > /etc/sudoers.d/sudoadmin#chown root.root /etc/sudoers.d/sudoadmin&&chmod 600 /etc/sudoers.d/sudoadmin


g) Выключаем root для ssh, разрешаем ssh только членам группы GroupLinuxAdmins@my.domen.
Редактируем /etc/ssh/sshd_config, изменив или добавив строки ниже. ВАЖНО! Тут и дальше имена групп нужно использовать только в нижнем регистре.

PermitRootLogin no
AllowGroups grouplinuxadmins


И перезапускаем sshd
#systemctl restart sshd


3) Установка FreeRadius
a) Собственно установка
#yum -y install freeradius freeradius-utils#ln -s /etc/raddb/mods-available/pam /etc/raddb/mods-enabled/pam


b) Редактируем /etc/raddb/sites-enabled/default:
Находим в разделе authenticate строку вида
# pam

и убираем комментарий в начале строки ( символ # )

с) Собственно базовый радиус установлен. Только для localhost но уже можем проверять.
Парольное слово в Radius для localhost по-умолчанию: testing123

# radtest userVPN password_for_userVPN localhost 0 testing123


Правильный ответ будет если в конце ответа
Received Access-Accept


При неправильном пароле (тоже стоит обязательно проверить ):
В конце ответа будет
Received Access-Reject
и дальше
(0) -: Expected Access-Accept got Access-Reject


d) Дабавляем систему, которой можно обращаться к Radius, т.е устройство, которой будет организовывать Cisco AnyconnectVPN. У меня это Cisco Firepower. Пусть у него будет IP 10.10.10.5.
Добавляем в файл /etc/raddb/clients.conf

client ftd {
ipaddr = 10.10.10.5
secret = secretFTD
}


И включаем радиус со стартом
#systemctl enable --now radiusd


e) Редактируем /etc/raddb/radiusd.conf. данная настройка нужна для того, чтобы Google Authenticator мог проверить файл $HOME/.google_authenticator для всех пользователей.
находим
user = radiusd
group = radiusd

и меняем на
user = root
group = root


f) Собственно базовый Radius установлен. Если при установке FreeRadius что-то идет не так, очень полезная возможность консольной работы с FreeRadius. Для этого стопаем службу и запускаем Radius в консольном режиме с debug
#systemctl stop radius#radiusd -Xx


4) Ставим Google Autenticator
a) К сожелению я не знаю как подружить Google Authenticator и selinux. Поэтому отключаем.
Файл /etc/selinux/config меняем:
SELINUX=enforcing

на
SELINUX=permissive

После чего
#setenforce 0

а лучше вообще перезагрузить машину

b)
#yum install y epel-release#yum install y google-authenticator


5) Модифицируем FreeRadius для 3 типов аутентификации
a) Редактируем /etc/raddb/mods-enabled/pam, добавляя строки
pam radius11812{
pam_auth = radiusd_ad
}

pam radius21812{
pam_auth = radiusd_ga
}


b) В папке /etc/pam.d копируем pam настройки для разных типов аутентификации
Для просто в AD берем системную
#ln s /etc/pam.d/password-auth-ac /etc/pam.d/radiusd_ad

Для просто GoogleAuth пишем самостоятельно в /etc/pam.d/radiusd_ga

#%PAM-1.0
#
auth required pam_google_authenticator.so nullok
auth required pam_permit.so
account required pam_nologin.so
account include password-auth
password include password-auth
session include password-auth


!!! очень важный момент. При такой конфигурации если отсутствует привязка пользователя в профиле к GoogleAuth то такой пользователь считается валидным. Если нужно без ввода цифр GoogleAuth не пускать вообще, не зависимо от привязки, то нужно в первой строке убрать nullok а вторую строку убрать вообще.

c) Копируем /etc/raddb/sites-enabled/default для двух дополнительных портов
# cp /etc/raddb/sites-enabled/default /etc/raddb/sites-enabled/radius11812# cp /etc/raddb/sites-enabled/default /etc/raddb/sites-enabled/radius21812


d) Редактируем /etc/raddb/sites-enabled/radius11812
Находим в разделе authenticate строку вида
pam

и заменяем на
Auth-Type pam {
radius11812
}


e) Аналогично /etc/raddb/sites-enabled/radius21812
Находим в разделе authenticate строку вида
pam

и заменяем на
Auth-Type pam {
Radius21812
}


6) Устанавливаем shellinabox
a)
#yum install y shellinabox#yum enable now shellinabox


b) В принципе этого достаточно. Но некоторые любят красоту ;). Тогда дополнительно ставим еще figlet, и шрифт rebel.tlf ( взять с репозитория https://github.com/xero/figlet-fonts и положить в /usr/share/figlet ).

c) Добавляем вызов логики генерации GoogleAuth токена для всех пользователей
#echo . /usr/local/etc/radius_user_profiles.sh >> /etc/skel/.bash_profile


d) Создаем /usr/local/etc/radius_user_profiles.sh ( это вариант с украшательствами )
#!/bin/bash# Set groups for vpn, etc. ##   !!! Names of groups without caps letters !!!#VPNissuer="MyCompany"GROUP_VPN="groupusevpn"# Get the aliases and functionsif [ -f ~/.bashrc ]; then        . ~/.bashrcfi# User specific environment and startup programs# Make several commands available from user shell# for group VPN that use 2FA Google authenticatorif [[ -n $(id $USER | grep $GROUP_VPN) ]]  then     clear    [[ ! -d $HOME/bin ]] && mkdir $HOME/bin    [[ ! -f $HOME/bin/id ]] && ln -s /usr/bin/id $HOME/bin/id    [[ ! -f $HOME/bin/google-auth ]] && ln -s /usr/bin/google-authenticator $HOME/bin/google-auth    [[ ! -f $HOME/bin/grep ]] && ln -s /usr/bin/grep $HOME/bin/grep    [[ ! -f $HOME/bin/figlet ]] && ln -s /usr/bin/figlet $HOME/bin/figlet    [[ ! -f $HOME/bin/rebel.tlf ]] && ln -s /usr/share/figlet/rebel.tlf $HOME/bin/rebel.tlf    [[ ! -f $HOME/bin/sleep ]] && ln -s /usr/bin/sleep $HOME/bin/sleep  # Set PATH env to <home user directory>/bin    PATH=$HOME/bin    export PATH    if [[ ! -e $HOME/.google_authenticator ]]      then        figlet -t -c -f $HOME/bin/rebel.tlf "Welcome to $VPNissuer GAuth setup portal"        sleep 1.5        echo "Please, run Google Autheticator to setup OTP and prepare to scan QR code.If you don't have, please download that from market:AppStore    - https://apps.apple.com/us/app/google-authenticator/id388497605Play Market - https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en"        sleep 1.5        google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER"        echo "Congratulations, now you can use an OTP token from application as a password to VPN."        logout    else        echo "You have already setup a Google Authenticator        "        logout    fifi

e) Устнавливаем разрешения на выполнение всем.
#chmod 755  /usr/local/etc/radius_user_profiles.sh


f) Можно файлы типа .google_authenticator вынести в отдельный каталог ( по-умолчанию это файлы $HOME/.google_authenticator). Увеличивает ли это безопасность системы? Нет, а удобство дело привычки. Для этого надо сделать несколько шагов:
  • в скрипте /usr/local/etc/radius_user_profiles.sh заменить строки
    if [[! -e $HOME/.google_authenticator ]]
    google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER"

    на
    if [[! -e /path_secrets/${USER} ]]
    google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER" --secret=/path_secrets/$USER
  • и в модулях PAM /etc/pam.d/radiusd и /etc/pam.d/radiusd_ga
    везде после pam_google_authenticator.so добавить параметр secret=/path_secrets/${USER}
    auth required pam_google_authenticator.so secret=/path_secrets/${USER} nullok
  • создать каталог
    #mkdir /path_secrets#chmod 777 /path_secrets
    

7) Теперь самое интересное. Shellinabox это по-сути графическая web оболочка для шелла. Для того чтоб не нарушить безопасность системы делаем отдельный sshd c ограничением по группе AD на нестандартном порту и направляем shelinabox на этот порт. Стандартный 22 остается для администраторов и снаружи недоступен.

a) Копируем systemd service скрипт и конфиг sshd:
#cp /usr/lib/systemd/system/sshd.service /usr/lib/systemd/system/sshd_web.service#cp /etc/ssh/sshd/sshd_config /etc/ssh/sshd_web_config


b) Редактируем /usr/lib/systemd/system/sshd_web.service заменяя строку
ExecStart=/usr/sbin/sshd -D $OPTIONS

на
ExecStart=/usr/sbin/sshd -D -f /etc/ssh/sshd_web_config $OPTIONS


c) Редактируем /etc/ssh/sshd_web_config добавляя или исправляя параметры:
port 2022
MaxAuthTries 3
MaxSessions 1
AllowGroups groupusevpn


Таким образом мы запускаем дополнительный шелл sshd на порту 2022 не открывая его на firewall т.к обращения к нему исключительно по интерфейсу local.

d) Редактируем /etc/sysconfig/shellinaboxd изменив параметр на
OPTS=" -s /:SSH:localhost:2022"


e) В папке /var/lib/shellinabox по умолчанию лежат самосгенеренные и самоподписанные сертификаты shellinabox. Лично у себя я установил дополнительно nginx в который внес реальные сертификаты ssl, вынеся shellinabox на порт 8443 ( любой нестандартный )

#yum install y nginx


Конфигурация для nginx:

server {
listen 443 ssl;
server_name shellinabox.my.domen;

add_header Strict-Transport-Security max-age=15768000; includeSubDomains always;

set $upstream localhost:8443;

proxy_intercept_errors on;
underscores_in_headers on;

location ~ ^/(.*) {
proxy_pass $upstream$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/ privkey.pem;
ssl_protocols TLSv1.2;
ssl_dhparam /etc/ssl/ssl-dhparams.pem;
}

и в /etc/sysconfig/shellinaboxd меняем
PORT=8443


f) Перезапускаем после всех изменений.
#systemctl daemon-reload#systemctl enable now sshd_web#systemctl enable now shellinabox

Если ставили nginx то
#systemctl enable now nginx


g) Открываем порты firewalld
firewall-cmd --new-zone=radius permanentfirewall-cmd --zone=radius --add-source=10.10.10.5 --permanentfirewall-cmd --zone=radius --add-port=1812/udp --permanentfirewall-cmd --zone=radius --add-port=11812/udp --permanentfirewall-cmd --zone=radius --add-port=21812/udp --permanentfirewall-cmd --reload


8) Тестируем весь конструктор.
a) Заходим на shellinabox.my.domen
b) Логинимся пользователем VPN и получаем QR-код для GoogleAuth
c) Ставим на смартфон GoogleAuthenticator и сканим им QR-код.
d)
#radtest userVPN password_for_userVPNXXXXXX localhost 0 testing123

где XXXXXX цифры с GoogleAuthenticator. Результат должен быть Received Access-Accept
e)
#radtest userVPN password_for_userVPN localhost:11812 0 testing123

Результат должен быть Received Access-Accept
f)
#radtest userVPN XXXXXX localhost:21812 0 testing123 

где XXXXXX цифры с GoogleAuthenticator. Результат должен быть Received Access-Accept

9) Собственно VPN
a) Если все предидущие этапы прошли успешно то прописываем сервер типа Radius c IP и портом 11812/UDP как первый фактор в CISCO AnyconnectVPN и его же с портом 21812/UDP как второй фактор.





b) Деплоим конфигурацию и проверяем.

Как понятно из процесса тестирования, те системы, которые не умеют отдельно спрашивать первый и второй фактор ( или мы не хотим факторы разделять специально) мы направляем на порт Radius 1812 и используем схему пароль_ADXXXXXX добавляя цифры с Google Authenticator сразу после пароля без пробела.

Незакрытые вопросы:
  • Смена пароля при истечении времени жизни пароля через FreeRadius. Буду благодарен за советы.
  • SELINUX и GoogleAuthenticator.
  • Хотелось бы более красивого, аккуратного и, главное, более управляемого варианта генерации GoogleAuth токена, чем банальный шелл-скрипт.


PS. В статье использовались материалы http://personeltest.ru/aways/habr.com/ru/post/516362, откуда взята идея shellinabox
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru