Аудит доступов VPN: кто и когда подключался
Рано или поздно у любого VPN-сервера с несколькими пользователями возникает вопрос: а кто вообще к нему подключался вчера в 23:40? Уволенный сотрудник, чей ключ забыли отозвать? Коллега, который зашёл с чужого IP? Или просто нужно закрыть требование службы безопасности «показать журнал доступа за последний месяц». Без настроенного учёта подключений ответ на такие вопросы — либо «не знаю», либо часы ковыряния в разрозненных логах. Ниже — рабочая схема: что логировать в OpenVPN и WireGuard, как собрать это в одном месте и как получать регулярные отчёты по активности, а не искать вручную каждый раз.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Зачем аудит доступов, если сервер и так работает
Аудит подключений нужен не «для галочки», а для трёх практических сценариев. Первый — расследование инцидента: что-то пошло не так, и нужно понять, кто был в сети в момент события. Второй — контроль отзыва доступа: увольнение сотрудника или закрытие проекта должно сопровождаться проверкой, что его сертификат или ключ действительно перестал использоваться, а не просто удалён из базы. Третий — банальная гигиена: если вы видите, что один и тот же аккаунт подключается одновременно с двух разных стран, это повод спросить, не утёк ли ключ.
Разница между «сервер логирует» и «у вас настроен аудит» в том, что во втором случае данные структурированы, хранятся достаточно долго и доступны в виде отчёта, а не «где-то в journalctl за последние два дня, пока не перезаписалось».
OpenVPN: логи и статус из коробки
OpenVPN изначально проектировался с учётом контроля доступа, поэтому у него есть встроенные механизмы, которых нет в WireGuard.
В server.conf для нормального учёта нужны минимум три директивы:
verb 3
log-append /var/log/openvpn/openvpn.log
status /var/log/openvpn/status.log 30
status-version 2
Файл status.log обновляется каждые 30 секунд и содержит текущий список подключённых клиентов с реальным IP, виртуальным IP, временем подключения и объёмом трафика:
CLIENT_LIST,ivan,203.0.113.45:44012,10.8.0.6,,1245012,987654,2026-08-28 09:12:41,1724832761,UNDEF
Этого достаточно для снимка «кто сейчас в сети», но не для истории за месяц — файл перезаписывается. Для полноценного журнала подключений/отключений используются скрипты client-connect и client-disconnect:
# добавить в server.conf
script-security 2
client-connect /etc/openvpn/scripts/log-connect.sh
client-disconnect /etc/openvpn/scripts/log-disconnect.sh
Сам скрипт простой — пишет строку в отдельный аудит-лог:
#!/bin/bash
# /etc/openvpn/scripts/log-connect.sh
echo "$(date '+%F %T') CONNECT cn=${common_name} real_ip=${trusted_ip} vpn_ip=${ifconfig_pool_remote_ip}" \
>> /var/log/openvpn/audit.log
Для log-disconnect.sh аналогично, но с добавлением bytes_received и bytes_sent — эти переменные OpenVPN тоже передаёт в окружение скрипта. В результате получаете построчный журнал вида «кто, откуда, когда пришёл и когда ушёл», который не перетирается и можно хранить сколько нужно.
Если у вас несколько пользователей с общими сертификатами (плохая практика, но встречается) — самое время развести их по индивидуальным сертификатам через easy-rsa, иначе common_name в логе не скажет вам ничего полезного.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверWireGuard: логов нет, придётся собирать самим
WireGuard спроектирован минималистично и принципиально не пишет журнал подключений — это осознанное решение авторов протокола. Всё, что у вас есть из коробки — команда wg show, которая отдаёт live-снимок:
wg show wg0 dump
Вывод по каждому peer включает публичный ключ, последний handshake (unix-время) и счётчики трафика, но не хранит историю. Если сервер перезапустить или peer давно не выходил на связь, прошлые события теряются.
Практическое решение — опрашивать wg show по расписанию и фиксировать изменения состояния. Простой вариант через cron раз в минуту:
#!/bin/bash
# /usr/local/bin/wg-audit.sh
STATE_FILE=/var/lib/wg-audit/last_handshakes.tsv
LOG_FILE=/var/log/wireguard/audit.log
mkdir -p /var/lib/wg-audit
wg show wg0 dump | tail -n +2 | while read -r pubkey psk endpoint allowed_ips handshake rx tx keepalive; do
prev=$(grep "^${pubkey}" "$STATE_FILE" 2>/dev/null | cut -f2)
if [ "$handshake" != "0" ] && [ "$handshake" != "$prev" ]; then
echo "$(date '+%F %T') HANDSHAKE peer=${pubkey:0:12}... endpoint=${endpoint} allowed_ips=${allowed_ips}" >> "$LOG_FILE"
fi
sed -i "/^${pubkey}/d" "$STATE_FILE"
echo -e "${pubkey}\t${handshake}" >> "$STATE_FILE"
done
Это не идеальный «журнал подключения», а журнал handshake-событий — WireGuard пересогласовывает ключи примерно раз в 2 минуты активности, поэтому реальное «подключение» будет виднее как серия хендшейков, а «отключение» вычисляется по отсутствию новых хендшейков дольше ~3 минут. Для большинства задач аудита этого достаточно: видно, кто и когда был активен, с какого IP.
Второй источник данных — сам факт входящих UDP-пакетов на порт WireGuard, если нужно видеть даже неудачные попытки подключения (например, с неверным ключом, которые WireGuard молча отбрасывает и вообще нигде не показывает). Логируется через nftables:
nft add rule inet filter input udp dport 51820 log prefix "wg-attempt: " limit rate 10/minute
Это уже не про легитимных пользователей, а про разведку — полезно, если сервер публично доступен и вы хотите видеть попытки сканирования порта.
Если аудит подключений для вас критичен (финансовый сектор, требования комплаенса), иногда проще держать OpenVPN именно для тех пользователей, кому нужен полный журнал, а WireGuard — для остальных, где важнее скорость. Сравнение подходов и нюансы разбирали в статье про двухфакторную аутентификацию для VPN — тот же принцип «где важнее контроль, там больше накладных расходов» применим и к логированию.
Централизация: логи не должны жить только на VPN-сервере
Если лог подключений лежит только на самом VPN-сервере, у него два слабых места: диск может закончиться, а при компрометации сервера тот же злоумышленник может подчистить журнал. Поэтому логи стоит копировать на отдельный хост.
Самый простой вариант — rsyslog с пересылкой по TCP/TLS на центральный лог-сервер:
# /etc/rsyslog.d/50-vpn-audit.conf на VPN-сервере
module(load="imfile")
input(type="imfile" File="/var/log/openvpn/audit.log" Tag="openvpn-audit:")
input(type="imfile" File="/var/log/wireguard/audit.log" Tag="wg-audit:")
action(type="omfwd" target="10.0.0.5" port="6514" protocol="tcp"
StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name")
Если у вас уже есть стек мониторинга, логичнее отправлять эти же файлы в Grafana Loki через Promtail — тогда отчёты строятся не bash-скриптом, а запросами LogQL, и вы получаете графики активности «из коробки». Как поднять сам стек, разобрано в статье про логи в Grafana Loki на VPS.
Автоматические отчёты по активности
Сырые логи полезны для расследования конкретного случая, но для регулярного контроля нужен сводный отчёт: кто подключался за сутки/неделю, сколько раз и на сколько суммарно.
Пример скрипта, который парсит журнал OpenVPN и WireGuard за сутки и формирует таблицу по пользователям:
#!/bin/bash
# /usr/local/bin/vpn-daily-report.sh
DATE=$(date -d "yesterday" '+%Y-%m-%d')
REPORT="/tmp/vpn-report-${DATE}.txt"
echo "Отчёт по VPN-доступам за ${DATE}" > "$REPORT"
echo "--- OpenVPN ---" >> "$REPORT"
grep "$DATE" /var/log/openvpn/audit.log | \
awk '{print $4}' | sort | uniq -c | sort -rn >> "$REPORT"
echo "--- WireGuard (по хендшейкам) ---" >> "$REPORT"
grep "$DATE" /var/log/wireguard/audit.log | \
awk '{print $3}' | sort | uniq -c | sort -rn >> "$REPORT"
cat "$REPORT"
Отправка в Telegram по cron, чтобы отчёт приходил каждое утро без ручного запуска:
# crontab -e
0 8 * * * /usr/local/bin/vpn-daily-report.sh > /tmp/report.txt && \
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendDocument" \
-F chat_id=<CHAT_ID> -F document=@/tmp/report.txt
На выходе — короткий файл вида:
--- OpenVPN ---
14 cn=ivan
6 cn=maria
1 cn=guest_temp
--- WireGuard (по хендшейкам) ---
212 peer=AbCdEf12...
Резкий выброс в цифрах (пользователь, обычно подключающийся 2-3 раза в день, вдруг даёт 200 событий) — сигнал проверить, не проблема ли это с роумингом клиента или не подозрительная ли активность.
Хранение, ротация и сроки
Лог подключений имеет смысл хранить дольше, чем стандартные системные логи, но не вечно — диск не резиновый, а часть данных (реальные IP пользователей) — персональные данные, для которых существуют требования по срокам хранения и защите. Разбор именно этой темы — в статье что хранить по закону про логи VPN-подключений, здесь только техническая часть.
Пример logrotate для аудит-логов с хранением 90 дней и сжатием:
# /etc/logrotate.d/vpn-audit
/var/log/openvpn/audit.log /var/log/wireguard/audit.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
create 0640 root adm
}
Если сервер держит несколько сервисов и логов в целом много, общие принципы ротации и защиты от переполнения диска стоит держать в голове отдельно — это разобрано в статье про ротацию логов, чтобы не забивался диск.
Как искать конкретное подключение при расследовании
Когда нужно быстро ответить на вопрос «кто заходил с IP 198.51.100.20 в ночь на вторник», порядок действий такой:
- Ищем по IP в аудит-логе OpenVPN:
grep "198.51.100.20" /var/log/openvpn/audit.log
- Для WireGuard ищем по
endpointв том же диапазоне дат — публичный ключ сопоставляем с именем через свой реестр (wg-easyили простой CSV-файлpubkey,владелец, который стоит вести отдельно, так как сам WireGuard имён не знает). - Смотрим системные логи входа на сервер за тот же промежуток (
journalctl -u sshd --since "2026-08-25 22:00" --until "2026-08-26 02:00") — если это была не просто VPN-сессия, а ещё и SSH после подключения, коррелируем по времени. - Если центральный лог-сервер настроен (раздел выше), сверяем те же данные там — на случай, если локальные логи на VPN-сервере уже подчищены.
Такая цепочка занимает 5-10 минут вместо часов, если данные уже собраны и структурированы — весь смысл настройки аудита именно в этом.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужно ли логировать, какие сайты посещал пользователь через VPN, или достаточно факта подключения?
Для большинства задач аудита доступа достаточно факта подключения: кто, когда, с какого IP, сколько трафика прошло суммарно. Логирование конкретных посещённых адресов — это уже DPI-уровень, требует отдельной инфраструктуры (прокси с логированием, deep packet inspection) и добавляет юридических вопросов о приватности пользователей. Начинайте с базового журнала подключений, расширяйте только если есть конкретное требование.
WireGuard в принципе может логировать так же подробно, как OpenVPN?
Нет, и это не баг, а архитектурное решение — WireGuard намеренно не хранит состояние сессий и не пишет журнал событий. Максимум, что можно получить, — приближённую картину через опрос wg show по расписанию, как описано выше. Если нужен точный built-in журнал подключений, для этой конкретной задачи OpenVPN подходит лучше.
Сколько ресурсов на VPS съедает такой аудит?
Немного: cron-скрипт раз в минуту и логи в десятки мегабайт в месяц при обычной нагрузке в 10-20 пользователей. На VPS с 1-2 vCPU и 2 ГБ RAM это не будет заметно даже рядом с самим VPN-сервисом.
Можно ли получать отчёты не в Telegram, а на почту или в корпоративный чат?
Да, скрипт из раздела про отчёты — это обычный bash, вывод можно направить куда угодно: mail, curl в Slack/Mattermost webhook, запись в S3-совместимое хранилище для архива. Логика сбора данных не меняется, меняется только последняя строчка с отправкой.
Что делать, если пользователи подключаются через роутер (Keenetic, MikroTik), а не напрямую?
Тогда реальный IP клиента вы увидите на VPN-сервере как IP роутера, а не конкретного устройства за ним — это ограничение архитектуры, а не логирования. Если важно различать устройства за одним роутером, единственный надёжный способ — выдавать каждому устройству отдельный VPN-профиль вместо общего туннеля на роутере.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →