Простая и быстрая настройка mesh VPN с помощью tinc
Периодически сталкиваюсь с какими-то программными продуктами, которые существуют уже много лет, удобны, легки, просто работают, но я о них по какой-то причине не слышал на протяжении всего времени их существования. На этой неделе открыл для себя tinc. Если кратко, то tinc - это vpn, который позволяет объединить несколько машин друг с другом, где каждая будет обмениваться при необходимости данными с каждой, т.е. не будет единой точки отказа. Чем прекрасен именно этот вариант - он требует минимальной настройки, конфигурационные файлы очень просты, создание ключа - тоже. Типичный сценарий для использования tinc - несколько географически удалённых филиалов одной сети. Поднимаем на двух машинах бридж, выдаём ему нужный локальный адрес, tinc поднимает tap или tun интерфейс, при создании/уничтожении интерфейса запускает скрипт, в который передаёт имя интерфейса, что позволяет добавить его в бридж или удалить из него. Всё просто работает, но есть один нюанс, о котором я расскажу ниже.
Для начала поставим tinc и создадим в /etc/tinc директорию, соответствующую имени сети. Пусть в нашем случае это будет просто networkname:
sudo apt-get install tinc bridge-utils
cd /etc/tinc
sudo mkdir networkname
cd networkname
Внутри этой директории нужно создать конфигурационный файл с именем tinc.conf и следующим содержимым:
Name = host1
Mode = switch
Interface = tap0
Port = 655
ConnectTo = host2
Соответственно, host1 - это имя нашей машины, host2 - это машина, к которой мы будем подключаться. Строк ConnectTo может быть сколько угодно, таким образом, каждый из ваших узлов может соединяться со всеми остальными, на которых запущен tinc. В этом случае желательно настроить синхронизацию конфигурационных файлов между машинами, чтобы не переносить их каждый раз руками или, ещё лучше, накатывать чем-то вроде ansible. Вдаваться подробно в параметры не вижу смысла, вот здесь есть замечательная и понятная документация по параметрам конфигурационного файла.
Tinc работает по udp протоколу, поэтому необходимо на всех машинах с tinc открыть 655-й порт udp. На обоих машинах в директории /etc/tinc/networkname нужно создать директорию hosts, после чего создать пару ключей - публичный и приватный с помощью tincd:
tincd -n networkname -K
Публичный ключ должен появиться в директории hosts в файле с именем, соответствующим значению поля Name в конфигурационном файле tinc.conf. Т.е. на host1 публичный ключ будет лежать в /etc/tinc/networkname/hosts/host1, а на host2 - в /etc/tinc/networkname/hosts/host2. Теперь на машине host1 мы должны создать файл /etc/tinc/networkname/hosts/host2 следующего содержания:
Address = 1.2.3.4
Cipher = aes-128-cbc
Digest = sha1
Compression = 0
-----BEGIN RSA PUBLIC KEY-----
SomeLongHashWasHere
-----END RSA PUBLIC KEY-----
Где 1.2.3.4 - это белый IP адрес host2, а в конце файла после Compression = 0 нужно вставить публичный ключ с host2, т.е. содержимое файла /etc/tinc/networkname/hosts/host2. Симметричным образом на машине host2 нужно создать файл /etc/tinc/networkname/hosts/host1, после чего на обеих машинах можно запускать сервис, но тут как раз и появляется та тонкость, о которой я писал в самом начале.
У меня было две машины - с Ubuntu 16.04 LTS и Ubuntu 18.04 LTS. На первой после запуска появился интерфейс tap0, а на второй - нет. Начал разбираться.
$ systemctl status tinc
● tinc.service - Tinc VPN
Loaded: loaded (/lib/systemd/system/tinc.service; enabled; vendor preset: enabled)
Active: active (exited) since Tue 2020-01-28 14:57:45 MSK; 4min 41s ago
Process: 7920 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 7920 (code=exited, status=0/SUCCESS)
Jan 28 14:57:45 git systemd[1]: Starting Tinc VPN...
Jan 28 14:57:45 git systemd[1]: Started Tinc VPN.
Запущен и тут же завершён с кодом возврата 0. Интересно, а что же внутри сервиса?
$ cat /lib/systemd/system/tinc.service
# This is a mostly empty service, but allows commands like stop, start, reload
# to propagate to all tinc@ service instances.
[Unit]
Description=Tinc VPN
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecReload=/bin/true
WorkingDirectory=/etc/tinc
[Install]
WantedBy=multi-user.target
Гениально! Внимание, запускаем VPN сервис // на самом деле нет! // ... Запустили! Наслаждайтесь! // на самом деле нет! //
Для сравнения на ubuntu 16.04 в статусе иное:
$ systemctl status tinc
● tinc.service - LSB: Start tinc daemons
Loaded: loaded (/etc/init.d/tinc; bad; vendor preset: enabled)
Active: active (running) since Tue 2020-01-28 14:55:06 MSK; 6min ago
Docs: man:systemd-sysv-generator(8)
Process: 31199 ExecStop=/etc/init.d/tinc stop (code=exited, status=0/SUCCESS)
Process: 31215 ExecStart=/etc/init.d/tinc start (code=exited, status=0/SUCCESS)
Tasks: 1
Memory: 372.0K
CPU: 32ms
CGroup: /system.slice/tinc.service
└─31224 /usr/sbin/tincd -n service
Проверил sys-v-init скрипты запуска сервиса на обеих машинах - отличия минимальны. Решил убрать файл сервиса на Ubuntu 18.04, после чего systemd вынужден будет вместо него использовать старый скрипт sys-v-init, проверил - работает!
$ sudo mv /lib/systemd/system/tinc.service .
$ sudo systemctl daemon-reload
$ systemctl status tinc
● tinc.service - LSB: Start tinc daemons
Loaded: loaded (/etc/init.d/tinc; generated)
Active: active (exited) since Tue 2020-01-28 14:57:45 MSK; 11min ago
Docs: man:systemd-sysv-generator(8)
Main PID: 7920 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 4915)
CGroup: /system.slice/tinc.service
$ sudo systemctl enable tinc
$ sudo systemctl restart tinc
$ systemctl status tinc
● tinc.service - LSB: Start tinc daemons
Loaded: loaded (/etc/init.d/tinc; generated)
Active: active (running) since Tue 2020-01-28 15:10:24 MSK; 6s ago
Docs: man:systemd-sysv-generator(8)
Process: 12683 ExecStop=/etc/init.d/tinc stop (code=exited, status=0/SUCCESS)
Process: 12701 ExecStart=/etc/init.d/tinc start (code=exited, status=0/SUCCESS)
Main PID: 7920 (code=exited, status=0/SUCCESS)
Tasks: 1 (limit: 4915)
CGroup: /system.slice/tinc.service
└─12720 /usr/sbin/tincd -n service
Jan 28 15:10:24 git systemd[1]: Starting LSB: Start tinc daemons...
Jan 28 15:10:24 git tinc[12701]: Starting tinc daemons: service.
Jan 28 15:10:24 git systemd[1]: Started LSB: Start tinc daemons.
Jan 28 15:10:24 git tinc.service[12720]: tincd 1.0.33 starting, debug level 0
Jan 28 15:10:24 git tinc.service[12720]: /dev/net/tun is a Linux tun/tap device (tap mode)
Jan 28 15:10:24 git tinc.service[12720]: Ready
После этого можно двигаться дальше. Итак, у нас на этот момент на обеих машинах должен быть интерфейс tap0. Далее возможны варианты - можно назначить на эти интерфейсы серые IP адреса и они будут видны друг-другу. Можно устроить роутинг через них. А можно создать два бриджа и добавить интерфейсы в бриджи, что даст возможность в те же бриджи потом добавить и физические интерфейсы, таким образом объединив удалённые подсети.
При создании интерфейса tinc может запустить скрипт tinc-up, если найдёт таковой в директории с конфигурационным файлом сети и аналогичным образом будет запущен tinc-down при опускании интерфейса. Вот примеры моих скриптов.
tinc-up:
#!/bin/sh
cd `dirname "$0"`
[ -f ".env" ] && . ./.env
BR="$(basename `pwd`)"
if [ -z "$(brctl show | awk 'NR>1 && $1~/^'"$BR"'$/')" ]; then
echo "Trying to bring up new bridge $BR"
brctl addbr "$BR"
[ -n "$ADDRESS" ] && echo "Setting address $ADDRESS to bridge $BR" && ifconfig "$BR" "$ADDRESS" netmask "$NETMASK" up
fi
ip link set $INTERFACE up
brctl addif "$BR" $INTERFACE
tinc-down:
#!/bin/sh
cd `dirname "$0"`
[ -f ".env" ] && . ./.env
BR="$(basename `pwd`)"
brctl delif "$BR" "$INTERFACE"
ip link set "$INTERFAСE" down
Нужные мне параметры берутся из файла .env, в который я их буду добавлять по мере необходимости и усложнения.
.env:
ADDRESS=10.11.12.13
NETMASK=255.255.255.0
IFACE=tap0
Скрипт в качестве имени сети берёт имя директории, в которой он запущен, проверяет наличие бриджа, если его нет, то создаёт его, назначает ему адрес сети и маску из файла .env и добавляет в него интерфейс tap0. Сетевой мост мы можем использовать и как стандартный интерфейс в том числе, что удобно.
На сегодня это всё.
P.S.: И не спрашивайте меня, почему на лого изображение боевого вертолёта. Я сам хотел бы это знать.
Теги: админское, networking