Развёртывание сети OpenVPN

Описание развёртывания OpenVPN сети, начиная с организации Центра Сертификации, выпуска ключей и сертификатов, и заканчивая установкой OpenVPN серверов и клиентов.

2020-03-31

Статья в процессе написания!

Я перерабатываю свою статью от 2014 года в соответствии с новыми стандартами и релизами OpenVPN.

Если лень много читать и хочется сразу запустить простую OpenVPN-сеть, то переходите к статье OpenVPN — это просто.

Reference manual for OpenVPN 2.4

Рекомендую полезную книгу для понимания симметричного, ассиметричного шифрования и много другого по этой темы: Саймон Сингх. Книга шифров: Тайная история шифров и их расшифровки

Что такое Закрытый Ключ, Открытый Ключ, Запрос На Сертификацию, Сертификат Открытого Ключа

Перевод Easy-RSA 3 Quickstart README

Введение

Изначально OpenVPN был разработан by James Yonan.

Описание из референс мануала

OpenVPN надёжный и чрезвычайно гибкий VPN демон. OpenVPN поддерживает SSL/TLS безопасность, ethernet-мосты, TCP или UDP транспортные туннели сквозь прокси или NAT, имеет поддержку собственного динамического назначения IP-адресов или через DHCP, масштабируется до сотен или тысяч подключений, и портирован на большинство из основных операционных систем.

OpenVPN тесно связан с OpenSSL библиотекой и наследует из неё множество криптографических возможностей.

OpenVPN поддерживает как обычное шифрование с использованием единственного секретного ключа (Static Key mode), так и шифрование на основе открытых ключей (SSL/TSL режим), с использованием клиентских и серверных сертификатов. OpenVPN поддерживает также и незашифрованные TCP/UDP туннели.

OpenVPN разработан для работы с TUN/TAP виртуальными сетевыми интерфейсами, которые доступны на большинстве платформ.

Overall, OpenVPN aims to offer many of the key features of IPSec but with a relatively lightweight footprint. (В общем, OpenVPN стремится предложить многое из ключевых функций IPSec, но с относительно lightweight footprint).

Краткое описание из моего личного опыта

OpenVPN — замечательный пакет, позволяющий прокинуть зашифрованный туннель к серверу из самых неудобных мест.

На мой взгляд, для шифрования трафика между серверами, находящимися в одном или различных дата-центрах, удобней использовать IPsec over IPv6.

Многих пугает создание сертификатов для работы OpenVPN, хотя эта часть налаживания работы OpenVPN до невозможности элементарна, благодаря проекту Easy-RSA.

Здесь я буду описывать настройку OpenVPN-сети на основе шифрования с открытыми ключами в том варианте, когда каждому серверу и клиенту выпускается уникальный сертификат с ограничением срока действия.

Описание работы

В описываемом варианте openvpn работает по схеме шифрования с открытыми ключами. Каждый участник openvpn-сети имеет закрытый (private) и, соответствующий ему, открытый (public) ключ-сертификат. Открытый ключ часто можно найти в файле-сертификате с расширением .crt, а закрытый (private) ключ обычно лежит в файле с расширением .key. Но сейчас я нередко использую способ, когда ключи описаны прямо в файле конфигурации.

Очень упрощённо схему работы OpenVPN можно описать так:
- Сначала сервер и клиент обмениваются своими публичными ключами. Кстати, они несекретны и могут храниться открыто.
- Потом обеими сторонами проводится проверка полученных ключей на предмет легитимности, то есть: срок действия, проверка подписи CA, проверка в списке отозванных ключей и т.д.
- Если стороны договорились, то начинается обмен данными:

  1. отправитель зашифровывает отправляемый пакет с помощью открытого ключа получателя;
  2. отправитель подписывает своим закрытым ключом зашифрованный пакет;
  3. пакет отправляется получателю;
  4. получатель проверяет подпись у полученного пакета с помощью открытого ключа отправителя;
  5. получатель расшифровывает пакет с помощью своего закрытого ключа, если подпись верна.

