Rozsahy
Co klíč smí dělat.
Slovník
Uzavřená množina ve tvaru resource:action. Dost malá na to, aby se dala člověku ukázat jako seznam zaškrtávátek, a dost stabilní na to, aby uložené oprávnění znamenalo totéž i po roce. Týmž slovníkem je psaná i ROLE pracovního prostoru a tentýž hlídá nástroje MCP, takže klient jen pro čtení odesílací nástroj ani neuvidí. Jedna abeceda, tři plochy.
| Rozsah | Uděluje |
|---|---|
| emails:send | Odesílání e-mailů |
| emails:read | Čtení odeslaných zpráv a jejich stavu doručení |
| drafts:read | Čtení konceptů |
| drafts:write | Vytváření a úprava konceptů |
| threads:read | Čtení vláken a zpráv |
| threads:write | Štítkování vláken, označování jako přečtené a archivace |
| labels:read | Čtení štítků |
| labels:write | Vytváření a úprava štítků |
| contacts:read | Čtení kontaktů |
| contacts:write | Přidávání, úprava a odebírání kontaktů |
| audiences:read | Čtení publik a toho, kdo v nich je |
| audiences:write | Vytváření a úprava publik a změny toho, kdo v nich je |
| calendar:read | Čtení událostí a pozvánek v kalendáři |
| calendar:write | Vytváření a změny událostí v kalendáři a odpovídání na ně |
| templates:read | Čtení e-mailových šablon a jejich náhledy |
| templates:write | Vytváření a úprava e-mailových šablon a odesílání s nimi |
| domains:read | Čtení domén a jejich stavu DNS |
| domains:write | Ověřování a konfigurace domén |
| webhooks:read | Čtení webhookových endpointů a doručení |
| webhooks:write | Vytváření, úprava a testování webhooků |
| rules:read | Čtení poštovních pravidel a jejich testování |
| rules:write | Vytváření, úprava a přeřazování poštovních pravidel |
| connections:read | Čtení toho, které schránky jsou připojené |
| members:read | Přehled o tom, kdo je v pracovním prostoru a co drží |
| members:write | Přidávání a odebírání lidí a změny toho, kam dosáhnou |
| roles:read | Čtení rolí, které tento pracovní prostor definuje |
| roles:write | Vytváření, úprava a mazání rolí |
| settings:read | Čtení nastavení schránky včetně podpisu |
| settings:write | Změny nastavení schránky a podpisu |
| keys:write | Výměna vlastního tajemství, aniž by někdo otevřel konzoli |
Klíč vytvořený bez promyšleného seznamu rozsahů dostane emails:send a nic víc. Bezpečná výchozí hodnota pro přihlašovací údaj je to nejužší, co ho ještě dělá užitečným.
Klíč je zastropován rolí, která za ním stojí
Klíč se dá vydat pod ROLÍ a role je strop, ne druhé oprávnění. Co klíč doopravdy smí, je PRŮNIK jeho vlastních rozsahů s oprávněními té role (key.scopes ∩ role.permissions), spočítaný jednou na hranici, při každém požadavku, ještě než se dojde k jakémukoli endpointu. Nic dál po proudu o existenci rolí neví: rozsah, který role nedrží, prostě není v seznamu, který kontroly rozsahů čtou.
Ty dva seznamy se tedy čtou společně a ani jeden sám o sobě nevyhrává. Klíč s emails:send pod rolí, která ho nedrží, odesílat nesmí; role s emails:send nedá nic klíči, který o něj nikdy nepožádal. Zaškrtnout rozsah znamená požádat o pravomoc a role rozhoduje, kolik z toho, oč jste požádali, dostanete.
Klíč BEZ role nemá strop, a je tedy tak široký jako pracovní prostor, pod kterým byl vydán. Tohle nese každý klíč vytvořený dřív, než role existovaly, a tohle vlastník dostane i dnes, když pole nechá být — null role je tedy pro klíč NEJŠIRŠÍ stav, ne nejužší. Proto také smazání role vyžaduje, abyste řekli, kam mají její klíče jít: nechat je osiřet by každý z nich potichu povýšilo.
Průnik se vyhodnocuje při každém požadavku, místo aby se klíči vyrazil při vydání. Zúžení role je díky tomu okamžité odebrání práv, platné už při dalším volání volajícího a bez nutnosti klíč rotovat, a rozšíření je okamžité úplně stejně, což je ta polovina, kterou stojí za to si pamatovat.
GET /ping a GET /keys/self hlásí scopes vedle grantedScopes a roleId kvůli jednomu konkrétnímu selhání. scopes je efektivní seznam a jediný, který k něčemu opravňuje; grantedScopes je to, s čím byl klíč vydán. Cokoli je v druhém a chybí v prvním, vzala role, a ten rozdíl je celá odpověď na „můj klíč má emails:send a dostávám insufficient_scope“. Řešením je změna role, ne další klíč.
curl "$OE/ping" -H "$AUTH" { "ok": true, "keyId": "4c1b257a66287fd113bd89d0", "mode": "live", "scopes": ["emails:read", "threads:read"], "roleId": "role_c40a95f21cc65d31c2a89e07", "grantedScopes": ["emails:send", "emails:read", "threads:read"], "workspaceId": "10417196-e324-4283-af98-66ec62167c47"}Pět oprávnění se ke klíči nikdy nedostane: api-keys:read, api-keys:write, billing:read, billing:write a workspace:manage. Jsou to oprávnění, ale ne rozsahy, takže žádná role, ať je sebeštědřejší, je na token nedostane: vyrobit další klíč, změnit, co smí jiný klíč, nebo pohnout tarifem dělá jen přihlášený člověk. Jediné, co klíč smí udělat sám sobě, je vyměnit si vlastní tajemství, a to za rozsahem keys:write. GET /roles/permissions označuje těch pět jako scope: false, a právě díky tomu může jedna komponenta vykreslit jak matici rolí, tak seznam zaškrtávátek při vytváření klíče.
roles:write je fakticky celý slovník a tvrdit opak by byla nebezpečnější dokumentace. Klíč, který ho drží, může PATCHnout přesně tu roli, která ho zastropuje, a nadělit si všechno ostatní — a protože se strop vyhodnocuje při každém požadavku, ten širší platí hned při dalším volání. Není to díra, kterou by šlo zalepit, protože editor rolí, který neumí upravovat role, není editor rolí. Je to důvod nedávat roles:write na klíč, který kdy potřeboval jen číst seznam členů.
Rozsah odesílání
Nezávisle na rozsazích se dá klíč zúžit v tom, jako kdo smí odesílat. Nese dva seznamy. domainAllowlist drží celé domény a klíč s doménou smí odesílat jako kterákoli adresa na ní, včetně adres vytvořených až po klíči. addressAllowlist drží jednotlivé adresy. Nechte oba prázdné a klíč je tak široký jako pracovní prostor, nikdy širší. GET /keys/self ukazuje oba seznamy a GET /addresses hlásí, co daný klíč doopravdy smí použít, což je odpověď na nevysvětlené from_address_forbidden.
Táž množina zužuje i to, co klíč čte. Odeslaná pošta, sledování a kalendář odpovídají jen za adresy, jako které klíč smí odesílat, takže klíč omezený na jednu doménu za jinou ani neodesílá, ani nečte. Celá doména navíc klíči dovolí nastavit sledovacího hostitele té domény, což klíč omezený na jednotlivé adresy nesvede.
Tři zúžení tedy, a skládají se, místo aby se přebíjela: rozsahy na klíči, oprávnění role nad ním a domény a adresy, které smí dát do hlavičky From. Odeslání potřebuje všechna tři a odmítnutí jmenuje jen to první, na které narazilo.