Управление доступом в дашбордах с Marimo и OPA: простое решение для сложных политик
В современном мире данных всё чаще требуется не только предоставлять пользователям интерактивные инструменты для анализа, но и жёстко контролировать, кто и к каким данным может обращаться. Классический подход — встраивать логику доступа прямо в код приложения — быстро становится негибким и трудно поддерживаемым. На помощь приходят специализированные решения: Marimo для построения дашбордов и OPA (Open Policy Agent) для централизованного управления политиками доступа.
В этой статье мы разберём, как написать простое приложение на Marimo, которое проверяет права пользователя через OPA, а затем обсудим, как эта связка может быть расширена на полноценный дашборд, работающий с Trino и управляющий доступом к данным на разных уровнях.
Что такое Marimo и OPA?
Marimo (https://github.com/marimo-team/marimo) — это современный интерактивный блокнот для Python, который сочетает в себе удобство Jupyter с реактивностью и возможностью превращать блокнот в веб-приложение. В отличие от классических блокнотов, Marimo автоматически пересчитывает ячейки при изменении входных данных, что делает его идеальным для создания дашбордов и инструментов анализа.
OPA (Open Policy Agent: https://www.openpolicyagent.org) — это универсальный движок политик с открытым исходным кодом. Он позволяет описывать правила доступа на языке Rego (декларативном, похожем на JSON) и принимать решения на основе входных данных (input). OPA работает как отдельный сервис, принимающий запросы и возвращающий разрешено или запрещено действие. Такой подход отделяет политики от кода приложения, упрощая их изменение, аудит и повторное использование.
Простой пример: проверка доступа в Marimo
Представьте, что у нас есть дашборд, в котором разные пользователи могут видеть разные разделы. Вместо того чтобы хардкодить условия в Python, мы выносим логику в OPA.
Ниже приведён фрагмент кода на Marimo, который реализует минимальный интерфейс для проверки доступа:
Запускаем OPA
podman run -d --name opa-server -p 8181:8181 openpolicyagent/opa \
run --server --addr=0.0.0.0:8181 --log-level debugСоздаем политику Rego
nano policy.rego
package app.authz
default allow = false
allow if {
input.user.role == "admin"
}Отправляем политику в OPA:
curl -X PUT --data-binary @policy.rego http://localhost:8181/v1/policies/my_policyДалее запускаем новый блокнот Marimo
mkdir marimo-opa
cd marimo-opa
uv init
uv add marimo requests
uv run marimo edit app.pyа теперь само приложение Marimo
import marimo as mo
import requests
# Элементы управления
user_role = mo.ui.dropdown(["user", "admin"], value="user", label="Роль пользователя:")
resource = mo.ui.text(value="dashboard", label="Ресурс:")
submit = mo.ui.button(label="Проверить доступ")
mo.hstack([user_role, resource, submit])После нажатия кнопки код отправляет запрос к OPA:
mo.stop(not submit.value, mo.md("*Нажмите кнопку для проверки прав*"))
opa_url = "http://localhost:8181/v1/data/app/authz/allow"
payload = {
"input": {
"user": {"role": user_role.value},
"resource": resource.value
}
}
try:
response = requests.post(opa_url, json=payload).json()
is_allowed = response.get("result", False)
status = mo.md("**Доступ разрешен**") if is_allowed else mo.md("**Доступ запрещен**")
except Exception as e:
status = mo.md(f"**Ошибка подключения к ОРА:** {e}")
statusЧто здесь происходит?
- Пользователь выбирает роль (user/admin) и вводит название ресурса.
- При клике на кнопку формируется JSON с полем `input`, содержащим роль и ресурс.
- Этот JSON отправляется в OPA по эндпоинту, который возвращает решение (`result` — true/false).
- На основе результата выводится сообщение о разрешении или запрете.
Этот пример демонстрирует, как легко интегрировать OPA в интерфейс на Marimo. Все политики (например, `admin` может всё, а `user` — только определённые ресурсы) хранятся отдельно в OPA и могут быть изменены без переписывания кода приложения.
Расширяем сценарий: дашборд на Trino с двойным контролем доступа
Теперь представим более реальную задачу: мы строим дашборд для аналитики, который выполняет SQL-запросы к Trino — распределённому движку для работы с большими данными. В Trino доступ к таблицам, схемам и столбцам также можно регулировать через OPA. Таким образом, у нас возникает два уровня авторизации:
- Уровень приложения (Marimo) — определяет, может ли пользователь вообще открыть определённый раздел дашборда или выполнить какое-то действие в интерфейсе.
- Уровень данных (Trino) — контролирует, какие именно данные (таблицы, колонки, строки) пользователь может запрашивать через SQL.
Эти два уровня могут обслуживаться разными экземплярами OPA или одним, но с разными пакетами политик. Например, в Marimo мы проверяем политику `app/authz/allow`, а в Trino — `trino/authz/allow`. Это даёт гибкость: политики для интерфейса и для данных могут управляться разными командами или обновляться независимо.
В нашем приложении Marimo после успешной проверки прав на доступ к разделу мы можем формировать SQL-запрос и отправлять его в Trino. При этом Trino, в свою очередь, проверит, имеет ли пользователь право читать запрашиваемые таблицы, используя свой OPA-агент. Если хотя бы один из агентов вернёт отказ, пользователь не получит данные.
Такая двухуровневая архитектура обеспечивает безопасность «в глубину» и позволяет тонко настраивать политики как на уровне интерфейса, так и на уровне сырых данных.
Управление политиками OPA: взгляд в будущее
Настройка и поддержка политик OPA, особенно когда речь идёт о десятках таблиц, ролей и атрибутов, может стать сложной задачей. Требуется не только писать правила на Rego, но и поддерживать актуальность данных о пользователях и ресурсах. Для упрощения этой работы существует проект Moat (Data Control Plane для Trino и OPA).
Moat предоставляет: https://github.com/moat-io/moat
- SCIM2.0-сервер для интеграции с провайдерами идентичности (Okta, EntraId и др.);
- ингестию атрибутов пользователей и групп из различных источников (SQL, LDAP);
- ингестию метаданных о таблицах и представлениях из каталогов данных;
- готовые политики Rego для типовых сценариев (RBAC, ABAC);
- OPA-совместимый Bundle API с кешированием для быстрого обновления политик.
Moat сам не принимает решений в рантайме — он лишь поставляет OPA необходимую информацию (политики и данные). Это позволяет удобно управлять множеством кластеров Trino и эфемерных окружений, добавляя OPA-контейнер в каждый координатор и указывая ему на Moat как источник бандлов.
Однако подробное рассмотрение Moat выходит за рамки этой статьи. Мы обязательно вернёмся к нему в отдельном материале, где разберём его архитектуру, настройку и примеры использования.
Заключение
Связка Marimo и OPA даёт разработчикам дашбордов мощный и гибкий инструмент для управления доступом. Вы можете отделить политики от кода, упростить их изменение и аудит, а также комбинировать несколько OPA-агентов для разных уровней — приложения и данных. В сочетании с Trino и такими инструментами, как Moat, эта экосистема становится полноценным решением для корпоративных аналитических платформ.
Попробуйте предложенный пример в своём проекте — и вы убедитесь, как легко внедрить централизованное управление доступом, не усложняя код приложения. А о Moat мы расскажем в следующий раз!