# ADR 0007. Доступ к ClickHouse: пользователи файлом, доверие нод секретом Дата: 9 августа 2026 года. Статус: принято. Реализация — отдельным тикетом. ## Решение У кластера четыре пользователя и три роли. - `default` — с паролем, только служебный: проверки здоровья нод и работа изнутри контейнеров. Приложения им не ходят. - `etl` с ролью `etl_writer` — чтение и запись во всех слоях. Им ходит Airflow и применяется DDL при подъёме стенда. - `bi` с ролью `bi_reader` — чтение витрин DM и слоя DDS. Им ходит Superset. - `analyst` с ролью `analyst_reader` — чтение всех слоёв. Им человек подключается снаружи, из своего клиента. Роль здесь шире прав на слои: образ ClickHouse требует отдельного разрешения на запросы `ON CLUSTER` и на чтение системных таблиц, а без второго клиент не открывает соединение вовсе. Состав прав каждой роли — работа тикета реализации. Пользователи, роли и права объявлены файлами настройки сервера, а не запросами SQL. Файл монтируется на обе ноды и лежит в git. Пароли живут в `.env` и попадают в настройку подстановкой по имени переменной; значения собраны по конвенции «слово-число-слово», потому что пароль `analyst` человек набирает руками. Ноды доверяют друг другу по общему секрету, объявленному в описании кластера. Учётные данные по репликам не расписываются. Сетевых ограничений на `default` нет: порты стенда и так открыты только на `127.0.0.1`, а внутри сети Compose дверь заперта паролем. Устройство модели — кто каким пользователем ходит и где живут пароли — опишет раздел README «Состав и доступ»; здесь только решение и доводы. Отдельного справочника по доступу в `docs/architecture/` не заводим: своего содержания сверх этих двух документов у него сегодня нет, а дом ему понадобится, когда появятся слои DDS и DM и гранты размножатся. Абзац README «У локального учебного кластера нет пароля» этим решением отменяется. ## Почему Стенд учит не администрированию доступа, а чтению отказа в правах: человек должен узнать в бою картину, которую видел здесь, и понимать, чего просить. Отсюда критерий отбора — модель должна читаться из текста ошибки, а не из описания. Поэтому пользователей мало, имена у них говорящие, а границы проходят там, где их обычно проводят в компаниях: `bi` видит витрины и слой DDS под ними, потому что так чаще всего и бывает; заодно расхождение витрины со слоем ниже остаётся проверяемым одним и тем же пользователем. **Секрет, а не учётные данные по репликам.** У каждой реплики в описании кластера своя учётка — вписанная явно или подразумеваемая, и тогда это беспарольный `default`. Подключение к соседней ноде идёт от неё, а не от того, кто задал вопрос. Значит, стоит `default` получить пароль — и без правки описания кластера межнодовые запросы встают. Починить это можно двумя способами, и они различаются не удобством. С учётными данными по репликам вся межшардовая работа идёт от одной общей учётки: на своей ноде права применяются, на соседней — нет. Ролевая модель тогда наполовину декорация, а это хуже её отсутствия: она утверждает разграничение, которого не существует. Общий секрет передаёт на соседа личность инициатора, стоит одной строки в описании кластера и не размножает пароль по репликам. Шифрование тут ни при чём; в соседнем `clickhouse-learning-cluster` выбран как раз путь с учётными данными по репликам, и там пароль вписан в каждую реплику каждого из трёх кластеров. Довод опирается на измеренное лишь наполовину: колонку `user` видно на живом стенде, а вот что права `bi` на соседнем шарде подменяются правами общей учётки — вывод из неё, и он ждёт измерения (см. конец документа). Окажись вывод неверным, выбор секрета устоит по остальным основаниям, но перестанет быть единственно возможным. **Файлы, а не SQL.** Объявленное файлом не оставляет состояния в томах: повторный `make up` на живом стенде ничего не сдвигает, правка пароля применяется перезапуском, источник истины — файл в git. Оба варианта с SQL — локальное хранилище доступа с `ON CLUSTER` и реплицированное в keeper — делают пользователей состоянием тома: `.env` на них больше не влияет, и появляется расхождение того же сорта, которое README уже описывает для Postgres и Grafana. Цена выбора известна: объявленных файлом пользователей нельзя менять запросами. Она принята как упрощение — сломать модель случайно труднее. **Что ещё отвергнуто.** Оставить всё на беспарольном `default` — цена нулевая, но и рассказать по итогам нечего. Раздать всем пароль без ролей — дёшево и показывает ровно тот антипаттерн, за который ругают в бою: все под одним админом. Вынести доступ в лекцию, как репликационную эксплуатацию, — довод «отдельный операционный домен» здесь не работает: у репликации это живые процессы, учения и runbook, а тут несколько десятков строк настройки и ноль эксплуатации. Запереть `default` ещё и по сети — второй замок на ту же дверь. **Отложено явно**: TLS и защищённые межсерверные соединения, настоящее хранилище секретов, внешние поставщики учётных записей, квоты и профили под пользователя, политики строк, аудит запросов. ## Следствия До появления слоёв DDS и DM читать `bi` нечего, и это намеренно. Дашборды рисуются поверх модели данных, а не поверх типизированных событий, поэтому доступ Superset к ODS не планировался и правами не выдаётся. Пока витрин нет, подключение Superset проверяется связью, а не запросом к таблице. Владелец матвью приёма определяется тем, кто применил DDL. Весь DDL стенда идёт через `IF NOT EXISTS`, поэтому на существующих томах три матвью сохранят нынешнего владельца, а на собранном заново стенде им станет `etl`. Работают оба — права есть у обоих, — но два стенда в этом расходятся. Лаба «сломать права» вариантом с файлами не закрывается: создать через SQL новую роль и нового пользователя ничто не мешает, и новую роль разрешено выдавать даже пользователю, объявленному файлом. Недоступно обратное — править объявленных файлом. Всё, что лаба создаст, живёт в томе и убирается `make clean`. ## Что проверено Сверено 9 августа 2026 года по документации ClickHouse через MCP Context7 и на живом стенде 26.3.17.56. - В `system.clusters` у каждой реплики своя колонка `user`; на стенде там `default`. Отсюда весь довод про общий секрет. - Секрет кластера аутентифицирует серверы хешем от соли, нонса, секрета и запроса и позволяет назначить пользователя, от которого запрос выполняется на соседней ноде. - Роли и права объявляются в файле настройки пользователей наравне с самими пользователями; SQL-хранилище доступа для этого не требуется. - Хранилище пользователей из файла — только для чтения: попытка изменить такого пользователя запросом даёт `ACCESS_STORAGE_READONLY`. - Роль, созданную через SQL, разрешено выдавать пользователю из файла — отдельное улучшение ClickHouse 2025 года, в 26.3 оно есть. - Настройку пользователей можно перечитать на живом стенде, в том числе на всём кластере сразу. - Подстановка значений из переменных окружения — общий механизм файлов настройки ClickHouse. - Весь DDL репозитория идёт через `IF NOT EXISTS` (файлы `sql/ddl/`). Осталось проверить при исполнении, и это работа тикета реализации: точная форма объявления секрета в описании кластера (готового примера в документации не нашлось); работает ли подстановка из окружения именно для пароля пользователя, и если нет — пароли лягут в файл настройки прямым текстом, а README назовёт это вслух; применяются ли на соседнем шарде права `bi`, а не общей учётки (вывод из колонки `user`, живьём не измерен — проверка требует создать пользователя); принимает ли ClickHouse права, выданные на ещё не созданную базу — на момент решения `dds` и `dm` не существуют.