fix(ops/alloy): второй слой маскировки query-секретов на сборщике логов (apps + infra) — defence-in-depth к #3353 #3377
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3377
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/3354-alloy-query-secret-scrub"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #3354 (follow-up #3154/#3353). Приложение маскирует query-секреты само (
log_scrub.py), но строки от других процессов (journald, сайдкар, GlitchTip/Forgejo с?token=) шли в Loki как есть.Что сделано
loki.process "scrub_credentials"— втораяstage.replace(#3115 не тронут) в обоих конфигах (alloy-apps.alloy,alloy-infra.alloy— Forgejo/GlitchTip пишут в тот же Loki):Поправка к постановке issue:
stage.replaceв Alloy заменяет содержимое захват-групп, а не весь матч (доказано рабочей стадией #3114 — группа на пароле,user@hostуцелевает). С([?&]…=)[^&\s"]+ → ${1}***имя параметра затёрлось бы литералом, а секрет остался. Поэтому группа на ЗНАЧЕНИИ,replace = "***". Множество имён посимвольно равно_SENSITIVE_QUERYприложения.Валидация
Локального
alloyи docker-демона нет; сделано: построчная сверка с соседней стадией + скрипт, распарсивший строковые литералы файла как JSON (проверка экранировки\\w), скомпилировавший regex и прогнавший семантику замены групп: uvicorn-строка →secret=***; 6 параметров в одной строке (вкл.client_secret,refresh_token,Access_Token) маскируются;?design=/signal_id/tokenize— нет; DSN после #3114 не портится.alloy fmt/validateна хосте — при приёмке.Деплой и ловушка
deploy-metrics.yml(триггерops/metrics/**) →agent-apps(Poincare) иagent-infra(Beget). Конфиг — bind-mount →up -dсчитает сервис неизменившимся, Alloy сам не перечитывает: после деплоя нуженdocker restart gendesign-alloyна каждом хосте (или/-/reload). Проверка доезда:docker exec gendesign-alloy grep -c apikey /etc/alloy/config.alloy(в старой версии 0).Живая приёмка (сделаю)
Проба процессом БЕЗ фильтра приложения (
logger 'test?secret=zzz-probe-3354'на хосте → journald → только новая стадия) → в Loki строка сsecret=***и безzzz-probe-3354. Отрицательный результат без положительного маркера не засчитывается.Валидация, которую воркер не мог сделать локально, выполнена на живом бинаре прода: файл ветки
alloy-apps.alloyскопирован в контейнерgendesign-alloy(Alloy v1.6.1) →alloy fmt /tmp/cfg.alloy— OK, синтаксис River валиден. Различающий маркерapikey: 1 в файле ветки, 0 в текущем/etc/alloy/config.alloy(проба увидит доезд). CI зелёный; мерж — по вердикту ревью. После деплояdeploy-metrics.yml:docker restart gendesign-alloyна обоих хостах (bind-mount,up -dне перечитает) + живая пробаlogger 'test?secret=zzz-probe-3354'→ Loki.Приёмка #3377 на проде (2026-09-06, оба хоста) — ✅ по значению.
Конфиг доехал через
deploy-metrics(server / agent-infra / agent-apps — success на1cff12cc), но на Beget контейнерgendesign-alloyпродолжал читать СТАРЫЙ файл: bind-mount одного файла держит inode, аgit checkoutв деплое пишет новый —statв контейнере показывал inode 572205 (mtime 26.08) против 551819 на хосте,grep -c apikey= 0.docker restart gendesign-alloyперепривязал путь → inode 551819, apikey=1. На Poincare контейнер файл видел, рестарт сделан для перечитывания.Живая проба рабочим трактом (
loggerна хосте → journald → Alloy → Loki на Beget), без фильтра приложения:{host="apps"}):gendesign-probe GET /x?secret=***&token=*** HTTP/1.1—zzz-probe-3354/zzz-tok-3354в Loki отсутствуют → MASKED.{host="infra"}):gendesign-probe-infra GET /y?api_key=*** HTTP/1.1—zzz-infra-3354отсутствует → MASKED.alloy fmtна прод-бинаре v1.6.1 — OK, оба контейнераhealthyпосле рестарта.Ловушка на будущее:
docker compose up -dвdeploy-metrics.yml(agent-шаг) не перечитывает одно-файловый bind-mount после смены inode — нужен--force-recreate alloyилиdocker restartпослеup. Заведу отдельный issue.up -dне перечитывает одно-файловый bind-mount конфига Alloy (Beget читал конфиг 26.08 после успешного деплоя #3377) #3380