
tailsnitch v1.7
Инструмент аудита безопасности для конфигураций Tailscale. Сканирует ваш tailnet на наличие неправильных конфигураций, излишне разрешительных политик доступа и нарушений лучших практик безопасности.
Tailsnitch
Аудитор безопасности конфигураций Tailscale. Tailsnitch сканирует вашу tailnet-сеть на наличие 57 ошибок конфигурации, излишне разрешающих контролей доступа и нарушений лучших практик безопасности.
Быстрый старт
# 1. Укажите свои учётные данные API Tailscale
export TS_API_KEY="tskey-api-..."
# 2. Запустите аудит
tailsnitch
# 3. Покажите только находки высокой степени серьёзности
tailsnitch --severity high
# 4. Исправьте некоторые проблемы ~интерактивно~ режим yolo
tailsnitch --fix
Установка
Загрузка готового бинарного файла
Загрузите последний релиз из GitHub Releases.
Пользователям macOS: Снимите атрибут quarantine после загрузки:
sudo xattr -rd com.apple.quarantine tailsnitch
Установка через Go
go install github.com/Adversis/tailsnitch@latest
Сборка из исходного кода
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
Аутентификация
Tailsnitch поддерживает два метода аутентификации. OAuth предпочтителен, если настроены оба.
Вариант 1: OAuth-клиент (рекомендуется)
OAuth-клиенты обеспечивают ограниченный, аудируемый доступ, который не истекает при увольнении сотрудников.
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
Создайте OAuth-клиент по адресу: https://login.tailscale.com/admin/settings/oauth
Необходимые области для аудита только на чтение:
all:read покрывает всё. Предоставление областей по отдельности:
| Область | Используется для |
|---|---|
policy_file:read | Файл политики tailnet — ACL-, NET-, SSH-* |
devices:core:read | Список устройств — DEV-, NET-, ACL-011 |
dns:read | Конфигурация DNS — DNS-001, DEV-007 |
auth_keys:read | Ключи аутентификации машин — AUTH-*, ACL-011 |
feature_settings:read | Настройки tailnet — DEV-008, DEV-009, DEV-014 |
logs:network:read | Настройка журналирования сетевого трафика — LOG-001 |
networking_settings:read | Настройка сертификатов HTTPS — NET-004 |
log_streaming:read | Назначения потоковой передачи журналов — LOG-002 |
webhooks:read | Конечные точки webhook — LOG-005, LOG-012 |
oauth_keys:read | OAuth-клиенты — LOG-006 |
users:read | Роли и статусы пользователей — USER-001, LOG-006 |
account_settings:read | Контакт для безопасности — LOG-011 |
devices:posture_attributes:read | Интеграции posture — DEV-014 |
Любая область, которую вы пропустите, влияет только на проверки, которым она нужна: такие проверки сообщают, что не смогли прочитать настройку, а не проходят успешно.
AUTH-005 и AUTH-006 читают федеративные удостоверения tailnet, которые консоль администратора называет доверенными учётными данными. Они поступают из того же списка ключей, что и ключи аутентификации, поэтому ожидается, что auth_keys:read их покрывает. Это не было подтверждено на живой tailnet-сети. Если список ключей не может быть прочитан, обе проверки сообщают «не оценено», а не «пройдено». Подтверждено ли, что отсутствующая область возвращает ошибку или вместо этого возвращает список с отфильтрованными удостоверениями, не установлено; если она фильтрует молча, AUTH-005 сообщит, что доверенных учётных данных не существует, а AUTH-006 не найдёт, что проверять.
Дополнительные области для режима исправления:
devices:core— Удаление устройств, изменение тегов (требуется выбор тега)auth_keys— Удаление ключей аутентификации
Tailnet Lock
DEV-010 и DEV-012 сообщают о Tailnet Lock, который API Tailscale не раскрывает как настройку tailnet. Устройства, заблокированные им, видны через API, но определение того, включён ли lock, требует локального CLI tailscale, который читает демон на машине, где запущен tailsnitch. При аудите другой tailnet-сети с помощью --tailnet учитывайте эту часть результата соответствующим образом. Используйте --tailscale-path, если бинарный файл находится в нестандартном месте.
Вариант 2: API-ключ
API-ключи действуют от имени пользователя, который их создал, и наследуют права этого пользователя.
export TS_API_KEY="tskey-api-..."
Создайте API-ключ по адресу: https://login.tailscale.com/admin/settings/keys
Примеры использования
Базовый аудит
# Запуск полного аудита
tailsnitch
# Показ также проходящих проверок (подробный режим)
tailsnitch --verbose
# Вывод в формате JSON для обработки
tailsnitch --json
# Аудит конкретной tailnet-сети (когда OAuth-клиент имеет доступ к нескольким)
tailsnitch --tailnet mycompany.com
Фильтрация результатов
# Показ только критических проблем и проблем высокой серьёзности
tailsnitch --severity high
# Фильтрация по категории
tailsnitch --category access # Проблемы ACL
tailsnitch --category auth # Аутентификация и ключи
tailsnitch --category device # Безопасность устройств
tailsnitch --category network # Сетевая доступность
tailsnitch --category ssh # Правила SSH
tailsnitch --category log # Журналирование и администрирование
# Запуск только конкретных проверок
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# Список всех доступных проверок
tailsnitch --list-checks
Интерактивный режим исправления
Режим исправления позволяет устранять проблемы напрямую через API Tailscale:
# Интерактивный режим исправления
tailsnitch --fix
# Предпросмотр того, что будет исправлено (пробный запуск)
tailsnitch --fix --dry-run
# Автовыбор безопасных исправлений (всё равно требует подтверждения)
tailsnitch --fix --auto
# Отключение журналирования аудита действий по исправлению
tailsnitch --fix --no-audit-log
Элементы, исправляемые через API:
| Проверка | Действие |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | Удаление ключей аутентификации |
| DEV-002 | Удаление тегов с пользовательских устройств |
| DEV-004 | Удаление устаревших устройств |
| DEV-005 | Авторизация ожидающих устройств |
Режим исправления также предоставляет прямые ссылки на консоль администратора для проблем, требующих ручного вмешательства.
Экспорт доказательств для SOC 2
Создание отчётов-доказательств для аудитов SOC 2 с сопоставлением общих критериев (CC):
# Экспорт в JSON
tailsnitch --soc2 json > soc2-evidence.json
# Экспорт в CSV (для электронных таблиц)
tailsnitch --soc2 csv > soc2-evidence.csv
Отчёт SOC 2 включает:
- Результаты тестов по каждому ресурсу (каждое устройство, ключ, правило ACL тестируются индивидуально)
- Сопоставления кодов CC (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2 и т. д.)
- Статус Pass/Fail/N/A для каждого контрольного теста
- Временная метка для цепочки аудита
Пример вывода CSV:
resource_type,resource_id,resource_name,check_id,check_title,cc_codes,status,details,tested_at
device,node123,prod-server,DEV-001,Tagged devices with key expiry disabled,CC6.1;CC6.3,PASS,Tags: [tag:server] key expiry enabled,2025-01-05T10:30:00Z
key,tskey-auth-xxx,tskey-auth-xxx,AUTH-001,Reusable auth keys exist,CC6.1;CC6.2;CC6.3,FAIL,Reusable key expires in 45 days,2025-01-05T10:30:00Z
Игнорирование известных рисков
Создайте файл .tailsnitch-ignore, чтобы скрывать находки для известных принятых рисков:
# .tailsnitch-ignore
# Игнорирование информационных проверок
ACL-008 # Мы намеренно не используем группы
ACL-009 # Устаревшие ACL подходят для нашего случая использования
# Игнорирование конкретных проверок средней серьёзности с обоснованием
DEV-006 # Внешние устройства — одобренные подрядчики
LOG-001 # Журналы потоков требуют тарифного плана Enterprise
# Игнорирование одного элемента в проверке вместо отключения всей проверки
ACL-011:tag:monitoring # широкий по замыслу; каждый другой тег всё равно проверяется
AUTH-001:tskey-auth-xxxx # автоматически ротируется через CI, отслеживается в TICKET-123
Строка называет либо целую проверку (ACL-011), либо один элемент внутри неё
(CHECK-ID:item, разделение по первому двоеточию — сам элемент может содержать
двоеточия). Правило для отдельного элемента скрывает только этот элемент: проверка
продолжает выполняться и по-прежнему сообщает обо всём остальном, что находит. Скрытие
каждого отмеченного элемента никогда не превращает проваленную проверку в пройденную —
находка остаётся, пониженная до информационной, поэтому скрытая находка никогда не
читается как выполненный контроль.
Расположение файлов игнорирования (проверяются по порядку):
.tailsnitch-ignoreв текущем каталоге~/.tailsnitch-ignoreв домашнем каталоге
Поскольку первое расположение — это рабочий каталог, файл игнорирования может
поступать из репозитория, а не от вас. Каждый запуск сообщает, какой файл он
использовал и сколько находок и элементов он скрыл, а --json записывает это в
поля ignore_file и ignored (CHECK-ID для целой проверки,
CHECK-ID:item для одного скрытого элемента). Используйте --no-ignore, чтобы пропустить файл.
# Использование конкретного файла игнорирования
tailsnitch --ignore-file /path/to/ignore
# Полное отключение обработки файла игнорирования
tailsnitch --no-ignore
Экспорт в JSON и обработка
# Экспорт полного отчёта
tailsnitch --json > audit.json
# Извлечение проваленных проверок в TSV
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Сводка по серьёзности
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# Список критических/высоких проблем со ссылками для администратора
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
Справочник команд
| Флаг | Описание |
|---|---|
--json | Вывод в формате JSON |
--severity | Фильтр по минимальной серьёзности: critical, high, medium, low, info |
--category | Фильтр по категории: access, auth, network, ssh, log, device, dns |
--checks | Запуск конкретных проверок (ID или слаги через запятую) |
--list-checks | Список всех доступных проверок и выход |
--tailnet | Указание tailnet-сети для аудита (по умолчанию: из API-ключа) |
--verbose | Показ также проходящих проверок |
--fix | Включение интерактивного режима исправления |
--auto | Автовыбор безопасных исправлений (требует --fix) |
--dry-run | Предпросмотр действий по исправлению без выполнения (требует --fix) |
--no-audit-log | Отключение журналирования аудита действий по исправлению |
--soc2 | Экспорт доказательств SOC 2: json или csv |
--tailscale-path | Путь к CLI tailscale (для проверок Tailnet Lock) |
--timeout | Общий бюджет времени на аудит (по умолчанию 2m) |
--ignore-file | Путь к файлу игнорирования |
--no-ignore | Отключение обработки файла игнорирования |
--version | Показ информации о версии |
Проверки безопасности
Tailsnitch выполняет 57 проверок безопасности в 7 категориях. См. docs/CHECKS.md для подробной документации по каждой проверке.
Критическая серьёзность
| ID | Проверка | Риск |
|---|---|---|
| ACL-001 | Политика «разрешить всё» по умолчанию | Все устройства имеют неограниченный доступ |
| ACL-002 | Неправильная конфигурация SSH autogroup:nonroot | SSH от имени любого пользователя, не являющегося root |
| ACL-006 | tagOwners слишком широкие | Повышение привилегий через теги |
| ACL-007 | Использование autogroup:danger-all | Доступ предоставлен внешним пользователям |
Высокая серьёзность
| ID | Проверка | Риск |
|---|---|---|
| ACL-011 | Достижимость тега пересекает границу доверия | Украденный многоразовый ключ создаёт тег, который достигает всего |
| AUTH-001 | Многоразовые ключи аутентификации | Неограниченное добавление устройств при краже |
| AUTH-002 | Ключи аутентификации с длительным сроком действия | Расширенное окно воздействия |
| AUTH-003 | Предварительно авторизованные ключи | Обход одобрения устройств |
| AUTH-006 | Субъект федеративного удостоверения слишком широкий | Любой субъект, за которого поручился эмитент, может создать тег |
| DEV-001 | Устройства с тегами без истечения срока ключа | Неограниченный доступ |
| DEV-002 | Пользовательские устройства с тегами | Сохраняются после удаления пользователя |
| DEV-010 | Tailnet Lock отключён | Нет защиты от украденных ключей |
| DEV-012 | Ожидающие подписи Tailnet Lock | Неподписанные узлы требуют проверки |
| NET-001 | Воздействие Funnel | Публичный доступ в интернет |
| NET-003 | Граница доверия маршрутизатора подсети | Незашифрованный трафик в локальной сети |
| SSH-002 | Root SSH без режима проверки | Не требуется повторная аутентификация |
Средняя серьёзность
| ID | Проверка | Риск |
|---|---|---|
| ACL-004 | Использование autogroup:member | Включены внешние пользователи |
| ACL-005 | Настроены AutoApprovers | Обход одобрения маршрутов |
| AUTH-004 | Неэфимерные ключи CI/CD | Накопление устаревших устройств |
| AUTH-005 | Федерация удостоверений рабочих нагрузок не используется | Долгоживущие ключи остаются похищаемыми |
| DEV-003 | Устаревшие клиенты | Потенциальные уязвимости |
| DEV-004 | Устаревшие устройства | Неиспользуемая поверхность атаки |
| DEV-005 | Неавторизованные устройства | Очередь ожидающих одобрения |
| DEV-007 | Чувствительные имена машин | Раскрытие в CT-журналах |
| DEV-009 | Конфигурация одобрения устройств | Может быть не включена |
| NET-004 | Раскрытие в CT-журналах HTTPS | Имена машин публичны |
| NET-005 | Видимость трафика узла выхода | Оператор видит весь трафик |
| NET-006 | Воздействие Serve | Локальные сервисы в tailnet |
| SSH-003 | Воздействие интерфейса Recorder | Сеансы видны сети |
Информационные
Проверки конфигурации журналирования, настроек DNS, ролей пользователей и элементов ручной проверки.
Серьёзность, зависящая от находки
Некоторые проверки оценивают то, что находят, а не несут одну фиксированную серьёзность. Три из них стоит выделить:
- ACL-011 сообщает о достижимости каждого тега как об информационной. Проверка проваливается только тогда, когда тег, который может назначить ключ аутентификации, достигает подстановочного назначения, маршрутизируемой подсети или исходящего трафика узла выхода: Высокая серьёзность, если многоразовый ключ назначает этот тег, Средняя, если только одноразовый ключ. Количество устройств никогда не определяет серьёзность.
- AUTH-005 сообщает о Средней серьёзности, когда в tailnet вообще нет доверенных учётных данных, и о Низкой, когда доверенные учётные данные существуют, но многоразовый ключ всё равно создаёт теги, которые ни одна из них не покрывает.
- AUTH-006 сообщает о Высокой серьёзности для субъекта, который является не чем иным, как подстановочным знаком, и о Низкой для более узкого подстановочного знака или отсутствующей аудитории.
Пример вывода
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.0.0 (build: abc123) |
+=====================================================================+
Используется файл игнорирования: .tailsnitch-ignore (3 правила)
=== ACCESS CONTROLS ===================================================
[CRITICAL] ACL-001: Активна политика «разрешить всё» по умолчанию
В вашей политике ACL отсутствует поле 'acls'. Tailscale применяет
политику «разрешить всё» по умолчанию, предоставляя всем устройствам полный доступ.
Исправление:
Определите явные правила ACL, следуя принципу наименьших привилегий.
Источник: https://tailscale.com/docs/reference/examples/acls
----------------------------------------------------------------------
=== AUTHENTICATION & KEYS =============================================
[HIGH] AUTH-001: Существуют многоразовые ключи аутентификации
Найдено 2 многоразовых ключа аутентификации. При компрометации
их можно повторно использовать для добавления нескольких устройств.
Детали:
- Ключ tskey-auth-xxx (истекает через 45 дней)
- Ключ tskey-auth-yyy (истекает через 89 дней)
Исправление:
Храните многоразовые ключи в менеджере секретов. Предпочитайте одноразовые ключи.
Источник: https://tailscale.com/docs/features/access-control/auth-keys
----------------------------------------------------------------------
SUMMARY
======================================================================
Critical: 1 High: 3 Medium: 5 Low: 2 Info: 8
Всего находок: 19 | Пройдено: 33
Проверки Tailnet Lock
Проверки Tailnet Lock (DEV-010, DEV-012) требуют локального CLI tailscale и выполняются против демона локальной машины. При аудите удалённой tailnet-сети через --tailnet эти проверки отражают локальный статус, а не аудируемую tailnet-сеть.
# Указание пользовательского пути к бинарному файлу tailscale при необходимости
tailsnitch --tailscale-path /opt/tailscale/bin/tailscale
Интеграция с CI/CD
Запускайте Tailsnitch в конвейерах CI/CD для обнаружения регрессий безопасности:
# Пример для GitHub Actions
- name: Audit Tailscale Security
env:
TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
TS_OAUTH_CLIENT_SECRET: ${{ secrets.TS_OAUTH_CLIENT_SECRET }}
run: |
tailsnitch --json > audit.json
# Завершить с ошибкой, если существуют проблемы критической или высокой серьёзности
if tailsnitch --severity high --json | jq -e '.summary.critical + .summary.high > 0' > /dev/null; then
echo "Найдены проблемы критической или высокой серьёзности!"
tailsnitch --severity high
exit 1
fi
Ссылки
- Руководство по усилению безопасности Tailscale
- Справочник по синтаксису ACL
- Tailscale SSH
- Журналирование аудита
- Tailnet Lock
Лицензия
MIT
Участие в разработке
См. CONTRIBUTING.md для получения рекомендаций.