Настраиваем OpenConnect middle server для доступа к закрытому контуру
Приветствую!

В этой заметке рассмотрим работу OpenConnect сервера в роли промежуточного сервера для доступа к закрытой инфраструктуре.

Сразу обозначу важный момент: основная цель здесь не в том, чтобы ещё раз поднять обычный ocserv. Этому у меня уже посвящена отдельная инструкция. Здесь интереснее другая часть: middle server, который принимает подключения от пользователей, сам поднимает клиентское OpenConnect-подключение к закрытому контуру и дальше маршрутизирует трафик.

Предисловие

📝 Сперва разберёмся с определением:

В моём случае задача была следующая: есть закрытая инфраструктура, доступная только через защищённую точку входа. При этом мне нужно было выдать доступ пользователям не напрямую в эту точку, а через отдельный промежуточный сервер, которым я могу управлять независимо.

Для этого я собрал Docker-образ, в котором рядом с ocserv работает ещё и клиент OpenConnect. Получается такая схема:

Чуть подробнее о том, что умеет образ:

Подготовка

Далее предполагается, что у вас есть два Linux-сервера:

Также предполагается, что на серверах:

Я буду использовать реальные домены, чтобы можно было получить валидные TLS-сертификаты от Let’s Encrypt. Для простого теста можно обойтись и внутренними сертификатами: если сертификат не примонтирован в ./data/ssl/live/$OC_SRV_CN/, entrypoint скрипт сгенерирует внутренний CA и серверный сертификат сам.

Вводные данные примера из статьи:

СерверВнешний IPVPN-подсетьРоль
private.r4ven.me188.227.86.9810.11.11.0/24Закрытая точка входа
middle.r4ven.me188.227.32.9210.10.10.0/24Промежуточный сервер для пользователей

Оба сервера работают под управлением Debian GNU/Linux 13-й версии.

Настройка private server

На private server нам нужен обычный ocserv, к которому middle server сможет подключиться как OpenConnect-клиент.

Подключаемся к private server по защищённому протоколу SSH и работаем от root:

BASH
ssh private.r4ven.me

sudo -i
Нажмите, чтобы развернуть и увидеть больше

Создаём рабочую директорию:

BASH
mkdir -vp /opt/openconnect

cd /opt/openconnect
Нажмите, чтобы развернуть и увидеть больше

Создаём файл описания сервисов:

BASH
vim compose.yaml
Нажмите, чтобы развернуть и увидеть больше
BASH
---

services:
  certbot:
    image: certbot/certbot
    container_name: certbot
    restart: no
    stop_grace_period: 5s
    cpus: 0.5
    mem_limit: 512M
    environment:
      TZ: ${TZ}
    hostname: certbot
    volumes:
      - ./data/ssl:/etc/letsencrypt
    entrypoint: >
      sh -c "
        certbot certonly --non-interactive --keep-until-expiring --standalone --preferred-challenges http --agree-tos --email ${OC_USER_EMAIL} -d ${OC_SRV_CN}; exit 0;
      "
    ports:
      - "80:80"

  openconnect:
    depends_on:
      certbot:
        condition: service_completed_successfully
    build:
      context: .
      dockerfile: Dockerfile
    image: r4venme/openconnect:v1.4-client
    container_name: openconnect
    restart: always
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 512M
    cap_add:
      - NET_ADMIN
      - NET_RAW
    hostname: openconnect
    env_file:
      - .env
    volumes:
      - ./data/:/etc/ocserv
    devices:
      - /dev/net/tun:/dev/net/tun
      - /dev/vhost-net:/dev/vhost-net
    ports:
      - "${OC_SRV_PORT}:${OC_SRV_PORT}/tcp"

  certbot_renew:
    depends_on:
      certbot:
        condition: service_completed_successfully
    image: certbot/certbot
    container_name: certbot-renew
    restart: unless-stopped
    stop_grace_period: 5s
    cpus: 0.5
    mem_limit: 512M
    environment:
      TZ: ${TZ}
    hostname: certbot-renew
    volumes:
      - ./data/ssl:/etc/letsencrypt
    entrypoint: >
      sh -c "
        trap exit TERM;
        while true; do
          certbot renew --non-interactive --keep-until-expiring --standalone --preferred-challenges http --agree-tos;
          sleep 24h;
        done
      "
    ports:
      - "80:80"
