Skip to content

k8sgpt отправляет поломки кластера языковой модели и обещает анонимизацию. Через три месяца пользователь спросил, где её границы, — и получил честный ответ, который держится третий год

v5 0 stars 0 forks 0 watchers 1 branch 0 runs Public
Проверочный токен в хвосте заменён на форму — дословный вид в разборе про утечки учит не томуv5

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:

go
1failures = append(failures, common.Failure{
2 Text: evt.Message,
3 Sensitive: []common.Sensitive{},
4})

Сообщение события отправляется как есть, список чувствительного при нём — пустой. Сорока строками ниже, в соседней ветке условия, — точно такой же.

А всего в дереве сегодня сорок таких мест: анализаторы подов, хранилища, конфигов, интеграции с keda и kyverno. Дописывали их разные люди в 2023, 2025 и 2026 годах.

«Пока» из июля 2023-го идёт третий год — и разошлось по сорока местам.

Хвост про себя

В тот же день та же болезнь нашлась у меня — и не чтением, а прогоном.

Пятнадцать моих агентов устроены как k8sgpt: скрипт собирает факты о машине, факты уезжают в модель. Разбор журнала отдаёт двадцать самых частых предупреждений дословно — а журнал пишут службы, и пишут в него что угодно.

Подставил сорок пять предупреждений nginx с токеном в пути запроса. В исходящих фактах:

code
145 open() "/srv/www/media?token=tk_…" failed (2: No such file or directory)

Токен здесь обрезан нарочно: он был проверочный и ничего не открывал, но дословный вид в разборе про утечки учит ровно противоположному — да и чужие сканеры секретов он споткнёт.

Мой список чувствительного был так же пуст и ровно по той же причине: заранее неизвестно, что служба напишет в журнал. Починено маскировкой в запускателе агентов — одно место на пятнадцать сборщиков; проверка после правки: «вырезано фрагментов: 1».

Разница между нами и k8sgpt только в масштабе последствий. А формулировка «то, что заранее неизвестно, мы пока не маскируем» — честная ровно настолько, насколько точно описывает дыру.

Что это значит для нас

1
Выписать, что уходит наружу ДОСЛОВНО

По каждому сборщику фактов ответить: какие разделы передают чужой текст без изменений, а какие отдают только счётчики и имена, придуманные вами.

Why: Маскировка всегда накрывает предсказуемое — то, что проект придумал сам. Опасно ровно обратное: текст, который написал кто-то другой.
$grep -nE 'journalctl|cat |curl |-o cat' сборщики/*.sh
Check
  • По каждому сборщику названы разделы с дословным чужим текстом
  • Для каждого такого раздела сказано, кто пишет этот текст на самом деле
  • Найден хотя бы один раздел, о котором вспомнили только при составлении списка
2
Резать в одном месте, а не в каждом сборщике

Маскировка ставится на общем пути — там, где факты передаются модели, — а не в каждом скрипте по отдельности.

Why: Пятнадцать сборщиков — это пятнадцать мест, где можно забыть, и один запускатель, где нельзя. Шестнадцатый сборщик напишут через месяц и про маскировку не вспомнят.
Check
  • Резка стоит на общем пути, а не в отдельных сборщиках
  • Новый сборщик получает маскировку, ничего не делая
  • При недоступности детектора остаётся запасной слой, а не тишина
3
Доказать подставленным секретом, а не чтением

Положить в источник фактов заведомо узнаваемую строку и посмотреть, дойдёт ли она до исходящих фактов — и в той же форме, в какой её ищете.

Why: Моя первая проверка сказала «чисто» дважды и оба раза соврала: сначала проба шла не того уровня, потом сборщик переписывал цифры, и греп по целому токену промахивался.
Check
  • Проба попадает в тот же канал, который читает сборщик (уровень, единица, частота)
  • Искали в той форме, в какой строка выходит после обработки, а не в исходной
  • До правки проба находит секрет, после — не находит

Найти в открытом проекте настоящую историю поломки, восстановить ход мысли по написанному и закончить проверкой своего кода

updated Sep 1, 2026

Better Auth: ограничение частоты считалось от последнего запроса, включая отклонённые, — и разблокировка не наступала никогда

updated Sep 2, 2026

Medusa: защита от повтора отказывает там, где можно было ответить, и пропускает там, где повтор стоит денег

updated Sep 2, 2026

Medusa: кнопка «убрать скидку» выдавала максимальную, потому что ноль в JavaScript ложный

updated Sep 2, 2026

Saleor: товар сняли с продажи — и строку из корзины покупателя стирали в фоне. Три с половиной года до теста, поменявшего знак

updated Sep 2, 2026

comlink-python: проверки на отказ стучались в адрес, который сервер не защищает, — и пять месяцев скрывали настоящую ошибку подписи

updated Sep 1, 2026