Application: "OpenVPN v2.1/2.4", "IPTables", "Bash".
Задача: настройка режима изоляции и разграничения доступа к сетевым ресурсам для клиентов "OpenVPN".
Типовая, просто настраиваемая и повсеместно применяемая, конфигурация сервера "OpenVPN" подразумевает указание диапазона обслуживаемых им IP-адресов, первые из которых при запуске автоматически забирается самим сервером, а остальные выдаются подключающимся клиентам в порядке очерёдности.
Такая схема хорошо работает до тех пор, пока мы не заходим разграничить доступ к тем или иным сетевым ресурсам клиентам VPN-сервиса. Естественный подход с принудительным заданием IP-адресации клиентских VPN-туннелей посредством CCD решает поставленную задачу, но оставляет дверь для несанкционированного входа, легко распахивающуюся по забывчивости или слабой компетенции администратора сервиса.
Исходим из того, что сервис "OpenVPN" настроен в соответствии с заглавной заметкой этого раздела.
Последовательность дальнейших действий такова:
1. Рассмотрение примера уязвимости типовой конфигурации "OpenVPN";
2. Введение промежуточной подсети в конфигурацию "OpenVPN";
3. Описываем сетевую конфигурацию клиента посредством CCD;
4. Ограничиваем межсетевые взаимодействия посредством "IPTables".
2. Введение промежуточной подсети в конфигурацию "OpenVPN";
3. Описываем сетевую конфигурацию клиента посредством CCD;
4. Ограничиваем межсетевые взаимодействия посредством "IPTables".
Рассмотрение примера уязвимости типовой конфигурации "OpenVPN".
Производственный процесс рано или поздно поставит перед нами задачу реализовать следующую схему взаимодействий:
a) Действующий IP-диапазон VPN-сервиса: 10.20.30.0/24 - этот диапазон уже задействован в работе, через него подключаются офисные сотрудники, например.
b) Новый IP-диапазон для временного субподрядчика: 10.20.40.0/24 - в него мы должны принудительно переводить подключающихся посредством CCD.
c) Представим, что при регистрации нового временного пользователя, который должен быть в диапазоне 10.20.40.0/24 мы забыли создать для него CCD-инструкции. Естественно, в соответствии с конфигурацией по умолчанию, этот пользователь будет адресован как обычный сотрудник предприятия в сети 10.20.30.0/24 - таким образом, для несанкционированного допуска даже не нужно предпринимать ничего специально, достаточно просто пропустить одну из операций процедуры регистрации нового пользователя.
b) Новый IP-диапазон для временного субподрядчика: 10.20.40.0/24 - в него мы должны принудительно переводить подключающихся посредством CCD.
c) Представим, что при регистрации нового временного пользователя, который должен быть в диапазоне 10.20.40.0/24 мы забыли создать для него CCD-инструкции. Естественно, в соответствии с конфигурацией по умолчанию, этот пользователь будет адресован как обычный сотрудник предприятия в сети 10.20.30.0/24 - таким образом, для несанкционированного допуска даже не нужно предпринимать ничего специально, достаточно просто пропустить одну из операций процедуры регистрации нового пользователя.
Для обхода вышеописанной проблемы я предпочитаю запускать VPN-сервер с обслуживаемым по умолчанию пулом IP-адресов из диапазона немаршрутизируемых "link-local addresses" адресов, а всем, без исключения, клиентам выдавать действительные IP-адреса посредством CCD.
Таким образом, если мы забудем явно задать клиенту его IP-адресацию в CCD-инструкциях, то он получит её в диапазоне, который дальше VPN-туннеля и несущей VPN-сервис операционной системы не маршрутизируется. Соответственно, сетевые запросы дальше VPN-сервера не уйдут.
Введение промежуточной подсети в конфигурацию "OpenVPN".
Пример конфигурации хорошо описан в инструкции по настройке "OpenVPN", опубликованной на сайте разработчиков.
Руководствуясь официальными рекомендациями, заменяем один параметр и добавляем новый в конфигурацию сервера "OpenVPN":
# vi /etc/openvpn/server.conf
....
# Задаём основной IP-адрес VPN-сервера и обслуживаемый "по умолчанию" сетевой диапазон
# (в него вводятся подключившиеся клиенты, для которых явно не переопределены
# параметры через CCD; таким образом мы гарантируем наличие CCD-описаний для
# всех клиентов - в противном случае они получают неработоспособное соединение):
ifconfig 169.254.255.2 169.254.255.1
# Задаём маршруты к обслуживаемым VPN-сервером подсетям
# (диапазоны клиентских IP-адресов, маршрутизируемые VPN-сервером,
# где шлюз автоматически устанавливается в виртуальный tun-интерфейс):
route 10.20.30.0 255.255.0.0
....
# Задаём основной IP-адрес VPN-сервера и обслуживаемый "по умолчанию" сетевой диапазон
# (в него вводятся подключившиеся клиенты, для которых явно не переопределены
# параметры через CCD; таким образом мы гарантируем наличие CCD-описаний для
# всех клиентов - в противном случае они получают неработоспособное соединение):
ifconfig 169.254.255.2 169.254.255.1
# Задаём маршруты к обслуживаемым VPN-сервером подсетям
# (диапазоны клиентских IP-адресов, маршрутизируемые VPN-сервером,
# где шлюз автоматически устанавливается в виртуальный tun-интерфейс):
route 10.20.30.0 255.255.0.0
....
Для применения изменений в конфигурации потребуется перезапуск сервера "OpenVPN":
# systemctl restart openvpn@server
Теперь в таблице маршрутизации должны появится новые сегменты IP-адресов:
# netstat -rn
Destination Gateway Genmask Flags ... Iface
0.0.0.0 10.20.30.1 0.0.0.0 UG ... ens3
10.20.30.0 0.0.0.0 255.255.255.0 U ... ens3
169.254.255.0 169.254.255.2 255.255.255.0 UG ... tun0
169.254.255.2 0.0.0.0 255.255.255.255 UH ... tun0
0.0.0.0 10.20.30.1 0.0.0.0 UG ... ens3
10.20.30.0 0.0.0.0 255.255.255.0 U ... ens3
169.254.255.0 169.254.255.2 255.255.255.0 UG ... tun0
169.254.255.2 0.0.0.0 255.255.255.255 UH ... tun0
Описываем сетевую конфигурацию клиента посредством CCD.
Упомянутая ранее в заглавной заметке настройки сервера "OpenVPN" директория файлов конфигураций клиентов должна содержать файлы описаний сетевой конфигурации соединения, имеющие имена установленного вида. Например, для клиента с "Common Name" имеющим значение "usernameOne" исполняется файл с именем "usernameOne". Файлы содержат команды сервера "OpenVPN". В нашей конфигурации мы навязываем каждому клиенту свой IP адрес и адрес "шлюза" для того, что бы можно было контролировать их трафик листами доступа.
Создаем директорию и файл настроек клиента:
# mkdir -p /etc/openvpn/server/ccd
# vi /etc/openvpn/server/ccd/usernameOne
# vi /etc/openvpn/server/ccd/usernameOne
# (compatible "topology net30")
ifconfig-push 10.20.30.3 10.20.30.2
# (routes are included as needed)
push "route 10.10.10.0 255.255.255.0"
;push "route 10.20.30.0 255.255.255.0"
push "route 192.168.30.0 255.255.255.0"
ifconfig-push 10.20.30.3 10.20.30.2
# (routes are included as needed)
push "route 10.10.10.0 255.255.255.0"
;push "route 10.20.30.0 255.255.255.0"
push "route 192.168.30.0 255.255.255.0"
Где:
"10.20.30.2" - IP виртуального "шлюза" на стороне VPN сервера;
"10.20.30.3" - IP "usernameOne" на стороне пользователя.
"10.20.30.3" - IP "usernameOne" на стороне пользователя.
Файлы CCD-конфигурации считываются каждый раз при подключении (и переподключении) клиента "OpneVPN", так что при их изменении перезапуска сервера не требуется.
Ограничиваем межсетевые взаимодействия посредством "IPTables".
После того, как мы распределили подключающихся клиентов "OpenVPN" по разным подсетям, остаётся лишь описать правила пропуска из этих подсетей в другие, средствами встроенного в "Linux" сетевого фильтра.
Всегда есть смысл предварительно ознакомиться с действующим набором фильтров и правил трансляции:
# iptables -L -n -v --line-numbers
# iptables -t nat -L -n -v --line-numbers
# iptables -t mangle -L -n -v --line-numbers
# iptables -t nat -L -n -v --line-numbers
# iptables -t mangle -L -n -v --line-numbers
Пишем простейший bash-скрипт, запуском которого будет создавать желаемую нам конфигурацию:
# cd /usr/local/etc
# vi ./set-iptables-rules.sh && chmod ug+x ./set-iptables-rules.sh
# vi ./set-iptables-rules.sh && chmod ug+x ./set-iptables-rules.sh
#!/bin/bash
# Предварительно очищаем три основные таблицы правил обработки трафика
iptables -t filter -F
iptables -t filter -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
# Правилом "по умолчанию" запрещаем все входящие и транзитные соединения
iptables -P FORWARD DROP
# Правилом "по умолчанию" разрешаем все входящие и исходящие соединения
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
# Явно обрубаем все соединения, не укладывающиеся в логику защитного экрана
iptables -A FORWARD -m conntrack --ctstate INVALID -j DROP
# Одним из первых правил разрешаем прохождение пакетов в уже установленных соединениях
# (исключение избыточной аналитики существенно снижает нагрузку на защитный экран)
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Administrators
iptables -A FORWARD -i tun0 -s 10.20.30.0/26 -d 0.0.0.0/0 -j ACCEPT -m comment --comment "Administrators - All networks"
# Employees
iptables -A FORWARD -i tun0 -s 10.20.30.64/26 -d 10.10.10.0/24 -j ACCEPT -m comment --comment "Employees - Service network"
iptables -A FORWARD -i tun0 -s 10.20.30.64/26 -d 192.168.10.0/24 -j ACCEPT -m comment --comment "Employees - Office network"
# Contractors
iptables -A FORWARD -i tun0 -s 10.20.30.192/26 -d 10.10.10.2/32 -j ACCEPT -m comment --comment "Contractors - DNS"
iptables -A FORWARD -i tun0 -s 10.20.30.192/26 -d 10.10.10.3/32 -j ACCEPT -m comment --comment "GitLab"
exit 0
# Предварительно очищаем три основные таблицы правил обработки трафика
iptables -t filter -F
iptables -t filter -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
# Правилом "по умолчанию" запрещаем все входящие и транзитные соединения
iptables -P FORWARD DROP
# Правилом "по умолчанию" разрешаем все входящие и исходящие соединения
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
# Явно обрубаем все соединения, не укладывающиеся в логику защитного экрана
iptables -A FORWARD -m conntrack --ctstate INVALID -j DROP
# Одним из первых правил разрешаем прохождение пакетов в уже установленных соединениях
# (исключение избыточной аналитики существенно снижает нагрузку на защитный экран)
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Administrators
iptables -A FORWARD -i tun0 -s 10.20.30.0/26 -d 0.0.0.0/0 -j ACCEPT -m comment --comment "Administrators - All networks"
# Employees
iptables -A FORWARD -i tun0 -s 10.20.30.64/26 -d 10.10.10.0/24 -j ACCEPT -m comment --comment "Employees - Service network"
iptables -A FORWARD -i tun0 -s 10.20.30.64/26 -d 192.168.10.0/24 -j ACCEPT -m comment --comment "Employees - Office network"
# Contractors
iptables -A FORWARD -i tun0 -s 10.20.30.192/26 -d 10.10.10.2/32 -j ACCEPT -m comment --comment "Contractors - DNS"
iptables -A FORWARD -i tun0 -s 10.20.30.192/26 -d 10.10.10.3/32 -j ACCEPT -m comment --comment "GitLab"
exit 0
Запускаем скрипт, формируя тем самым набор правил фильтрации трафика:
# /usr/local/etc/set-iptables-rules.sh
Устанавливаем подсистему, автоматически воссоздающую правила защитного экрана "Linux Debian/Ubuntu" на этапе старта операционной системы:
# aptitude install iptables-persistent
# /etc/init.d/netfilter-persistent save
# /etc/init.d/netfilter-persistent save