Bezpečnost a autentizace

5 min čtení

Bezpečnost a autentizace

PgArachne se plně spoléhá na systém oprávnění PostgreSQL. Nevynalézá znovu Access Control Lists (ACL). PgArachne podporuje čtyři metody autentizace. Metody 1–3 používají SET LOCAL ROLE k přepnutí identity; metoda 4 (přímé přihlášení) se připojuje přímo jako daný uživatel, takže přepnutí role není zapotřebí.

Toto platí pro JSON-RPC a MCP endpointy. SSE endpoint je jedinou výjimkou — autentizuje volajícího, ale nepřepíná roli ani jinak nekontroluje oprávnění na úrovni kanálu, protože kanály PostgreSQL LISTEN/NOTIFY nejsou databázové objekty s vlastním GRANTem, který by šlo vynutit. Co to v praxi znamená, najdete na stránce o SSE.

1. Interaktivní přihlášení (JWT)

Uživatelé se autentizují pomocí svého skutečného PostgreSQL uživatelského jména a hesla pomocí HTTP Basic autentizace na POST /{prefix}/{database}/token. Pokud je úspěšná, obdrží krátkodobý JWT. Při použití tohoto tokenu přepne PgArachne aktivní roli na tohoto uživatele po dobu trvání každého požadavku.

curl -X POST http://localhost:8080/db/my_database/token -u demo_user:user_password
→ {"token":"eyJhbGciOi...","token_type":"Bearer","expires_in":28800}

Přihlašovací údaje putují v hlavičce Authorization, nikdy v těle JSON, a přihlášení má vlastní URL, takže ho reverzní proxy může omezovat bez čtení těl požadavků. Odpověď nelze nikdy cachovat.

Vyžaduje JWT_SECRET. Pokud není nastaven, vrací endpoint HTTP 404 (-32601) a klienti místo toho použijí přímé přihlášení (metoda 4) nebo API tokeny (metoda 2).

2. Služby (API tokeny)

Pro automatizované systémy nebo skripty lze použít dlouhodobé API tokeny.

  • Tokeny jsou uloženy v tabulce pgarachne.api_tokens.
  • Každý token je mapován na konkrétního databázového uživatele/roli.
  • Token odešlete v hlavičce Authorization: Bearer <token>.

Vytváření API tokenů vyžaduje pgarachne_admin. Použijte pgarachne.add_api_token(...) s rolí, která je členem pgarachne_admin.

3. Externí identity provider (vlastní JWT)

Pokud uživatele autentizujete mimo PgArachne (například v externí autentizační službě), můžete JWT vydávat tam a posílat ho přímo do PgArachne.

  • Formát hlavičky: Authorization: Bearer <jwt>.
  • Podepisování: pouze HMAC (HS256/HS384/HS512) se stejným JWT_SECRET, jaký má PgArachne.
  • Povinné claimy: db_role (řetězec, nesmí být prázdný) a db_name (řetězec, musí odpovídat /db/:database).
  • Povinný claim: exp (unixový časový otisk) pro expiraci tokenu.

Vyžaduje JWT_SECRET; bez něj se hodnoty Bearer ověřují pouze jako API tokeny.

Minimální příklad těla tokenu:

{
  "db_role": "demo_user",
  "db_name": "my_database",
  "exp": 1767225600
}

Důležité: asymetrické JWT algoritmy (např. RS256/ES256) aktuální implementace serveru nepřijímá.

4. Přímé přihlášení databázovými údaji (Basic Auth)

Nejjednodušší možnost: zasílejte PostgreSQL uživatelské jméno a heslo s každým požadavkem prostřednictvím standardní HTTP Basic Authentication. PgArachne otevře vyhrazený connection pool autentizovaný přímo jako daný uživatel — SET LOCAL ROLE se neprovede.

Authorization: Basic <base64(uzivatel:heslo)>

Příklad s curl:

curl -X POST http://localhost:8080/db/my_database/jsonrpc \
  -u demo_user:heslo \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"api.hello_world","params":{},"id":1}'