Нажмите, чтобы развернуть и увидеть больше

Создаём .env:

BASH
vim .env
Нажмите, чтобы развернуть и увидеть больше

Для private server достаточно серверной части. Параметры клиента и split tunneling оставляем выключенными (хотя при необходимости он также может быть и middle сервером):

BASH
# System
TZ="Europe/Moscow"

# Certbot, если используете Let's Encrypt
OC_USER_EMAIL="kar-kar@r4ven.me"

# OpenConnect server
OC_SRV_PORT="443"
OC_SRV_CN="private.r4ven.me"
OC_SRV_CA="R4ven private CA"
OC_IPV4_NET="10.11.11.0"
OC_IPV4_MASK="255.255.255.0"
OC_DNS1="8.8.8.8"
OC_DNS2="8.8.4.4"
OC_CAMOUFLAGE_ENABLE="true"
OC_CAMOUFLAGE_SECRET="secretPrivateServerWord"
OC_CAMOUFLAGE_REALM="Private service"
Нажмите, чтобы развернуть и увидеть больше

Запускаем:

BASH
docker compose up -d

docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Теперь создадим пользователя, которым middle server будет подключаться к private server:

BASH
docker exec -it openconnect ocuser private "Private Client"
Нажмите, чтобы развернуть и увидеть больше

Готовый файл появится здесь:

BASH
ls -l ./data/secrets/private.p12
Нажмите, чтобы развернуть и увидеть больше

Копируем его во временную директорию, чтобы затем забрать на middle server:

BASH
cp -v ./data/secrets/private.p12 /tmp/private.p12

chmod 644 /tmp/private.p12
Нажмите, чтобы развернуть и увидеть больше

Настройка автозапуска с помощью Systemd

Когда всё проверили, можно настроить автозапуск нашего private server через systemd:

BASH
docker compose down
Нажмите, чтобы развернуть и увидеть больше
BASH
cat << EOF > /etc/systemd/system/openconnect.service
[Unit]
Description=OpenConnect middle server
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
WorkingDirectory=/opt/openconnect
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
systemctl daemon-reload

systemctl enable --now openconnect

journalctl -fu openconnect
Нажмите, чтобы развернуть и увидеть больше

Настройка middle server

Теперь переходим к основной части. Именно middle server будет принимать пользовательские подключения и решать, куда отправлять их трафик.

Как говорил ранее, есть поддержка двух режимов:

Начнём с общей подготовки.

С помощью scp копируем файл .p12 на middle server, затем подключаемся к нему и также переходим на root:

BASH
scp private.r4ven.me:/tmp/private.p12 middle.r4ven.me:/tmp

ssh middle.r4ven.me

sudo -i
Нажмите, чтобы развернуть и увидеть больше

Теперь создаём рабочую директорию, копируем в неё файл .p12 и создаём файл описания сервисов:

BASH
mkdir -vp /opt/openconnect

cd /opt/openconnect

cp /tmp/private.p12 ./

vim compose.yaml
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

BASH
---

services:
  certbot:
    image: certbot/certbot
    container_name: certbot
    restart: no
    stop_grace_period: 5s
    cpus: 0.5
    mem_limit: 512M
    environment:
      TZ: ${TZ}
    hostname: certbot
    volumes:
      - ./data/ssl:/etc/letsencrypt
    entrypoint: >
      sh -c "
        certbot certonly --non-interactive --keep-until-expiring --standalone --preferred-challenges http --agree-tos --email ${OC_USER_EMAIL} -d ${OC_SRV_CN}; exit 0;
      "
    ports:
      - "80:80"

  openconnect:
    depends_on:
      certbot:
        condition: service_completed_successfully
    build:
      context: .
      dockerfile: Dockerfile
    image: r4venme/openconnect:v1.4-client
    container_name: openconnect
    restart: always
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 512M
    cap_add:
      - NET_ADMIN
      - NET_RAW
    hostname: openconnect
    env_file:
      - .env
    volumes:
      - ./data/:/etc/ocserv
      - ${OC_CLIENT_0_CERT_FILE}:${OC_CLIENT_0_CERT_FILE}
      # - ${OC_CLIENT_1_CERT_FILE}:${OC_CLIENT_1_CERT_FILE}
      # - /etc/iproute2/rt_tables.d:/etc/iproute2/rt_tables.d
    devices:
      - /dev/net/tun:/dev/net/tun
      - /dev/vhost-net:/dev/vhost-net
    ports:
      - "${OC_SRV_PORT}:${OC_SRV_PORT}/tcp"

  certbot_renew:
    depends_on:
      certbot:
        condition: service_completed_successfully
    image: certbot/certbot
    container_name: certbot-renew
    restart: unless-stopped
    stop_grace_period: 5s
    cpus: 0.5
    mem_limit: 512M
    environment:
      TZ: ${TZ}
    hostname: certbot-renew
    volumes:
      - ./data/ssl:/etc/letsencrypt
    entrypoint: >
      sh -c "
        trap exit TERM;
        while true; do
          certbot renew --non-interactive --keep-until-expiring --standalone --preferred-challenges http --agree-tos;
          sleep 24h;
        done
      "
    ports:
      - "80:80"
Нажмите, чтобы развернуть и увидеть больше

Режим Full Routing

Ниже представлена схема сетевого взаимодействия, когда весь клиентский трафик отправляется через upstream-туннель middle server:

Для такого режима включаем OC_CLIENT_ENABLE и добавляем параметры подключения к private серверу:

BASH
vim .env
Нажмите, чтобы развернуть и увидеть больше
BASH
# System
TZ="Europe/Moscow"

# Certbot, если используете Let's Encrypt
OC_USER_EMAIL="kar-kar@r4ven.me"

# OpenConnect server
OC_SRV_PORT="443"
OC_SRV_CN="middle.r4ven.me"
OC_SRV_CA="R4ven CA"
OC_IPV4_NET="10.10.10.0"
OC_IPV4_MASK="255.255.255.0"
OC_DNS1="8.8.8.8"
OC_DNS2="8.8.4.4"
OC_CAMOUFLAGE_ENABLE="true"
OC_CAMOUFLAGE_SECRET="secretMiddleServerWord"
OC_CAMOUFLAGE_REALM="Middle service"

# OpenConnect client
# Optional: force physical uplink interface for NAT rules. Empty means auto-detect.
# OC_MAIN_IFACE="eth0"
OC_CLIENT_ENABLE="true"
OC_CLIENT_IFACE="oc-middle"
OC_CLIENT_CHECK_INTERVAL="5"
OC_CLIENT_CHECK_THRESHOLD="3"

# Number of configured OC_CLIENT_<index> profiles.
# Set to "2" when OC_CLIENT_1_* variables are enabled, "3" for OC_CLIENT_2_*, etc.
OC_CLIENT_COUNT="1"

OC_CLIENT_0_SSL_FLAG=true
OC_CLIENT_0_SERVER="private.r4ven.me"
OC_CLIENT_0_SERVER_PORT="443/?secretPrivateServerWord"
OC_CLIENT_0_CERT_FILE="/opt/openconnect/private.p12"
OC_CLIENT_0_CERT_PASS="p12SecretInBase64encode"
OC_CLIENT_0_CHECK_HOST="10.11.11.1"

