Compare commits
No commits in common. "f469903adf1d7033ed978b1fe64532b3ba4daf98" and "1cefd806b3d1e0321811a7f066fd55a5c4cabf50" have entirely different histories.
f469903adf
...
1cefd806b3
2 changed files with 3 additions and 89 deletions
|
|
@ -1,67 +0,0 @@
|
||||||
"""postgres-exporter не должен печатать пароль БД в лог.
|
|
||||||
|
|
||||||
ЧТО БЫЛО. Версия v0.16.0 при КАЖДОЙ ошибке сбора печатала полный DSN вместе с
|
|
||||||
паролем:
|
|
||||||
|
|
||||||
msg="error scraping dsn" err="queryNamespaceMappings returned 1 errors"
|
|
||||||
dsn="postgresql://<роль>:<ПАРОЛЬ>@<хост>:5432/<база>?sslmode=disable"
|
|
||||||
|
|
||||||
Строки уходили в Loki — около 210 в сутки с двух хостов, при ретенции 30 дней
|
|
||||||
это тысячи паролей в хранилище логов (#3114).
|
|
||||||
|
|
||||||
ЧТО ПРОВЕРЕНО ОПЫТОМ 27.08, а не взято из документации. Стенд: чистый постгрес
|
|
||||||
в скретч-контейнере, роль без прав, тот же `ops/metrics/postgres/queries.yml`,
|
|
||||||
что и на проде — то есть ровно та ошибка, что случалась в бою.
|
|
||||||
|
|
||||||
v0.16.0 → строк с паролем: 1
|
|
||||||
v0.18.0 → строк с паролем: 0
|
|
||||||
|
|
||||||
Отдельно опровергнут обходной путь, который предлагался в issue: форма
|
|
||||||
`DATA_SOURCE_URI` + `DATA_SOURCE_USER` + `DATA_SOURCE_PASS` НЕ помогает —
|
|
||||||
экспортер собирает DSN внутри и печатает его целиком точно так же (тот же
|
|
||||||
стенд, тот же результат: 1 строка с паролем). То есть починка «через
|
|
||||||
переменные окружения» была бы работой вхолостую.
|
|
||||||
|
|
||||||
Паритет метрик проверен там же: все пять пользовательских запросов отдаются
|
|
||||||
обеими версиями одинаково, v0.18 добавляет три встроенные и не теряет ни одной.
|
|
||||||
|
|
||||||
Тест сторожит только нижнюю границу версии: откат на v0.16.x вернул бы утечку.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
|
||||||
COMPOSE = REPO_ROOT / "docker-compose.metrics-agent.yml"
|
|
||||||
|
|
||||||
# Первая версия, в которой пароль в лог не попадает (проверено опытом, см. шапку).
|
|
||||||
MIN_SAFE = (0, 18, 0)
|
|
||||||
|
|
||||||
_TAG = re.compile(r"postgres-exporter:v(\d+)\.(\d+)\.(\d+)")
|
|
||||||
|
|
||||||
|
|
||||||
def _versions() -> list[tuple[int, int, int]]:
|
|
||||||
text = COMPOSE.read_text(encoding="utf-8")
|
|
||||||
return [(int(a), int(b), int(c)) for a, b, c in _TAG.findall(text)]
|
|
||||||
|
|
||||||
|
|
||||||
def test_all_three_exporters_are_pinned() -> None:
|
|
||||||
"""Экспортеров три — на всех трёх версия должна быть явной.
|
|
||||||
|
|
||||||
Страховка от того, что тест ниже начнёт проверять пустоту: если кто-то
|
|
||||||
заменит тег на `latest` или удалит сервис, здесь станет видно.
|
|
||||||
"""
|
|
||||||
assert len(_versions()) == 3, (
|
|
||||||
f"ожидались три закреплённые версии postgres-exporter, найдено: {_versions()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_exporter_older_than_the_leaking_one() -> None:
|
|
||||||
"""Ни один экспортер не смеет быть старше версии, где утечка закрыта."""
|
|
||||||
for v in _versions():
|
|
||||||
assert v >= MIN_SAFE, (
|
|
||||||
f"postgres-exporter v{'.'.join(map(str, v))} печатает пароль БД в лог "
|
|
||||||
f"при каждой ошибке сбора — минимум v{'.'.join(map(str, MIN_SAFE))}"
|
|
||||||
)
|
|
||||||
|
|
@ -163,27 +163,8 @@ services:
|
||||||
# ── postgres-exporter: Птица (только на Poincare) ────────────────────────────
|
# ── postgres-exporter: Птица (только на Poincare) ────────────────────────────
|
||||||
# WAL/сутки, n_tup_upd против n_tup_hot_upd, рост TOAST, коннекты, горизонт
|
# WAL/сутки, n_tup_upd против n_tup_hot_upd, рост TOAST, коннекты, горизонт
|
||||||
# vacuum — то, из-за отсутствия чего раздутие копилось 91 день незамеченным.
|
# vacuum — то, из-за отсутствия чего раздутие копилось 91 день незамеченным.
|
||||||
# v0.18.0, а не v0.16.0: та печатала ПОЛНЫЙ DSN вместе с паролем в каждую
|
|
||||||
# ошибку сбора (#3114). Строка вида
|
|
||||||
# msg="error scraping dsn" err="queryNamespaceMappings returned 1 errors"
|
|
||||||
# dsn="postgresql://<роль>:<ПАРОЛЬ>@<хост>:5432/<база>?sslmode=disable"
|
|
||||||
# уходила в Loki при каждом скрейпе — около 210 строк в сутки с двух хостов,
|
|
||||||
# при ретенции 30 дней это тысячи паролей в хранилище логов.
|
|
||||||
#
|
|
||||||
# Воспроизведено на скретч-контейнерах 27.08 (постгрес + роль без прав +
|
|
||||||
# этот же queries.yml): v0.16.0 печатает пароль, v0.18.0 — нет.
|
|
||||||
#
|
|
||||||
# NB: форма DATA_SOURCE_URI + DATA_SOURCE_USER + DATA_SOURCE_PASS, которую
|
|
||||||
# предлагали как обходной путь, НЕ помогает — проверено тем же опытом:
|
|
||||||
# экспортер собирает DSN внутри и печатает его целиком точно так же.
|
|
||||||
# Утечку закрывает только версия образа.
|
|
||||||
#
|
|
||||||
# Паритет метрик проверен на том же стенде: все пять пользовательских
|
|
||||||
# запросов из queries.yml отдаются обеими версиями одинаково
|
|
||||||
# (PG_EXPORTER_EXTEND_QUERY_PATH в v0.18 работает), v0.18 добавляет три
|
|
||||||
# встроенные метрики и не теряет ни одной.
|
|
||||||
postgres-exporter-gendesign:
|
postgres-exporter-gendesign:
|
||||||
image: quay.io/prometheuscommunity/postgres-exporter:v0.18.0
|
image: quay.io/prometheuscommunity/postgres-exporter:v0.16.0
|
||||||
container_name: gendesign-pg-exporter-gendesign
|
container_name: gendesign-pg-exporter-gendesign
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
profiles: ["apps"]
|
profiles: ["apps"]
|
||||||
|
|
@ -211,7 +192,7 @@ services:
|
||||||
|
|
||||||
# ── postgres-exporter: МЕРА (только на Poincare) ─────────────────────────────
|
# ── postgres-exporter: МЕРА (только на Poincare) ─────────────────────────────
|
||||||
postgres-exporter-tradein:
|
postgres-exporter-tradein:
|
||||||
image: quay.io/prometheuscommunity/postgres-exporter:v0.18.0
|
image: quay.io/prometheuscommunity/postgres-exporter:v0.16.0
|
||||||
container_name: gendesign-pg-exporter-tradein
|
container_name: gendesign-pg-exporter-tradein
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
profiles: ["apps"]
|
profiles: ["apps"]
|
||||||
|
|
@ -235,7 +216,7 @@ services:
|
||||||
# forgejo + glitchtip. Нужен и сам по себе, и как страховка: рост базы glitchtip
|
# forgejo + glitchtip. Нужен и сам по себе, и как страховка: рост базы glitchtip
|
||||||
# ничем не ограничен — политики ретенции у GlitchTip нет вообще.
|
# ничем не ограничен — политики ретенции у GlitchTip нет вообще.
|
||||||
postgres-exporter-infra:
|
postgres-exporter-infra:
|
||||||
image: quay.io/prometheuscommunity/postgres-exporter:v0.18.0
|
image: quay.io/prometheuscommunity/postgres-exporter:v0.16.0
|
||||||
container_name: gendesign-pg-exporter-infra
|
container_name: gendesign-pg-exporter-infra
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
profiles: ["infra"]
|
profiles: ["infra"]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue