Короткий ответ
Подрядчик — отдельный identity: свой ключ WireGuard / свой сертификат OpenVPN / своя AD-учётка без админских групп, свой [Peer] с AllowedIPs = 10.8.0.20/32 на сервере. На клиенте подрядчика в туннель кладут только то, что нужно: часто /32 бастиона 10.0.10.10, не всю 10.0.10.0/24. Срок в календарь + отзыв как у уволенного. Не давайте общий office.conf из чата сотрудников и не открывайте 3389 в WAN «на время проекта».
Фиксируйте в заявке: ФИО, компания, цель (RDP к pc01), префиксы, дата окончания, кто утвердил.
Симптомы и как отличить
Плохой доступ уже выдан, если:
- в
wg showодин peer на «ООО Интегратор» сAllowedIPs 10.0.0.0/8; - подрядчик логинится учётки
ivanovсотрудника; - нет MFA, нет журнала.
Нужна другая статья, если сотрудник штатный — шаблон сотрудника со split на LAN. Если увольнение — отзыв.
Возможные причины
- Shared key = нельзя отозвать одного человека.
- Широкий маршрут = сканирование DC, шары, принтеры.
- Домен-админ «чтобы побыстрее поставили 1С».
- RDP с интернета параллельно VPN.
- Нет логов, кто коннектился в инцидент.
Диагностика
wg show
wg show wg0 allowed-ipsOpenVPN CCD: уникален ли client-config-dir / сертификат CN. RRAS: уникальная учётка в NPS.
Get-VpnConnection
Get-ADUser -Identity 'vendor.petrov' -Properties MemberOf, AccountExpirationDate, EnabledСоставьте: какие 10.0.10.0/24 хосты ему реально нужны (лучше один jump).
Решение
1. Identity
- AD:
vendor.<фамилия>, OU подрядчиков,AccountExpirationDate, группаVPN-VendorsнеDomain Admins. - OpenVPN: отдельный client cert, CN=vendor.petrov, CRL готов.
- WireGuard:
wg genkeyтолько для него, public на сервере.
2. Адресация туннеля
Выдайте свободный 10.8.0.20/32. На сервере WG:
[Peer]
PublicKey = <vendor>
AllowedIPs = 10.8.0.20/32Не давайте ему 10.8.0.0/24 на сервере (это cryptokey routing чужих пиров).
3. Маршруты клиента подрядчика
AllowedIPs = 10.8.0.1/32, 10.0.10.10/32Только шлюз (если нужен) и бастион. Не 10.0.10.0/24.
Windows RAS:
Add-VpnConnectionRoute -ConnectionName 'Vendor' -DestinationPrefix '10.0.10.10/32'4. Firewall на шлюзе
FORWARD: 10.8.0.20 → 10.0.10.10 порты 3389 (или 22), drop остальное. Даже если ошибутся AllowedIPs, ACL спасёт.
iptables -A FORWARD -s 10.8.0.20/32 -d 10.0.10.10 -p tcp --dport 3389 -j ACCEPT
iptables -A FORWARD -s 10.8.0.20/32 -d 10.0.10.0/24 -j DROPНе ufw disable.
5. На бастионе
Локальная или dedicated учётка, не domain admin. Журнал RDP. NLA. См. RDP-статьи.
6. MFA и срок
Где возможно — MFA на VPN (MFA). Календарь отзыва. После проекта — чеклист отзыва.
7. Журнал
Включите учёт подключений (журналирование).
Стенд: три проверки ACL
Подрядческий пир 10.8.0.20. С его конфига:
ping -c 1 10.0.10.10
ping -c 1 10.0.10.11
nc -vz 10.0.10.10 3389
nc -vz 10.0.10.11 3389
nc -vz 10.0.10.10 445Ожидание: жив только согласованный хост и порт. Если 445 открылся «сам» — дыра FORWARD или слишком широкий AllowedIPs на клиенте (он поставил 10.0.10.0/24). Серверный DROP на 10.8.0.20 → 10.0.10.0/24 кроме 3389 к бастиону должен спасать даже кривой клиентский конфиг.
Второй человек подрядчика с тем же файлом .conf: wg show на сервере увидит прыгающий endpoint. Заведите второй ключ, первый не шарьте. CMDB: pubkey, ФИО, компания, 10.8.0.20, дата конца.
AD:
Get-ADUser vendor.petrov -Properties AccountExpirationDate, MemberOf, EnabledExpiration в прошлом при живом WG-пире = дыра. Снимайте оба.
Не выдавайте домен-админа «на день установки». Локальный админ на бастионе + журналы RDP. После проекта — чеклист отзыва, не «оставим, вдруг доделка».
Отдельный endpoint не обязателен, но отдельный [Peer] — да. Не кладите подрядчика в тот же AllowedIPs-групповой список, что сотрудники. На nftables заведите набор vendor_peers с 10.8.0.20, правила читаемее, чем десяток однострочников iptables. Журналируйте wg show dump без private key в SIEM, чтобы видеть handshake после даты окончания договора.
wg show wg0 dump | awk '$4=="10.8.0.20/32" {print}'Если подрядчику нужен Git по SSH на 10.0.10.40, это новый /32 и порт 22 в ACL, новая строка в заявке, не «ну раз VPN уже есть». Каждый ресурс — изменение политики. Windows-клиент подрядчика: Get-VpnConnection не заменяет WG; выдайте инструкцию того стека, который реально стоит, иначе они включат RAS L2TP и откроют 1701 «сами».
Срок в календаре без remove peer бесполезен так же, как disable AD без WG. Поставьте напоминание за 3 дня и в день X. После X wg show не должен содержать его pubkey. Договор: запрет пересылки .conf в личный мессенджер; при нарушении — ротация ключа как инцидент, не «перевыпустим когда-нибудь».
Как проверить, что проблема устранена
С подрядческого пира:
- ping
10.0.10.10ок,10.0.10.11fail; - RDP только на согласованный хост;
ip route get 10.0.10.11не в туннель (или ACL drop);- второй ноутбук с тем же ключом не должен существовать.
С сервера: wg show handshake только с ожидаемого endpoint. AD expiration в будущем, MemberOf минимален.
ping -c 1 10.0.10.10
ping -c 1 10.0.10.11Если не помогло
- Нужен «весь VLAN на неделю установки» — временный широкий маршрут с датой в тикете и напоминанием, не бессрочно.
- Их корпоративный VPN конфликтует overlapping — NAT/перенумерация.
- Требуют домен-админа — эскалируйте, не соглашайтесь в чате.
Профилактика
- Шаблон
vendor-peer.conf.j2в ansible. - Ежеквартальный review пиров без handshake 30+ дней.
- Запрет шаринга конфигов в договоре.
- 3389 с WAN закрыт.
FAQ
Можно ли одну учётку на компанию подрядчика?
Юридически иногда да, технически плохо: нет персональной ответственности. Лучше персона + их MFA.
Подрядчик на Mac, у нас только RAS L2TP
Выдайте WG или OpenVPN 2.6, не открывайте L2TP/1701 в WAN. L2TP legacy.
Нужен SMB на файловую шару
/32 файлового сервера + share permissions + отдельная учётка, не «вся LAN».
Они просят AnyDesk параллельно
Либо VPN, либо согласованный tool с журналом. Два дырявых канала — хуже.
Как дать доступ на день
Expiration AD + WG peer с календарём. Не «потом удалим».