lan0: локальная сеть глобального масштаба
Предыстория
У нас есть группы серверов, расположенные в разных датацентрах и даже городах. На текущий момент используются 6 датацентров. Между бОльшей частью этих серверов идёт интенсивный обмен трафиком и не всегда по безопасным протоколам. В связи с этим было решено создать общую «локальную» сеть между всеми имеющимися серверами. Имеющийся опыт построения сетей при помощи OpenVPN с использованием маршрутизации подсказывал, что это далеко не самое лучшее решение. Идеальной была бы одноранговая сеть. Решение оказалось не таким уж и сложным и далеко не новым. Будем использовать OpenVPN и Bridge-utils.
Классическая сеть на OpenVPN предполагает наличие одного (или нескольких) собственно серверов с OpenVPN и клиентов, которые к нему подключаются. Не секрет, что OpenVPN поддерживает tcp и udp соединения. Поскольку у нас выделенные серверы без какой-либо неконтролируемой фильтрации трафика, то выбираем udp вариант, тем более, что он имеет меньшие задержки в передаче данных.
Первый сервер
Первый сервер (фактически это наша точка обмена трафиком) настраиваем по классической схеме. На большинстве серверов установлен Debian, поэтому всё описание имеет лёгкий уклон в сторону его особенностей.
aptitude install openvpn openvpn-blacklist
cd /etc/openvpn/
cp -R /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/easy-rsa
mkdir /etc/openvpn/keys
chmod 750 /etc/openvpn/keys
Правим /etc/openvpn/easy-rsa/vars следующим образом:
export EASY_RSA="/etc/openvpn/easy-rsa"
export KEY_DIR="/etc/openvpn/keys"
export KEY_SIZE=2048
export KEY_COUNTRY="RU"
export KEY_PROVINCE="MSK"
export KEY_CITY="Samara"
export KEY_ORG="Regtime Ltd."
export KEY_EMAIL="support@regtime.net"
Далее по той же классической схеме готовим ключи:
cd /etc/openvpn/easy-rsa
. ./vars
./clean-all
./build-ca
./build-key-server servername
./build-dh
Создаём минимальный конфиг для сервера в /etc/openvpn/udp-server. Параметров может быть намного больше и простор для оптимизации огромный.
dev tap0
proto udp
port 1194
ca keys/ca.crt
cert keys/servername.crt
key keys/servername.key
dh keys/dh2048.pem
user nobody
group nogroup
server 172.18.5.208 255.255.255.240
persist-key
persist-tun
status /dev/shm/openvpn-status-udp
verb 3
client-to-client
client-config-dir ccd-udp
log-append /var/log/openvpn-udp.log
comp-lzo
script-security 2
up "/etc/init.d/lan0 start"
down "/etc/init.d/lan0 stop"
Подключаем его и запускаем сервер:
ln -s udp-server udp-server.conf
/etc/init.d/openvpn start
Обратите внимание на последний три строки конфига. Именно они сделают этот сервер пригодным для использования в одноранговой сети. Стоит отметить, что сделать это можно только для udp сервера. Сам скрипт выглядит так — /etc/init.d/lan0:
#!/bin/bash ### BEGIN INIT INFO # Provides: lan0 # Required-Start: $network $remote_fs $syslog openvpn # Required-Stop: $network $remote_fs $syslog openvpn # Should-Start: # Should-Stop: # X-Start-Before: $x-display-manager gdm kdm xdm wdm ldm sdm nodm # X-Interactive: true # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: lan0 service ### END INIT INFO . /lib/lsb/init-functions PATH=/bin:/sbin:/usr/bin:/usr/sbin br="lan0" tap="tap0" eth="eth1" eth_ip="172.18.5.2" eth_netmask="255.255.255.0" eth_broadcast="172.18.5.255" case "$1" in start) brctl addbr $br brctl addif $br $eth for t in $tap; do brctl addif $br $t done for t in $tap; do ifconfig $t 0.0.0.0 promisc up done ifconfig $eth 0.0.0.0 promisc up ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast ;; stop) ifconfig $br down brctl delbr $br ifconfig $eth $eth_ip netmask $eth_netmask broadcast $eth_broadcast ;; *) echo "usage lan0 {start|stop}" exit 1 ;; esac exit 0
Этот же скрипт можно использовать для rc.d.
update-rc.d lan0 defaults
Последовательность при ручном запуске такая:
/etc/init.d/openvpn start
/etc/init.d/lan0 start
При ручной остановке:
/etc/init.d/lan0 stop
/etc/init.d/openvpn stop
Следует учесть, что при перезапуске OpenVPN lan0 будет подниматься заново. В некоторых случаях это нужно делать вручную. Например, через cron задача выглядит так:
[ -n "`/sbin/ifconfig tap0`" ] && [ -z "`/usr/sbin/brctl show|grep tap0`" ] && /etc/init.d/lan0 start
Собственно сервер готов. Теперь надо создать ключи и сертификаты для клиентов.
Клиенты
На созданном сервере создаём сертификаты для клиентов, которые будут подключаться снаружи:
cd /etc/openvpn/easy-rsa
. ./vars
./build-key client
Разумеется, имя каждого клиента (здесь client) должно быть уникальным.
После ввода/подтверждения данных для сертификата появятся следующие файлы:
client.crt
client.csr
client.key
На стороне клиента нам понадобятся следующий файлы из каталога /etc/openvpn/keys на сервере:
ca.crt
client.key
client.crt
На клиенте тоже устанавливаем OpenVPN:
aptitude install openvpn openvpn-blacklist
mkdir /etc/openvpn/keys
chmod 750 /etc/openvpn/keys
Копируем ключ и сертификаты в /etc/openvpn/keys:
Создаём простейший конфиг /etc/openvpn/client.conf:
dev tap0
proto udp
client
remote server 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca keys/ca.crt
cert keys/client.crt
key keys/client.key
comp-lzo
verb 3
status /dev/shm/client-status-udp
log /var/log/openvpn-client.log
ping 10
ping-restart 1800
script-security 2
up "/etc/init.d/lan0 start"
down "/etc/init.d/lan0 stop"
Для вхождения в общую одноранговую сеть используется тот же скрипт lan0 (исправив eth_ip на нужный), что и на сервере.
Множество серверов
В сети может быть несколько точек обмена трафиком. При этом очень желательно, чтобы клиент мог подключиться к любой из них и попасть в ту же сеть. Ничего сложного в этом нет. Можно настроить любое количество серверов указанным выше способом. Но есть два нюанса.
1. Каждый сервер должен выдавать отдельные уникальные IP адреса.
Хотя для lan0 это зачастую и не важно. Это достигается заменой одной строки в конфигах:
server 172.18.5.208 255.255.255.240
2. Нужно синхронизировать сертификаты между серверами OpenVPN.
Это уже чуть сложнее, но решаемо.
Самое простое решение — это конечно же скопировать каталог /etc/openvpn/keys по ssh. Но есть способ лучше — rsync.
Для двухстороннего обмена нам потребуется два скрипта — загрузки обновлений и скачивания оных.
Загрузка — push
#!/bin/bash export RSYNC_RSH="ssh -c arcfour -o Compression=no -x -l root" rsync \ -zu --modify-window=10 -aHAX --numeric-ids --sparse \ /etc/openvpn/keys remotehost:/etc/openvpn/keys
Обновление — pop
#!/bin/bash export RSYNC_RSH="ssh -c arcfour -o Compression=no -x -l root" rsync --delete-after \ -zu --modify-window=10 -aHAX --numeric-ids --sparse \ remotehost:/etc/openvpn/keys /etc/openvpn/keys
Обратите внимание на ключ —delete-after. Он используется для того чтобы после синхронизации удалить файлы которых нет на стороне назначения. Т.е. pop удалит локально всё то чего нет на remotehost.
Обратите внимание на порядок обновления ключей. В нормальных условиях новые ключи и сертификаты нужно создавать на первом (основном) сервере OpenVPN, а все последующие должны с него получать обновления через pop. Т.о. push нам не нужен вообще. Но в общем случае можно добавлять новых пользователей на любом сервере и вот тогда надо сначала нужно сделать push для загрузки, а затем pop на всех остальных OpenVPN серверах.
Поскольку взаимодействие идёт по ssh, то всем серверам нужно обменяться ключами ssh для root’а. Ключ можно сгенерить при помощи команды
ssh-keygen -t rsa -b 2048
а скопировать при помощи
ssh-copy-id remotehost
Учтите, что на всех этих серверах должен быть разрешен вход для root. Для безопасности можно отключить авторизацию по паролю. /etc/ssh/sshd_config
PermitRootLogin yes
PasswordAuthentication no
Теперь после добавления нового клиента нужно сделать push на сервере, где собственно ключ был добавлен и pop на всех остальных OpenVPN серверах.
Люди
Иногда сотрудникам приходится работать не из офиса, но им нужен доступ в локальную сеть. Это тоже легко реализовать в рамках lan0. Но поскольку здесь нет однозначности в вопросах операционных систем и фильтрации трафика, то лучше здесь использовать более медленный, но неприхотливый tcp вариант работы OpenVPN.
Конфиг /etc/openvpn/tcp-server:
dev tun0
proto tcp
port 1194
ca keys/ca.crt
cert keys/server.crt
key keys/server.key
dh keys/dh2048.pem
user nobody
group nogroup
server 172.18.5.248 255.255.255.240
persist-key
persist-tun
status /dev/shm/openvpn-status-tcp
verb 3
client-to-client
client-config-dir ccd-tcp
push "route 172.18.5.0 255.255.255.0"
log-append /var/log/openvpn-tcp.log
comp-lzo
Ключ и сертификат подготавливаются также как и для udp. Конфиг для такого подключения будет даже несколько проще — client.ovpn:
client
proto tcp
remote server 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
comp-lzo
Клиенты под разные операционки лучше качать с официального сайта: http://openvpn.net/
Отредактированная гуманитариями версия: http://habrahabr.ru/company/webnames/blog/162193/