Ситуация, когда устройства видны в Tailscale, но нужный сайт, API, база данных или SSH-порт не открывается, не всегда означает поломку VPN. Часто туннель исправен, а конкретный поток не совпадает с правилом доступа: источник определен не той группой, сервер получил тег, в назначении забыли порт, запрос идет через subnet router или приложение слушает только localhost. Поэтому исправление нужно начинать не с переустановки клиента и не с разрешения всего трафика, а с точного описания соединения.

Tailscale поддерживает два формата сетевой политики: современные grants и прежние ACL. Для новых конфигураций документация рекомендует grants, а ACL продолжают работать. Если пользовательская политика уже задана, доступ, который явно не разрешен подходящим правилом, блокируется. При полностью отсутствующей пользовательской политике применяется стандартное разрешение всего трафика. Это различие важно: иногда проблема появляется сразу после замены исходной allow-all политики на собственный файл с ограничениями.

Не расширяйте доступ до выяснения причины

Самая опасная реакция на недоступный сервис — временно разрешить всем источникам все назначения и порты. Такое изменение действительно может скрыть ошибку, но одновременно открывает административные панели, базы и внутренние интерфейсы всей сети. Временное правило часто остается навсегда. Безопаснее сохранить текущую политику, зафиксировать один воспроизводимый запрос и менять только одно условие за раз.

  • экспортируйте или сохраните версию действующего tailnet policy до изменения;
  • запишите учетную запись пользователя и имя исходного устройства;
  • проверьте, есть ли у исходного и целевого узла теги;
  • зафиксируйте Tailscale IP, MagicDNS-имя и реальный адрес назначения;
  • укажите протокол и порт сервиса, например TCP 443 или UDP 53;
  • отметьте, установлен ли Tailscale на целевом узле или трафик идет через subnet router;
  • проверьте время последнего успешного доступа и время изменения политики;
  • не публикуйте auth key, ключи узлов, токены API и полный файл политики в открытых чатах.

Опишите поток как четыре точных параметра

Правило доступа проверяет не абстрактное намерение «разрешить разработчику внутренний сервис», а конкретный поток. Его удобно записывать как источник, назначение, протокол и порт. Источником может быть пользователь, группа, тег или autogroup. Назначением — пользовательский узел, тегированный сервер, Tailscale IP, хост, сервис либо подсеть. Протокол и порт должны совпасть с тем, куда в действительности обращается клиент.

Источник: group:developers или tag:ci Назначение: tag:internal-app или 100.x.y.z Сеть: TCP Порт: 443 Путь: напрямую по Tailscale или через subnet router

Если хотя бы один элемент описан неверно, правило может выглядеть логичным, но не применяться. Например, браузер открывает HTTPS на 443, а в политике разрешен только 80. Приложение подключается к IP из локальной подсети, а правило разрешает Tailscale-адрес самого роутера. Сервер после назначения тега больше не совпадает с правилом, рассчитанным на владельца-пользователя.

Сначала отделите сеть Tailscale от самого сервиса

Проверка должна идти от нижнего слоя к верхнему. Наличие узла в списке еще не доказывает доступность приложения, а успешный tailscale ping не проверяет TCP-порт веб-сервера. Он показывает, что клиент знает целевой узел и способен построить путь внутри tailnet. После него требуется отдельная проверка нужного порта.

tailscale status tailscale ping <имя-узла-или-100.x.y.z> # Linux/macOS: проверка прикладного порта nc -vz <имя-узла> 443 curl -vk --connect-timeout 5 https://<имя-узла>/ # Windows PowerShell Test-NetConnection <имя-узла> -Port 443

Результаты дают разные ветки диагностики. Если узел не виден или tailscale ping не проходит, сначала проверяются состояние клиента, вход в нужный tailnet, срок действия устройства и базовая политика. Если ping проходит, а TCP-порт закрыт, нужно разбирать правило для порта, локальный firewall, адрес прослушивания и состояние приложения. Если соединение устанавливается по IP, но не по имени, причина обычно в DNS, а не в ACL.

Проверьте, какое правило должно разрешить соединение

В grants источник задается через src, назначение через dst, а сетевые возможности через ip. Например, разрешение HTTPS должно включать TCP 443. В старых ACL источник указывается в src, а назначение вместе с портом — в dst. Не следует механически переносить поле из одного формата в другой: сначала определите, какой раздел реально используется в вашем policy file. Grants и ACL могут сосуществовать, поэтому проверяйте весь файл, а не только последний измененный блок.

// Схема минимального разрешения в формате grants { "src": ["group:developers"], "dst": ["tag:internal-app"], "ip": ["tcp:443"] }

Это пример структуры, а не готовая политика для вставки без проверки. Названия групп и тегов должны существовать в вашем tailnet, а порт должен соответствовать сервису. Для нескольких приложений лучше создавать отдельные понятные правила, чем объединять десятки несвязанных портов в одно широкое разрешение. Так проще тестировать изменения и понимать назначение каждого доступа.

Группа существует, но пользователь в нее не попадает

Сравните адрес учетной записи в группе с фактической identity пользователя. Ошибка в домене, старая учетная запись после смены SSO или ожидание, что вложенная группа развернется автоматически, приводят к несовпадению источника. Тест выполняйте именно под учетной записью проблемного пользователя, а не под администратором, которому доступ может давать отдельная autogroup.

После назначения тега изменился источник или владелец

Теги применяются к устройствам и меняют способ сопоставления узла с политикой. Если автоматизированный сервер или рабочая станция теперь идентифицируется как tag:ci либо tag:server, правило только для конкретного пользователя может перестать соответствовать потоку. При этом tagOwners определяет, кто имеет право назначать тег, но сам по себе не дает сетевой доступ к тегированному узлу. Нужное разрешение все равно должно присутствовать в grants или ACL.

Назначение совпало, но порт другой

Проверьте редиректы и реальную конфигурацию клиента. Пользователь вводит HTTP-адрес на 80, сервер перенаправляет на HTTPS 443, а разрешен только первый порт. Панель может работать на 8443, API — на 8080, база — на собственном порту. Если используется балансировщик, правило должно разрешать адрес и порт фактического первого назначения, а не только внутренний backend.

Отдельно проверьте subnet router

Когда Tailscale не установлен на целевом устройстве, трафик обычно идет через узел, который рекламирует локальный CIDR. В этом случае исправная политика — только одна часть маршрута. Подсеть должна рекламироваться, маршрут должен быть одобрен в панели, клиент должен принять его, а операционная система роутера — пересылать пакеты. Политика при этом должна разрешать именно адрес в целевой подсети и нужный порт.

  1. Проверьте, что subnet router подключен к tailnet и не просрочен.
  2. Сверьте рекламируемый CIDR с адресом сервиса и маской сети.
  3. Убедитесь, что маршрут одобрен или корректно настроен через autoApprovers.
  4. Проверьте принятие маршрутов клиентом на платформе, где это требуется.
  5. Исключите пересечение удаленной подсети с локальной сетью клиента.
  6. Проверьте IP forwarding, обратный маршрут и firewall на роутере.
  7. Разрешите в политике точный адрес или подсеть назначения и только необходимые порты.

Пересекающиеся сети особенно коварны. Если дома и в офисе используется одинаковая подсеть, например 192.168.1.0/24, операционная система может отправлять пакет в локальный Wi-Fi вместо Tailscale-маршрута. Расширение ACL тогда не поможет. Нужно изменить адресный план, применить более специфичный маршрут или использовать отдельный Tailscale-адрес сервиса.

Проверьте MagicDNS и фактический адрес

Имя сервиса может разрешаться не в тот адрес, который разрешен политикой. Сравните результат DNS на рабочем и проблемном устройстве. Внутреннее имя иногда возвращает локальный адрес через split DNS, публичный адрес через системный резолвер или старый адрес после переименования узла. Проверка по Tailscale IP помогает отделить DNS от политики, но не должна становиться постоянным обходным решением.

  • сравните nslookup или dig для имени на двух клиентах;
  • проверьте поисковые домены и split DNS в настройках tailnet;
  • убедитесь, что приложение не использует сохраненный IP;
  • сверьте сертификат TLS с именем, по которому открывается сервис;
  • проверьте, не отправляет ли proxy запрос на публичный адрес вместо Tailscale;
  • после исправления очистите только релевантный DNS-кеш и повторите тест.

Убедитесь, что приложение принимает соединение

Даже идеальная политика не откроет сервис, который не запущен или слушает только 127.0.0.1. На целевом сервере проверьте сокет и процесс без перезапуска. Для веб-приложения адресом прослушивания обычно должен быть Tailscale IP либо подходящий интерфейс, а доступ дополнительно ограничивается firewall и самой авторизацией приложения. Открывать приложение на всех интерфейсах без необходимости не следует.

# Linux: только чтение состояния ss -lntup systemctl status <service> --no-pager journalctl -u <service> --since '15 minutes ago' --no-pager # Проверка локально и по Tailscale IP curl -v http://127.0.0.1:<port>/ curl -v http://100.x.y.z:<port>/

Если сервис работает в Docker, Kubernetes или отдельном network namespace, порт должен быть опубликован в нужный интерфейс. Контейнер может отвечать изнутри, но быть недоступным с хоста. Сравните bind address, проброс портов, ingress и правила host firewall. Не отключайте firewall целиком: добавьте узкое правило для интерфейса Tailscale, целевого порта и допустимого источника, затем проверьте отрицательный сценарий.

Соберите матрицу диагностики

Одна команда редко доказывает причину. Составьте короткую матрицу из двух источников и двух портов. Один источник должен иметь доступ, второй — не иметь. Один порт должен быть разрешен, второй — закрыт. Такая проверка показывает, действительно ли действует принцип минимальных прав, и не маскирует ли проблему локальный firewall или отдельная роль администратора.

Тест A: разрешенный пользователь -> сервис:443 = доступ Тест B: разрешенный пользователь -> сервис:22 = запрет Тест C: посторонний пользователь -> сервис:443 = запрет Тест D: разрешенный пользователь -> другой сервис:443 = по политике Тест E: то же соединение по имени и по ожидаемому IP = одинаковый результат

В журнале фиксируйте время, исходный узел, назначение, порт и результат. Не сохраняйте секреты. Если доступ зависит от device posture, добавьте в матрицу состояние ОС, клиента и требуемых атрибутов. Тогда станет видно, блокирует ли сеть, контекст устройства или само приложение.

Используйте policy tests до сохранения

Tailnet policy поддерживает тесты, которые проверяют ожидаемый доступ и ожидаемый запрет. Они особенно полезны при изменении групп, тегов и большого числа сервисов: ошибка обнаруживается в редакторе политики до влияния на пользователей. Минимальный набор должен подтверждать рабочий сценарий и хотя бы один отрицательный сценарий для каждого критичного сервиса.

  • разрешенный пользователь достигает только нужного назначения;
  • разрешен конкретный порт, а соседний административный порт закрыт;
  • пользователь вне группы не получает доступ;
  • тегированный автоматический узел имеет только необходимое направление;
  • изменение группы не открывает доступ ко всей подсети;
  • маршрут через subnet router не дает доступ к лишним адресам;
  • миграция с ACL на grants сохраняет ожидаемые разрешения и запреты.

Синтаксис тестов зависит от используемой части policy file, поэтому берите актуальный пример из официальной документации Tailscale и адаптируйте его к своим идентификаторам. Не вставляйте непроверенный фрагмент из старой статьи: селекторы и рекомендуемый формат со временем меняются.

Безопасно внесите минимальное изменение

  1. Создайте резервную копию действующей политики или зафиксируйте ее в системе контроля версий.
  2. Добавьте одно узкое разрешение для подтвержденного источника, назначения, протокола и порта.
  3. Добавьте положительный и отрицательный policy test.
  4. Проверьте синтаксис и результаты тестов в редакторе.
  5. Сохраните изменение и повторите матрицу с проблемного устройства.
  6. Проверьте, что посторонний источник и лишний порт по-прежнему заблокированы.
  7. Удалите временное исключение, если оно использовалось для локализации.
  8. Запишите причину, изменение и способ отката.

Если разрешение не помогло, не расширяйте его вслепую. Вернитесь к слоям: DNS, маршрут, адрес прослушивания, firewall, контейнер и авторизация приложения. Совпадение результата с сохранением политики еще не доказывает, что именно ACL была причиной. Например, одновременно мог перезапуститься сервис или обновиться маршрут.

Типичные ошибки при восстановлении доступа

  • разрешить *:* и считать проблему решенной;
  • путать право назначить тег в tagOwners с правом подключаться к тегированному серверу;
  • проверять только под администратором или владельцем tailnet;
  • разрешить Tailscale IP роутера вместо адреса сервиса за subnet router;
  • не указать порт после перехода с одного формата политики на другой;
  • смешать синтаксис grants и ACL в одном объекте;
  • игнорировать тег источника после автоматизации регистрации устройства;
  • тестировать имя, которое разрешается в публичный или локальный адрес;
  • переустановить Tailscale и потерять диагностические данные до проверки политики;
  • отключить системный firewall вместо добавления минимального правила;
  • открыть порт на хосте, когда приложение слушает только внутри контейнера;
  • не проверить отрицательный сценарий после восстановления рабочего доступа.

Как проверить результат после исправления

Исправление считается завершенным не тогда, когда один раз открылась страница, а когда воспроизводимо выполняется нужная матрица доступа. Проверьте соединение после перезапуска клиента, повторного входа пользователя и обновления DNS. Для subnet router добавьте проверку после перезапуска роутера. Для сервиса проверьте прикладной запрос, а не только открытый TCP-порт.

  • целевой сервис отвечает с разрешенного устройства;
  • ответ приходит по ожидаемому Tailscale или приватному адресу;
  • лишние порты и источники остаются закрытыми;
  • имя MagicDNS дает тот же результат, что и ожидаемый IP;
  • маршрут не конфликтует с локальной сетью клиента;
  • policy tests проходят после повторного открытия редактора;
  • в приложении нет новых ошибок авторизации или TLS;
  • временные широкие правила удалены;
  • изменение и откат описаны в журнале эксплуатации.

Как предотвратить повторение

Поддерживаемая политика строится вокруг ролей и сервисов, а не случайных IP и персональных исключений. Используйте группы для людей, теги для машинных ролей, точные порты и небольшие правила с понятными названиями. Новые конфигурации разумно проектировать на grants, а существующие ACL мигрировать постепенно, сохраняя тесты поведения на каждом этапе.

  • храните policy file в системе контроля версий и проверяйте изменения вторым человеком;
  • добавляйте положительные и отрицательные tests для критичных сервисов;
  • ведите реестр тегов, групп, subnet routes и владельцев сервисов;
  • удаляйте устаревшие группы, устройства и временные исключения;
  • проверяйте изменения SSO и состава групп до отключения старой учетной записи;
  • контролируйте адреса прослушивания и firewall после обновлений приложений;
  • избегайте пересекающихся подсетей у офисов и удаленных пользователей;
  • проводите регулярную проверку минимальных прав и сценария отката.

Когда нужна помощь с Tailscale и политикой доступа

Если ACL Tailscale блокирует нужный сервис и причина не определяется по проверкам выше, я могу разобрать поток от исходного устройства до приложения, проверить grants или ACL, группы, теги, MagicDNS, subnet routes, firewall и адрес прослушивания. Сначала фиксирую текущую конфигурацию и безопасный откат, затем предлагаю минимальное изменение и проверяю как разрешенные, так и запрещенные сценарии. В заявке достаточно указать схему сети, проблемный источник, назначение и порт без передачи секретных ключей.