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/

1 комментарий к записи “lan0: локальная сеть глобального масштаба”

Оставить комментарий

Вы должны быть авторизованы, чтобы оставить комментарий.