Достаточно часто возникают ситуации когда нужно использовать 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
Однако надо помнить что поскольку пароль хранится в открытом виде то он может быть похищен вредоносной программой, или третьим лицом, имеющим доступ к компьютеру.
Что дальше? Например можно доработать скрипт аутентификации чтобы он хранил не пароли, а их хэши, добавить к этим хэшам соль, перенести хранение этих данных в БД и написать веб-интерфейс для управления логинами и паролями. Но это мы оставим читателю;)
На этом всё. Приятной и безопасной вам работы!
