Настройка OpenVPN с использованием сертификатов X.509


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

Необходимо создать виртуальную частную сеть между несколькими офисами компании, подключенными к Интернет. Как известно, существует множество решений данного вопроса, которые многократно сравнивались по соотношениям функциональности / надежности / стоимости. Рекомендую Вам прочитать статью А. Бешкова Создаем кроссплатформенную виртуальную частную сеть VPN на основе OpenVPN. В ней описано очень простое, но достаточно надежное решение на базе бесплатного пакета OpenVPN, использующее статические ключи для шифрования трафика. OpenVPN позволяет разворачивать гораздо более гибкие конфигурации и использовать сертификаты TLS/SSL вместо статических ключей. В данной статье рассмотрена одна из таких конфигураций.
Исходные данные

Имеется сервер с FreeBSD, через который подсеть центрального офиса подключена к Интернет. На нем будет развернут сервер OpenVPN. Имеется два удаленных филиала, подсети которых также подключены к Интернет через серверы с FreeBSD (они будут клиентами OpenVPN) и компьютер системного администратора с Windows XP (он также будет клиентом OpenVPN). Локальная подсеть центрального офиса имеет адрес 192.168.0.0/24; локальная подсеть филиала № 1 - 192.168.1.0/24; локальная подсеть филиала № 2 - 192.168.2.0/24. Необходимо создать виртуальную частную сеть routed-типа (т.е. не пропускающую широковещательный трафик), с топологией Point-To-Multi-Point (один сервер и несколько клиентов), использующую для шифрования трафика TLS/SSL и обеспечивающую следующую политику маршрутизации:
из локальной подсети центрального офиса доступны компьютеры локальных подсетей обоих филиалов,
из локальных подсетей филиалов доступны компьютеры локальной подсети центрального офиса,
c компьютера системного администратора доступны компьютеры всех локальных подсетей.

При реализации описанного ниже я руководствовался документом OpenBSD Installation (в настоящее время документ по неизвестным причинам удален с сервера) и материалами Форума OpenNET. Я использовал (и продолжаю использовать) пакет OpenSSL, входящий в состав операционной системы, и последнюю версию порта OpenVPN. За время существования виртуальной частной сети ОС сервера и клиентов постепенно обновлялись с версии 4.10 до версии 8.2.
Установка сервера OpenVPN

Перед установкой сервера OpenVPN необходимо добавить в файл конфигурации ядра строку pseudo-device tun, если таковая отсутствует, пересобрать ядро и перезагрузить систему. Затем нужно установить OpenVPN из портов:1
2 cd /usr/ports/security/openvpn
make install


Файлы конфигурация сервера OpenVPN хранятся в папке /usr/local/etc/openvpn. Для создания этой папки, а также всех необходимых вложенных папок и файлов необходимо выполнить следующую последовательность команд:

mkdir /usr/local/etc/openvpn
cd /usr/local/etc/openvpn
mkdir ccd
mkdir certs
mkdir crl
mkdir keys
mkdir private
mkdir req
chmod 700 keys private
echo "01" > serial
touch index.txt


Указанные команды создают папку /usr/local/etc/openvpn; вложенные в нее папки: ccd (конфигурации удаленных клиентов), certs (сертификаты клиентов и сервера), crl (списки отзыва сертификатов), keys (закрытые ключи сертификатов клиентов и сервера), private (закрытый ключ самоподписного доверенного сертификата (CA), req (запросы на сертификаты); ограничивают права доступа к папкам keys и private; создают базу данных сертификатов (файлы serial и index.txt).
Файл конфигурации OpenSSL

По умолчанию OpenSSL использует файл конфигурации /etc/ssl/openssl.cnf. Я рекомендую создать отдельный файл конфигурации OpenSSL в папке /usr/local/etc/openvpn. Данный файл должен называться openssl.cnf и иметь следующее содержимое:

[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /usr/local/etc/openvpn
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/certs
certificate = $dir/CA_cert.pem
serial = $dir/serial
crl = $dir/crl/crl.pem
private_key = $dir/private/CA_key.pem
RANDFILE = $dir/private/.rand
default_days = 3650
default_crl_days = 365
default_md = md5
unique_subject = yes
policy = policy_any
x509_extensions = user_extensions
[ policy_any ]
organizationName = match
organizationalUnitName = optional
commonName = supplied
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
x509_extensions = CA_extensions
[ req_distinguished_name ]
organizationName = Organization Name (must match CA)
organizationName_default = Company
organizationalUnitName = Location Name
commonName = Common User or Org Name
commonName_max = 64
[ user_extensions ]
basicConstraints = CA:FALSE
[ CA_extensions ]
basicConstraints = CA:TRUE
default_days = 3650
[ server ]
basicConstraints = CA:FALSE
nsCertType = server

Создание самоподписного доверенного сертификата (CA)

Для создания самоподписного доверенного сертификата (Certification Authority, CA) и закрытого ключа для него необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl req -new -nodes -x509 -keyout private/CA_key.pem -out CA_cert.pem -days 3650

Команда req заставляет OpenSSL создать сертификат, ключи: -new - cоздать запрос на сертификат, -nodes - не шифровать закрытый ключ, -x509 (совместно с -new) - создать самоподписной сертификат (CA), -keyout - задает местонахождение закрытого ключа, -out - задает местонахождение самоподписного сертификата, -days - задает время действия сертификата (365x10 дней, что приблизительно равно десяти годам). В процессе выполнения команды на экран будут выданы запросы о вводе таких параметров как: Country Name, State or Province Name; Locality Name; Organization Name; Organizational Unit Name; Common Name; Email Address. Самым важным параметром является значение Common Name. В данном случае оно должно совпадать с FQDN-именем сервера. Для просмотра результата генерации самоподписного сертификата и закрытого ключа необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:


openssl x509 -noout -text -in CA_cert.pem (для сертификата)
openssl rsa -noout -text -in private/CA_key.pem (для закрытого ключа)

Создание сертификата сервера

Перед созданием сертификата сервера необходимо создать запрос на сертификат сервера и закрытый ключ сервера. Для этого необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl req -new -nodes -keyout keys/server.pem -out req/server.pem


Команда и ключи OpenSSL рассмотрены выше. В процессе выполнения комнды Вам опять придется ответить на вопросы. Ответы должны соответствовать ответам из предыдущего пункта. В ответ на дополнительные запросы "A challenge password []:" и "An optional company name []:" необходимо просто нажать <Enter>. Для просмотра результата генерации запроса на сертификат и закрытого ключа сервера необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:

openssl req -noout -text -in req/server.pem (для запроса на сертификат)
openssl rsa -noout -text -in keys/server.pem (для закрытого ключа)

Для создания сертификата сервера необходимо подписать запрос на сертификат сервера самоподписным доверенным сертификатом (CA). Для этого необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl ca -batch -config openssl.cnf -extensions server -out certs/server.pem -infiles req/server.pem

Команда ca заставляет OpenSSL подписать запрос на сертификат, ключи: -config задает местонахождение файла конфигурации OpenSSL, -extensions - задает секцию файла конфигурации OpenSSL, содержащую дополнительные параметры генерируемого сертификата, -out - задает местонахождение генерируемого сертификата, -infiles - задает местонахождение запроса на сертификат, -batch - избавляет Вас от ответов на дополнительные вопросы. В процессе выполнения команды Вам будет задан вопрос "Sign the certificate? [y/n]:", на который нужно ответить утвердительно, после чего произойдет генерация сертификата и обновление базы данных сертификатов (файлов index.txt и serial). Для просмотра результата генерации сертификата необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl x509 -noout -text -in certs/server.pem

Создание файла параметров Диффи-Хэлмана

Для создания файла параметров Диффи-Хэлмана, предназначенного для обеспечения более надежной защиты данных при установке соединения клиента с сервером, необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl dhparam -out dh2048.pem 2048

Команда dhparam приказывает OpenSSL создать файл параметров Диффи-Хэлмана, число 2048 определяет разрядность в битах. Внимание: данная команда выполняется достаточно медленно даже на очень мощных компьютерах.
Создание клиентских сертификатов

Процедура создания клиентских запросов на сертификаты и закрытых ключей, подписания запросов на сертификаты и генерации сертификатов, а также просмотра запросов на сертификаты, сертификатов и закрытых ключей полностью аналогична соответствующей процедуре для сервера. Сделаю одно небольшое замечание: запросы на сертификаты, закрытые ключи и сертификаты должны иметь шаблонные имена, например, вида: req/RClient для запросов на сертификаты, keys/KClient для закрытых ключей и certs/CClient для сертификатов, соответственно. Слово Client должно быть заменено именем клиента, которое обязательно должно соответствовать значению параметра Common Name, вводимого при генерации запроса на сертификат для соответствующего клиента. Возможность дублирования Common Name у нескольких клиентов определяется конфигурацией сервера. Для генерации запроса на сертификат и закрытого ключа, а также подписания запроса на сертификат и генерации сертификата для клиента Client необходимо выполнить следующие команды, находясь в папке /usr/local/etc/openvpn:

openssl req -new -nodes -keyout keys/KClient.pem -out req/RClient.pem
openssl ca -batch -config openssl.cnf -out certs/CClient.pem -infiles req/RClient.pem


Для просмотра сгенерированных запроса на сертификат, закрытого ключа и сертификата клиента Client необходимо выполнить следующие команды, находясь в папке /usr/local/etc/openvpn:

openssl req -noout -text -in req/RClient.pem (для запроса на сертификат)
openssl rsa -noout -text -in keys/KClient.pem (для закрытого ключа)
openssl x509 -noout -text -in certs/CClient.pem (для сертификата)

На данном этапе для рассматриваемого случая необходимо создать три групы, состоящих из запроса на сертификат / закрытого ключа / сертификата, с именами Rclient1 / Kclient1 / Cclient1, Rclient2 / Kclient2 / Cclient2 и Rclient3 / Kclient3 / Cclient3 для филиала № 1 (Common Name - client1), для филиала № 2 (Common Name - client2) и для системного администратора (Common Name - client3), соответственно.


Создание списка отзыва сертификатов

Для создания списка отзыва сертификатов необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl ca -config openssl.cnf -gencrl -out crl/crl.pem


Команда ca с ключем -gencrl заставляет OpenSSL создать список отзыва сертификатов, ключи: -config рассмотрен выше, -out - задает местонахождение списка отзыва сертификатов. Данная команда создает пустой список отзыва сертификатов. Для того, чтобы отозвать сертификат клиента Client необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl ca -config openssl.cnf -revoke certs/CClient.pem


Команда ca с ключем -revoke заставляет OpenSSL отозвать заданный сертификат, ключ -config рассмотрен выше. Для просмотра списка отозванных сертификатов необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openssl crl -noout -text -in crl/crl.pem

Создание статического ключа HMAC

Для создания статического ключа HMAC, обеспечивающего дополнительную защиту от DoS-атак и флудинга UDP-портов, необходимо выполнить следующую команду, находясь в папке /usr/local/etc/openvpn:1 openvpn --genkey --secret ta.key

Файл конфигурации сервера

По умолчанию конфигурация сервера OpenVPN хранится в файле openvpn.conf, который должен находится в папке /usr/local/etc/openvpn. В рассматриваемом случае файл конфигурации имеет следующий вид:

dev tun
local <Внешний IP-адрес сервера>
port 1194
proto udp
server 10.0.0.0 255.255.255.0
push "route 10.0.0.0 255.255.255.0"
route 192.168.1.0 255.255.255.0
route 192.168.2.0 255.255.255.0
client-config-dir ccd
client-to-client
tls-server
dh /usr/local/etc/openvpn/dh2048.pem
ca /usr/local/etc/openvpn/CA_cert.pem
cert /usr/local/etc/openvpn/certs/server.pem
key /usr/local/etc/openvpn/keys/server.pem
crl-verify /usr/local/etc/openvpn/crl/crl.pem
tls-auth /usr/local/etc/openvpn/ta.key 0
comp-lzo
keepalive 10 120
tun-mtu 1500
mssfix 1450
persist-key
persist-tun
user openvpn
group openvpn
verb 3

В данном файле заданы следующие значения параметров сервера OpenVPN: dev - интерфейс OpenVPN, local и port - IP-адрес и порт, на которых OpenVPN принимает входящие соединения, proto - протокол (в данном случае UDP), server - пул IP-адресов, выделенный для виртуальной частной сети и автоматически распределяемый между клиентами, push - команда OpenVPN, передаваемая клиенту и выполняемая клиентом (в данном случае "route 10.0.0.0 255.255.255.0" добавляет на стороне клиента маршрут к виртуальной частной сети), route - добавляет на стороне сервера маршруты к локальным подсетям, находящимся за клиентами, client-config-dir - папка с файлами конфигурации клиентов, client-to-client - разрешение клиентам "видеть" друг друга (естественно, при наличии соответствующих правил маршрутизации), tls-server - включение поддержки TLS; dh - местонахождение файла параметров Диффи-Хэлмана, ca - местонахождение самоподписного доверенного сертификата (CA), cert - местонахождение сертификата сервера, key - местонахождение закрытого ключа сервера, crl-verify - местонахождение списка отзыва сертификатов, tls-auth - местонахождение статического ключа HMAC, comp-lzo - использование LZO-компрессии трафика, keeplive - поддержание соединения (в данном случае отправка пингов каждые 10 секунд, и закрытие соединения через две минуты после отсутствия ответных пакетов, как сервером, так и клиентами), tun-mtu и mssfix - параметры передачи данных по тоннелю, persist-tun - не закрывать / открывать по-новой tun-устройство при получении сигнала SIGUSR1 (перезапуск без привилегий root) или при выполнении ping-restarts, user и group - пользователь и группа, от имени которых работает OpenVPN после запуска (запуск выполняется под root'ом), verb - уровень детализации сообщений, выдаваемых OpenVPN в /var/log/messages.
Файлы конфигурации клиентов

Файлы конфигурации клиентов являются текстовыми файлами и содержат команды, выполняемые сервером при подключении клиентов. Имена файлов конфигурации клиентов должны соответствовать Common Name клиентов, т.е. при подключении клиента с Common Name client1 сервер выполнит команды, заданные в файле client1 и т.д. Файлы конфигурации клиентов должны находиться в папке /usr/local/etc/openvpn/ccd. Для рассматриваемого случая необходимо создать три файла конфигурации клиентов client1-client3:

cd /usr/local/etc/openvpn/ccd
touch client1 client2 client3


Файл client1 должен содержать две команды: добавляющую клиенту маршрут к локальной подсети центрального офиса, а также определяющую адрес локальной подсети, находящейся за клиентом:

push "route 192.168.0.0 255.255.255.0"
iroute 192.168.1.0 255.255.255.0


Файл client2 аналогичен файлу client1 за исключением адреса локальной подсети, находящейся за клиентом:

push "route 192.168.0.0 255.255.255.0"
iroute 192.168.2.0 255.255.255.0

Файл client3 должен содержать команды, добавляющие клиенту маршруты к локальным подсетям центрального офиса и обоих филиалов:

push "route 192.168.0.0 255.255.255.0"
push "route 192.168.1.0 255.255.255.0"
push "route 192.168.2.0 255.255.255.0"

Существуют и другие способы задания маршрутов, а также другие команды, которые могут присутствовать в файлах конфигурации клиентов. На этот счет лучше всего внимательно изучить OpenVPN Man Page и HOWTO.
Написано позже: в связи с часто повторяющимися вопросами добавил заметку Назначение статических IP-адресов клиентам OpenVPN.
Автоматический запуск сервера

Для автоматического запуска сервера OpenVPN при загрузке операционной системы необходимо добавить строку openvpn_enable="YES" в файл /etc/rc.conf.
Замечания по настройке брандмауэров

Для корректной работы сервера OpenVPN необходимо внести следующие изменения в настройки брандмауэра:
Разрешить прохождение любого трафика через интерфейс OpenVPN;
Разрешить прохождение UDP-трафика на внешний адрес сервера порт 1194;
Разрешить прохождение любого трафика из виртуальной частной сети в локальную подсеть;
Разрешить прохождение любого трафика из локальной подсети в виртуальную частную сеть;
Разрешить прохождение любого трафика из локальной подсети филиала № 1 в локальную подсеть;
Разрешить прохождение любого трафика из локальной подсети в локальную подсеть филиала № 1;
Разрешить прохождение любого трафика из локальной подсети филиала № 2 в локальную подсеть;
Разрешить прохождение любого трафика из локальной подсети в локальную подсеть филиала № 2.

Для ipfw (мой случай) нужно добавить следующие правила:

/sbin/ipfw -q add pass ip from any to any via ${vif}
/sbin/ipfw -q add pass udp from any to ${oip} 1194 in via ${oif}
/sbin/ipfw -q add pass ip from ${vnet} to ${inet} out via ${iif}
/sbin/ipfw -q add pass ip from ${inet} to ${vnet} in via ${iif}
/sbin/ipfw -q add pass ip from 192.168.1.0/24 to ${inet} out via ${iif}
/sbin/ipfw -q add pass ip from ${inet} to 192.168.1.0/24 in via ${iif}
/sbin/ipfw -q add pass ip from 192.168.2.0/24 to ${inet} out via ${iif}
/sbin/ipfw -q add pass ip from ${inet} to 192.168.2.0/24 in via ${iif}

Переменные shell имеют следующие значения: oip - внешний IP-адрес сервера, inet - адрес локальной подсети (в нашем случае - 192.168.0.0/24), vnet - адрес виртуальной частной сети (в нашем случае 10.0.0.0/24), iif - имя внутреннего интерфейса сервера (например, rl1), oif - имя внешнего интерфейса сервера (например, rl0), vif - имя интерфейса OpenVPN (например, tun0).
Настройка брандмауэров клиентов выполняется аналогично. Правила, начиная с пятого, зависят от реализованной политики маршрутизации. Для нашего случая правила ipfw для клиента client1 будут иметь вид (не забудьте, что теперь переменная shell inet определяет адрес локальной подсети клиента client1 - 192.168.1.0/24):

/sbin/ipfw -q add pass ip from any to any via ${vif}
/sbin/ipfw -q add pass udp from any to ${oip} 1194 in via ${oif}
/sbin/ipfw -q add pass ip from ${vnet} to ${inet} out via ${iif}
/sbin/ipfw -q add pass ip from ${inet} to ${vnet} in via ${iif}
/sbin/ipfw -q add pass ip from 192.168.0.0/24 to ${inet} out via ${iif}
/sbin/ipfw -q add pass ip from ${inet} to 192.168.0.0/24 in via ${iif}


Правила ipfw для клиента client2 не отличаются от правил для клиента client1 (не забудьте, что теперь переменная shell inet определяет адрес локальной подсети клиента client2 - 192.168.2.0/24).
Передача ключевых файлов клиенту

Для передачи файлов клиенту лучше использовать какой-либо твердый носитель, например дискету, но ни в коем случае не сеть Интернет. Чтобы скопировать файлы, необходимые клиенту Client, на дискету, нужно выполнить следующую последовательность команд:

mount -t msdos /dev/fd0 /mnt
cd /usr/local/etc/openvpn
cp certs/CClient.pem /mnt
cp keys/KClient.pem /mnt
cp CA_cert.pem /mnt
cp ta.key /mnt
umount /mnt

Данные команды монтируют дискету к папке /mnt, копируют сертификат клиента, закрытый ключ клиента, самоподписной доверенный сертификат (CA) и статический ключ HMAC на дискету, а затем размонтируют ее.
Клиентское программное обеспечение

Если клиент работает под FreeBSD, то установка клиента OpenVPN ничем не отличается от установки сервера (используется тот же самый порт), если под Windows, есть два варианта - OpenVPN и OpenVPN GUI. Первый вариант больше подходит для постоянно включенных серверов (OpenVPN может быть установлена как служба Windows), второй - для мобильных клиентов, периодически подключающихся к корпоративной сети. Например, я использую на домашнем ноутбуке OpenVPN GUI, когда мне нужно подключиться к корпоративной сети. Во всех перечисленных случаях файлы конфигурации имеют один и тот же формат. Внимание: в случае использовании Windows-клиентов не забывайте использовать в файлах конфигурации двойные бэкслэши вместо одинарных слэшей, используемых в файлах конфигурации Unix-клиентов.
Файл конфигурации клиентского программного обеспечения

Конфигурация клиента OpenVPN хранится в файле openvpn.conf, который должен находится в папке /usr/local/etc/openvpn, если мы имеем дело с FreeBSD-клиентом, или в файле с произвольным именем и расширением .ovpn, который должен находиться в папке C:Program FilesOpenVPNconfig, если при установке OpenVPN (OpenVPN GUI) не был задан путь, отличный от предлагаемого по умолчанию. Рассмотрим файл конфигурации клиента client3, установленного на ноутбук с Windows XP. Клиент OpenVPN GUI установлен в каталог по умолчанию, а ключевые файлы, которые ранее были переписаны на дискету, сохранены на диске P: в папке OpenVPN (я предпочитаю шифровать этот диск). Для рассматриваемого случая файл конфигурация клиента OpenVPN имеет следующий вид:


client
dev tun
proto udp
remote <IP-адрес сервера OpenVPN>
tls-client
tls-remote <FQDN сервера OpenVPN>
ca "P:\OpenVPN\CA_cert.pem"
cert "P:\OpenVPN\Ссlient3.pem"
key "P:\OpenVPN\Kсlient3.pem"
tls-auth "P:\OpenVPN\ta.key" 1
ns-cert-type server
comp-lzo
tun-mtu 1500
mssfix 1450
verb 3


В данном файле заданы следующие значения параметров клиента OpenVPN: client - упрощенный вариант указания того, что это файл конфигурации клиента, dev - устройство OpenVPN, proto - протокол (в данном случае UDP), remote - IP-адрес сервера OpenVPN, tls-client - включение поддержки TLS, tls-remote - Common Name сервера OpenVPN, ca - местонахождение самоподписного доверенного сертификата (CA), cert - местонахождение сертификата клиента, key - местонахождение закрытого ключа клиента, tls-auth - местонахождение статического ключа HMAC, comp-lzo, tun-mtu, mssfix и verb рассмотрены выше. Повторяю, файлы конфигурации FreeBSD-клиентов отличаются только форматом задания путей к файлам.
Заключение

С помощью описанной виртуальной частной сети ежедневно осуществляется работа как со службами Windows (Remote Administrator и Terminal Services), так и со службами Unix (FTP, NFS, SSH и Telnet). Если в процессе настройки у Вас возникнут проблемы, внимательно анализируйте лог-файлы и читайте обсуждение cтатьи на форуме OpenNET. Если ничего не помогает, задавайте мне вопросы, попробуем решить проблему вместе.

http://www.sergeysl.ru/freebsd-openvpn-x509/

Обновлено: 12.03.2015