Кратко: сборка ClickHouse® от Altinity под названием Antalya обеспечивает поддержку аутентификации на основе токенов OAuth в полностью открытом исходном коде. Определяйте пользователей в поставщике удостоверений, а затем используйте поддержку OAuth в Antalya для управления учетными записями пользователей и их доступом с помощью всей мощи набора инструментов RBAC в ClickHouse.
Начиная с версии 26.3, сборка Antalya от Altinity обладает поддержкой корпоративного уровня (GA) для аутентификации на основе токенов через OAuth и OIDC (OpenID Connect). Ранее у стандартного ClickHouse® было два способа управления пользователями: вручную (с помощью файлов конфигурации или SQL) или через сервер LDAP. На практике администраторы полагались на общие учетные данные сервисных аккаунтов. Это приводит к ряду проблем: пароли сложно ротировать, контроль доступа является слишком общим, а при возникновении проблем трудно выяснить, кто именно что сделал.
Системы на основе токенов, напротив, работают с недолговечными токенами. Пароль, попавший не в те руки, может оставаться действительным в течение дней, недель или дольше; токен же истекает по истечении относительно короткого периода времени. (Вы сами определяете, как быстро истекает срок действия токена, разумеется.) Вы можете настроить Antalya так, чтобы предоставлять очень детализированный доступ к вашим данным на основе информации в токене. Кроме того, у вас есть журнал аудита каждого сгенерированного токена, что значительно упрощает отслеживание действий пользователей.
Поставщик удостоверений OAuth (IdP) предназначен для управления пользователями в масштабах всей организации. Вы можете определять пользователей и группы, а затем назначать им разрешения на основе групп, в которые они входят. Вы получаете всю выразительную мощь синтаксиса RBAC в ClickHouse без необходимости создавать индивидуальных пользователей.
Благодаря поддержке аутентификации на основе токенов Antalya может интегрироваться с вашим существующим поставщиком удостоверений для контроля доступа к данным ClickHouse с помощью недолговечных токенов. (Keycloak — это поставщик удостоверений, который мы рассмотрим здесь, но Okta, Entra и другие системы, совместимые с OIDC, работают аналогичным образом.)
Мы рассмотрим пример приложения, которое демонстрирует работу аутентификации на основе токенов…
Представьте проживание в отеле как сценарий на основе токенов. Когда вы регистрируетесь, вы предоставляете сотруднику стойки регистрации свои учетные данные, обычно удостоверение личности с фотографией и кредитную карту. Как только сотрудник убеждается, что вы — это тот, за кого себя выдаете, вы получаете ключ-карту. На ключ-карте записано примерно следующее: «эта карта истекает в полдень 17 июля, ее держатель имеет право открывать двери номера 438, тренажерного зала и лаундж-зоны на 9-м этаже, а также может подниматься на 4-й и 9-й этажи на лифте».
Важная часть этой метафоры: когда вы прикладываете ключ-карта к считывателю на дверном замке, считыватель просто считывает данные с карты. Если считыватель находится на двери номера 438 и сейчас 8:30 утра 17 июля, дверь открывается и впускает вас. Считывателю все равно, кто вы; он смотрит только на срок действия карты и на то, что, согласно карте, вам разрешено делать. Именно так наше демонстрационное приложение использует токены доступа.
С чем мы работаем
В нашем обсуждении мы рассмотрим систему на основе токенов, состоящую из трех компонентов:
- Поставщик удостоверений (IdP), который генерирует, обновляет и отзывает токены.
- Клиентское приложение, которое взаимодействует с IdP для получения и управления токенами, а также отправляет их к ресурсам. В мире управления доступом это называется зависимой стороной (relying party), что означает ее зависимость от IdP в вопросах проверки личности пользователя.
- Сервер Antalya, который принимает токен доступа от клиентского приложения вместе с запросом клиентского приложения на доступ к данным ClickHouse. Он проверяет токен, а затем принимает решение о том, должен ли быть выполнен запрос клиентского приложения. В мире OAuth это называется сервером ресурсов.
Мы будем использовать три разных типа токенов:
- ID-токен, который сообщает нам, кем является пользователь
- Токен доступа, который имеет срок действия и сообщает нам, что держатель токена имеет право делать (при условии, конечно, что он действителен)
- Токен обновления (refresh token), который также имеет срок действия, хотя его время жизни обычно намного больше, чем у токена доступа. Клиентское приложение может отправить токен обновления в IdP, чтобы получить новый токен доступа. IdP отправляет токен обновления клиентскому приложению; клиентское приложение никогда не отправляет токен обновления никому, кроме IdP.
Эти токены основаны на трех стандартах:
- OAuth 2.0 — стандарт для выпуска ограниченных по области применения и сроку действия токенов доступа и токенов обновления. Мы будем использовать OAuth для авторизации. Сервер ресурсов использует токен доступа, чтобы определить, что разрешено делать его держателю, а клиентское приложение может использовать токен обновления для получения нового токена доступа по истечении срока действия старого.
- OIDC, который определяет стандартный набор полей (email, preferred_username, given_name, family_name и т. д.), входящих в ID-токен, чтобы сообщить приложению, кем является держатель токена. Мы будем использовать OIDC для аутентификации.
- JSON Web Tokens (JWT) — формат JSON, содержащий необходимые нам данные. JWT состоит из заголовка, полезной нагрузки (payload) и подписи. Поля в полезной нагрузке называются утверждениями (claims); например, "email": "mateo@example.com" — это утверждение. ID-токены OIDC должны быть JWT; токены доступа и обновления OAuth часто являются JWT, но также могут быть…
- …непрозрачными токенами (opaque tokens), которые вообще не являются стандартом. По сути, это строки поиска, которые имеют значение только для IdP (например, KfHMt8N8MuWy6gzXcGX). Единственный способ проверить непрозрачный токен — отправить его в IdP. Токены доступа и обновления OAuth могут быть непрозрачными токенами.
Возвращаясь к метафоре с отелем: ID-токен OIDC — это ваше удостоверение личности с фотографией, а токен доступа OAuth — это ключ-карта от вашего номера.
Наше демонстрационное приложение
Мы рассмотрим систему, которая использует Grafana в качестве клиентского приложения, сборку ClickHouse Antalya от Altinity в качестве сервера ресурсов и Keycloak в качестве IdP. Вот как токены и данные циркулируют в системе:
Рисунок 1. Архитектура приложения
Путь пользователя от входа в систему до отображения дашборда с данными из ClickHouse выглядит следующим образом:
- Пользователь входит в Grafana. Grafana перенаправляет пользователя в Keycloak, после чего пользователь вводит свои учетные данные на экране входа Keycloak.
- Если учетные данные пользователя действительны, Keycloak отправляет в Grafana ID-токен, токен доступа и токен обновления.
- Пользователь хочет увидеть дашборд с данными ClickHouse, поэтому Grafana должна выполнить запрос к серверу Antalya. Она отправляет запрос и токен доступа в Antalya.
- Antalya проверяет токен доступа. Если ондействителен, Antalya отправляет результаты запроса обратно в Grafana. (Проверка токенов — тема для отдельной статьи.)
- Grafana отображает дашборд пользователю.
Важнейшей частью этого стека является плагин Altinity для Grafana для работы с ClickHouse. Он использует поддержку OAuth в Grafana, поэтому мы настраиваем его так, чтобы он передавал в ClickHouse токен доступа вместо имени пользователя/пароля или каких-либо других учетных данных.
Пользовательский опыт
Главное преимущество приложений на основе токенов заключается в том, что детали аутентификации и авторизации скрыты от пользователя. Как только пользователь входит в IdP, он получает доступ к различным ресурсам без необходимости повторной аутентификации, и обычно этот доступ сохраняется без проблем до истечения срока действия токена обновления. Давайте посмотрим, что видит пользователь при работе с нашим приложением.
Прежде всего, пользователь переходит на экран входа в Grafana:
Рисунок 2. Экран входа в Grafana со ссылкой на Keycloak
Пользователь нажимает «Войти через Keycloak» и попадает на экран входа в Keycloak:
Рисунок 3. Экран входа в Keycloak
После входа через Keycloak пользователь перенаправляется в Grafana. Первое, что он видит, — это дашборд по умолчанию:
Рисунок 4. Дашборд «Обзор для руководства»
Данные о продажах, отображаемые здесь, поступают из ClickHouse. Возвращаясь к нашей диаграмме последовательности выше, пользователь не видит ничего из шагов 2, 3 или 4. Он входит в систему и сразу попадает на свой дашборд.
Как мы используем токены
Пример приложения использует токены для трех целей:
- Проверка пользователя. Grafana проверяет токен идентификации (ID token), сверяя его подпись с открытым ключом IdP.
- Определение того, какие дашборды Grafana видит пользователь. В Grafana есть три роли — Администратор (Admin), Редактор (Editor) и Просмотрщик (Viewer). Информация в токене идентификации определяет роль пользователя. Для нашего примера мы определили три дашборда. Администраторы видят все три, редакторы — два из трех, а просмотрщики — только дашборд с обзором, показанный выше.
- Определение того, к каким базам данных ClickHouse пользователь имеет доступ. За дашбордами Grafana стоят запросы ClickHouse. Когда Grafana отправляет этот запрос в Antalya, информация в токене доступа (access token) также определяет роль пользователя в ClickHouse. В отличие от Grafana, ClickHouse позволяет определять столько ролей, сколько нам нужно, и каждая роль может иметь чрезвычайно точные права (grants). Для демо мы определили роли clickhouse_admins, clickhouse_analysts и clickhouse_readers.
Как все это работает вместе
В нашем примере приложения Keycloak, Grafana и ClickHouse работают вместе, используя токены для аутентификации владельцев токенов и авторизации доступа к данным. Вот что нам нужно определить и настроить во всех этих компонентах:
Keycloak
В нашей конфигурации Keycloak мы создали шесть групп:
- grafana-admins, grafana-editors и grafana-viewers для Grafana
- clickhouse-admins, clickhouse-analysts и clickhouse-readers для ClickHouse.
Мы также определили трех пользователей:
- amara: пароль amara, принадлежит к группам grafana-admins и clickhouse-admins
- helen: пароль helen, принадлежит к группам grafana-editors и clickhouse-analysts
- mateo: пароль mateo, принадлежит к группам grafana-viewers и clickhouse-readers.
И мы определили интерфейс между Keycloak и Grafana. Часть этого включает в себя установку URL нашего сервера Grafana в качестве допустимого инициатора запросов для Keycloak. Мы также настроили сервер Keycloak на добавление утверждения (claim) groups в токен доступа:
Рисунок 5. Токен доступа с определенными группами
(В токене доступа гораздо больше информации, но она не имеет отношения к нашему обсуждению.) Grafana использует группы, чтобы определить, какие дашборды разрешено видеть владельцу этого токена. При загрузке дашборда она отправляет токен доступа в ClickHouse при выполнении запросов для заполнения виджетов на дашборде. ClickHouse аналогичным образом использует группы, чтобы определить, к каким базам данных и таблицам разрешен доступ владельцу этого токена.
Grafana
В нашем примере приложения Grafana использует токены двумя способами: она использует токен идентификации, чтобы определить, какие дашборды пользователю разрешено видеть, и управляет токеном доступа, передавая его в ClickHouse всякий раз, когда необходимо выполнить запрос для построения дашборда. Во взаимодействии с ClickHouse Grafana никак не изменяет токен доступа; она просто передает его в ClickHouse.
Прежде всего, Grafana должна использовать токен идентификации, чтобы определить, какой доступ должен быть у пользователя. Как упоминалось ранее, в Grafana есть три группы: Admin, Editor и Viewer. Мы сопоставляем имена групп, определенные в Keycloak, с группами Grafana. Это соответствие интуитивно понятно:
- grafana-admins → Admin
- grafana-editors → Editor
- grafana-viewers → Viewer
Мы определяем источник данных ClickHouse с помощью плагина Altinity ClickHouse для Grafana. Что важно, в конфигурации плагина мы указываем Grafana пересылать свои OAuth-токены в ClickHouse.
Рисунок 6. Настройка плагина Altinity Grafana для пересылки OAuth-токенов в ClickHouse
Grafana получает токены от поставщика личных данных; здесь мы инструктируем ее передавать токены идентификации и доступа в ClickHouse с каждым запросом. ClickHouse, как мы обсудим через минуту, затем использует содержимое токена, чтобы определить, что владелец этого токена может делать.
У нас также есть три дашборда:
- Дашборд администратора — виден только администраторам, содержит подробную информацию о клиентах (PII)
- Дашборд аналитики — виден только редакторам и администраторам, суммирует доходы, возвраты и маржу
- Обзор для руководства — виден всем пользователям, высокоуровневая сводка тенденций продаж
Когда пользователь входит в систему, список дашбордов содержит только те дашборды, которые ему разрешено просматривать. Это вид Амары; Хелен и Матео даже не знают о существовании дашборда администратора. Аналогично, Матео не знает о существовании аналитического дашборда.
Рисунок 7. Список дашбордов, доступных пользователям с правами администратора
Antalya
Что приводит нас к конфигурации Antalya. Мы определили роли clickhouse_readers, clickhouse_analysts и clickhouse_admins. Затем мы предоставили им доступ следующим образом:
Рисунок 8. Иерархия ролей и привилегий в нашей конфигурации ClickHouse.
clickhouse_readers предоставляет пользователю доступ только для чтения к базе данных reports. Всем остальным ролям предоставляется доступ clickhouse_reader либо напрямую, либо транзитивно. Затем роли clickhouse_analysts предоставляется доступ к базе данных analytics. В завершение, роли clickhouse_admins предоставляется роль clickhouse_analysts, а затем ей предоставляется доступ к запросам к сырой (raw) базе данных и системным таблицам system.query_log и system.processes.
Наконец, нам нужно выполнить некоторую работу по настройке XML, чтобы подсказать Antalya, как найти сервер Keycloak и проверить токены. Подробности см. в документации по Antalya OAuth.
Наша полная конфигурация
Глядя на конфигурацию всех этих компонентов, мы настроили Keycloak на генерацию необходимых нам утверждений групп (groups claims). Каждый токен имеет одну из трех ролей Grafana (grafana-viewers, grafana-editors или grafana-admins) и одну из трех ролей ClickHouse (clickhouse_readers, clickhouse_analysts или clickhouse_admins). Когда Grafana видит утверждение groups, она определяет, к каким дашбордам пользователю разрешено получить доступ. А когда этим дашбордам нужно получить данные из Antalya, Grafana передает токен доступа, после чего Antalya использует утверждение groups для определения применимых РОЛЕЙ и ПРИВИЛЕГИЙ (GRANT) ClickHouse.
Давайте пройдемся по дашбордам, чтобы посмотреть, как Grafana и ClickHouse авторизуют (или нет) пользователя, идентифицированного по токену. Ранее мы рассматривали дашборд Executive Overview. Этот дашборд виден всем пользователям Grafana, и все отображаемые на нем данные поступают из базы данных reports, поэтому показанное выше представление работает для всех. Виджет «Revenue by Channel» запрашивает данные из таблицы reports.channel_summary; все остальные поступают из reports.monthly_revenue.
Теперь перейдем к дашборду Analytics:
Рисунок 9. Дашборд аналитики
Grafana предоставляет доступ к дашборду Амаре и Хелен (а также всем остальным с соответствующими ролями). Виджет «Top Products by Revenue» берется из reports.product_performance, а все остальное — из analytics.orders.
Между прочим, использование разных групп для Grafana и ClickHouse позволяет изолировать ошибки при предоставлении доступа пользователям. Например, предположим, что мы добавили Матео в группы grafana-editors и clickhouse-readers. Мы хотим дать Матео доступ только к данным в базе данных reports, но включение его в группу grafana-editors дает ему доступ к дашборду Analytics. Это не имеет значения: ClickHouse отклонит любой запрос к базе данных analytics, поскольку он находится в clickhouse-readers. Каждый виджет на рисунке 9 выше, кроме «Top Products by Revenue», не будет содержать никаких данных. Например, для «Revenue by Category» требуется доступ к analytics.orders, поэтому он будет пустым:
Рисунок 10. Виджет Grafana, запрос которого был отклонен ClickHouse
Наконец, дашборд Admin:
Рисунок 11. Дашборд Admin
Grafana предоставляет доступ к дашборду Admin только Амаре. Все виджеты визуализируют данные из таблицы raw.orders.
В каждом случае Grafana и ClickHouse корректно ограничивают доступ к дашбордам и данным.
Пользователи в OAuth, Grafana и ClickHouse
Давайте подведем итог, рассмотрев пользователей, которые существуют в Grafana и ClickHouse. Как мы упоминали ранее, мы управляем пользователями через поставщика идентификационных данных. Единственными созданными нами пользователями были пользователи в Keycloak: Амара, Хелен и Матео. Мы не определяли их явно в Grafana и ClickHouse. Сначала давайте посмотрим на консоль администратора Grafana, чтобы увидеть список пользователей:
Рисунок 12. Список пользователей в консоли администратора Grafana
(Обратите внимание на метку Generic OAuth рядом с пользователями, которых мы определили в Keycloak.) Аналогично, давайте воспользуемся clickhouse-client, чтобы посмотреть, кто определен в ClickHouse:
┌─name──────────────┬─auth_type──────────────┐1. │ default │ ['plaintext_password'] │2. │ helen@example.com │ ['jwt'] │3. │ amara@example.com │ ['jwt'] │4. │ mateo@example.com │ ['jwt'] │ └───────────────────┴────────────────────────┘
(Значением auth_type для пользователей, определенных в Keycloak, является jwt.) И Grafana, и ClickHouse создали пользователей на основе токенов, сгенерированных поставщиком идентификационных данных. Обратите внимание, что Амара, Хелен и Матео появляются в списке выше, потому что они уже входили в систему раньше. Если бы мы проверяли списки пользователей до того, как кто-либо вошел в Grafana, единственными пользователями были бы admin в Grafana и default в ClickHouse.
Давайте пойдем дальше: определим пользователя maddie в Keycloak и добавим ее в группы grafana-admins и clickhouse_admins.
Ни сервер Grafana, ни сервер ClickHouse раньше не видели Мэдди и даже не знают о ее существовании, пока она не войдет в систему. Но как только она это сделает, она появится в списке пользователей в Grafana и ClickHouse:
Рисунок 13. Обновленный список пользователей в консоли Grafana
В системной таблице ClickHouse system.users также появился новый элемент:
┌─name───────────────┬─auth_type──────────────┐1. │ default │ ['plaintext_password'] │2. │ maddie@example.com │ ['jwt'] │3. │ helen@example.com │ ['jwt'] │4. │ amara@example.com │ ['jwt'] │5. │ mateo@example.com │ ['jwt'] │ └────────────────────┴────────────────────────┘
Мы определили нового пользователя в одном месте: у поставщика идентификационных данных. Grafana и ClickHouse взяли это на себя.
Резюме
Использование токенов OAuth и OIDC значительно упрощает управление пользователями и их доступом к ресурсам во всей нашей среде. Как мы видели здесь, мы определили группы у нашего поставщика идентификационных данных (Keycloak), затем сопоставили их с группами в Grafana и ролями в Antalya, а затем использовали эти группы и роли для управления доступом к дашбордам, базам данных и другим ресурсам. Нам не нужно определять пользователей в каждом компоненте системы, а генерируемые нами токены имеют ограниченный срок жизни и поддаются отслеживанию. При необходимости мы можем отозвать доступ пользователя ко всему, просто заблокировав его у поставщика идентификационных данных. И самое главное — у нас по-прежнему есть доступ ко всем надежным средствам контроля доступа, встроенным в ClickHouse. Поддержка OAuth в Antalya позволяет управлять доступом к ресурсам на основе централизованно управляемых удостоверений и ролей.