# OC_CLIENT_1_SSL_FLAG=false
# OC_CLIENT_1_SERVER="private2.example.com"
# OC_CLIENT_1_SERVER_PORT="443/?SecretUrl"
# OC_CLIENT_1_CERT_FILE="/opt/openconnect/private2.p12"
# OC_CLIENT_1_CERT_PASS="p12SecretInBase64encode"
# OC_CLIENT_1_CHECK_HOST="10.12.12.1"
Нажмите, чтобы развернуть и увидеть больше

Разбор параметров OC_CLIENT

Теперь подробнее разберём параметры, которые отвечают за исходящее OpenConnect-подключение из middle server в private server.

ПараметрПримерОписание
OC_CLIENT_ENABLE"true"Включает OpenConnect-клиент внутри контейнера. Если значение false, middle server работает как обычный ocserv.
OC_CLIENT_IFACE"oc-middle0"Имя интерфейса, который создаст upstream OpenConnect-клиент. Это имя дальше используется в маршрутах, nftables и split tunneling.
OC_CLIENT_CHECK_INTERVAL"5"Интервал health check в секундах. Скрипт регулярно проверяет доступность OC_CLIENT_<index>_CHECK_HOST через OC_CLIENT_IFACE.
OC_CLIENT_CHECK_THRESHOLD"3"Сколько неудачных проверок подряд нужно получить, прежде чем скрипт начнёт переподключение.
OC_CLIENT_COUNT"1"Количество описанных upstream-профилей. Если используете OC_CLIENT_0_* и OC_CLIENT_1_*, здесь должно быть "2".

Для каждого upstream-профиля используется индекс: 0, 1, 2 и так далее.

ПараметрПримерОписание
OC_CLIENT_0_SSL_FLAG"true"Если true, сертификат private server считается доверенным. Если false, клиент дополнительно отвечает yes на подтверждение сертификата. Для боевого использования лучше настроить валидный сертификат и оставить true.
OC_CLIENT_0_SERVER"private.r4ven.me"Адрес private server, к которому будет подключаться OpenConnect-клиент.
OC_CLIENT_0_SERVER_PORT"443/?secretPrivateServerWord"Порт и, при необходимости, camouflage secret. Если camouflage не используется, можно указать просто "443".
OC_CLIENT_0_CERT_FILE"/opt/openconnect/private.p12"Путь к .p12 на хосте и внутри контейнера.
OC_CLIENT_0_CERT_PASS"..."Пароль от .p12, закодированный в base64.
OC_CLIENT_0_CHECK_HOST"10.11.11.1"Адрес, который проверяется через upstream-туннель. Обычно удобно указать адрес самого private server внутри VPN-подсети.

Логика работы следующая:

Несколько upstream-профилей

Если закрытая инфраструктура доступна через несколько точек входа, можно описать несколько профилей:

BASH
OC_CLIENT_COUNT="2"

OC_CLIENT_0_SSL_FLAG="true"
OC_CLIENT_0_SERVER="private.r4ven.me"
OC_CLIENT_0_SERVER_PORT="443/?secretPrivateServerWord"
OC_CLIENT_0_CERT_FILE="/etc/ocserv/secrets/private.p12"
OC_CLIENT_0_CERT_PASS="p12SecretInBase64encode"
OC_CLIENT_0_CHECK_HOST="10.11.11.1"

OC_CLIENT_1_SSL_FLAG="true"
OC_CLIENT_1_SERVER="private2.r4ven.me"
OC_CLIENT_1_SERVER_PORT="443/?secretPrivate2ServerWord"
OC_CLIENT_1_CERT_FILE="/opt/openconnect/private2.p12"
OC_CLIENT_1_CERT_PASS="anotherP12SecretInBase64"
OC_CLIENT_1_CHECK_HOST="10.12.12.1"
Нажмите, чтобы развернуть и увидеть больше

Если текущий профиль перестаёт проходить health check, скрипт сначала пытается переподключиться к нему же. Если это не помогает, он переключается на следующий профиль. И так по кругу, пока куда-нибудь не подключится и health check будет успешным.

Запуск middle server

Запускаем middle server:

BASH
docker compose up -d

docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Создаём пользователя уже на middle server:

BASH
docker exec -it openconnect ocuser middleuser "Middle User"
Нажмите, чтобы развернуть и увидеть больше

Копируем клиентский .p12 в /tmp:

BASH
cp -v ./data/secrets/middleuser.p12 /tmp/middleuser.p12

chmod 644 /tmp/middleuser.p12
Нажмите, чтобы развернуть и увидеть больше

Проверка Full Routing

На клиентской машине скачиваем .p12 файл:

BASH
scp middle.r4ven.me:/tmp/middleuser.p12 ./
Нажмите, чтобы развернуть и увидеть больше

Подключаемся к middle server:

BASH
sudo openconnect -c ./middleuser.p12 'middle.r4ven.me/?secretMiddleServerWord'
Нажмите, чтобы развернуть и увидеть больше

Проверяем внешний IP:

BASH
curl ifconfig.me
Нажмите, чтобы развернуть и увидеть больше

В ответ должен прийти внешний IP private server, потому что весь трафик клиента ушёл через middle server, а затем через upstream-туннель на private server.

Дополнительно можно посмотреть маршрут:

BASH
mtr -wb linuxmint.com
Нажмите, чтобы развернуть и увидеть больше

Он должен идти через middle server (10.10.10.1) затем через private server (10.11.11.1).

Режим Split Routing

Теперь рассмотрим более интересный режим. В нём пользователь подключается к middle server, но через private server уходит только тот трафик, который мы явно указали.

Например:

Схема получается такая:

Для этого включаем клиентскую часть и добавляем split tunneling:

BASH
# System
TZ="Europe/Moscow"

# Certbot, если используете Let's Encrypt
OC_USER_EMAIL="kar-kar@r4ven.me"

# OpenConnect server
OC_SRV_PORT="443"
OC_SRV_CN="middle.r4ven.me"
OC_SRV_CA="R4ven CA"
OC_IPV4_NET="10.10.10.0"
OC_IPV4_MASK="255.255.255.0"
OC_DNS1="8.8.8.8"
OC_DNS2="8.8.4.4"
OC_CAMOUFLAGE_ENABLE="true"
OC_CAMOUFLAGE_SECRET="secretMiddleServerWord"
OC_CAMOUFLAGE_REALM="Middle service"

# OpenConnect client
# Optional: force physical uplink interface for NAT rules. Empty means auto-detect.
# OC_MAIN_IFACE="eth0"
OC_CLIENT_ENABLE="true"
OC_CLIENT_IFACE="oc-middle0"
OC_CLIENT_CHECK_INTERVAL="5"
OC_CLIENT_CHECK_THRESHOLD="3"

# Number of configured OC_CLIENT_<index> profiles.
# Set to "2" when OC_CLIENT_1_* variables are enabled, "3" for OC_CLIENT_2_*, etc.
OC_CLIENT_COUNT="1"

OC_CLIENT_0_SSL_FLAG=true
OC_CLIENT_0_SERVER="private.r4ven.me"
OC_CLIENT_0_SERVER_PORT="443/?secretPrivateServerWord"
OC_CLIENT_0_CERT_FILE="/opt/openconnect/private.p12"
OC_CLIENT_0_CERT_PASS="p12SecretInBase64encode"
OC_CLIENT_0_CHECK_HOST="10.11.11.1"

# Split tunneling
OC_SPLIT_ENABLE="true"
OC_SPLIT_TUNNEL_DNS="true"
OC_SPLIT_ROUTES='
192.168.25.0/24
10.1.0.0/16
1.1.1.1/32
'
OC_SPLIT_DOMAINS='
ifconfig.me
example.com
gnu.org
'
Нажмите, чтобы развернуть и увидеть больше

Разбор параметров OC_SPLIT

Теперь разберём split tunneling. Он включается только вместе с OC_CLIENT_ENABLE=true, потому что без upstream-туннеля разделять трафик просто некуда.

ПараметрПримерОписание
OC_SPLIT_ENABLE"true"Включает режим выборочной маршрутизации. Если false, при включённом OC_CLIENT_ENABLE трафик пользователей уходит в upstream-туннель целиком.
OC_SPLIT_TUNNEL_DNS"true"Отправляет DNS-серверы, указанные в OC_DNS1 и OC_DNS2, через upstream-туннель. Полезно, если эти DNS доступны только из private network.
OC_SPLIT_ROUTES192.168.25.0/24Начальный список IP-адресов и подсетей, которые нужно отправлять через private server.
OC_SPLIT_DOMAINSexample.comНачальный список доменов, IP-адреса которых dnsmasq будет добавлять в nftables set для маршрутизации через private server.

При включении split tunneling внутри контейнера происходит несколько вещей:

Попробую описать чуть понятнее:

Одним из преимуществ данного способа является формирование nftset по wildcard. Другими словами, вы добавляете домен example.com в список и при обращении к доменам нижнего уровня, например test.example.com, трафик автоматически пойдет через OpenConnect туннель.

Подобную схему я уже ранее реализовывал в статье по подключению роутера на OpenWRT к OpenConnect серверу.

Домены

Домены можно указать сразу в .env:

BASH
OC_SPLIT_DOMAINS='
ifconfig.me
example.com
gnu.org
'
Нажмите, чтобы развернуть и увидеть больше

При первом запуске entrypoint скрипт положит их в файл:

BASH
./data/domains.txt
Нажмите, чтобы развернуть и увидеть больше

После запуска удобнее редактировать уже этот файл:

BASH
vim ./data/domains.txt
Нажмите, чтобы развернуть и увидеть больше

Формат простой:

TEXT
ifconfig.me
example.com
gnu.org
Нажмите, чтобы развернуть и увидеть больше

Пустые строки и строки с # игнорируются.

Подсети и IP-адреса

Маршруты можно также указывать через .env:

BASH
OC_SPLIT_ROUTES='
192.168.25.0/24
10.1.0.0/16
1.1.1.1/32
'
Нажмите, чтобы развернуть и увидеть больше

Или после запуска редактировать файл:

BASH
vim ./data/routes.txt
Нажмите, чтобы развернуть и увидеть больше

Формат такой же простой:

TEXT
192.168.25.0/24
10.1.0.0/16
1.1.1.1/32
Нажмите, чтобы развернуть и увидеть больше

Изменения в domains.txt и routes.txt подхватываются автоматически. Контейнер перезапускать не нужно. В случае обновления переменных в .env придётся перезапускать контейнер.

Запуск middle server

BASH
docker compose down

docker compose up -d

docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Проверка Split Routing

Подключаемся к middle server на клиенте:

BASH
sudo openconnect -c ./middleuser.p12 'middle.r4ven.me/?secretMiddleServerWord'
Нажмите, чтобы развернуть и увидеть больше

Проверяем домены из списка:

BASH
curl ifconfig.me

curl eth0.me
Нажмите, чтобы развернуть и увидеть больше

Если ifconfig.me добавлен в OC_SPLIT_DOMAINS, он должен открываться через private сервера. Если eth0.me в список не добавляли, он должен показать внешний IP middle сервера.

Проверяем маршруты:

BASH
mtr -wb example.com

mtr -wb linuxmint.com

mtr -wb 1.1.1.1
Нажмите, чтобы развернуть и увидеть больше

Обратите внимание на второй hop: для адресов из списка трафик должен уходить в сторону middle/private цепочки, а для остальных адресов - идти обычным путём.

Пример обновления списков доменов и подсетей на лету

Например, добавим домен и отдельный IP:

BASH
echo 'eth0.me' >> ./data/domains.txt

echo '9.9.9.9/32' >> ./data/routes.txt
Нажмите, чтобы развернуть и увидеть больше

Через некоторое время на клиенте можно сбросить DNS-кеш и проверить:

BASH
resolvectl flush-caches

curl eth0.me

mtr -wb 9.9.9.9
Нажмите, чтобы развернуть и увидеть больше