Kdy použít přímé přihlášení:
  • Rychlé prototypování a lokální vývoj — není třeba správa tokenů.
  • Interní služby, kde jsou přihlašovací údaje již bezpečně spravovány.
  • Situace, kdy by vydání JWT předem zbytečně komplikovalo řešení.

Klíčové rozdíly oproti metodám s tokeny:

  • Příkaz GRANT demo_user TO pgarachne není vyžadován — PgArachne roli nepřepíná.
  • PostgreSQL Row-Level Security a oprávnění definovaná pomocí GRANT jsou vynucena standardně, protože spojení běží přímo pod daným uživatelem.
  • Connection pooly jsou udržovány pro každého uživatele zvlášť a mají maximální dobu životnosti 5 minut. Po změně hesla stará spojení vyprší během tohoto okna.
  • Aby idempotency klíče fungovaly s přímým přihlášením, udělte uživateli oprávnění EXECUTE ON FUNCTION pgarachne.save_idempotency_key(text, text).

Oprávnění proxy: vyžadováno pouze pro metody 1–3

Při autentizaci pomocí JWT nebo API tokenů se PgArachne připojuje jako systémový uživatel definovaný v DB_USER (např. pgarachne) a přepíná identitu pomocí SET LOCAL ROLE. Systémový uživatel musí být členem každé cílové role.

-- Vyžadováno pouze pro JWT / API-token autentizaci:
GRANT demo_user TO pgarachne;

Tento grant není zapotřebí při použití přímého přihlášení (metoda 4).

Srovnání metod autentizace

MetodaHlavičkaSET LOCAL ROLEGRANT … TO pgarachneNejlépe pro
JWT (/token)Bearer <jwt>✅ AnoVyžadovánoUživatelské relace
API TokenBearer <token>✅ AnoVyžadovánoAutomatizované služby
Externí JWTBearer <jwt>✅ AnoVyžadovánoIntegrace externího IdP
Přímé přihlášeníBasic <b64>❌ NeNevyžadovánoVývoj, interní služby

Které funkce lze volat

PgArachne nemá žádný vlastní seznam povolených schémat — co smí role volat, rozhodují výhradně oprávnění PostgreSQL. Funkci lze volat (a vypisují ji capabilities, MCP tools/list i export OpenAPI), pokud přijímá jediný parametr jsonb, role na ni má EXECUTE a role má USAGE na jejím schématu. Funkce ve schématech pg_catalog, information_schema, pgarachne a funkce patřící rozšířením jsou kvůli přehlednosti z výpisu vynechány, platí pro ně ale stejná oprávnění.

Výchozí nastavení PostgreSQL je benevolentní

Ve výchozím stavu PostgreSQL uděluje EXECUTE na každou novou funkci roli PUBLIC a každá role má USAGE na schématu public. Pomocnou funkci public.something(jsonb) tak může přes API volat jakákoli autentizovaná role, dokud oprávnění neodeberete. Doporučené nastavení:

-- Nové funkce nebudou spustitelné pro všechny (spusťte jako role, která je vytváří):
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

-- API funkce držte ve vyhrazeném schématu a oprávnění udělujte explicitně:
GRANT USAGE ON SCHEMA api TO demo_user;
GRANT EXECUTE ON FUNCTION api.hello_world(jsonb) TO demo_user;

Ochrana proti útokům hrubou silou

LOGIN_RATE_LIMIT a LOGIN_RATE_LIMIT_PER_IP platí pro všechny metody autentizace, na všech endpointech (JSON-RPC, MCP, SSE, OpenAPI):

  • /token: každý pokus se započítává do limitu na (IP, uživatelské jméno) i do limitu na IP.
  • Přímé přihlášení (Basic Auth): neúspěšné pokusy se započítávají do limitu na (IP, uživatelské jméno) i do limitu na IP. Úspěšné požadavky se nepočítají, takže legitimní klient, který posílá údaje s každým požadavkem, nikdy není omezen.
  • Bearer tokeny (JWT nebo API token): neúspěšné pokusy se započítávají do limitu na IP.

Po vyčerpání limitu jsou další pokusy odmítány s HTTP 429, dokud neuplyne okno (LOGIN_RATE_WINDOW) — a to bez jakékoli kontroly přihlašovacích údajů.