Третья сторона, имея на руках закрытые ключи обеих сторон, может вычислить из них соответствующие открытые ключи, и на лету просматривать закриптованный трафик. Именно поэтому закрытый ключ чрезвычайно секретен и при подозрении на его кражу, должен быть отозван, то есть запрещён к приёму в OpenVPN-сети. Процедура отзыва описана ниже.

Важной частью OpenVPN-сети является Центр Сертификации. Центр Сертификации Easy-RSA, который будет описан в этой статье, представляет собой самый обычный каталог с файлами, в котором лежат скрипты и, выпускаемые ими, файлы ключей и сертификатов.

В идеальной конфигурации, для организации Центра Сертификации, необходимо иметь отдельный сервер, максимально защищённый от вторжений/не подключённый к интернету. Доступ к нему предоставлен ограниченному числу лиц, операторов CA.

В моём случае нецелесообразно организовывать отдельный CA-сервер для редких генераций сертификатов и ключей новых openvpn-серверов и клиентов. Поэтому папку центра сертификации я храню в секретном месте и, по мере необходимости, раскрываю криптоконтейнер на свободной надёжной машине, чтобы произвести необходимые процедуры.

Технические детали

При поднятии OpenVPN-сервиса на машине, не важно, будет ли это сервер или клиент, список сетевых интерфейсов дополнится виртуальным сетевым дивайсом tun. Ему будет назначен частный ip-адрес в соответствии с параметрами, заданными в файле конфигурации (например, "192.168.2.1/24").

lo
enp2s0
enp2s1
tun0 192.168.2.1/24

Именно через этот сетевой интерфейс будет проходить локальный незашифрованный трафик, и прослушивая его tcpdump'ом мы увидим привычные пакеты, например icmp request/echo, с номерами частных ip-адресов в полях источника и назначения. Одновременно с этим, прослушивая соответствующий физический интерфейс, мы увидим пакеты с internet ip-адресами в заголовке, но с криптомешаниной в поле для данных, в каковом поле находится инкапсулированный icmp-пакет, который мы и наблюдаем на устройстве tun. Естественно, что из-за инкапсуляции размер MTU уменьшен, поэтому не забываем обеспечивать клиенту посылку Path MTU Discovery к требуемому серверу с помощью соответствующих правил внутри туннеля и вне его.

Максимальное количество устройств tun равняется 1024, судя по linux/tun.c. То есть, если специально не указывать в конфигурационных файлах номер tun (tun0...tun1023), то для следующего запускаемого виртуального интерфейса, будет назначен порядковый незанятый номер, начиная с tun0. В правилах iptables, для выборки всех tun-devices, надлежит использовать параметр tun+ (iptables -A INPUT -i tun+ -j REJECT).

Использование отдельного сетевого устройства tun позволяет ограничивать трафик между локальными узлами простыми правилами iptables, задаваемыми для интерфейса tun. Например, iptables -A INPUT -i tun1 -p icmp --icmp-type echo-request -j ACCEPT -m conntrack --ctstate NEW разрешит пинг хоста по его частному ip-адресу. Опять напомню для тех, кто фильтрует ICMP о Path MTU Discovery и прочее связанное с этим.

Описание сетевого протокола OpenVPN

OpenVPN's network protocol. Из описания понятно, что обмен информацией происходит по двум каналам, один из которых для управления, а другой для передачи данных. То есть датаграмма может содержать два типа полезной нагрузки (payload): либо управляющую информацию, либо передаваемые данные.

Измененения по сравнению со статьёй 2014 года

Вместо долгой, иногда многоминутной, генерации dh-параметра для каждого сервера, теперь используется ecdh-curve, который не требует статичного файла. Новая опция самостоятельно и, благодаря курвам, быстро генерирует необходимую информацию, и видимо, каждый раз новую, при запуске openvpn.

Для шифрования выбирается современный AEAD-шифр AES-256-GCM, который обеспечивает не только конфиденциальность, но и целостность информации.

Относительно новая опция topology subnet, в отличии от старых net30 и p2p, позволяет эффективней раздавать ip-адреса из пула. Один клиент — один адрес.

FAQ

Почему в этой статье описано использование в OpenVPN tun-интерфейса (работает на третьем уровне OSI)?
Потому что tap-интерфейс, работающий на втором уровне OSI, за многие годы использования OpenVPN, мне ни разу для него не понадобился. Естественно, если, например, нужен мост, то необходимо использовать tap-интерфейс.

Почему выбран UDP для туннеля?
UDP-протокол обеспечивает лучшую защиту для DoS-атак и сканирования портов, чем TCP-протокол. К тому же, внутри UDP-туннеля будут ходить TCP-пакеты, а значит, в случае потери одного внутреннего TCP-пакета, автоматически будет инициирована отправка нового UDP-пакета, содержащего отсутствующий внутренний TCP-пакет. При использовании же TCP-туннеля, в вышеописанном случае, произойдёт избыточная повторная отправка двух пакетов:
- копия потерянного внешнего туннельного TCP-пакета;
- новый туннельный TCP-пакет, содержащий потерянный внутренний TCP-пакет.

В каких случаях выбирать proto tcp?
В некоторых сетях можно встретить запрет на хождение UDP. Или для маскировки под трафик https на 443 порт. Также Mikrotik до сих пор не имеет поддержки udp для OVPN.

Развёртывание сети OpenVPN

Мне кажется, я подобрал правильную последовательность действий для развёртывания сети. Сначала, на подходящем компьютере, создадим Центр Сертификации и выпустим необходимое количество ключей и сертификатов для серверов и клиентов. Потом займёмся установкой программного обеспечения и проверкой работы.

Создание CA, выпуск ключей и сертификатов

Центр Сертификации звучит очень сложно. На самом деле никакого дополнительного софта компилировать и собирать не надо. Создадим все необходимые для работы OpenVPN-сети файлы с помощью скриптиков из пакета Easy-RSA. Будет достаточно разместить EasyRSA в отдельной папке в домашнем каталоге, или, например, на флэшке. В самом крайнем случае, если нет нужды в постоянной или эпизодической работе по созданию новых ключей и сертификатов, то можно всё проделать прямо на OpenVPN-сервере, не забыв, после, надёжно удалить каталог.

Для создания ключей и сертификатов достаточно прав обычного пользователя.

1. Клонирование easy-rsa

В выделенном для CA каталоге клонируем текущую мастер-ветку Easy-RSA и подготавливаем файл с переменными vars, изменяющими настройки генерации ключей по умолчанию:

git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3
cp vars.example vars

2. Установка переменных vars

Данный файл, как понятно из его названия, содержит переменные, которые достаточно установить один раз.

Редактируем файл vars для усиления криптографии создаваемых сертификатов.

На мой взгляд шифрование на основе эллиптических кривых отвечает современным веяниям. Оно быстрее классических при, примерно, такой же надёжности. Поэтому и здесь выбран EASYRSA_ALGO ec, плюс обязательное уточнение протокола EASYRSA_CURVE secp384r1.

Усилим хэш-функцию EASYRSA_DIGEST "sha512", используемую для проверки сертификата на целостность.

Срок действия сертификата ЦА равняется десяти годам, что более чем достаточно. Иначе можно применить в настройках сервера опцию для добавления нового сертификата CA до истечения срока действия текущего сертификата.

По умолчанию срок действия выданных сертификатов 825 дней, то есть два года и три месяца. Раньше было 720 дней,

3. Первичная инициализация PKI

Первоначальная инициализация PKI:

$ ./easyrsa init-pki

4. Создание секретного ключа и сертификата Центра Сертификации

Будем использовать секретный ключ, защищённый паролем. Это означает, что при каждом подписывании новых сертификатов, потребуется вводить пароль.

$ ./easyrsa build-ca

В случае, если кража ключей CA с последующим несанкционированным выпуском ключей не принципиальна, то существует способ отказаться от установки пароля на секретный ключ CA:

$ ./easyrsa build-ca nopass

5. Разделяемый секрет ta.key

Будет удобно здесь же создать разделяемый секрет, использующийся и серверами, и клиентами. Все участники сети обязаны иметь одинаковый ta.key.

Ключ из файла ta.key используется в директиве --tls-crypt для шифрования и аутентификации всех пакетов канала управления. Это усилит безопасность сокрытием сертификатов, используемых для TLS соединения. Также усложняется идентификация трафика, как принадлежащего OpenVPN. Provides “poor-man’s” post-quantum security, against attackers who will never know the pre-shared key (i.e. no forward secrecy).

Новая опция --tls-crypt не требует использования --key-direction, в отличии от --tls-auth с обязательным указанием направления.

Если следовать мануалу OpenVPN, то разделяемый секрет правильно генерировать командой:

openvpn --genkey --secret pki/ta.key

Если же пакет openvpn не установлен, то я, на скорую руку, подобрал менее безопасный способ:

echo '-----BEGIN OpenVPN Static key V1-----' > pki/ta.key; \
head -c 256 /dev/urandom | hexdump -e '16/1 "%02x" "\n"' >> pki/ta.key; \
echo '-----END OpenVPN Static key V1-----' >> pki/ta.key

Во втором, небезопасном способе, отсутствует возможность проконтролировать качество секрета, но, как мне кажется, вероятность отсутствия приемлемой информации в /dev/urandom исчезающе мала. Если есть подозрения, то стоит заглянуть в файл ta.key и убедиться, что в нём наблюдается мешанина подобная этой:

-----BEGIN OpenVPN Static key V1-----
5c39a91bc38d7fb094f7539ac0e8bcf8
489408ec8206387c2b8e430c8ceb7219
56f1f083edc774d2388347d8648aecdf
91b6d0b6e55156b678c4f4cd1248eab5
8567796acbd170862848e827ebefca98
111efc575d61dfe67e1bed7cc1c61675
af5e5fd6b4684b07b3f6ee6578a35807
0e60f568698d0988c8c0f3ebbec6932f
1c95b4c52ace5ac21992ab22b63fc587
da3ce8f3845dd08f75ab603d65d02e4d
2e58aa24815dd2ddf73ebe7e4fb435c7
0d498a9a126cad36d0b3ea2a1812ba64
471bd745acba7b698bde5b2a43c2de76
84793548b1520379051b720af685a577
c1be42ab32b428f4661414a7d73527d3
a262b611478c658828f6f18bf8833e09
-----END OpenVPN Static key V1-----

Для очистки совести можно проверить openvpn --test-crypto --secret ta.key или openvpn --test-crypto --secret ta.key --verb9, но эта проверка даст плохой результат только при наличии одних нулей в файле ta.key.

Что дальше

Переходим к созданию файлов конфигураций, ключей и сертификатов. Имена для новых сертификатов выбираем произвольные. Совпадение с именем хоста не обязательно. Для серверного сертификата выберем имя srv1 и т.д., а для клиентского сертификата cln1 и т.д.

Невозможно выпустить несколько сертификатов под одним именем. Вместо выпуска нового сертификата, необходимо за 30 дней (переменная EASYRSA_CERT_RENEW в vars) до окончания срока действия сертификата, произвести перевыпуск сертификата. В этом случае будет сгенерирован новый приватный ключ и новый сертификат для этого ключа. Старые сертификаты не попадут в отозванные, так как необходимо успеть заменить ключ и сертификат на сервере до окончания срока действия предыдущего сертификата.

Создание файла конфигурации для OpenVPN-сервера

Разжёвывание

