Netbird ACL и группы доступа: настройка
Сразу после установки self-hosted Netbird все подключённые устройства попадают в одну группу All с открытой политикой «разрешить всё между всеми» — удобно для теста, опасно в продакшене: любой скомпрометированный ноутбук сотрудника получает сетевой доступ ко всем серверам разом. Ниже — как устроена модель доступа Netbird на уровне групп и Policies, чем она отличается от ACL в Tailscale/Headscale, и как перейти от «плоской» тестовой сети к сегментированной по ролям.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Как устроена модель доступа: Peers, Groups, Policies
В Netbird доступ описывается тремя сущностями:
- Peer — отдельное устройство в сети (сервер, ноутбук, шлюз) со своим WireGuard-ключом и внутренним IP.
- Group — именованный набор пиров. Пир может состоять в нескольких группах одновременно.
- Policy (в Dashboard — раздел «Access Control») — правило вида «пирам из группы A разрешено обращаться к пирам из группы B по такому-то протоколу и портам».
После установки в системе уже есть группа All (в неё автоматически попадает каждый новый пир) и политика Default, которая разрешает трафик All → All по всем протоколам и портам. Это стартовая точка, а не рекомендуемая конфигурация: пока Default включена, любые более узкие правила, которые вы добавите поверх, ничего не меняют — Netbird применяет политики по принципу «ИЛИ»: если хотя бы одна включённая политика разрешает пару пиров, трафик между ними пройдёт, даже если остальные политики его запрещают. Отсюда прямое следствие: сегментацию сети имеет смысл начинать не с добавления новых правил, а с отключения (не обязательно удаления — можно выключить тумблером) политики Default.
Важно понимать границы модели: Policy решает, разрешено ли WireGuard-соединение между пирами на уровне control-plane. Она не заменяет firewall внутри самой машины — если Netbird разрешил доступ до сервера по 443/tcp, а ufw/iptables на сервере этот порт всё равно блокирует, соединение не пройдёт. Это два независимых слоя, которые нужно держать согласованными.
Чем это отличается от ACL в Tailscale и Headscale
Если раньше настраивали ACL в Tailscale или Headscale, разница ощущается сразу. Там политика доступа — один YAML/HuJSON-файл с группами, тегами (tagOwners) и списком правил accept, который заливается на control-сервер целиком:
acls:
- action: accept
src: ["group:admins"]
dst: ["tag:servers:22,443"]
В Netbird такого единого файла нет в принципе — Groups и Policies это отдельные объекты в базе management-сервера, которые создаются и редактируются по отдельности через Dashboard или API, а не одним коммитом в git. Это даёт пару практических отличий:
- Гранулярность применения. В Headscale изменение одной строчки в файле означает пересборку и применение всей политики целиком. В Netbird можно включить/выключить или отредактировать одну конкретную Policy, не трогая остальные — удобно для точечных изменений, но требует дисциплины: легко забыть про старое правило, которое всё ещё где-то разрешает лишнее.
- Нет системы
tagOwners. В Tailscale теги — это отдельный механизм с контролем того, кто имеет право присвоить устройству тег (что важно как граница безопасности: сам пир не может произвольно назначить себе привилегированный тег). В Netbird группа — это просто список пиров без встроенной модели «владения» тегом; ограничение того, кто может менять состав групп, обеспечивается ролями пользователей Dashboard (Admin/User), а не механизмом внутри самой ACL-модели. - GUI по умолчанию, а не файл в git. Headscale и его ACL-файл естественно ложатся в GitOps-процесс — политика ревьюится в pull request. У Netbird основной интерфейс — веб-панель, а версионирование правил «как код» требует отдельного решения через REST API или Terraform (см. ниже), это не встроено по умолчанию так же плотно, как у файлового подхода Headscale.
Подробнее оба подхода целиком, включая архитектуру и требования к серверу, разобраны в статье Netbird или Tailscale: self-hosted альтернативы и в материале про свой control-сервер для Tailscale на Headscale.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверГруппы: создание и автоматическое назначение пиров
Группу можно создать заранее в Dashboard (Access Control → Groups → Add Group) и потом руками раскидать по ней пиров, но для сети из десятков устройств ручное перетаскивание не масштабируется. Есть три способа автоматизировать назначение:
- Группа на Setup Key. При создании ключа (
Setup Keys → Create Setup Key) можно сразу указать список групп — каждый пир, который зарегистрируется по этому ключу, автоматически в них попадёт. Это самый предсказуемый способ для инфраструктуры: под каждую роль сервера — свой setup key.
netbird up --management-url https://vpn.example.com \
--setup-key <ключ-с-группой-servers-prod>
- Группы из claim'ов identity provider. Если пользователи логинятся через внешний OIDC (Zitadel, Keycloak, Entra ID) с группами в токене, Netbird может сопоставить группы IdP с группами Netbird автоматически при первом входе пользователя — тогда состав группы «admins» в Netbird синхронизируется с тем, что задано в вашем каталоге пользователей, а не дублируется вручную.
- Ручное редактирование через Dashboard или API — подходит для точечных исключений (например, временно добавить один ноутбук в группу
servers-readonlyдля диагностики).
Разумная стартовая раскладка групп для небольшой инфраструктуры:
| Группа | Кто в неё входит |
|---|---|
servers-prod | продакшен-серверы приложений и БД |
servers-staging | тестовые окружения |
admins | ноутбуки инженеров с полным доступом |
dev | рабочие станции разработчиков |
gateway-office | шлюз с маршрутом в офисную локальную сеть |
Policies: правила доступа между группами
Создаётся Policy в Dashboard через Access Control → Add Policy: имя, источник (одна или несколько групп), назначение (одна или несколько групп), протокол (All/TCP/UDP/ICMP), диапазон портов и тумблер Bidirectional — если включён, правило действует в обе стороны (A может достучаться до B, и B до A), если выключен — только в одну (A → B, обратно нет). Для типичной раскладки из таблицы выше набор правил может выглядеть так:
| Policy | Источник | Назначение | Протокол/порты | Bidirectional |
|---|---|---|---|---|
admins-to-all | admins | servers-prod, servers-staging | All | нет |
dev-to-staging | dev | servers-staging | TCP 22, 80, 443, 8000-8100 | нет |
prod-internal | servers-prod | servers-prod | All | да |
gateway-office-route | gateway-office | admins, dev | All | да |
Логика чтения: разработчики (dev) не имеют прямого доступа к продакшену вообще — для этой пары групп не создано ни одной policy, и по умолчанию (после отключения Default) это означает запрет. Инженеры (admins) могут дойти в одну сторону до обоих окружений. Серверы продакшена видят друг друга полностью (нужно для внутреннего трафика кластера — например, между приложением и базой).
После применения правило начинает действовать на онлайн-пирах почти сразу — management-сервер проталкивает обновлённый конфиг по уже открытому каналу. Пир, который был offline в момент изменения, получит актуальные правила при следующем подключении. Проверить фактическую связность удобнее всего с самой машины:
netbird status
curl -v --connect-timeout 3 http://100.64.x.x:8080
Если netbird status показывает пир как Connected, а запрос всё равно виснет — почти всегда дело либо в отсутствующей policy для этой пары групп, либо в локальном firewall принимающей стороны, а не в самом Netbird.
ACL как код: REST API и Terraform
Раз единого файла политики в Netbird нет, воспроизводимость конфигурации приходится собирать через API. Сначала генерируем Personal Access Token в Dashboard (Users → ваш профиль → Personal Access Tokens), дальше группы и политики создаются обычными HTTP-запросами:
# создать группу
curl -s -X POST https://vpn.example.com/api/groups \
-H "Authorization: Bearer <PAT>" -H "Content-Type: application/json" \
-d '{"name": "servers-prod"}'
# создать policy (source/destination — ID групп, полученные из ответа выше)
curl -s -X POST https://vpn.example.com/api/policies \
-H "Authorization: Bearer <PAT>" -H "Content-Type: application/json" \
-d '{
"name": "admins-to-all",
"enabled": true,
"rules": [{
"sources": ["<group-id-admins>"],
"destinations": ["<group-id-servers-prod>"],
"bidirectional": false,
"protocol": "all",
"action": "accept"
}]
}'
Для более систематического подхода есть официальный Terraform-провайдер netbirdio/netbird — он оборачивает тот же REST API в декларативные ресурсы, и правила доступа можно хранить в git и катить через terraform plan/apply, приближая Netbird к тому же GitOps-workflow, что у Headscale из коробки:
resource "netbird_group" "servers_prod" {
name = "servers-prod"
}
resource "netbird_policy" "admins_to_all" {
name = "admins-to-all"
enabled = true
rule {
sources = [netbird_group.admins.id]
destinations = [netbird_group.servers_prod.id]
bidirectional = false
protocol = "all"
action = "accept"
}
}
Точный синтаксис провайдера меняется между релизами — сверьтесь с актуальной схемой в реестре Terraform перед использованием в проде.
Posture Checks и типичные ошибки конфигурации
Помимо групп и Policies, у Netbird есть отдельный слой — Posture Checks: условие поверх policy, которое проверяет состояние пира перед тем, как разрешить ему трафик. Типичные условия — минимальная версия клиента netbird, разрешённая ОС, гео/сеть подключения. Удобно для BYOD: разрешить доступ к продакшену только пирам не старше определённой версии клиента с включённым полнодисковым шифрованием — устройство, не прошедшее проверку, не получит доступ, даже состоя в нужной группе.
Частые ошибки при настройке ACL в Netbird:
- Забыли отключить
Default. Самая частая причина «правила есть, а сегментации нет» — политики складываются через ИЛИ, и разрешающийDefault: All → Allперекрывает любые более узкие ограничения, пока сам активен. - Пир не добавлен ни в одну нужную группу. Убрали пира из
All, но не добавили в целевую группу — он останется полностью изолированным, и безnetbird statusна самой машине это легко принять за баг сети. - Заблокировали себе доступ во время тестирования. Отключая
Defaultна живой инфраструктуре, держите запасной путь — например, отдельную временную policy для своей admin-группы, которую не трогаете. - ACL Netbird и локальный firewall рассинхронизированы. Policy разрешает WireGuard-туннель, но
ufw/iptablesна сервере может независимо резать те же порты — проверяйте оба слоя, а не только Dashboard. - Порты указаны не для того протокола. Правило на
TCP 51820не откроет тот же порт для UDP — протокол и порты в Policy привязаны друг к другу явно.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Что произойдёт, если удалить группу All совсем?
Netbird не даст удалить служебную группу All — она системная и обновляется автоматически при регистрации новых пиров. Отключить или удалить можно связанную с ней policy Default, саму группу — нет.
Можно ли ограничить доступ по конкретному IP пира, а не только по группе?
Прямого правила «по IP» в модели Policy нет — сегментация строится через группы. Но пира можно выделить в отдельную группу из одного устройства и написать под неё точечную policy, что даёт тот же результат.
ACL применяется мгновенно или нужен рестарт клиента?
Мгновенно для пиров, у которых открыто соединение с management-сервером — обновление конфигурации приходит по существующему каналу без переустановки туннеля. Офлайн-пир получит актуальные правила при следующем подключении.
Как посмотреть, какая именно policy разрешила или запретила соединение?
Dashboard не показывает трассировку «эта policy сработала для этого пакета» — приходится реконструировать вручную по списку активных policy для пары групп. Для сложных схем стоит вести отдельную табличку соответствия, иначе разобраться в пересекающихся правилах через полгода будет сложно.
Работают ли Posture Checks в бесплатной self-hosted версии без подписки?
Доступность конкретных фич меняется между релизами — перед тем как закладывать Posture Checks в архитектуру, сверьтесь с текущим лицензированием на странице тарифов проекта.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →