Пустой список чувствительного
k8sgpt отправляет поломки кластера языковой модели и обещает анонимизацию. Через три месяца пользователь спросил, где её границы, — и получил честный ответ, который держится третий год
miki/pustoy-spisok-chuvstvitelnogo · v5
k8sgpt отправляет поломки кластера языковой модели и обещает анонимизацию. Через три месяца пользователь спросил, где её границы, — и получил честный ответ, который держится третий год
k8sgpt — инструмент, который смотрит на кластер Kubernetes, находит поломки и отправляет их объяснять языковой модели. Описание в шапке репозитория без скромности: Giving Kubernetes Superpowers to everyone.
Заведён 21 марта 2023 года. На сегодня — 8140 звёзд, 1045 форков, больше сотни людей, вложивших код, девяносто одна открытая задача. Go, Apache-2.0, отдельная организация k8sgpt-ai — то есть не репозиторий одного человека, а команда с процессом.
Задача открывается по шаблону — с галочками «искал похожие задачи», полями для версий K8sGPT, Kubernetes и операционной системы. В разборе ниже человек оставит их пустыми — _No response_ — и это не небрежность: у него не поломка, у него вопрос.
Отвечают по существу и быстро. Мейнтейнер — через шесть дней и со ссылкой на конкретные строки в pod.go. Основатель — в тот же день, когда вопрос стал неудобным.
Спрашивающего не отправляют читать код. Ему отвечают списком — и он остаётся в проекте писать документацию.
Анонимизация появилась у них на третьей неделе жизни проекта: репозиторий заведён 21 марта, флаг приехал 10 апреля. О том, что данные чужого кластера уезжают к постороннему поставщику, здесь подумали сразу.
Именно поэтому разбор ниже — не про небрежность.
10 апреля 2023. Приезжает PR #242 «feat: add anonymize option» от matthisholleville. Влит через два дня — fb75434.
Флаг обещает простое: перед отправкой модели чувствительное заменят.
В README появляется строка среди ключевых возможностей: Anonymization. Строка короткая и успокаивающая.
14 апреля, через два дня после вливания. Приезжает коммит fe52951 от Alex Jones — того самого основателя, который через три месяца будет отвечать на неудобный вопрос.
Название приводится как есть, с опечаткой:
feat: anoymization based on pr feedback
Анонимизацию переделывают по замечаниям в ревью — через два дня после того, как её влили. Здесь не добавили флаг и забыли: над ним ещё поработали чужими руками и глазами.
5 июля, три месяца спустя. jatinmehrotra открывает issue #541. Заголовок звучит вежливо и настораживающе одновременно: «Что означает KEY FEATURE[Anonymization] в README?»
В поле «шаги воспроизведения» — одна строка:
Searched the entire REPO for the meaning of events where anonymization would not apply.
Искал по всему репозиторию, что означают события, к которым анонимизация не применяется.
Он не сообщает об ошибке. Он сообщает, что не нашёл границы.
Но ещё раньше, 19 апреля — через девять дней после того, как анонимизация появилась, — в pod.go приезжает коммит 3c7e0bb от Peter Pan:
chore: analyze Pod ReadinessProbe faliure
Он учит анализатор разбирать отказ проверки готовности — и вместе с полезным делом приносит в этот файл первый Sensitive: []common.Sensitive{}.
Это не небрежность автора и не повод искать виноватого. Это форма структуры: чтобы сообщить о поломке, надо заполнить оба поля, а что класть во второе, если текст пришёл извне и ты о нём ничего не знаешь? Пустой список — единственный ответ, который компилируется.
11 июля. Отвечает arbreezy, мейнтейнер. Ответ занимает абзац, и в нём есть предложение, ради которого стоит читать весь разбор:
In a few analysers like Pod, we feed to the AI backend the event messages which are not known beforehand thus we are not masking them for the time being.
В нескольких анализаторах, например Pod, мы отдаём модели тексты событий, которые заранее неизвестны, — и поэтому пока их не маскируем.
Перечитайте, что именно не маскируется. Не «сложное» и не «редкое», а то, что заранее неизвестно.
Маскировка накрывает предсказуемое: имена подов и пространств имён — их придумал сам проект, он же знает, как они выглядят. И не накрывает то, что в кластер написал кто-то другой.
12 июля. jatinmehrotra возвращается с четырьмя вопросами подряд: какие анализаторы маскируют, какие нет, что именно заменяется и когда починят остальное. А потом задаёт тот, ради которого всё и затевалось:
In the docs it was mentioned that k8sgpt is being used in production for customer projects… does it not pose a security risk to the customer sensitive information?
В документации сказано, что k8sgpt используют в продакшене на клиентских проектах… не создаёт ли это риска для чувствительных данных клиента?
Вопрос неудобный. Человек собирается ставить инструмент в проект и спрашивает прямо, чем это ему обойдётся.
В тот же день отвечает AlexsJones — один из основателей проекта.
Он не уходит в общие слова и не обещает «безопасность на уровне предприятия». Он выкладывает список: маскируется у Statefulset, Service, PodDisruptionBudget, Node, NetworkPolicy, Ingress, HPA, Deployment, Cronjob. Не маскируется у ReplicaSet и PersistentVolumeClaim — и тут же объясняет почему: оттуда не уходит ничего опознающего, только сам факт, что штука сломана.
Список, названный вслух, — это и есть честно названная цена. Он же показывает, что границу до этого разговора никто не записывал: её пришлось собирать в ответе на вопрос.
19 июля. Приезжает PR #559 «docs: fix readme for anonymization» — 70bec05.
Автор — тот же jatinmehrotra, который две недели назад пришёл с вопросом. Спросил, получил ответ, написал документацию сам.
От вопроса до правки — четырнадцать дней.
Сегодня. Тот же файл, строки 130–133:
Сообщение события отправляется как есть, список чувствительного при нём — пустой. Сорока строками ниже, в соседней ветке условия, — точно такой же.
А всего в дереве сегодня сорок таких мест: анализаторы подов, хранилища, конфигов, интеграции с keda и kyverno. Дописывали их разные люди в 2023, 2025 и 2026 годах.
«Пока» из июля 2023-го идёт третий год — и разошлось по сорока местам.
В тот же день та же болезнь нашлась у меня — и не чтением, а прогоном.
Пятнадцать моих агентов устроены как k8sgpt: скрипт собирает факты о машине, факты уезжают в модель. Разбор журнала отдаёт двадцать самых частых предупреждений дословно — а журнал пишут службы, и пишут в него что угодно.
Подставил сорок пять предупреждений nginx с токеном в пути запроса. В исходящих фактах:
Токен здесь обрезан нарочно: он был проверочный и ничего не открывал, но дословный вид в разборе про утечки учит ровно противоположному — да и чужие сканеры секретов он споткнёт.
Мой список чувствительного был так же пуст и ровно по той же причине: заранее неизвестно, что служба напишет в журнал. Починено маскировкой в запускателе агентов — одно место на пятнадцать сборщиков; проверка после правки: «вырезано фрагментов: 1».
Разница между нами и k8sgpt только в масштабе последствий. А формулировка «то, что заранее неизвестно, мы пока не маскируем» — честная ровно настолько, насколько точно описывает дыру.
Что это значит для нас
По каждому сборщику фактов ответить: какие разделы передают чужой текст без изменений, а какие отдают только счётчики и имена, придуманные вами.
grep -nE 'journalctl|cat |curl |-o cat' сборщики/*.sh- По каждому сборщику названы разделы с дословным чужим текстом
- Для каждого такого раздела сказано, кто пишет этот текст на самом деле
- Найден хотя бы один раздел, о котором вспомнили только при составлении списка
Маскировка ставится на общем пути — там, где факты передаются модели, — а не в каждом скрипте по отдельности.
- Резка стоит на общем пути, а не в отдельных сборщиках
- Новый сборщик получает маскировку, ничего не делая
- При недоступности детектора остаётся запасной слой, а не тишина
Положить в источник фактов заведомо узнаваемую строку и посмотреть, дойдёт ли она до исходящих фактов — и в той же форме, в какой её ищете.
- Проба попадает в тот же канал, который читает сборщик (уровень, единица, частота)
- Искали в той форме, в какой строка выходит после обработки, а не в исходной
- До правки проба находит секрет, после — не находит
Related lists
Найти в открытом проекте настоящую историю поломки, восстановить ход мысли по написанному и закончить проверкой своего кода
Better Auth: ограничение частоты считалось от последнего запроса, включая отклонённые, — и разблокировка не наступала никогда
Medusa: защита от повтора отказывает там, где можно было ответить, и пропускает там, где повтор стоит денег
Medusa: кнопка «убрать скидку» выдавала максимальную, потому что ноль в JavaScript ложный
Saleor: товар сняли с продажи — и строку из корзины покупателя стирали в фоне. Три с половиной года до теста, поменявшего знак
comlink-python: проверки на отказ стучались в адрес, который сервер не защищает, — и пять месяцев скрывали настоящую ошибку подписи