В идеале, как указано в Перевод Easy-RSA 3 Quickstart README, создание ключей и их сертификация производится в несколько этапов и на разных компьютерах. Но здесь мы сократим эти этапы (генерирование секретного ключа и создание запроса на сертификат на одной системе, сертификация открытого ключа на другой) до одной команды easyrsa build-server-full nopass inline. Опция nopass позволяет сгенерировать беспарольный приватный ключ, что удобно для использования на серверах. Опция inline подготовит единственный файл .creds со встроенными ключами и сертификатами для удобного добавления к файлу конфигурации.

Подготовим отдельный скрипт для генерирования единственного файла .conf, содержащего почти всё необходимое.

В скрипте, к имени файла ключа и сертификата будет добавляться дата истечения их срока действия. Естественно, термин "срок действия" касается только сертификата, но мне показалось удобным и к ключу добавить эту информацию. В принципе нет необходимости менять приватный ключ, если только он не был скомпрометирован, тогда как есть команда easyrsa renew для перевыпуска нового сертификата на основе старого приватного ключа.

!!! Нет необходимости хранить в Центре Сертификации приватные ключи. Даже неприемлимо. Достаточно хранить только сертификаты по той причине, что они могут понадобиться при процедуре отзыва скомпрометированных ключей. В случае отсутствия копии сертификата, который необходимо добавить в список отозванных, есть способ отловить его во время подключения. Но я не помню как это делается.

!!! Вывод: в папку kits достаточно кидать единственный файл srv1.conf со всем необходимым внутри. Добавить затирание приватного ключа shred -u pki/private/srv1.key. По той причине, что необходимо удалять приватные ключи и другие файлы, их содержащие, то лучше использовать нежурналируемую файловую систему.

Минимально необходимый конфигурационный файл для сервера имеет вид (знак "точка с запятой" в начале строки отмечает неактивную опцию):

;local #.#.#.#
;multihome

dev tun
;dev tun200
port 9216
proto udp

server 10.0.0.1 255.255.255.0
;server 192.168.200.0 255.255.255.0
topology subnet
;push "redirect-gateway def1 bypass-dhcp"
;push "dhcp-option DNS 1.1.1.1"
client-config-dir ccd

cipher AES-256-GCM
ecdh-curve secp384r1
dh none
;compress lz4
keepalive 10 60

max-clients 252
float
;tun-mtu 1300
;fragment 1300
;mssfix

chroot jail
user nobody
group nogroup
persist-key
persist-tun

status-version 2
;verb 3
mute 20

Необходимо дополнить файл конфигурации индивидуальными строками:

;ifconfig-pool-persist srv1-ipp.txt
status srv1-status.log
log srv1.log

Плюс встроить в файл конфигурации ключи и сертификаты из файла .creds:

<cert>
-----BEGIN CERTIFICATE-----
MIICHzCCAaWgAwIBAgIQWz71AIR7P0KwleHrcT9cfzAKBggqhkjOPQQDBDATMREw
................................................................
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCzHouw2FY0pAes3l9h
................................................................
-----END PRIVATE KEY-----
</key>
<ca>
-----BEGIN CERTIFICATE-----
MIIB3DCCAWKgAwIBAgIJAMgvGpBBFuF9MAoGCCqGSM49BAMEMBMxETAPBgNVBAMM
................................................................
-----END CERTIFICATE-----
</ca>
<tls-crypt>
-----BEGIN OpenVPN Static key V1-----
d87c829b654879b7cd16469089354840
................................
-----END OpenVPN Static key V1-----
</tls-crypt>

Цимес

<!--
Для автоматизации всего вышеуказанного, в каталоге с файлом ./easyrsa, создадим скрипт newsrv.sh:

#!/bin/bash
# Example for use: ./gensrv.sh srv1
SRVNAME=$1
FILECONF=${SRVNAME}.conf

# Computing a expire date of certificate.
EXPDATECERT=${SRVNAME}"-"$(date -u +%Y%m%d \
-d "+$(grep '^set_var EASYRSA_CERT_EXPIRE' vars \
|awk '{print $3}') days")-$(date -u +%H%M)

