Всички проекти

Идентичност и достъп

pacod-id

Едно място, където хора и машини влизат — и където се записва какво имат право да правят във всички ваши продукти.

pacod-id е OpenID Connect доставчик за собствени приложения, с акаунти, организации, присвоявания на роли и поток от промени, който продуктите следят, за да решават за достъпа локално. Написан на Rust, с клиентски библиотеки за Rust, TypeScript и Python.

  • Apache-2.0
  • Версия 0.1.0
  • Предварителна

Възможности

  • OpenID Connect доставчик

    Вход за вашите собствени приложения, проверен с тестовия пакет за съответствие на OpenID Foundation.

  • Акаунти и организации

    Хора, организации, присвоявания на роли, служебни акаунти, поща и одитна следа.

  • Един механизъм за правила, три порта

    Манифести на продукти, scopes, allowed, has_role и touches — на Rust, TypeScript и Python, като и трите минават едни и същи YAML тестови вектори.

  • Поток за оторизация

    Продуктите следят поток от промени в присвояванията на роли и решават за достъпа локално, без допълнително извикване при всяка заявка.

  • Токени, направени както трябва

    Compact JWS с RS256 и ES256 върху ring, JWKS, introspection и token exchange.

  • Брандиран вход

    Хоствани страници за вход и акаунт с бранд за всеки продукт, в светла и тъмна тема, на четири езика.

  • Готови клиенти

    Rust клиентски crate, Python пакет с FastAPI зависимости и поток за вход за SvelteKit като backend-for-frontend.

  • Готов за работа

    Docker образ, среда за разработка с поща и симулиран Google, както и Helm чарт.

Мястото в системата

Хора и услугиLLM доставчициAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Хора и услугиLLM доставчициAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Диаграма: как се свързват проектите на pacod Извиквания към LLM Докоснете проект, за да видите с какво е свързан.

Вход за цяло семейство продукти

pacod-id е услугата за идентичност зад продуктите на pacod. Хората влизат веднъж и достигат до конзолата на шлюза, платформата за агенти, CMS студиото и базата знания с един и същ акаунт. Машините също влизат — като служебни акаунти.

Услугата съществува, за да не се налага всеки продукт сам да поддържа пароли, писма за акаунти и административни страници. Акаунтите са в един общ пул: sub на даден човек е един и същ във всяка област (realm). Между продуктите се различава как изглежда входът и кой какво може да прави там — и pacod-id записва и двете.

Това е OpenID Connect доставчик за вашите собствени приложения. Всеки клиент е описан в конфигурацията: няма динамична регистрация и няма екран за съгласие.

Области, клиенти и токени

Областта (realm) е един issuer хост със собствен бранд, бисквитка за вход, езици и правила: дължина на паролата, продължителност на сесията, дали всеки може да се регистрира, кои роли управляват акаунтите. pacod-id избира областта по хоста на заявката, така че два бранда могат да споделят един пул от акаунти и въпреки това да изглеждат като два продукта. Брандът на областта е един от петте вградени: gateway, cms, kb, както и shop и bazaar за измисления продукт, който използват документацията и тестовете.

Клиентът е едно приложение от един от три вида:

Вид Типична употреба Grants
confidential Backend-for-frontend на продукт, който пази тайна authorization_code, refresh_token
public Нативно или мобилно приложение; кодовете му пази само PKCE authorization_code, refresh_token
service Сървърът на продукт, който говори с pacod-id client_credentials, token exchange

Предлага се само authorization code flow, като PKCE (S256) се изисква от всеки клиент, включително от confidential клиентите.

  • Access токените са JWT (RFC 9068), RS256 или ES256 според клиента, валидни по подразбиране 5 минути (от 2 до 15). Те казват кой, в коя сесия и с какъв scope, но не носят роли.
  • id_token живее 5 минути и носи адреса и името, когато scopes ги поискат.
  • Refresh токените са непрозрачни и се сменят при всяко използване. Ако след 30-секунден гратисен период бъде представен вече заменен токен, всички сесии на акаунта се прекратяват и собственикът получава писмо.
  • Token exchange (RFC 8693) позволява на услугата на даден продукт да действа от името на човек, в рамките на неговите права, като act посочва услугата.

Входът с Google се включва поотделно за всяка област. Когато сесия приключи, всеки клиент, който е имал grant в нея и има back-channel logout URI, получава logout токен.

Решения за достъпа на място

Ролите нарочно не се записват в access токените. При стартиране всеки продукт изпраща манифест: своите типове scopes, своите роли и техните права, както и кой какво може да присвоява. Scopes образуват дърво — от platform, по избор през organisation:<id>, до собствените типове на продукта, например gw.workspace:ws_1. Присвояването е роля, притежавана в един scope, и правата ѝ важат надолу: роля в организация важи във всяко работно пространство под нея.

product: shop
scope_types:
  profile: { parent: platform }
roles:
  admin:
    at: [platform]
    permissions: [admin.read, admin.write, profiles.assign]
    protected: true
  profile_editor:
    at: [profile]
    permissions: [profile.edit]
grant:
  default: admin.write

pacod-id съхранява присвояванията и проверява всяка тяхна промяна: за да се даде роля, е нужно правото за присвояване от манифеста в този scope, а роля с protected никога не губи последния си притежател.

Механизмът за правила отговаря на allowed, has_role, touches и can_grant. Той съществува на Rust, TypeScript и Python. И трите минават едни и същи YAML тестови вектори (policy/engine-vectors/). Векторите са спецификацията, така че решението е едно и също, където и да бъде взето.

Потокът за оторизация

Всеки продукт пази собствено копие на присвояванията и следи промените:

  1. При стартиране зарежда snapshot: своя каталог, организациите и своите scopes, присвояванията на своите роли, деактивираните и изтритите акаунти и наскоро прекратените сесии — всичко към един пореден номер, seq.
  2. След това чака промените след този seq чрез long poll, до 30 секунди на заявка. Отговорът идва веднага щом нещо се промени: PostgreSQL LISTEN събужда чакащата заявка.
  3. Промените се пазят 7 дни. Курсор, по-стар от това, получава 410 и продуктът зарежда snapshot отново.

Събитията обхващат присвоявания, акаунти, сесии, служебни токени, scopes и каталози. Записите връщат seq на потока, така че продукт, който трябва да прочете собствения си запис, изчаква копието му да навакса. Клиентските библиотеки за Rust и Python правят всичко това в своя кеш на присвояванията.

Измерено с make measure на една машина за разработка (Docker Desktop на Apple silicon), промяна достига до вече чакащ последовател с p99 около 10 ms при цел под една секунда.

Компонентите

