Настраиваем корпоративный VPNПоявился у меня небольшой набор VPS, на которых уже стоит различное ПО для хранения данных. Для всего этого нужно настраивать защищенное соединение. Из прошлой статьи про настройку VPS мы узнали что на наши машины постоянно кто-то ломится, а это заставляет еще раз подумать о безопасности сетевого контура.
Каждое ПО предоставляет свои средства настройки шифрования данных, но есть другой путь - объединить все VPS в единую приватную сеть (VPN) и закрыть доступ из сети Интернет. Таким образом весь трафик во внутренней сети будет шифроваться, а в эту сеть можно попасть только будучи клиентом VPN, но чтобы им стать нужно получить соотвествующий сертификат.
Центр Сертификации (
ЦС)/Certification Authority (CA) - выдает подписанные сертификаты для сервера и клиентов сетиVPN.
Сервер OpenVPN - ПО организующее безопасный туннель внутри небезопасной сети Интернет.
Клиент OpenVPN - узел в сети
VPN, использующий безопасный туннель для взаимодействия с другими клиентами.
Сервер и клиенты OpenVPN - генерирует файл запрос на сертификат (.req), и вместе с ним генерирует приватный ключ (.key):


Файлы:
.crt) - заверенны ЦС, позволяют идентифицировать узел, используются для шифрования трафика.key) - используются для расшифровки трафикаta.key) - элемент механизма проверки целостности информации, гарантии того что информация в ненадежной среде не была измененаПриватные ключи никогда не должны покидать узлы, на которых генерируются. Обмениваться можно только запросами на сертфиикаты и сертификатами.
Некоторые руководства по настройке
VPNрекомендуют размещатьЦСи сервер OpenVPN на разных серверах. Это другое руководство, здесь мы будем использовать один и тот же сервер.
Нам нужно следующее ПО:
PKI)VPN$ sudo apt install openvpn easy-rsa
Необходимо завести отдельного пользователя для работы с ЦС и дать ему sudo:
$ sudo adduser username
$ sudo usermod -aG sudo username
Переключаемся на нашего нового пользовтаеля:
$ sudo su byurrer
Создаем директорию, в которой будем вести работу с ЦС, создаем симлинки на easy-rsa и ограничиваем права доступа:
$ mkdir ~/easy-rsa
$ ln -s /usr/share/easy-rsa/* ~/easy-rsa/
$ chmod 700 ~/easy-rsa
Задаем параметры криптографии (эллиптические кривые, Elliptic Curve Cryptography, ECC), создаем файл vars:
$ nano vars
И записываем следующее:
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
Другие возможные параметры можно посмотреть в var.example.
Сроки по умолчанию:
ЦС - 10 летИнициализируем PKI и создаем ЦС:
$ ./easyrsa init-pki
# будет предложено ввести пароль, рекомендуется
# будет сгенерирован ca.crt
$ ./easyrsa build-ca
Сгенерируем запрос создания ключа доступа для сервера OpenVPN (без пароля) и подписываем:
$ ./easyrsa gen-req server nopass
$ ./easyrsa sign-req server server
Нужно будет подтвердить что ключ из доверенного источника, а также ввести пароль если закрытый ключ ЦС зашифрован паролем.
Создаем общий секретный ключ tls_crypt для дополнительной безопасности:
$ openvpn --genkey --secret ta.key
Первоначальные работы с ЦС законены, теперь мы имеем:
server.crt - подписанный открытый ключ сервера OpenVPNserver.key - закрытый ключ сервера OpenVPNca.crt - открытый ключ ЦСta.key - общий секретный ключ (HMAC)Перемещаем все это в директорию /etc/openvpn/server:
$ sudo cp pki/issued/server.crt /etc/openvpn/server
$ sudo cp pki/private/server.key /etc/openvpn/server
$ sudo cp pki/ca.crt /etc/openvpn/server
$ sudo cp ta.key /etc/openvpn/server
Берем пример конфига для сервера OpenVPN:
$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/server/
$ sudo gunzip /etc/openvpn/server/server.conf.gz
$ sudo nano /etc/openvpn/server/server.conf
Теперь поочередено вносим в него правки.
Включаем HMAC firewall:
tls-crypt ta.key
Устанавливаем более надежный уровень шифрования:
cipher AES-256-GCM
auth SHA256
Судя по всему при использовании эллиптических кривых, ключ Диффи — Хеллмана не нужен, убираем:
dh none
Разрешаем клиентам соединяться друг с другом:
client-to-client
В нашей VPN каждый клиент должен иметь статический IP адрес, который мы будем задавать самостоятельно, для этого будем использовать CCD (Client Config Dir):
# указание диретории конфигов подключаемых клиентов и шлюз
client-config-dir ccd
route 10.8.0.0 255.255.255.0
И запуск OpenVPN без привелегий:
user nobody
group nogroup
Теперь нужно включить IP forwarding чтобы сервер VPN мог выполнять свои функции - перенаправлять трафик через сеть VPN:
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo systemctl -f enable openvpn-server@server.service
$ sudo systemctl start openvpn-server@server.service
$ sudo systemctl status openvpn-server@server.service
Если сервер OpenVPN не запускается, тогда нужно смотреть журнал и выяснять в чем дело:
sudo journalctl -xe
Все действия по выдаче доступа нашим клиентам будут осуществляться на сервере OpenVPN (там же где
ЦС). Здесь же генерация файла запроса, приватного ключа и выдача подписанного сертификата. Клиенты будут получать один готовый.ovpnфайл, что весьма удобно.
Создаем директорию для хранения клиентских собранных конфигураций для подключения к нашей VPN:
$ mkdir -p ~/client-configs/files
$ chmod -R 700 ~/client-configs
Копируем пример конфига клиента OpenVPN:
$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
$ nano ~/client-configs/base.conf
В этом базовом конфиге нужно:
# указать публичный ip адрес сервера OpenVPN
remote your_server_ip 1194
# запуск без привелегий
user nobody
group nogroup
# ta.key встроим в сам конфиг, поэтому здесь отключим
;tls-auth ta.key 1
# более надежное шифрование
cipher AES-256-GCM
auth SHA256
# направление ключа
key-direction 1
Создадим скрипт сборки конфига клиента .ovpn:
$ nano make_config.sh
Вставим следущий код:
#!/bin/bash
CA_DIR=~/easy-rsa/pki
KEY_DIR=~/easy-rsa/pki/issued
PRIVATE_DIR=~/easy-rsa/pki/private
PRIVATE_OVPN_DIR=/etc/openvpn/server
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${CA_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${PRIVATE_DIR}/${1}.key \
<(echo -e '</key>\n<tls-crypt>') \
${PRIVATE_OVPN_DIR}/ta.key \
<(echo -e '</tls-crypt>') \
> ${OUTPUT_DIR}/${1}.ovpn
Ограничим доступ к этому скрипту:
$ chmod 700 ~/client-configs/make_config.sh
Сгенерируем запрос на сертификат, приватный ключ и подпишем сертификат:
$ ./easyrsa gen-req client_name nopass
$ ./easyrsa sign-req client client_name
Инфомрацию о сертификате можно получить так:
$ ./easyrsa client_name
Укажем желаемый статический IP клиента (10.8.0.2) и адрес шлюза/сервера OpenVPN (10.8.0.1) конфиг в CCD:
$ sudo echo "ifconfig-push 10.8.0.2 10.8.0.1" > /etc/openvpn/server/ccd/client_name
Теперь соберем клиентский конфиг .ovpn:
./make_config.sh client_name
Если наш клиент это другой сервер, тогда размещаем конфиг полученный на предыдущем шаге по пути /etc/openvpn/client/client_name.conf а запускаем демон OpenVPN:
$ sudo systemctl -f enable openvpn-client@client_name.service
$ sudo systemctl start openvpn-client@client_name.service
Смотрим статус, если демон запущен значит узел подключился к VPN:
$ sudo systemctl start openvpn-client@client_name.service
Проверим список доступных интерфейсов, должен появиться tun:
$ ip -br a
byurrer@byurrer-S15C:~$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
enp3s0 DOWN
tun0 UNKNOWN 10.8.0.130 peer 10.8.0.1/32 fe80::5ac:b84d:b2a6:6cd3/64
Если клиент на Ubuntu Desktop, тогда можно все сделать через удобный графический интерфейс. Заходим в Настроки - Сеть нажимаем + возле VPN, затем Импортировать из файла:

Чтобы ходить в Интернет не через VPN, а через внешнюю сеть, надо зайти в настройки этого VPN на вкладку IPv4 и включить Использовать это подключение только для ресурсов в этой сети:

Нам нужно чтобы из внешнего мира нельзя было достучаться до наших VPS, но только через VPN. Иными словами только клиент VPN должен иметь возможность соединяться с другими клиентами сети. Это можно сделать при помощи фаервола, например iptables.
Изолируя
VPSот внешнего мира при помощиVPNмы можем расслабитсья и не думать проTLSвнутри сети.
Посмотрим список доступных сетевых интерфейсов:
$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
ens3 UP 185.105.90.67/24 2a09:5302:ffff::da2/48 fe80::5054:ff:fe10:233f/64
Здесь:
lo - localhostens3 - доступ к внешней сетиЕсли на VPS есть Docker, тогда могут быть интерфейсы с префиксами br и veth, а также bridge интерфейс docker0.
Еще полезно знать список открытых портов, чтобы после настройки фаервола проверить их доступность извне.
Для начала, будем думать что нам запрещено все, а теперь открываем то, что нам нужно.
Документация подсказывает что нужно разрешить весь входящий udp трафик на 1194 порту:
$ sudo iptables -A INPUT -p udp --dport 1194 -j ACCEPT
И разрешить входящий трафик из tun интерфейсов (это и есть трафик VPN адресованный локальной машине):
$ sudo iptables -A INPUT -i tun+ -j ACCEPT
Теперь нужно разрешить доступ к локальному резолверу, иначе будут задержки при подключении к ssh:
$ sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
Разрешим весь исходящий трафик от localhost (если этого не сделать, то иногда, исходящий трафик с localhost будет отклонятся и могут быть проблемы с nginx при проксировании на localhost, странно, но вот так):
$ sudo iptables -A INPUT -i lo -j ACCEPT
Если у нас на VPS есть Docker, тогда надо разрешить исходящие пакеты с br+ интерфейсов:
$ sudo iptables -A INPUT -i br+ -j ACCEPT
Как мы помним из предыдущей статьи про iptables, выше мы разрешили только установить соединение, но не продолжить, поэтому разрешаем продолжать то, что уже начато:
$ sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
Теперь установим политику по умолчанию DROP - отбрасывать все что явно не разрешено:
$ sudo iptables -P INPUT DROP
Трафик внутри нашего кластера VPS будет ходить не только по tun интерфейсам, могут быть запросы с tun на другие интерфейсы, поэтому нужно разрешить весь перенаправляемый трафик:
$ sudo iptables -A FORWARD -i tun+ -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
Если на VPS есть Docker, и его сетевые интерфейсы не должны быть доступны снаружи (даже при пробросе портов), но сами контейнеры должны уметь ходить в интернет, тогда:
# запрещаем новые входящие соединения из интерфейса, который смотрит наружу
$ sudo iptables -A FORWARD -i ens+ -o br+ -m state --state NEW -j DROP
# разрешаем все соединения, которые установленные и относящиеся к установленным соединениям
# таковыми будут те, в которых контейнер отправлет запрос в Интернет и получает ответ
$ sudo iptables -A FORWARD -i ens+ -o br+ -m state --state RELATED,ESTABLISHED -j ACCEPT
Теперь установим политику по умолчанию DROP - отбрасывать все что явно не разрешено:
$ sudo iptables -P FORWARD DROP
В некоторой части эта статья основана на других статьях из интернетов, например очень помогла статья на digitalocean и эта на habr, иногда смотрел на эту статью, а с ccd помогла эта статья. Вначале изучаения читал эту статью, возможно что-то из нее тоже перенял.