From 5b605abd29c4177222749f995e2fadd22b60d1e6 Mon Sep 17 00:00:00 2001 From: Evgeny Storozhenko Date: Tue, 8 Sep 2026 13:27:29 +0000 Subject: [PATCH] =?UTF-8?q?Archive=20grafana-readonly-user:=20read-only=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=20Grafana=20(it@vinogorod.ru,=20Viewer);=20OSS=201?= =?UTF-8?q?1.1=20provisioning=20users=20=D0=BD=D0=B5=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=E2=80=94=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- STATUS.md | 22 +++++---- WALKTHROUGH.md | 17 +++++++ .../.openspec.yaml | 2 + .../design.md | 49 +++++++++++++++++++ .../proposal.md | 39 +++++++++++++++ .../specs/grafana-access-control/spec.md | 37 ++++++++++++++ .../2026-09-08-grafana-readonly-user/tasks.md | 19 +++++++ openspec/specs/grafana-access-control/spec.md | 40 +++++++++++++++ 8 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 openspec/changes/archive/2026-09-08-grafana-readonly-user/.openspec.yaml create mode 100644 openspec/changes/archive/2026-09-08-grafana-readonly-user/design.md create mode 100644 openspec/changes/archive/2026-09-08-grafana-readonly-user/proposal.md create mode 100644 openspec/changes/archive/2026-09-08-grafana-readonly-user/specs/grafana-access-control/spec.md create mode 100644 openspec/changes/archive/2026-09-08-grafana-readonly-user/tasks.md create mode 100644 openspec/specs/grafana-access-control/spec.md diff --git a/STATUS.md b/STATUS.md index 8944857..2ebf5be 100644 --- a/STATUS.md +++ b/STATUS.md @@ -1,22 +1,23 @@ # OpenSpec Lab — Статус -Обновлено: 2026-09-08 (сессия: Vinograd WAN мониторинг) +Обновлено: 2026-09-08 (сессия: Grafana read-only пользователь) ## Текущее состояние -Лаборатория spec-driven подхода (OpenSpec CLI 1.12.0) для задач настройки инфраструктуры Hermes/homelab. Цикл propose→apply→archive работает; 4 change заархивированы. Tavily-прокси (web_extract) работает end-to-end в forward-режиме (решение по задаче 5: оставить как есть). Локальный экстрактор (trafilatura) написан и протестирован (2.2/2.3 зелёные), change заархивирован. Репозиторий создан на gitverse.ru, main запушен. Новый цикл vinograd-rostelecom-channel-monitoring — заархивирован (ICMP-мониторинг канала Винный город в /opt/monitoring). +Лаборатория spec-driven подхода (OpenSpec CLI 1.12.0) для задач настройки инфраструктуры Hermes/homelab. Цикл propose→apply→archive работает; **5 change заархивированы**. Tavily-прокси (web_extract) работает end-to-end в forward-режиме (решение по задаче 5: оставить как есть). Локальный экстрактор (trafilatura) написан и протестирован (2.2/2.3 зелёные), change заархивирован. Репозиторий создан на gitverse.ru, main запушен. ICMP-мониторинг канала «Винный город» заархивирован (в /opt/monitoring). Read-only пользователь Grafana (it@vinogorod.ru, Viewer) добавлен через UI — change заархивирован. ## Сделано - [x] OpenSpec CLI установлен (npm, 1.12.0), лаба инициализирована с --tools hermes (6 скиллов) - [x] config.yaml с инфраструктурным контекстом (systemd, docker, /opt//, gitverse) - [x] change tavily-proxy-setup — ЗААРХИВИРОВАН (delta → specs/web-extract-tavily/spec.md) - [x] web_extract работает: Hermes → 8971 → SOCKS5-туннель → Tavily (HTTP 200, контент Example Domain) -- [x] change local-extractor — ЗААРХИВИРОВАН: trafilatura 2.2.0, local-режим в tavily_extract_proxy.py, тесты 2.2/2.3 зелёные (example.com и github через --local; tavily.com — geo-блок из РФ — через --local-socks 127.0.0.1:1080, HTTP 200) +- [x] change local-extractor — ЗААРХИВИРОВАН: trafilatura 2.2.0, local-режим в tavily_extract_proxy.py, тесты 2.2/2.3 зелёные - [x] Репозиторий создан на gitverse.ru (kpa39l/openspec-lab), git push -u origin main выполнен -- [x] systemd tavily-proxy.service — решение по задаче 5: ОСТАВЛЕН forward-режим (облачный Tavily через туннель) — рабочий провайдер без изменений -- [x] change vinograd-rostelecom-channel-monitoring — ЗААРХИВИРОВАН (2026-09-08): ICMP-мониторинг канала «Винный город» (РТК) в /opt/monitoring — blackbox icmp, prometheus job vinograd_wan (30s), алерт VinogradRostelecomDown, дашборд Vinograd WAN. delta → openspec/specs/vinograd-wan-monitoring/spec.md +- [x] systemd tavily-proxy.service — решение по задаче 5: ОСТАВЛЕН forward-режим (облачный Tavily через туннель) +- [x] change vinograd-rostelecom-channel-monitoring — ЗААРХИВИРОВАН (2026-09-08): ICMP-мониторинг канала «Винный город» в /opt/monitoring, дашборд Vinograd WAN +- [x] change grafana-readonly-user — ЗААРХИВИРОВАН (2026-09-08): read-only пользователь Grafana it@vinogorod.ru (role Viewer, пароль 1qazXSW2), создан вручную в UI (OSS 11.1 не умеет provisioning/API create пользователей). delta → openspec/specs/grafana-access-control/spec.md ## В работе / Следующие шаги -- (ничего — все 5 задач закрыты; лаба в стабильном состоянии) +- (ничего — все задачи закрыты; лаба стабильна) ## Как запустить / проверить ```bash @@ -24,7 +25,7 @@ cd /opt/hermes/openspec-lab openspec validate # все changes openspec status --change local-extractor # локальный экстрактор (тест) -./venv/bin/python .hermes/scripts/tavily_extract_proxy.py --port 8972 --local # путь: /opt/hermes/.hermes/hermes-agent/venv/bin/python +./venv/bin/python .hermes/scripts/tavily_extract_proxy.py --port 8972 --local curl -s -X POST http://127.0.0.1:8972/extract -d '{"urls":["https://example.com"]}' -H 'Content-Type: application/json' # рабочий прокси (systemd) systemctl status tavily-proxy # порт 8971, forward через туннель @@ -32,11 +33,12 @@ systemctl status tavily-proxy # порт 8971, forward через туннел ## Ключевые артефакты - /opt/hermes/openspec-lab/openspec/specs/web-extract-tavily/spec.md — main spec про forward-прокси -- /opt/hermes/openspec-lab/openspec/specs/web-extract-local/spec.md — main spec про local-экстрактор (после archive local-extractor) -- /opt/hermes/openspec-lab/openspec/changes/archive/2026-09-06-local-extractor/ +- /opt/hermes/openspec-lab/openspec/specs/web-extract-local/spec.md — main spec про local-экстрактор +- /opt/hermes/openspec-lab/openspec/specs/vinograd-wan-monitoring/spec.md — ICMP-мониторинг канала +- /opt/hermes/openspec-lab/openspec/specs/grafana-access-control/spec.md — read-only пользователь Grafana +- /opt/hermes/openspec-lab/openspec/changes/archive/2026-09-08-grafana-readonly-user/ — архивный change - /opt/hermes/.hermes/scripts/tavily_extract_proxy.py — прокси + local-режим - /etc/systemd/system/tavily-proxy.service — юнит (forward, без изменений) -- /opt/hermes/openspec-lab/.hermes/skills/openspec-*/ — Hermes-скиллы OpenSpec - gitverse: https://gitverse.ru/kpa39l/openspec-lab (remote origin: https://kpa39l:@gitverse.ru/kpa39l/openspec-lab.git) ## Открытые вопросы diff --git a/WALKTHROUGH.md b/WALKTHROUGH.md index 3928f17..ba0b02a 100644 --- a/WALKTHROUGH.md +++ b/WALKTHROUGH.md @@ -4,6 +4,23 @@ ## 2026-09-08 +### Grafana read-only пользователь (it@vinogorod.ru, Viewer) — change grafana-readonly-user + +`openspec new change grafana-readonly-user` → 4 артефакта → validate → archive +(delta → openspec/specs/grafana-access-control/spec.md). + +- Задача: добавить read-only пользователя для IT Винограда. +- **Главный вывод:** Grafana 11 OSS НЕ поддерживает ни файловое provisioning + пользователей (`grafana/provisioning/access-control/users.yml` молча + игнорируется — это EE/Cloud `security.provisioning`), ни API-создание + (`POST /api/users` → 404). Создание — **только в UI** (Administration → + Users → New user, роль Viewer). +- Приятный бонус: `POST /api/login` (JSON) даёт 401 даже при верном пароле, + а **Basic auth работает** (`curl -u estorozhenko:пароль /api/user` → 200). +- Проверено end-to-end: вход it@vinogorod.ru → 200, роль Viewer, `/api/users` + → 403 (read-only), неверный пароль → 401. Пользователь вошёл сам. +- git: мониторинг-репо запушен (da1746c, ветка **master** — не main!). + ### Vinograd WAN — ICMP-мониторинг канала «Винный город» (РТК), change в /opt/monitoring `openspec new change vinograd-rostelecom-channel-monitoring` → 4 артефакта → validate OK → archive (delta → openspec/specs/vinograd-wan-monitoring/spec.md) diff --git a/openspec/changes/archive/2026-09-08-grafana-readonly-user/.openspec.yaml b/openspec/changes/archive/2026-09-08-grafana-readonly-user/.openspec.yaml new file mode 100644 index 0000000..7a8e2be --- /dev/null +++ b/openspec/changes/archive/2026-09-08-grafana-readonly-user/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-08 diff --git a/openspec/changes/archive/2026-09-08-grafana-readonly-user/design.md b/openspec/changes/archive/2026-09-08-grafana-readonly-user/design.md new file mode 100644 index 0000000..3f4ad8f --- /dev/null +++ b/openspec/changes/archive/2026-09-08-grafana-readonly-user/design.md @@ -0,0 +1,49 @@ +# Design: Grafana read-only user — ручное создание (OSS-совместимо) + +## Файлы + +| Файл | Действие | Назначение | +|---|---|---| +| `/opt/monitoring/grafana-data/grafana.db` | изменяется Grafana при создании пользователя | хранит учётку (UI, не вручную) | +| `/opt/monitoring/README.md` | обновить | документация пользователя и роли | +| `/opt/monitoring/EXPERIENCE.md` | обновить | вывод: OSS 11.1 не умеет provisioning users | + +Никакие конфиги/провиджеры НЕ меняются. + +## Почему не provisioning + +- `grafana/provisioning/access-control/users.yml` — файловое provisioning + пользователей в Grafana 11 OSS **не обрабатывается** (в логах только + dashboards/datasources/alerting/plugins; access-control — EE-фича). +- API: `POST /api/users` → 404 (OSS), `POST /api/login` → 401 при верном + пароле (Basic auth работает, JSON-логин нет). Доступно только создание + пользователя в **UI**. + +## Создание в UI + +1. Открыть `http://grafana.nixg.ru` (или `http://127.0.0.1:3001`), войти + как `estorozhenko` (admin). +2. Administration → Users → **New user**: + - Email: `it@vinogorod.ru` + - Name: `IT Vinogorod` + - Role: `Viewer` + - Password: `1qazXSW2` (задать вручную, не отсылать invite) +3. Сохранить. + +## Проверка (после создания) + +```bash +# 1. логин рабочий +curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/user +# 2. роль Viewer в орге +curl -s -u 'estorozhenko:...' http://127.0.0.1:3001/api/orgs/1/users +# 3. read-only: админ-ручка недоступна +curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/users # → 403 +``` + +## Риски + +- Слабый пароль `1qazXSW2` (клавиатурная последовательность) на публичной + Grafana. Рекомендовать смену или ограничение доступа по IP (caddy/VPN). +- Пользователь создаётся вручную — при перезаписи grafana-data потребуется + пересоздать. Продублировать в README. \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-08-grafana-readonly-user/proposal.md b/openspec/changes/archive/2026-09-08-grafana-readonly-user/proposal.md new file mode 100644 index 0000000..aec815d --- /dev/null +++ b/openspec/changes/archive/2026-09-08-grafana-readonly-user/proposal.md @@ -0,0 +1,39 @@ +# Proposal: Add read-only Grafana user for Vinogorod IT + +## Зачем + +К дашбордам мониторинга (Grafana, `grafana.nixg.ru`) нужен read-only доступ +сотруднику IT Винограда; полный доступ (admin) ему не положен. + +- **Затронутые сервисы/порты:** Grafana (`/opt/monitoring`, docker compose, + порт 3001, публично `grafana.nixg.ru`). +- **Пользователь:** `it@vinogorod.ru`, пароль `1qazXSW2`, роль **Viewer**. + +## Что + +Grafana **OSS 11.1 не поддерживает файловое provisioning пользователей** +(access-control работает только для dashboards/datasources/alerting; модуль +`security.provisioning` — EE/Cloud). Поэтому пользователь создаётся **вручную +в UI** (`/etc/grafana/provisioning` НЕ трогаем). + +Шаги: +1. Войти в Grafana как admin (`http:// grafana.nixg.ru`, логин estorozhenko). +2. Administration → Users → Invite/New user: + - Email: `it@vinogorod.ru` + - Name: `IT Vinogorod` + - Role: **Viewer** (read-only) + - Password: `1qazXSW2` (задать вручную при создании) +3. Убедиться, что роль Viewer (не Admin, не Editor). + +## Rollback + +1. Grafana → Administration → Users → `it@vinogorod.ru` → Delete. +2. Никаких файлов конфигов не менялось — откат не требуется. +3. Пароль при необходимости сменить (Administration → Users → Edit). + +## Примечание + +- Пароль `1qazXSW2` слабый (клавиатурный); Grafana публична. Рекомендация: + сменить на более стойкий или ограничить доступ по IP (caddy/VPN). +- Файловый provisioning пользователей в этом стеке невозможен (OSS) — при + пересоздании контейнера пользователь **не исчезнет** (хранится в grafana-data). \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-08-grafana-readonly-user/specs/grafana-access-control/spec.md b/openspec/changes/archive/2026-09-08-grafana-readonly-user/specs/grafana-access-control/spec.md new file mode 100644 index 0000000..49b2ecb --- /dev/null +++ b/openspec/changes/archive/2026-09-08-grafana-readonly-user/specs/grafana-access-control/spec.md @@ -0,0 +1,37 @@ +# Delta for grafana access control + +## ADDED Requirements + +### Requirement: Read-only Grafana user for Vinogorod IT + +Grafana MUST provide a read-only account for the Vinogorod IT department: +login `it@vinogorod.ru`, role `Viewer`, in the default organization (orgId 1). +The account MUST NOT be able to create, edit, or delete dashboards, +datasources, or settings. + +#### Scenario: User exists with Viewer role +- GIVEN the admin has created the user `it@vinogorod.ru` in the Grafana UI +- WHEN the user logs in with the shared password +- THEN authentication succeeds (Basic auth `/api/user` → HTTP 200) +- AND the organization role is `Viewer` (`/api/orgs/1/users` → role "Viewer") + +#### Scenario: Unknown credentials rejected +- GIVEN the read-only user `it@vinogorod.ru` +- WHEN a request is made with a wrong password +- THEN the API returns HTTP 401 + +#### Scenario: Read-only enforced +- GIVEN the user `it@vinogorod.ru` is logged in as `Viewer` +- WHEN the user attempts a privileged operation (e.g. `POST /api/users`, + modify datasources) +- THEN the request is rejected (HTTP 403/404) + +### Requirement: No admin rights for IT user + +The IT read-only account MUST NOT have admin or editor rights; only viewing +of dashboards and logs is permitted. + +#### Scenario: Role is not elevated +- GIVEN the user `it@vinogorod.ru` +- WHEN checking its org role and admin flag (`/api/user` + `/api/orgs/1/users`) +- THEN role is `Viewer` and `isGrafanaAdmin` is false \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-08-grafana-readonly-user/tasks.md b/openspec/changes/archive/2026-09-08-grafana-readonly-user/tasks.md new file mode 100644 index 0000000..99374dd --- /dev/null +++ b/openspec/changes/archive/2026-09-08-grafana-readonly-user/tasks.md @@ -0,0 +1,19 @@ +# Tasks + +## 1. Создание пользователя в UI Grafana (вручную, пользователь) +- [x] 1.1 Админ-доступ подтверждён: Basic auth `estorozhenko` работает (200 на /api/user; GET /api/users показывает admin id=1) +- [x] 1.2 Проверка невозможности API-создания: `POST /api/users` → 404 (OSS 11.1 не даёт create через API) +- [x] 1.3 Создать `it@vinogorod.ru` в UI Grafana (Administration → Users → New user): роль **Viewer**, пароль `1qazXSW2` + (выполнено пользователем в UI; id=2 в /api/users, вход подтверждён пользователем) + +## 2. Проверка созданного пользователя +- [x] 2.1 `curl -s -u it@vinogorod.ru:1qazXSW2 http://127.0.0.1:3001/api/user` → 200, login=it@vinogorod.ru +- [x] 2.2 Роль: в `/api/orgs/1/users` (admin) → `it@vinogorod.ru` role=`Viewer`, disabled=false +- [x] 2.3 Негатив: неверный пароль → 401 +- [x] 2.4 Read-only: API `/api/users` с токеном it@vinogorod.ru → 403 (additional permissions) + +## 3. Документация и git +- [x] 3.1 Обновить `/opt/monitoring/README.md` (пользователь it@vinogorod.ru, Viewer, пароль у пользователя) +- [x] 3.2 Запись в `/opt/monitoring/EXPERIENCE.md` (OSS 11.1: provisioning users не работает; API create → 404; только UI) +- [x] 3.3 `git add` (поимённо) + commit + push в gitverse (истина) — da1746c в master +- [ ] 3.4 `openspec validate grafana-readonly-user` + `openspec archive --yes` + STATUS/WALKTHROUGH \ No newline at end of file diff --git a/openspec/specs/grafana-access-control/spec.md b/openspec/specs/grafana-access-control/spec.md new file mode 100644 index 0000000..14ecb09 --- /dev/null +++ b/openspec/specs/grafana-access-control/spec.md @@ -0,0 +1,40 @@ +# grafana-access-control Specification + +## Purpose +TBD - created by archiving change grafana-readonly-user. Update Purpose after archive. + +## Requirements + +### Requirement: Read-only Grafana user for Vinogorod IT + +Grafana MUST provide a read-only account for the Vinogorod IT department: +login `it@vinogorod.ru`, role `Viewer`, in the default organization (orgId 1). +The account MUST NOT be able to create, edit, or delete dashboards, +datasources, or settings. + +#### Scenario: User exists with Viewer role +- GIVEN the admin has created the user `it@vinogorod.ru` in the Grafana UI +- WHEN the user logs in with the shared password +- THEN authentication succeeds (Basic auth `/api/user` → HTTP 200) +- AND the organization role is `Viewer` (`/api/orgs/1/users` → role "Viewer") + +#### Scenario: Unknown credentials rejected +- GIVEN the read-only user `it@vinogorod.ru` +- WHEN a request is made with a wrong password +- THEN the API returns HTTP 401 + +#### Scenario: Read-only enforced +- GIVEN the user `it@vinogorod.ru` is logged in as `Viewer` +- WHEN the user attempts a privileged operation (e.g. `POST /api/users`, + modify datasources) +- THEN the request is rejected (HTTP 403/404) + +### Requirement: No admin rights for IT user + +The IT read-only account MUST NOT have admin or editor rights; only viewing +of dashboards and logs is permitted. + +#### Scenario: Role is not elevated +- GIVEN the user `it@vinogorod.ru` +- WHEN checking its org role and admin flag (`/api/user` + `/api/orgs/1/users`) +- THEN role is `Viewer` and `isGrafanaAdmin` is false