Ловушка двух tailnet: устаревший ключ, который правил не ту сеть
Клиенты подключаются к арендованному Mac через Tailscale. Правило доступа по SSH мы держим в политике tailnet и управляем им из кода. Когда аренда начинается, адрес клиента добавляется. Когда заканчивается, удаляется. Маленькая скучная система. А потом она сообщила нам, что все клиенты потеряли доступ, и это была неправда.
Что сообщил инструмент
Плановая проверка объявила, что правило SSH для клиентов пустое. По её словам, три платящих клиента больше не могли подключиться. Для бизнеса, чей продукт это доступ к машине, такое сообщение равносильно пожарной тревоге.
Правило не было пустым. Мы читали другой tailnet.
Две сети, один псевдоним
В аккаунте было два tailnet. В одном весь парк: арендованные Mac, хаб и все общие доступы клиентов. Другой был старой личной сетью, оставшейся с начальной настройки. В нём были мёртвая машина и ноутбук.
API Tailscale позволяет указать tailnet по имени или передать -, что означает "тот tailnet, которому принадлежит вызывающий ключ". Наш код передавал -. Это работает, пока ключ один. Ключи это неотличимые на вид строки, поэтому - молча следует за тем, который оказался в окружении. В один файл конфигурации прокрался устаревший ключ.
Опасной была запись
Чтение, которое врёт, отнимает вечер. Запись, которая врёт, вызывает инцидент. У того же инструмента есть режим починки, который приводит правило доступа в соответствие с текущими клиентами. Запущенный на не том tailnet, он добросовестно вписал три реальных адреса почты клиентов в политику старой сети. Там они ни на что не влияли.
На самом деле ни один клиент не пострадал. Tailnet парка всё это время оставался нетронутым и правильным. Но несколько минут автоматика правила контроль доступа не в той сети и сообщала об успехе.
Исправление: называйте сеть
Мы перестали передавать -. Теперь код явно указывает tailnet парка. Ключ, который его не видит, громко падает, а не уходит в ту сеть, которую видит.
Теперь каждый запуск выводит tailnet, с которым работал. Если в этой строке не парк, результаты ниже ничего не значат. И вы узнаёте об этом до того, как начнёте по ним действовать.
Общий урок
Удобное значение по умолчанию, которое означает "то, на что указывают эти учётные данные", становится ловушкой, как только учётных данных больше одних. Оно превращает неправильный ключ из ошибки в тихое перенаправление. Всё, что пишет, должно называть свою цель. Тогда неправильные учётные данные приведут к сбою, а не к успеху там, где вы не собирались.
Это та же форма, что и у других тихих сбоев, которые мы описали в посте проверки, которые не могут упасть. Инструмент был уверен. Инструмент ошибался. И ничто из его вывода не подсказало бы вам этого, пока он не начал называть сеть, которую правит.
Вопросы
- Как API-ключ Tailscale выбирает, какой tailnet править?
- Ключ принадлежит одному tailnet, а имя tailnet '-' в API означает «тот tailnet, которому принадлежит этот ключ». Два ключа от двух tailnet выглядят одинаково, поэтому '-' молча следует за ключом.
- Как надёжно отличить два tailnet?
- Никогда не на глаз. Сравните, какие устройства видит каждый ключ. Правильный ключ видит ваш парк. Неправильный видит всё остальное, что есть у этого аккаунта.
- Стоит ли инструментам вообще использовать псевдоним tailnet '-'?
- Не для того, что что-то записывает. Указывайте tailnet явно. Тогда ключ от не той сети получит 404, а не будет тихо править не тот ACL.
Посчитайте свои цифры в калькуляторе или арендуйте раннер.