# Making needed keys and certificates.
./easyrsa build-server-full ${SRVNAME} nopass inline

# Adding the 'ta.key' to the file '.creds'.
echo '<tls-crypt>' >> pki/${SRVNAME}.creds
cat pki/ta.key >> pki/${SRVNAME}.creds
echo '</tls-crypt>' >> pki/${SRVNAME}.creds
# Now in file '.creds' are all needed keys and certificates.

# Preparing '.conf'


# Renaming 'srv1.crt' to 'srv1-20220322-1232.crt' for convenient use.
# Revoke производится по номеру сертификата и имени.
# mv pki/issued/${SRVNAME}.crt pki/issued/${SRVNAME}-${EXPDATECERT}.crt

# Shredding all the private files and unneeded the `request file`.
shred -u pki/${SRVNAME}.creds
shred -u pki/private/${SRVNAME}.key
shred -u pki/reqs/${SRVNAME}.req

-->

Разъяснение некоторых опций

local

При наличии нескольких сетевых интерфейсов, этот параметр позволит указать тот интерфейс, на котором openvpn должен принимать запросы.

multihome

Эту опцию необходимо активировать в случае присутствия на сервере нескольких сетевых интерфейсов и отсутствующего параметра local. Так как openvpn будет слушать все интерфейсы, то есть вероятность, что клиент будет получать ответ от сервера с другого ip-адреса, что не позволит установить коннект. Эта опция заставит openvpn отправлять пакеты с того интерфейса, на который они пришли.

server 192.168.200.0 255.255.255.0

Использование этой опции автоматически применит следующие опции:
mode server
tls-server

topology subnet

В отличии от устаревших net30 и p2p, эта опция, в сочетании с вышеуказанными в конфиге dev tun200 и server 192.168.200.0 255.255.255.0:
- на сервере сетевому интерфейсу tun200 назначается ip-адрес 192.168.200.1/24
- клиентам раздаются ip-адреса из пула 192.168.200.2/24 – 192.168.200.253/24
- клиентам, командой push "route-gateway 192.168.200.1", проталкивает маршрут к шлюзу 192.168.200.1.

client-config-dir ccd

Опция полезна в тех случаях, когда определённый клиент является шлюзом в какие-либо сети. В каталоге /etc/openvpn/ccd размещаются файлы (имя файла = CommonName клиента) для описания сетей за клиентами. В файле описывается маршрут iroute 192.168.0.0 255.255.254.0, который доступен через подключившегося клиента. В этом же файле могут указываться индивидуальные push "route ... отправляемые клиенту, в дополнение к общим, указываемых в серверном файле .conf. Также нельзя забыть указать уже в серверном файле .conf такой же маршрут от клиента, но строкой route 192.168.0.0 255.255.254.0 192.168.200.1 0.

ecdh-curve secp384r1

Опция используется для создания Diffie Hellman параметра, необходимого для первичного безопасного обмена ключами. Ранее использовалась опция dh file.pem, для которого приходилось выполнять ресурсоёмкую и долгую процедуру по генерированию параметра, например для 2048 бита, командой openssl dhparam -out dh2048.pem 2048.

keepalive 10 60

Если применяется на сервере, то эта опция на клиенте (если таковая присутствует) будет заменена посылкой push "ping 10" и push "ping-restart 60". Сервер сбросит соединение, если клиент перестанет отвечать. Клиент за NAT'ом периодически посылая пакеты, поддерживает связь с сервером, что не позволит NAT'у преждевременно сбросить соединение. На мобильных аппаратах не всегда полезна для заряда батареи.

Создание файла конфигурации для OpenVPN-клиента

Аналогично серверному easyrsa build-server-full, для клиента используем easyrsa build-client-full, чтобы одной командой пройти путь от генерации ключа с созданием запроса на сертификацию, до выпуска сертификата.