Достаточно часто возникают ситуации когда нужно использовать OpenVPN, но по какой-то причине нет возможности генерировать отдельный сертификат на каждого пользователя. В этом случае хорошим решением будет использование авторизации по логину и паролю.
Рассмотрим пример подобного решения. Для начала возьмём недорогой VPS с FreeBSD 11.1 и в первую очередь установим необходимое ПО. Нам понадобится собственно OpenVPN, пакет denyhosts, чтобы хоть как-то "защитить" SSH от брутфорс-атак и Perl, на котором мы напишем скрипт аутентификации:
pkg install openvpn denyhosts perl5
Приступаем к настройке. Создадим директорию для хранения конфигурации и скопируем скрипты генерации ключей:
mkdir -p /usr/local/etc/openvpn cp -av /usr/local/share/easy-rsa /usr/local/etc/openvpn/easy-rsa
Перейдём в директорию со скриптами генерации ключей:
/usr/local/etc/openvpn/easy-rsa
Отредактируем файл vars, чтобы он принял примерно такой вид:
if [ -z "$EASYRSA_CALLER" ]; then echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2 echo "This is no longer necessary and is disallowed. See the section called" >&2 echo "'How to use this file' near the top comments for more details." >&2 return 1 fi set_var EASYRSA "$PWD" set_var EASYRSA_PKI "$EASYRSA/../keys" set_var EASYRSA_REQ_COUNTRY "US" set_var EASYRSA_REQ_PROVINCE "New Jersey" set_var EASYRSA_REQ_CITY "New Jersey" set_var EASYRSA_REQ_ORG "Best Company" set_var EASYRSA_REQ_EMAIL "your@email.com" set_var EASYRSA_REQ_OU "IT"
Генерируем ключи:
./easyrsa.real init-pki ./easyrsa.real build-ca nopass ./easyrsa.real gen-dh ./easyrsa.real build-server-full main nopass
Далее нам нужно написать скрипт аутентификации. Скрипт будет максимально простой: он будет брать из переменных окружения логин и пароль и в случае успеха завершаться с кодом 0, а в случае неудачи - кодом 1. собственно скрипт:
#!/usr/bin/env perl use strict; use warnings; use diagnostics; #use Data::Dumper; #print Dumper(\%ENV); # Хэш с данным пользователей # Ключ - логины # Значения - пароли my %auth_data = ( 'vasya' => 'meg4P4ss54', 'petya' => 'S3cretP4ss', ); my $user = $ENV{username} or die("Bad login!\n"); my $pass = $ENV{password} or die("Bad password!\n"); exit 1 unless defined($auth_data{$user}); exit 1 unless $auth_data{$user} eq $pass; exit 0;
Его надо сохранить как "/usr/local/etc/openvpn/checkpass.pl". Затем создадим файл конфигурации сервера OpenVPN ("/usr/local/etc/openvpn/main.conf"):
mode server daemon tls-server # Подсеть, используемая в виртуальной сети между сервером и клиентами server 172.16.251.128 255.255.255.224 # Порт сервера port 443 # Протокол. Если использовать tcp и порт 443, то трафик будет похож на https ;) # Но с udp трафик бегает чуть быстрее proto udp dev tun0 #tun-mtu 1480 ca "/usr/local/etc/openvpn/keys/ca.crt" cert "/usr/local/etc/openvpn/keys/issued/main.crt" key "/usr/local/etc/openvpn/keys/private/main.key" dh "/usr/local/etc/openvpn/keys/dh.pem" # Явно укажем используемы шифр cipher "AES-256-CBC" # Если мы хотим кому-то из пользователей персональные настройки # То их надо размещать в этой директории client-config-dir /usr/local/etc/openvpn/ccd # Явно говорим что клиент должен весь свой трафик завернуть в тоннель push "redirect-gateway def1" # DNS, рекоммендуемые клиенту push "dhcp-option DNS 8.8.8.8" push "dhcp-option WINS 8.8.8.8" keepalive 10 120 persist-key persist-tun # В качестве бонуса будем сжимать трафика:) comp-lzo script-security 3 # Клиентский сертификат не нужен verify-client-cert none # Логин пользователя будет использоваться вместо имени клиентского сертификата # Например при поиске настроек в client-config-dir username-as-common-name # Путь к скрипту аутентификации auth-user-pass-verify "/usr/local/etc/openvpn/checkpass.pl" via-env # Логи лишними не бывают:) verb 3 log-append /var/log/openvpn.log
Добавляем в /etc/rc.conf строки:
openvpn_enable="YES" openvpn_if="tun" openvpn_configfile="/usr/local/etc/openvpn/main.conf" openvpn_dir="/usr/local/etc/openvpn"
И запускаем сервер:
/usr/local/etc/rc.d/openvpn start
Теперь нам нужно включить пересылку пакетов между интерфейсами сервера. Добавляем в /etc/rc.conf строку:
gateway_enable="YES"
Чтобы включить пересылку пакетов не перезагружая сервер выполним команду:
sysctl net.inet.ip.forwarding=1
Приступаем к настройке файрволла. Мы будем использовать pf, как самый современный и простой в настройке. Создадим файл конфигурации "/etc/pf.rules" следующего содержания:
set limit { states 20000, frags 5000 } set timeout { adaptive.start 6000, adaptive.end 12000 } set skip on { lo0 } # Внешний интерфейс сервера (см. вывод ifconfig) if_ext = "vtnet0" # Интерфейс, используемый openvpn if_int = "tun0" # Подсеть, используемая OpenVPN net_int = "172.16.251.128/27" set block-policy drop set state-policy if-bound scrub in # NAT для внутренней сети nat pass on $if_ext from $net_int -> ($if_ext) static-port # Разрешаем всё на loopback-интерфейсе pass quick on lo0 all # Разрешаем исходящий трафик pass out quick on $if_ext inet proto tcp from ($if_ext) to any flags S/SA keep state pass out quick on $if_ext inet proto { udp, icmp } from ($if_ext) to any keep state # Разрешаем доступ к серверу по SSH pass in quick on $if_ext inet proto tcp from any to ($if_ext) port 22 flags S/SA keep state # Разрешаем доступ к OpenVPN pass in quick on $if_ext inet proto udp from any to ($if_ext) port 443 # Разрешаем пинговать наш сервер:) pass in quick on $if_ext inet proto icmp from any to ($if_ext) # Разрешаем все обращения к нашему серверу от клиентов OpenVPN pass in quick on $if_int from $net_int to any keep state # Блокируем весь остальной трафик block drop all
Закончив создание файла конфигурации допишем в /etc/rc.conf строки:
pf_enable="YES" pf_rules="/etc/pf.rules"
И запускаем файрволл командой:
/etc/rc.d/pf start
Остаётся настроить denyhosts и настройка сервера будет завершена. Создаём файл "/usr/local/etc/denyhosts.conf" следующего содержания:
SECURE_LOG = /var/log/auth.log HOSTS_DENY = /etc/hosts.allow PURGE_DENY=6h BLOCK_SERVICE = ALL DENY_THRESHOLD_INVALID = 5 DENY_THRESHOLD_VALID = 10 DENY_THRESHOLD_ROOT = 2 DENY_THRESHOLD_RESTRICTED = 1 WORK_DIR = /usr/local/share/denyhosts/data SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES HOSTNAME_LOOKUP=NO LOCK_FILE = /var/run/denyhosts.pid DAEMON_LOG = /var/log/denyhosts DAEMON_SLEEP = 30s DAEMON_PURGE = 1h
Дописываем в /etc/rc.conf строку:
denyhosts_enable="YES"
запускаем denyhosts:
/usr/local/etc/rc.d/denyhosts start
На этом настройка сервера закончена. Переходим к настройке клиента. Тут всё совсем просто: создаём директорию для файлов конфигурации клиента и помещаем в неё файл ca.crt с сервера (на сервере полный путь к нему: "/usr/local/etc/openvpn/keys/ca.crt". Затем там же создаём файл client.ovpn и записываем в него:
comp-lzo nobind dev tun # Протокол proto udp # IP и порт на сервере remote IP-вашего-сервера 443 script-security 2 persist-key persist-tun client resolv-retry infinite ca ca.crt cipher "AES-256-CBC" verb 3 # Запрашивать у пользователя логин и пароль auth-user-pass
Теперь можно запустить openvpn-клиент с этим файлом конфигурации, ввести логин и пароль и спокойно пользоваться сервисом.
Если же необходимо сохранить логин и пароль то нужно в директории с конфигурацией клиента создать файл pswd.dat, содержащий две строки:
лоигн_пользователя пароль_пользователя
А в файле client.ovpn заменить строку auth-user-pass на:
auth-user-pass pswd.dat
Однако надо помнить что поскольку пароль хранится в открытом виде то он может быть похищен вредоносной программой, или третьим лицом, имеющим доступ к компьютеру.
Что дальше? Например можно доработать скрипт аутентификации чтобы он хранил не пароли, а их хэши, добавить к этим хэшам соль, перенести хранение этих данных в БД и написать веб-интерфейс для управления логинами и паролями. Но это мы оставим читателю;)
На этом всё. Приятной и безопасной вам работы!