Governance, festet i kjernen
I MindooDB er governance en egenskap ved selve datalaget - ikke et påbygg på en betrodd server eller et applikasjonslag. Tilgangspolicy, identitet og et kryptografisk beviselig revisjonsspor som kan gjenskapes for et gitt tidspunkt, lagres og håndheves i databasekjernen. Gevinsten: du kan bevise ikke bare hva som ble endret, men også hvem som fikk lov å endre det - på det tidspunktet endringen faktisk kom inn i tenanten.
Det har to halvdeler: en skriveside som styrer hvem som kan opprette, endre eller slette dokumenter - håndhevet også når brukerne er offline - og en leseside som styrer hvem som kan se data, ved å kombinere en tilgangsport på synkroniseringsnivå med admin-blind nøkkeldistribusjon. Begge bygger på ende-til-ende-krypteringen i MindooDB.
Governance er en egenskap ved datalaget
De fleste stakker skyver governance oppover, til serveren eller applikasjonen: databasen lagrer rader, og noe annet avgjør hvem som får ta i dem og fører loggen. MindooDB snur det om. Policy, identitet, full historikk og revisjonssporet ligger i de samme ende-til-ende-krypterte append-only-lagrene - så garantiene følger med dataene på tvers av servere, peers og enheter som er offline, og de overlever en fullstendig kompromittert server.
Policyer og regler er admin-signerte dokumenter i katalogdatabasen, og selv append-only. Det nøyaktige øyeblikket governance ble slått på - eller midlertidig av - er en del av det permanente sporet, ikke en konfigurasjonsendring uten spor.
Hver oppføring bærer en betrodd tid, og katalogen fører en tidsreisekjede over sin egen historikk. Dermed kan wasAllowedAt(op, user, dbid, at) spille av hvilke regler som gjaldt og hvem som var autorisert på et hvilket som helst tidligere tidspunkt - en deterministisk avgjørelse som alle ærlige replikaer er enige om.
Hver endring er Ed25519-signert og kan dermed ikke fornektes, og den bevitnes mot en betrodd klokke. Brudd forsvinner ikke i stillhet - de føres i en karantene- og revisjonslogg per tenant som Haven viser, så selv avviste forsøk kan ettergås.
Tilgangsdokumenter inneholder nøkkellister per enhet; tilbakekalling er rett og slett å fjerne nøkler, og en uttrykkelig fjernsletting av enheten fjerner hele tenanten fra en stjålet eller forlatt enhet neste gang den kobler seg til - livsløpet til identiteten styres i den samme signerte katalogen.
Modellen med to nivåer
Hver regel faller inn under ett av to nivåer, ut fra hva synkroniseringsserveren kan se. Serveren håndterer utelukkende chiffertekst pluss litt metadata i klartekst - den kan aldri lese innholdet i dokumenter. Denne ene forskjellen er hele arkitekturen: den lar MindooDB gi et ærlig løfte om hva som er kryptografisk garantert, og hva som håndheves av policy blant klienter som samarbeider.
| Nivå | Hva det sjekker | Håndheves av | Styrke |
|---|---|---|---|
| Nivå 1 - identitet | Forfatterens identitet, måldatabase, operasjonstype | Server og klienter | Kryptografisk - serveren nekter å bevitne en oppføring som bryter regelen, så den kan ikke spre seg |
| Nivå 2 - innhold | Det faktiske dokumentinnholdet (withfields) | Bare klientene | Policy - avgrenser ærlige klienter og former brukeropplevelsen. En manipulert klient kan bare omgå den lokalt; alle ærlige replikaer sjekker withfields på nytt ved mottak og setter en endring som bryter regelen i karantene, så den blir aldri synlig for noen andre |
Vitnekvitteringer: en betrodd klokke du ikke behøver å stole på klienten for
Det vanskeligste spørsmålet i et lokal-først-system er "hvilken klokke stoler vi på?". En bruker som arbeider offline, kunne tilbakedatere sine egne oppføringer for å snike en endring forbi en policy. MindooDB svarer på det med en vitnekvittering: en bekreftelse, signert av et betrodd vitne (din synkroniseringsserver), på at en oppføring ble godtatt på et bestemt tidspunkt. Hvert håndhevingspunkt bruker dermed nøyaktig én klart definert klokke.
SDK-en vurderer nivå 1 + nivå 2 mot brukerens lokale katalogtilstand på gjeldende lokale tid. Er det tillatt, lagres oppføringen lokalt uten vitnefelt og er synlig med én gang på denne enheten. Brukerens egen klokke styrer brukerens eget lokale bilde - det er greit, for endringen har ennå ikke kommet inn i den delte tenanten.
Serveren vurderer nivå 1 mot sin egen tilstand på servertid. Er det tillatt, stempler den receivedAt, fester vitnenøkkelen, signerer kvitteringen og returnerer vitnefeltene, slik at de flyter tilbake til avsenderen og videre. Nekter den, kommer et strukturert AccessDenied tilbake, og oppføringen blir liggende lokalt - den kan ikke spre seg.
Mottakeren kontrollerer signaturen på kvitteringen mot listen over betrodde vitner. En gyldig signatur betyr at nivå 1 var oppfylt på receivedAt, så som standard vurderes det ikke om igjen. Mottakeren sjekker deretter nivå 2 lokalt og materialiserer endringen eller sender den til en lokal karantene- og revisjonslogg.
Slik konfigureres avgjørelsene
All tilstand for tilgangskontroll ligger i directory-databasen, som bare administratorer har tilgang til, og synkroniseres til alle deltakere. Alt serveren trenger for nivå 1 er kryptert med $publicinfos-nøkkelen, så det kan leses uten å ha standardnøkkelen til tenanten; withfields-innhold kan serveren aldri lese. Hvert kall som endrer noe, er admin-signert.
En standardpolicy for tenanten og valgfrie policyer per database avgjør hvilke operasjoner som nektes med mindre en tillatelsesregel treffer:
- Opprette, endre, slette og gjenopprette - tillatt som standard, til du nekter dem
- Snapshot og purge - kun for admin som standard
- Lesing - grunnlaget for lese-/synkroniseringsporten på databasenivå, finjustert av leseregler
- Tillatte database-ID-er - tenantens liste over hvilke databaser som får finnes; serveren nekter å opprette eller synkronisere noen database utenfor den
- Standard krypteringsnøkkel - hvilken nøkkel et nytt dokument bruker når ingen er angitt; en bekvemmelighet, ikke en sikkerhetskontroll
- Hovedbryter - ett flagg som slår av alle tilgangssjekker på én gang
En helt ny tenant har ikke noe policy-dokument i det hele tatt, så alt er tillatt til en administrator skriver ett. Hver revisjon legges til historikken, så det nøyaktige vinduet for aktivering og deaktivering forblir etterprøvbart. Og det avgjørende: hver endring vurderes mot de policyene som var aktive på endringens egen betrodde tid (receivedAt). Endringer som kom inn i tenanten etter aktiveringen omfattes, mens tidligere endringer avgjøres mot den implisitte alt-er-tillatt-standarden - eksisterende data får dermed unntak automatisk, uten noe migreringstrinn.
Hver regel gjelder en operasjonstype og en database ("*" = alle), og lister brukerne eller gruppene den gjelder for. Vurderingen er mengdebasert og uavhengig av rekkefølge:
- en deny-regel som treffer → nektet
- ellers en allow-regel som treffer → tillatt
- ellers avgjør grunnlaget i policyen
Uavhengigheten av rekkefølge er viktig fordi regeldokumenter flettes mellom replikaer via CRDT-er - det finnes ingen regelrekkefølge å bli uenige om.
En server kan bare komme til en avgjørelse på nivå 1. Står bare en innholdsregel på nivå 2 mellom tillat og nekt, behandler den oppføringen som tillatt på nivå 1 og overlater withfields-sjekken til klientene. Hver avgjørelse gir et strukturert resultat - allowed, en lesbar reason, matchedRuleId og tier - som SDK-en bruker til å gråe ut handlinger en bruker ikke kan utføre.
En withfields-klausul sjekker en punktsti inne i dokumentet med et lukket sett operatorer (equals, contains, gt, …) og plassholdere som ${user.usernames}. Hver klausul vurderes mot en valgt dokumenttilstand:
- before - dokumentet som det er (standard for endring og sletting): "du må allerede være redaktør". En vurdering mot after ville la noen legge seg selv inn og autorisere sin egen redigering.
- after - dokumentet med endringen anvendt (standard for oppretting): "den som oppretter, må føre seg selv inn i
myeditors".
Regler treffer på brukerens hashede brukernavn, gruppehashene (også for nestede grupper) og reserverte pseudotokens:
$everyone- alle registrerte brukere$admin- bare administratorer$author- den opprinnelige oppretteren av dokumentet (nivå 1, eiermodell)
Tilbakekalling skjer ved å fjerne nøkler fra det admin-signerte tilgangsdokumentet - ingen egne tilbakekallingsdokumenter. En administrator kan i tillegg signere en uttrykkelig fjernsletting av enheten per nøkkel, som fjerner tenanten fra en stjålet eller forlatt enhet neste gang den kobler seg til.
Et CRM med redaktører per post
Her går vi gjennom én realistisk policy fra ende til ende, så delene faller på plass. Tenanten har en crm-database, og vi vil ha fire regler: alle kan opprette kontakter, men må føre seg selv inn i myeditors; bare en allerede oppført redaktør kan endre en kontakt; bare den opprinnelige oppretteren kan slette den; og HR-gruppen kan endre alt som en overstyring for ledere.
Grunnlaget er deny. Regel 1 treffer via $everyone, og dens withfields går gjennom fordi myeditors i after-tilstanden inneholder Alice → tillatt. Serveren bekrefter bare nivå 1 og bevitner deretter oppføringen.
Regel 2 treffer via $everyone, men dens withfields feiler: myeditors i before-tilstanden inneholder ikke Bob → nektet lokalt, selv om endringen hans prøver å legge ham selv inn. En manipulert klient kunne sende den, men alle ærlige mottakere setter den i karantene ved materialisering.
Regel 3 treffer via $author - oppretternøkkelen og den som signerer slettingen løses til samme bruker → tillatt og bevitnet (nivå 1, overlever en ondsinnet klient). Regel 4 lar hvilket som helst medlem av HR-gruppen endre enhver kontakt uavhengig av myeditors.
Dette viser arbeidsdelingen: regler på nivå 1 ($author, gruppen hr) håndheves på serveren og overlever en ondsinnet klient; regler på nivå 2 (innholdssjekkene på myeditors) håndheves av hver ærlige klient og settes i karantene ved mottak hvis de brytes.
Tilgangskontroll for lesing
Skriveregler avgjør hvem som kan endre data; lesetilgang avgjør hvem som kan se dem - og MindooDB håndhever det på to nivåer, begge admin-signert og kryptert med $publicinfos, slik at serveren uten tillit kan bruke de metadataene den trenger uten noen gang å ha tenant-nøkkelen.
1. En lese-/synkroniseringsport på databasenivå. Et denyDocRead-grunnlag pluss doc_read-regler (samme vurdering etter deny-overrides-allow, rettet mot brukere, grupper, $everyone eller $admin) avgjør hvem som i det hele tatt kan åpne og synkronisere en database. Det er vevd rett inn i synkroniseringssystemet: en bruker som mister lesetilgangen, slutter å få oppdateringer og kan ikke lenger åpne sin egen allerede synkroniserte lokale kopi. Fordi porten står foran hver synkroniseringsoperasjon, er lesing den overordnede porten per database - den styrer også skriving: den som ikke kan lese en database, kan heller ikke opprette data i den (og ville ellers skrevet dokumenter vedkommende aldri fikk se).
2. Konfidensialiteten til dokumenter er fortsatt kryptografisk. Et dokument kan bare leses av den som har en nøkkel i sin KeyBag (det personlige, passordbeskyttede nøkkellageret) som dekrypterer det - serveren tar aldri en leseavgjørelse her. Nøkkeldistribusjon er måten de nøklene kommer trygt til de rette folkene: en admin-signert policy sier hvilke brukere og grupper som skal ha hver nøkkel, og hver klient holder sin KeyBag i takt med den automatisk. Det er opt-in - med den delte standardnøkkelen og ingen leseport kan alle lese alt, akkurat som før.
I kontrollpunktet på serveren vurderer den samme hooken som sjekker listen over tillatte database-ID-er, også doc_read for den autentiserte identiteten mot betrodd servertid, og nekter å levere eller ta imot forsendelser for en nektet database - ikke tillatte oppdateringer blir rett og slett aldri levert. I takt med det nekter klienten å åpne en database brukeren har mistet tilgangen til, så en bruker med tilbakekalt tilgang får ikke engang lest sin lokalt synkroniserte kopi. directory-databasen er aldri underlagt porten (den bærer nettopp de policyene porten avhenger av); administratoren er unntatt.
Når en nøkkel sendes til en bruker, krypteres den med den brukerens personlige offentlige (RSA-)nøkkel, så bare vedkommende kan pakke den ut - ingen andre brukere, og ikke engang administratoren, kan lese nøkkelen. Derfor er distribusjonen admin-blind: den som alt har nøkkelen, pakker den for mottakerne, og administratoren bare signerer og publiserer resultatet. En vanlig bruker kan forberede en distribusjon og gi den til en administrator for signering - også til en administrator som ikke har nøkkelen.
Hver klient holder sin KeyBag i takt med policyen ved oppstart og etter hver synkronisering. Send en nøkkel til en bruker, og neste synkronisering henter inn dokumentene den nøkkelen åpner - de dukker opp i databasen, nå lesbare. Trekk nøkkelen inn igjen, og de dokumentene forsvinner: de lokale kopiene som ikke lenger kan dekrypteres, fjernes fra databasen, cachene og visningene. Opprykk, rotasjoner og bytte av avdeling flyter automatisk gjennom dette.
Som et vern om båndbredden slutter serveren også å levere data som er kryptert med en nøkkel en bruker har mistet. Men en fjernet bruker som beholdt en gammel kopi, kan fortsatt lese det vedkommende alt hadde - den virkelige grensen er derfor rotasjon: gi en ny versjon av nøkkelen bare til de gjenværende mottakerne, så bruker hver framtidige endring en versjon den fjernede brukeren aldri fikk.
App-distribusjon styrt av policy
Det samme admin-signerte maskineriet som distribuerer nøkler, distribuerer også Haven-applikasjoner. En administrator publiserer en policy som navngir hvilke apper en tenant tilbyr og hvem som skal få dem, og hver Haven-klient avstemmer sin lokale applikasjonsliste mot policyen etter at katalogen er synkronisert - så å ta en bruker inn i en tenant installerer automatisk appene tenanten publiserer, og tilbakekalt tilgang fjerner dem igjen.
I motsetning til en nøkkel bærer en app ingen hemmelighet, så distribusjonen handler bare om hvem som får hva. App-definisjonen og metadataene er kryptert med tenant-nøkkelen, så serveren uten tillit ser bare chiffertekst, men ruter likevel policyen til de rette mottakerne.
En policy retter seg mot både enkelte brukere og hele grupper. En push-liste sier hvem som skal få en app; en pull-liste tar den tilbake. Gruppemedlemskap løses opp på distribusjonstidspunktet, så å legge til eller fjerne noen i en gruppe endrer hvem som får appen uten at policyen røres, og et pull vinner alltid over et push når de overlapper.
En vanlig bruker kan forberede en ny distribusjon - eller en endring i en som finnes - og gi den til en administrator som en ferdig forespørsel om signering. Administratoren går gjennom den og signerer policy-dokumentet; bare den admin-signaturen gjør den gjeldende. Det speiler nøkkeldistribusjonen nøyaktig, så de samme folkene som alt forvalter nøkler, forvalter apper.
Etter hver katalogsynkronisering sammenligner hver klient policyen med det den har lokalt: den installerer apper den nå skal ha, oppdaterer en app når publisert versjon eller detaljer endres, og fjerner enhver app den ikke lenger har rett til - alt uten at brukeren løfter en finger.
En distribuert app er merket som administrert av tenanten og viser hvilken tenant den kom fra. Administrerte apper kan brukeren verken redigere eller fjerne - bare duplisere til en privat kopi for lokal bygging og testing - slik at tenantens publiserte versjon forblir den autoritative.
Etterprøvbar av design, ærlig om grensene
Fordi hver oppføring bærer en betrodd tid (receivedAt, med createdAt som reserve for rent lokale oppføringer) og katalogen fører en tidsreisekjede over sin egen historikk, kan du svare på "fikk bruker X lov til å endre dette dokumentet da endringen faktisk kom inn i tenanten?" - og gjenskape nøyaktig hvordan tilgangen til en bruker endret seg over tid. Spørringen wasAllowedAt(op, user, dbid, at) gjør dette til et førsteklasses API. Brudd på nivå 2 forsvinner ikke i stillhet; de føres i en karantenelogg per tenant som Haven viser i revisjonsvisningen.
Laget styrer både skriving og lesing (på dokument- og nøkkelnivå). Det kan ikke hindre en manipulert klient fra å skrive en oppføring lokalt, men det hindrer at oppføringen blir tatt inn i tenanten, og leseporten på serveren hindrer at data uten rettigheter noen gang kommer fram til en klient. v1 bygger på synkronisering via server som vitne. Synkronisering fra enhet til enhet over Iroh finnes nå, men en peer utsteder ingen vitnekvittering: enheten som mottar vurderer identitetsreglene selv, og serveren vurderer oppføringen på nytt når den kommer. Vitnekvitteringer utstedt av en peer og ekte lesekontroll på feltnivå (nøkler per felt) står fortsatt som senere arbeid. Historikken krypteres aldri om på stedet, siden forfattersignaturene ligger over chifferteksten.
MindooDB Haven samler den samme ende-til-ende-krypteringen, signerte historikken og innebygde governance i et rolig arbeidsområde på alle plattformer - også revisjonsvisningen som viser endringer i karantene. Prøv den gratis betaen, eller les deg inn i detaljene.