Welcome to my personal place for love, peace and happiness 🤖

Управление доступом в дашбордах с 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. Таким образом, у нас возникает два уровня авторизации:

  1. Уровень приложения (Marimo) — определяет, может ли пользователь вообще открыть определённый раздел дашборда или выполнить какое-то действие в интерфейсе.
  2. Уровень данных (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 мы расскажем в следующий раз!

Follow this blog
Send
Share
Tweet
Pin