Част Какво
crates/pacod-id Услугата: OpenID Connect доставчик, акаунти, организации, присвоявания на роли, потокът за оторизация, поща, одит
crates/pacod-id-authz Механизмът за правила
crates/pacod-id-jose Compact JWS (RS256, ES256) върху ring и JWKS
crates/pacod-id-client Проверка на токени, кешът на присвояванията, introspection, token exchange за продукти на Rust
python/ Пакетът pacod_id: механизъм за правила, проверка на токени, FastAPI зависимости
packages/* @pacod/id-authz, @pacod/ui, @pacod/id-client, @pacod/id-sveltekit
ui/ Хостваните страници за вход и акаунт

Услугата е един изпълним файл на Rust с три listener-а:

Listener Порт За
публичен 8070 Браузъри и приложения, през TLS reverse proxy: крайните точки на OpenID Connect и хостваните страници
вътрешен 8071 Само сървърите на продуктите: токени, потокът, introspection, прекратяване на сесии, административният API
метрики 9170 /healthz, /readyz и /metrics

Хостваните страници за вход, акаунт и администрация са статичен SvelteKit build, който изпълнимият файл сервира сам. @pacod/ui съдържа дизайн токените, темите на брандовете и компонентите за вход, които използва всеки продукт на pacod — включително този уебсайт.

Модел на сигурността

Основните защити според модела на заплахите:

  • Пароли: Argon2id на минимума на OWASP (19 MiB, 2 преминавания), 12 знака по подразбиране и списък със забранени често срещани пароли. Ограниченията на опитите за вход се пазят в PostgreSQL и са общи за всички инстанции: по акаунт, по познат браузър и по IP адрес.
  • Без разузнаване на акаунти: входът, възстановяването на парола и регистрацията отговарят еднакво, независимо дали за адреса има акаунт.
  • Ключове за подписване: създава ги самият pacod-id, пазят се запечатани в базата под ключ за криптиране на ключове (PID_KEK) и се ротират на всеки 90 дни, като следващият ключ се публикува ден по-рано. Аварийната ротация е една команда.
  • Съхранени тайни: refresh токените и връзките от писмата — като SHA-256, клиентските тайни и служебните токени — като HMAC с отделен pepper. Собствените редове в лога на pacod-id никога не съдържат парола, токен или ключ.
  • Изложеност: публичният listener не обслужва вътрешни и административни пътища, а NetworkPolicy на Helm chart-а допуска вътрешния порт само от източниците, които посочите. На общия edge в пълния стек на pacod маршрут има само публичният listener.
  • Образ: статичен musl изпълним файл върху distroless, без root права и без shell.

Експлоатация

Областите и клиентите се описват в един TOML файл; тайните — никога. Тайната на клиента идва от променливата, която посочва неговият secret_env.

[[realm]]
name = "gateway"
issuer = "https://id.example.com"
brand = "gateway"
locales = ["en", "bg", "de", "ru"]
self_signup = false

[[client]]
id = "pacod-gw-console"
realm = "gateway"
kind = "confidential"
secret_env = "PGW_UI_CLIENT_SECRET"
redirect_uris = ["https://console.example.com/auth/callback"]
audience = "pacod-gw"

pacod-id check-config проверява файла без база данни. Освен него услугата се нуждае от PID_DATABASE_URL, PID_KEK и PID_TOKEN_PEPPER, всяка зададена като променлива, като файл или чрез директория с тайни.

  • База данни: PostgreSQL, със собствена роля, която не е superuser. Миграциите само добавят и се изпълняват при всяко стартиране под advisory lock.
  • Инстанции: произволен брой споделят една база. Всяка изпраща чакащите писма и logout-и и презарежда ключовете и каталозите; една от тях, която държи lease, ротира ключовете и изтрива старите редове.
  • Поща: никоя заявка не чака SMTP. Писмата отиват в outbox, в бранда и езиците на областта, и се изпращат повторно в продължение на около осем часа.
  • Първи администратор: създава се при стартиране от PID_BOOTSTRAP_ADMIN_*.
  • Наблюдение: /readyz проверява базата и ключа за подписване. /metrics дава броя и продължителността на заявките по listener. Логовете са в JSON, без ред за всяка заявка. Входовете, промените на роли и действията на администраторите отиват в одитния журнал, който се пази 400 дни и се чете от административните страници.

Шлюз, който досега сам е вписвал хората, може да ги прехвърли с pacod-id import gw: паролите, административните токени и връзките в поканите продължават да работят.

make compose-up стартира среда за разработка в pacod-net — Docker мрежата, в която влиза всеки продукт на pacod. Compose конфигурацията ѝ е в два файла. docker-compose.yml съдържа само pacod-id. docker-compose.standalone.yml добавя собствени копия на общите компоненти, от които се нуждае: PostgreSQL (pacod-postgres), pacod-db-init, който при всяко стартиране създава ролята pacod_id и нейната база, ако липсват, и пощенски sink (pacod-mailpit), плюс симулирания Google (id-mock-idp). Средата слуша само на 127.0.0.1, с issuer на http://127.0.0.1:26070.

Пълният стек на pacod, pacod-demo (работещ на demo.pacod.io), зарежда само първия файл. Той пуска един PostgreSQL, един пощенски sink, един edge и един pacod-id за всички продукти, с една-единствена област за всички тях. platform/ съдържа дела на pacod-id от тази конфигурация: скрипта му за базата, маршрута му в общия Caddy и задачата му в Prometheus. При общ PostgreSQL сървър моделът на заплахите съветва всеки продукт да има собствена роля, която не е superuser: продукт, който се свързва като superuser, може да чете таблиците на pacod-id.

Какво още липсва

  • pacod-id 0.1.0 още не е издаден. Надграждане, резервно копие и възстановяване не са изпробвани.
  • Helm chart-ът минава helm lint и проверките на схемите, но още не е инсталиран на клъстер. Истински SMTP сървър и истинският Google не са пробвани; mock-ът от средата за разработка — да.
  • Тестовете за съответствие на OpenID Foundation са пускани локално: плановете Config, Basic и RP-Initiated Logout минават без нито едно неизпълнено условие, а един тест на Back-Channel Logout е блокиран от собствения сертификат на тестовия пакет. Локалните пускания не са сертификация.
  • Още няма MFA и passkeys, а оттам и claim acr; документацията ги посочва като планирани.
  • Няма claims за адрес и телефон; scope profile дава name и locale.
  • Вътрешният listener говори обикновен HTTP и освен ограниченията при вход няма общо ограничение на заявките.

Още документация

Екранни снимки

Технологии

Написан на
  • Rust
  • TypeScript
  • Python
Технологии
  • Rust
  • axum
  • PostgreSQL
  • OpenID Connect
  • SvelteKit
  • Docker
  • Helm

Бърз старт

Разработка и тестване
make test-servicesmake verifymake e2e
Изграждане и стартиране на образа
make imagemake compose-up

Работи с

  • pacod-gw

    Конзолата на шлюза може да вписва хората през pacod-id и проверява ролите в работните пространства с неговия механизъм за правила.

  • pacod-ap

    Приложението и административната конзола на платформата за агенти влизат през pacod-id като confidential клиент.

  • pacod-cms

    Студиото вписва хората през pacod-id и съхранява там ролите за всяка организация и за всеки сайт.

  • pacod-kb

    Потребителският интерфейс на базата знания е OIDC клиент на pacod-id; ролите viewer, editor и admin се предоставят там.

Лиценз

Apache-2.0