Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> Security —> OpenVPN+авторизация

Хитрая настройка OpenVPN

Автор: arksu.


Как то понадобилось настроить ВПН сервер с максимально жестокими политиками доступа: авторизация по ключу - для каждого юзера отдельного, авторизация по паре логин+пароль. причем ключ и пара логин+пароль у каждого юзера строго индивидуальны. стал рыть маны, искать статьи на сайте в основном делал по статье поэтому не буду пересказывать как ставить и настраивать, как генерить ключи (по статье сам лично разобрался, разумеется не без пива =))

А расскажу лучше про фишки OpenVPN. Вот выдержка из мана:

--auth-user-pass-verify script method
Require the client to provide a username/password (possibly in
addition to a client certificate) for authentication.

OpenVPN will execute script as a shell command to validate the
username/password provided by the client.

If method is set to "via-env", OpenVPN will call script with the
environmental variables username and password set to the user-
name/password strings provided by the client. Be aware that
this method is insecure on some platforms which make the envi-
ronment of a process publicly visible to other unprivileged pro-
cesses.

If method is set to "via-file", OpenVPN will write the username
and password to the first two lines of a temporary file. The
filename will be passed as an argument to script, and the file
will be automatically deleted by OpenVPN after the script re-
turns. The location of the temporary file is controlled by the
--tmp-dir option, and will default to the current directory if
unspecified. For security, consider setting --tmp-dir to a
volatile storage medium such as /dev/shm (if available) to pre-
vent the username/password file from touching the hard drive.

The script should examine the username and password, returning a
success exit code (0) if the client's authentication request is
to be accepted, or a failure code (1) to reject the client.

This directive is designed to enable a plugin-style interface
for extending OpenVPN's authentication capabilities.

To protect against a client passing a maliciously formed user-
name or password string, the username string must consist only
of these characters: alphanumeric, underbar ('_'), dash ('-'),
dot ('.'), or at ('@'). The password string can consist of any
printable characters except for CR or LF. Any illegal charac-
ters in either the username or password string will be converted
to underbar ('_').

Care must be taken by any user-defined scripts to avoid creating
a security vulnerability in the way that these strings are han-
dled. Never use these strings in such a way that they might be
escaped or evaluated by a shell interpreter.

Смысл в следующем: есть возможность запускать в дополнение авторизации по ключам отдельный пользовательский скрипт для авторизации, и передавать ему логин пасс либо через переменные окружения (via-env), либо через файл (via-file).
Скрипт после проверки должен завершатся либо с кодом 0 - проверка успешна, либо с кодом 1 - сбой авторизации
Сразу скажу что в логине можно использовать только буквы латинского алфавита, цифры, ('_'), ('-'), ('.'), ('@'). (про русские имена пользователей можно СРАЗУ ЗАБЫТЬ!)

Я не стал передавать параметры через файл - потенциальная дырка, а передал через переменные окружения (via-env)

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

#!/usr/local/bin/php
<?php

$host="localhost";
$user="db_user";
$pass="db_pass";
$db_name="db_name";

mysql_connect($host,$user,$pass) OR DIE("Не могу прислюнявица к мускулу!");
mysql_select_db($db_name) or die(mysql_error());
mysql_query("SET NAMES koi8r");
mysql_query("SET CHARSET koi8r");
mysql_query("SET collation_connection = koi8r_general_ci");
mysql_query("SET collation_database = koi8r_general_ci");
mysql_query("SET collation_database = koi8r_general_ci");
mysql_query("SET character_set_client = koi8r");
mysql_query("SET character_set_connection = koi8r");
mysql_query("SET character_set_database = koi8r");
mysql_query("SET character_set_results = koi8r");

$login = getenv("username"); // получаем логин
$pass = getenv("password"); // получаем пасс
$cn = getenv("common_name"); // получаем имя сертификата под которым юзер пытается войти

if (($login != $pass) && ($login !="") && ($pass !=""))
{
                $res = mysql_query('select * from `vpn` where `login`="'.$login.'" and `enabled`=1');
                if (mysql_num_rows($res) == 1)
                {
                        $row = mysql_fetch_array($res);
                        if (($row['pass'] == $pass) && ($login== $cn)) { exit(0); } // авторизация успешна!
                }
        exit (1);
} else exit (1);
?>

вот мой получившийся конфиг сервера
#порт на котором работает сервер
port 23
# протокол - советую udp
proto udp
# - используемый тип устройства и номер
dev tun0
#указываем файл CA
ca /usr/local/etc/openvpn/keys/ca.crt
#указываем файл с сертификатом сервера
cert /usr/local/etc/openvpn/keys/server.crt
#указываем файл с ключем сервера
key /usr/local/etc/openvpn/keys/server.key
#указываем файл Диффи Хельман
dh /usr/local/etc/openvpn/keys/dh1024.pem
#задаем IP-адрес сервера и маску подсети
# (виртуальной сети) - можно произвольную, (я выбрал такую)
server 172.16.250.0 255.255.255.0

#задаем МАРШРУТ который передаём клиентту
# и маску подсети для того чтобы он "видел"
# сеть за опенвпн сервером (сеть 192.168.0.0/24)
push "route 192.168.0.0 255.255.255.0"
push "route 192.168.10.0 255.255.255.0"
push "route 192.168.20.0 255.255.255.0"

# указываем где хранятся файлы с
# настройками IP-адресов клиентов
client-config-dir ccd
# добавляем маршрут сервер-клиент
route 172.16.250.0 255.255.255.252
# включаем TLS аутификацию
tls-server
# указываем tls-ключ, и указываем 0 для сервера, а 1 для клиента
tls-auth keys/ta.key 0
# таймаут до реконекта
tls-timeout 120
auth MD5 #
# включаем шифрацию пакетов
cipher BF-CBC
keepalive 10 120
# сжатие трафика
comp-lzo
# максимум клиентов
max-clients 100
user nobody
group nobody
# Не перечитывать ключи после получения
# SIGUSR1 или ping-restart
persist-key
# Не закрывать и переоткрывать TUN\TAP
# устройство, после получения
# SIGUSR1 или ping-restart
persist-tun
# логгирование (не забудьте создать эту дирректорию /var/log/openvpn/)
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
# Уровень информации для отладки
verb 3
auth-user-pass-verify /usr/local/bin/vpn_check via-env # ВОТ ОНА СТРОКА ДЛЯ СКРИПТА АВТОРИЗАЦИИ

конфиг клиента:
dev tun
proto udp
remote vpn.mydomain.ru
port 23
client
resolv-retry infinite
ca ca.crt
cert client.crt
key client.key
tls-client
tls-auth ta.key 1
auth MD5
cipher BF-CBC
ns-cert-type server
comp-lzo
persist-key
persist-tun
verb 3
auth-user-pass

все остальное делал по статье, добавил скриптик для упрощения генерации ключей, админку прикрутил на пыхе, поднял nginx - и жить стало легче!
P.S. сервер работает не первый месяц в продакшне - нестабильности не выявил =)

P.S.S
скрипт для создания таблички

CREATE TABLE IF NOT EXISTS `vpn` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `login` varchar(20) NOT NULL,
  `pass` varchar(20) NOT NULL,
  `enabled` tinyint(2) NOT NULL,
  PRIMARY KEY (`id`)
)



размещено: 2008-11-26,
последнее обновление: 2008-12-04,
автор: arksu


zloidemon, 2008-12-04 в 11:48:49

It's work! ++++

hub, 2008-12-04 в 23:46:50

А зачем вы в статьях юзаете "auth MD5"? если его не задавать он будет юзать SHA1 160 битный который более секюрен.

gonzo111, 2009-06-23 в 15:35:14

ну а где собственно скрипт /usr/local/bin/vpn_check  ????

gonzo111, 2009-06-25 в 16:48:08

для файловой аутентификации скрипт
тк скрипт-пример перловский из репозитария у меня не заработал
взято отсюда http://kyxap.crimea.ua/articles/stuff/openvpn/password_authentication

auth-user-pass-verify /usr/local/etc/openvpn/auth.pl via-env
Скрипт /usr/local/etc/openvpn/auth.pl
#!/usr/bin/perl

use strict;

my $passwdfile = "/usr/local/etc/openvpn/users";
my $isValidUser = 0;
my $username;
my $password;
my $thisUsername = $ENV{'username'};
my $thisPassword = $ENV{'password'};

open (PASSWORDS,"$passwdfile") or die "can't find file: $passwdfile : $!\n";

while (<PASSWORDS>) {
   ($username,$password)= split (/:/, $_);
   chomp $username;
   chomp $password;
   if ($username eq $thisUsername && $password eq $thisPassword) {
       $isValidUser = 1;}
}
close PASSWORDS;

if ($isValidUser == 1) {
   print "ERR\n";
   exit 0;
} else {
   print "OK\n";
   exit 1;
}

gonzo111, 2009-06-25 в 16:49:13

Формат файла /usr/local/etc/openvpn/usersrnlogin:passwordrnlogin2:pass2

gonzo111, 2009-06-25 в 16:51:06

Формат файла /usr/local/etc/openvpn/usersrnrnlogin:passwordrnlogin2:pass2

gonzo111, 2009-09-30 в 14:11:00

в скрипте заменил на
my $thisUsername = $ENV{\'common_name\'};
тогда ему по барабану какой логин
проверяет common_name из сертификата

ключ клиента быстрее делать через ./build-key-pkcs12 client1

gonzo111, 2009-10-12 в 13:07:58

для нормального логирования без перезаписи файла лучше поставить
log-append   /var/log/openvpn/openvpn.log

newsyslog
/var/log/openvpn/openvpn.log            644  5   100  *     ZC.

При openvpn restart падает ругаясь на то что не хватает прав
не долго думая добавил его в monit
# openvpn
 check process openvpn with pidfile /var/run/openvpn.pid
   start program = "/usr/local/etc/rc.d/openvpn start"
   stop program  = "/usr/local/etc/rc.d/openvpn stop"
   if 5 restarts within 8 cycles then timeout

6a6ka, 2009-10-25 в 0:45:52

В твоем скрипте не достает переменную пароля...

gonzo111, 2009-12-17 в 1:35:28

вот какие надо ставить права
# chown -R root:wheel /etc/openvpn
# chmod 700 /etc/openvpn/keys
# chmod 644 /etc/openvpn/keys/{ca.crt,dh1024.pem,server.crt}
# chmod 600 /etc/openvpn/keys/{server.key,ta.key}

to 6a6ka все там у меня достает

gonzo111, 2009-12-17 в 3:05:03

После четырех лет разработки вышел релиз
http://www.opennet.ru/opennews/art.shtml?num=24679
курить
http://openvpn.net/changelog-beta.html

magras, 2010-02-27 в 1:29:59

> Я не стал передавать параметры через файл - потенциальная дырка, а передал через переменные окружения (via-env)

Цитата из официального мана (http://openvpn.net/index.php/open-source/documentation/manuals/65-openvpn-20x-manpage.html):
If method is set to "via-env", OpenVPN will call script with the environmental variables username and password set to the username/password strings provided by the client. Be aware that this method is insecure on some platforms which make the environment of a process publicly visible to other unprivileged processes.

If method is set to "via-file", OpenVPN will write the username and password to the first two lines of a temporary file. The filename will be passed as an argument to script, and the file will be automatically deleted by OpenVPN after the script returns. The location of the temporary file is controlled by the --tmp-dir option, and will default to the current directory if unspecified. For security, consider setting --tmp-dir to a volatile storage medium such as /dev/shm (if available) to prevent the username/password file from touching the hard drive.

Так что потенциальная дырка это как раз "via-env".

a-zet, 2010-08-06 в 8:46:58

В статье нет самого главного, а только упоминание: админка на пыхе. Выложите плиз.

mng, 2012-05-03 в 19:00:05

не  работал ваш  скрпт  до тех пор, пока не  поменял exit на  return



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0409 секунд
Из них PHP: 32%; SQL: 68%; Число SQL-запросов: 77 шт.
Исходный размер: 34515; Сжатая: 9408