Запуск в режиме network_mode: host

Хоть и работа сервисов в изолированной Docker среде - это преимущество, оно же имеет и недостатки. В случае работы клиентского подключения к private server внутри контейнера, скорость клиентов, подключённых к middle server может быть, в среднем, в 3 раза ниже.

Если вам критически важна скорость, то можно запустить middle server в сетевом режиме хоста. Для этого просто замените директиву ports на network_mode: host.

Пример:

BASH
---

services:
  openconnect:
    depends_on:
      certbot:
        condition: service_completed_successfully
    build:
      context: .
      dockerfile: Dockerfile
    image: r4venme/openconnect:v1.4-client
    container_name: openconnect
    restart: always
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 512M
    cap_add:
      - NET_ADMIN
      - NET_RAW
    hostname: openconnect
    env_file:
      - .env
    volumes:
      - ./data/:/etc/ocserv
    devices:
      - /dev/net/tun:/dev/net/tun
    network_mode: host
Нажмите, чтобы развернуть и увидеть больше

Я постарался по максимуму адаптировать логику работы скриптов внутри контейнера так, чтобы они идентичным образом работали и в сетевом режиме хоста.

Настройка автозапуска с помощью systemd

Когда всё проверили, можно настроить автозапуск нашего middle server через systemd:

BASH
docker compose down
Нажмите, чтобы развернуть и увидеть больше
BASH
cat << EOF > /etc/systemd/system/openconnect.service
[Unit]
Description=OpenConnect **middle server**
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
WorkingDirectory=/opt/openconnect
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
systemctl daemon-reload

systemctl enable --now openconnect

journalctl -fu openconnect
Нажмите, чтобы развернуть и увидеть больше

Полезные команды для диагностики

Посмотреть логи контейнера:

BASH
docker compose logs -f openconnect
Нажмите, чтобы развернуть и увидеть больше

Проверить, поднялся ли upstream-интерфейс:

BASH
docker exec -it openconnect ip addr show oc-middle0
Нажмите, чтобы развернуть и увидеть больше

Посмотреть policy routing:

BASH
docker exec -it openconnect ip rule show
docker exec -it openconnect ip route show table 430
docker exec -it openconnect ip route show table 431
Нажмите, чтобы развернуть и увидеть больше

Посмотреть nftables:

BASH
docker exec -it openconnect nft list table ip oc_nat

docker exec -it openconnect nft list chain DOCKER-USER
Нажмите, чтобы развернуть и увидеть больше

Посмотреть текущие домены и маршруты split tunneling:

BASH
cat ./data/domains.txt
cat ./data/routes.txt
Нажмите, чтобы развернуть и увидеть больше

При необходимости можно вручную очистить nftables set с доменными IP:

BASH
docker exec -it openconnect nft flush set ip oc_nat oc_set
Нажмите, чтобы развернуть и увидеть больше

Послесловие

Во время разработки образа было выпито не мало кружек чая и потрачено сильно больше нервов, чем планировалось. Но результат того стоил, я считаю.

В итоге получился очень удобный и гибкий инструмент для управления маршрутизацией внутри приватных сетей.

Пользователи подключаются к middle server, а дальше вы сами выбираете логику: отправлять весь их трафик через private server или пропускать туда только нужные домены и подсети.

Мне такой подход нравится тем, что он не требует раздавать пользователям прямой доступ к private server. Private-контур остаётся закрытым, а middle server можно отдельно обновлять, переносить, ограничивать и использовать как управляемую точку входа.

Уверен у многих пользователей могут возникнут различные вопросы. Смело задавайте их в Вороньем чате, в issue на GitHub или пишите мне на почту: kar-kar@r4ven.me.

Спасибо, что читаете. Всех благ!

Авторские права

Автор: Иван Чёрный

Ссылка: https://r4ven.me/networking/nastraivaem-openconnect-middle-server-dlya-dostupa-k-zakrytomu-konturu/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша