Экстренный VPN сервер Openconnect с двухфакторной авторизацией на Centos 8

  • Tutorial

Предисловие


Вечерком воскресенья в середине марта мне поступил телефонный звонок, суть которого заключалась а том, что 200+ человек не приедут в понедельник в офис, а переводятся на «удалёнку». Фраза: одни на «удаленку», а админы на «продлёнку», завертелась у меня в голове.


Нельзя сказать, что удаленного доступа к внутренним ресурсам у нас не было совсем, но мы использовали IPSEC VPN на связке Shrew soft VPN client + Pfsense для экстренного доступа некоторых IT специалистов к вмененным им в поддержку информационным системам. У Shrew soft VPN client проявлялась особенность, заключавшаяся в том, что после некоторого количества успешных соединений перестают работать ipv4 маршруты. Лечилась данная ситуация перезапуском Windows служб или перезагрузкой конечного устройства. Перспектива объяснять коллегам этот нюанс неопределенное количество раз в день вызывала нервный тик и тремор конечностей одновременно.


Муки выбора


Я определил следующие требования к решению для организации VPN до офисных систем:

  1. Простота настройки. В надежде, что некоторые справятся самостоятельно;
  2. Наличие клиента для популярных операционных систем;
  3. Поддержка парольной авторизации Active Directory; Срочный Выпуск ключей(сертификатов) не входил в мои планы
  4. Двухфакторная аутентификация. Желательно бесплатно;
  5. Минимальные вложения, а лучше бесплатно, поскольку бюджет 2020 на IT-оборудование не предполагал затрат на шлюз удаленного доступа;
  6. И предсказуемая стабильность и производительность;

Новомодный WireGuard работает на ключах, openvpn-gui, имхо, имеет не самый дружелюбный интерфейс клиента, пару лет назад я пробовал SoftEther VPN, но остался недоволен производительностью, про Shrew soft писал выше. Openconnect VPN Server + OpenConnect SSL VPN Client — настройка клиента 1 строкой поддержка всех популярных платформ, возможность работать только по tcp, поддержка духфакторной аутентификации, интеграция с LDAP, то что надо! Еще и совместимость с Cisco Anyconnect client :)


Настройка


Настройку сервера я производил на базе ОС Centos 8. При установке Centos 8 в минимальной конфигурации я постоянно сталкиваюсь с некорректной работы русской локали, которая решается установкой glibc-langpack-en, и заменой системного шрифта>

dnf install glibc-langpack-en
setfont UniCyr_8x16
Меняем в /etc/vconsole.conf FONT="UniCyr_8x16"

Настройка межсетевого экрана:


#Устанавливаем зону trusted по-умолчанию для всех сетевых интерфейсов
#В связи с переходом на nftables есть проблема с работой Firewalld в части правил в цепочке Forward. Пока рекомендуют использовать зону trusted 
firewall-cmd --set-default-zone=trusted
#Добавляем новую службу в firewalld - ocserv (используются порты 443/tcp 443/udp)
firewall-cmd --permanent --new-service=ocserv
firewall-cmd --permanent --service=ocserv --set-description="OpenConnect SSL VPN Server"
firewall-cmd --permanent --service=ocserv --add-port=443/tcp
firewall-cmd --permanent --service=ocserv --add-port=443/udp
#Внешнему интерфейсу(в моем случае ens192) назначаем зону drop
firewall-cmd --zone=drop --change-interface=ens192 --permanent
firewall-cmd --reload
#В зону drop добавляем разрешающее правило для созданной службы ocserv
firewall-cmd --zone=drop --permanent --add-service=ocserv
firewall-cmd --reload

OpenConnect SSL VPN Server может использовать для авторизации механизм pam. Для «сквозной» авторизации клиентов Active Directory добавим наш новый сервер в домен:


#Установим необходимые пакеты 
dnf install realmd sssd oddjob oddjob-mkhomedir adcli samba-common samba-common-tools krb5-workstation

Проверим доступность инфрастуктуры Active Directory
realm  discover mydomain.ru

mydomain.ru
type: kerberos
realm-name: MYDOMAIN.RU
domain-name: mydomain.ru
configured: no
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

 #Подключение к домену  Active Directory
realm join mydomain.ru -U Username

Автоматически будет сформирован конфигурационный файл службы SSSD (System Security Services Daemon) /etc/sssd/sssd.conf. Необходимо добавить пока еще не установленную службу VPN сервера ocserv в настройки. Параметр use_fully_qualified_names отвечает за формат имени пользователя.
Листинг /etc/sssd/sssd.conf
[sssd]
domains = mydomain.ru
config_file_version = 2
services = nss, pam
default_domain_suffix = mydomain.ru

[domain/mydomain.ru]
ad_domain = mydomain.ru
ad_gpo_map_remote_interactive = +ocserv
krb5_realm = MYDOMAIN.RU
realmd_tags = manages-system joined-with-adcli
cache_credentials = True
id_provider = ad
krb5_store_password_if_offline = True
default_shell = /bin/bash
ldap_id_mapping = True
use_fully_qualified_names = True
fallback_homedir = /home/%u@%d
access_provider = ad

Включим и запустим службу SSSD

systemctl enable sssd
systemctl start sssd

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

realm permit --all

На данном этапе должна заработать аутентификация по ssh на сервер для пользователей домена.

Выбирая модуль для реализации двухфакторной двухэтапной аутентификации я посмотрел на стоимость поддерживаемого из коробки Duo security и выбрал TOTP (Time-based One-time Password) в лице Google Authenticator. В этой реализации критическим важным является момент синхронизации времени сервера службами точного времени. Проверить корректность работы демона chronyd можно командой: chronyc sources

Вывод chronyc sources
210 Number of sources = 2
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- ntp1.vniiftri.ru 1 6 17 1 -171us[ -171us] ± 2166us
^* ntp2.vniiftri.ru 1 6 17 1 -237us[ -57us] ± 2494us

Установка Google Authenticator:

dnf install epel-release
dnf install google-authenticator qrencode-libs

Далее необходимо из под учетной записи пользователя на сервере(sudo su DomainUser) выполнить команду google-authenticator и ответив в положительно на все вопросы получить индентификатор/qr-код для приложения Google Authenticator на смартфоне пользователя (IOS, Google play)

Установка Openconnect VPN Server:

dnf install ocserv
#Включим автозапуск сервера при загрузке
systemctl enable ocserv

Конфигурационный файл /etc/ocserv/ocserv.conf
auth = «pam»
#IPv4 внешний адрес на котором работает служба
listen-host = 1.1.111.1
tcp-port = 443
udp-port = 443
run-as-user = ocserv
run-as-group = ocserv
socket-file = ocserv.sock
chroot-dir = /var/lib/ocserv
isolate-workers = true
max-clients = 0

#Ограничение на кол-во сессий с одинаковым логином
max-same-clients = 1
keepalive = 32400
dpd = 90
mobile-dpd = 1800
switch-to-tcp-timeout = 25
try-mtu-discovery = true

#LetsenCrypt сертификаты для шифрования
server-cert = /etc/letsencrypt/live/vpn.mydomain.ru/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.mydomain.ru/privkey.pem

########################
cert-user-oid = 0.9.2342.19200300.100.1.1
compression = true
tls-priorities = "@SYSTEM"
auth-timeout = 240
idle-timeout = 1200
mobile-idle-timeout = 2400
min-reauth-time = 300
max-ban-score = 50
ban-reset-time = 300
cookie-timeout = 300
deny-roaming = false
rekey-time = 172800
rekey-method = ssl
use-occtl = true
pid-file = /var/run/ocserv.pid
device = vpns
predictable-ips = true
default-domain = vpn.mydomain.ru
#Адрес сети для VPN клиентов
ipv4-network = 192.168.178.0/24

#Настройка маршрутизации DNS-запросов
tunnel-all-dns = true
dns = 192.168.1.1
########################
ping-leases = false

#Маршрутизация VPN клиента к внутренним сетям
route = 192.168.1.0/255.255.255.0
route = 192.168.2.0/255.255.255.0
########################
cisco-client-compat = true
dtls-legacy = true
user-profile = profile.xml

Получаем сертификаты LetsEncrypt для шифрования VPN трафика. Поднимать веб сервер для этого вовсе не обязательно. Создавать задание на регулярный перевыпуск сертификатов я не стал, полагая, что 3-х месяцев хватит для разрешения ситуации с COVID-19 в том или ином ключе.


firewall-cmd --zone=drop --add-service=http
curl -O  https://dl.eff.org/certbot-auto
mv certbot-auto /usr/local/bin/certbot-auto
chown root /usr/local/bin/certbot-auto
chmod 0755 /usr/local/bin/certbot-auto
certbot-auto certonly --standalone --preferred-challenges http -d vpn.mydomain.ru
firewall-cmd --zone=drop --remove-service=http

Включаем двухфакторную аудентификацию и запускаем службу VPN сервера

sed '/^#%PAM-1.0$/a auth       required     pam_google_authenticator\.so' /etc/pam.d/ocserv
systemctl start ocserv
systemctl start ocserv

Включаем возможность пересылки трафика между интерфейсами

echo "net.ipv4.ip_forward=1">/etc/sysctl.d/0-ocserv.conf
sysctl -w net.ipv4.ip_forward=1


Клиентам предлагаем установить openconnect-gui. В настройках профиля указываем наш сервер vpn.mydomain.ru




При подключении на запрос Password от клиента необходимо заполнять OTP из Google Authenticator. На запрос Password1 пароль пользователя Active Directory.







Три недели полет нормальный...

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 16

    0
    Поддержка парольной авторизации Active Directory

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

      0

      Я и сам не в восторге от этой идеи. Добавили 2 этап авторизации для повышения безопасности и защиты от брута. Задача была срочная и связана с обеспечением работы предприятия в форс-мажорной ситуации.

        +1

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

          –1

          тут же sso не пахнет

            0

            Ну тут смотря какие у клиентов девайсы. Если корпоративные лаптопы в домене… то Kerberos и вот это всё.


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

        0
        Спасибо за статью. С момента начала изоляции — это единственная статья про конкретная реализацию VPN для компании, остальные просто пиар.
        Есть пара вопросов:
        Нижеуказанная информация — это из личного опыта или где-то есть инфа от Redhat?
        #В связи с переходом на nftables есть проблема с работой Firewalld в части правил в цепочке Forward.
        Использование Google Authenticator:
        Далее необходимо из под учетной записи пользователя на сервере(sudo su DomainUser)
        Подразумевается, что для каждого пользователя домена необходимо запускать эту команду, а результат работы высылать каждому пользователю, не так ли? Это если я правильно понимаю работу Google Authenticator
          0
          По nftables:
          Есть сведения от firewalld тут и тут чуть больше тут
          По google auth Да, вы правы. У себя мы сделали чуть по другому мы проверяем если в личной папке пользователя есть сформированный файл .google_authenticator то pam использует 2FA если нет, то просто авторизация по связке логин+пароль. И потихоньку генерили qr и рассылали пользователям.
            0
            По-моему в firewalld штатно никогда не было настроек для установки разрешения форвардинга между интерфейсами. Всегда требовалось заводить '--direct' правила.
              –1
              Вся проблема в том, что --direct не работают в Centos 8
                +1
                О, это новость. Но вот здесь они упоминают: "You can add permanent direct rules with the /etc/firewalld/direct.xml file."
                  0
                  Я имел ввиду только --direct в части Forward пакетов внутри одной зоны между двумя сетевыми интерфейсами
                  firewall-cmd --direct --add-rule ipv4 filter FORWARD 0  -i vpns0 -o ens224  -j ACCEPT
                  firewall-cmd --direct --add-rule ipv4 filter FORWARD 0  -i ens224 -o vpns0  -j ACCEPT
                    0
                    Для --direct правил здесь лучше использовать штатную предустановленную цепочку FORWARD_direct, а не напрямую FORWARD.

                    Отличная практическая статья, спасибо.
                      0
                      Заказывал сегодня centos 8, сразу же заметил что в поставке по дефолту был только nftables.
                      Вникнул, по мне, так удобнее чем firewalld, снова конфиг в файлах (привет любителям iptables-save > /etc/sysconfig/iptables)
                      PS: iifname "vpns+" не работает, заметно по счетчикам. Сделал через ip saadr
                      # nft list table inet filter
                      table inet filter {
                      	chain input {
                      		type filter hook input priority 0; policy drop;
                      		iif "lo" accept comment "Accept any localhost traffic"
                      		ct state invalid drop comment "Drop invalid connections"
                      		ct state established,related accept comment "Accept traffic originated from us"
                      		icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
                      		icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
                      		tcp dport ssh ct state new limit rate 15/minute accept comment "Avoid brute force on SSH"
                      		meta l4proto { tcp, udp } @th,16,16 25443 accept comment "Accept ocserv"
                      		tcp dport 28443 accept comment "Accept stunnel"
                      		tcp dport { http, https } accept
                      		counter packets 2729 bytes 196569 comment "Count any other traffic"
                      	}
                      
                      	chain forward {
                      		type filter hook forward priority 0; policy drop;
                      		ct state invalid drop comment "Drop invalid connections"
                      		ct state established,related accept comment "Accept traffic originated from us"
                      		iifname "vpns+" counter packets 0 bytes 0 accept
                      		ip saddr 172.16.1.0/24 accept
                      	}
                      
                      	chain output {
                      		type filter hook output priority 0; policy accept;
                      	}
                      }
                      
                        0
                        Примечательно, что переход на дефолт nftables произошёл в RHEL8.0, которая базировалась на Fedora 28. А в самой Федоре переход на дефолт nftables осуществили только в F32, вышедшей неделю назад.

                        PS. И firewalld соответственно работает на nftables бэкенде, а direct-правила в нём используют iptables-бэкенд, и это превносит свои странные особенности:
                        firewalld uses nftables by default

                        With this update, the nftables filtering subsystem is the default firewall backend for the firewalld daemon. To change the backend, use the FirewallBackend option in the /etc/firewalld/firewalld.conf file.

                        This change introduces the following differences in behavior when using nftables:
                        1. iptables rule executions always occur before firewalld rules
                          • DROP in iptables means a packet is never seen by firewalld
                          • ACCEPT in iptables means a packet is still subject to firewalld rules
                        2. firewalld direct rules are still implemented through iptables while other firewalld features use nftables
                        3. direct rule execution occurs before firewalld generic acceptance of established connections

            0
            Что заставляет людей использовать Shrew, умерший еще в 2013 году и более не развивающийся?
              0
              Он бесплатный и стабильно работает.

            Only users with full accounts can post comments. Log in, please.