Piattaforma · Governance e controllo degli accessi

Governance, integrata nel nucleo

In MindooDB la governance è una proprietà dello strato dei dati stesso, non un'aggiunta montata sopra un server o uno strato applicativo di cui fidarsi. Policy di accesso, identità e un audit trail dimostrabile crittograficamente e riproducibile a un istante preciso sono archiviati e applicati nel nucleo del database. Il vantaggio: puoi dimostrare non solo che cosa è cambiato, ma anche chi era autorizzato a cambiarlo, nel momento in cui la modifica è davvero entrata nel tenant.

Ha due metà: un lato scrittura che stabilisce chi può creare, modificare o eliminare i documenti — applicato anche quando gli utenti sono offline — e un lato lettura che stabilisce chi può vedere i dati, combinando un gate di accesso a livello di sincronizzazione con una distribuzione delle chiavi cieca per l'admin. Entrambi si appoggiano alla cifratura end-to-end di MindooDB.

Governance integrata nel nucleo: i dispositivi client inviano richieste di scrittura firmate attraverso un policy gate di regole firmate dall'admin; le scritture consentite raggiungono il database cifrato, quelle negate vengono bloccate, mentre una cronologia di audit mostra l'autorizzazione in ogni istante
Perché è governance, non solo permessi

La governance è una proprietà dello strato dei dati

La maggior parte degli stack spinge la governance verso l'alto, nel server o nell'applicazione: il database salva le righe e qualcos'altro decide chi può toccarle e tiene il log. MindooDB rovescia l'impostazione. Policy, identità, cronologia completa e audit trail vivono negli stessi store cifrati end-to-end e append-only, quindi le garanzie viaggiano con i dati attraverso server, peer e dispositivi offline, e sopravvivono anche a un server compromesso del tutto.

La policy come dato versionato

Policy e regole sono documenti firmati dall'admin nel database directory e sono a loro volta append-only. Il momento esatto in cui la governance è stata attivata — o disattivata temporaneamente — fa parte del registro permanente, non è una modifica di configurazione che non lascia traccia.

Autorizzazione riproducibile

Ogni voce porta con sé un tempo attendibile e la directory conserva una catena time-travel della propria cronologia. Così wasAllowedAt(op, user, dbid, at) può riprodurre quali erano le regole e chi era autorizzato in qualunque momento passato: un verdetto deterministico su cui ogni replica onesta concorda.

Responsabilità dimostrabile

Ogni modifica è firmata con Ed25519, quindi non ripudiabile, e attestata contro un orologio attendibile. Le violazioni non vengono scartate in silenzio: finiscono in un log di quarantena e audit per ogni tenant, che Haven mostra. Così resta tracciabile anche un tentativo rifiutato.

Identità, revoca e cancellazione

Le concessioni contengono array di chiavi per ogni dispositivo; revocare significa semplicemente rimuovere chiavi, e un'esplicita cancellazione remota rimuove l'intero tenant da un dispositivo rubato o dismesso alla connessione successiva: il ciclo di vita dell'identità è governato nella stessa directory firmata.

L'idea di fondo

Il modello a due tier

Ogni regola ricade in uno dei due tier, in base a ciò che il server di sincronizzazione può vedere. Il server tratta soltanto testo cifrato più un piccolo insieme di metadati in chiaro: il corpo dei documenti non può leggerlo mai. Questa sola distinzione è tutta l'architettura: permette a MindooDB di fare una promessa onesta su cosa è garantito crittograficamente e cosa invece è applicato dalle policy tra client che collaborano.

Tier 1 e Tier 2 a confronto
Le regole di identità di Tier 1 verificano autore, database e tipo di operazione e sono applicate sia dal server sia dai client; le regole di contenuto di Tier 2 verificano withfields e sono applicate solo dai client
Una regola è di Tier 2 se e solo se ha una clausola withfields. Tutto il resto è Tier 1.
I due tier a confronto
Tier Cosa verifica Applicata da Forza
Tier 1 - IdentitàIdentità dell'autore, database di destinazione, tipo di operazione Server e clientCrittografica - il server si rifiuta di attestare una voce che viola la regola, che non può quindi propagarsi
Tier 2 - ContenutoIl contenuto effettivo del documento (withfields)Solo i client Policy - regola i client onesti e modella l'esperienza d'uso. Un client manomesso può aggirarla solo in locale; ogni replica onesta ricontrolla withfields alla ricezione e mette in quarantena la modifica che viola la regola, che non diventa quindi visibile a nessun altro
Il problema dell'orologio offline

Ricevute del testimone: un orologio attendibile senza doversi fidare del client

La domanda più difficile in un sistema local-first è: "a quale orologio crediamo?". Chi lavora offline potrebbe retrodatare le proprie voci per far passare una modifica aggirando una policy. MindooDB risponde con una ricevuta del testimone: un'attestazione, firmata da un testimone fidato (il tuo server di sincronizzazione), che una voce è stata accettata a un'ora precisa. Ogni punto di applicazione usa così esattamente un orologio ben definito.

Il ciclo di vita di una scrittura
Il dispositivo dell'autore crea una voce e la invia; il server, come testimone, verifica il Tier 1, marca receivedAt e firma una ricevuta; le altre repliche la ricevono e si fidano della ricevuta. Una voce negata resta in locale e non può sincronizzarsi.
Chi ha perso un diritto semplicemente non riesce a sincronizzare la modifica in questione: l'orologio offline non può mai servire a retrodatare qualcosa per aggirare una policy.
Scenario A
Scrittura in locale

L'SDK valuta Tier 1 + Tier 2 contro lo stato locale della directory dell'utente, all'ora locale corrente. Se l'operazione è consentita, la voce viene salvata in locale senza campi del testimone ed è subito visibile su questo dispositivo. Sulla vista solo locale decide l'orologio dell'utente, e va bene: la modifica non è ancora entrata nel tenant condiviso.

Scenario B
Invio a un server

Il server valuta il Tier 1 contro il proprio stato, all'ora del server. Se l'operazione è consentita, marca receivedAt, registra la chiave del testimone, firma la ricevuta e restituisce i campi del testimone, così che tornino al mittente e proseguano. Se la nega, restituisce un AccessDenied strutturato e la voce resta in locale: non può propagarsi.

Scenario C
Ricezione da un server

Chi riceve verifica la firma della ricevuta contro il proprio elenco di testimoni fidati. Una firma valida significa che il Tier 1 era soddisfatto all'ora receivedAt, quindi per impostazione predefinita non viene rivalutato. Il ricevente controlla poi il Tier 2 in locale e materializza la modifica oppure la indirizza a un log locale di quarantena e audit.

Regole, policy e identità

Come si configurano le decisioni

Tutto lo stato del controllo degli accessi vive nel database directory, accessibile solo agli admin, e si sincronizza con tutti i partecipanti. Tutto ciò che al server serve per il Tier 1 è cifrato con la chiave $publicinfos, quindi è leggibile senza possedere la chiave predefinita del tenant; il contenuto di withfields il server non può leggerlo mai. Ogni chiamata che modifica qualcosa è firmata dall'admin.

Le policy fissano la baseline

Una policy predefinita del tenant e policy opzionali per singolo database definiscono quali operazioni sono negate se nessuna regola allow corrisponde:

  • Creazione, modifica, eliminazione e ripristino - consentite per impostazione predefinita, finché non le neghi
  • Snapshot & purge - per impostazione predefinita solo per gli admin
  • Lettura - la baseline del gate di lettura/sincronizzazione a livello di database, affinata dalle regole di lettura
  • ID dei database consentiti - l'elenco dei database che possono esistere nel tenant; il server si rifiuta di creare o sincronizzare qualsiasi database fuori da quell'elenco
  • Chiave di crittografia predefinita - quale chiave usa un nuovo documento quando non ne viene indicata una; una comodità, non una misura di sicurezza
  • Interruttore generale - un flag che disattiva in un colpo solo ogni controllo di accesso

Un tenant appena creato non ha alcun documento di policy, quindi tutto è consentito finché un admin non ne scrive uno. Ogni revisione viene aggiunta alla cronologia, così la finestra esatta di attivazione e disattivazione resta verificabile. Soprattutto: ogni modifica è giudicata in base alle policy attive al suo tempo attendibile (receivedAt). Le modifiche entrate nel tenant dopo l'attivazione ne sono coperte, mentre le precedenti si risolvono contro l'implicito «tutto consentito»: i dati preesistenti sono quindi salvaguardati automaticamente, senza alcun passaggio di migrazione.

Le regole decidono con deny-overrides-allow

Ogni regola riguarda un tipo di operazione e un database ("*" = tutti) ed elenca gli utenti o i gruppi a cui si applica. La valutazione è insiemistica e indipendente dall'ordine:

  • una regola deny che corrisponde → negato
  • altrimenti una regola allow che corrisponde → consentito
  • altrimenti decide la policy di baseline

L'indipendenza dall'ordine conta perché i documenti delle regole si fondono tra le repliche tramite CRDT: non c'è alcun ordine di regole su cui poter essere in disaccordo.

Un server può arrivare solo a un verdetto di Tier 1. Se tra consentire e negare c'è soltanto una regola di contenuto di Tier 2, tratta la voce come consentita al Tier 1 e lascia ai client il controllo di withfields. Ogni decisione restituisce un risultato strutturato — allowed, un reason leggibile, il matchedRuleId e il tier — che l'SDK usa per disattivare le azioni che un utente non può compiere.

withfields: vincoli sul contenuto

Una clausola withfields verifica un percorso con punti all'interno del documento, con un insieme chiuso di operatori (equals, contains, gt, …) e segnaposto come ${user.usernames}. Ogni clausola viene valutata contro uno stato scelto del documento:

  • before - il documento esistente (predefinito per modifica ed eliminazione): "devi essere già un editor". Valutare lo stato after permetterebbe di aggiungersi da soli e autorizzare la propria modifica.
  • after - il documento con la modifica applicata (predefinito per la creazione): "chi crea deve aggiungersi a myeditors".
Identità, gruppi e revoca

Le regole vengono confrontate con l'hash del nome utente, con gli hash dei suoi gruppi (compresi quelli annidati) e con pseudo-token riservati:

  • $everyone - tutti gli utenti registrati
  • $admin - solo gli admin
  • $author - chi ha creato originariamente il documento (Tier 1, modello di proprietà)

La revoca si ottiene rimuovendo le chiavi dal documento di concessione firmato dall'admin: non esistono documenti di revoca separati. Un admin può inoltre emettere un'esplicita cancellazione remota del dispositivo, da attivare consapevolmente, firmandola per chiave: il tenant viene rimosso da un dispositivo rubato o dismesso alla connessione successiva.

Esempio pratico

Un CRM con editor per singolo record

Qui una policy realistica viene percorsa dall'inizio alla fine, così i pezzi si incastrano. Il tenant ha un database crm e vogliamo quattro regole: tutti possono creare contatti ma devono inserirsi in myeditors; solo chi è già elencato come editor può modificare un contatto; solo chi l'ha creato può eliminarlo; e il gruppo HR può modificare qualsiasi cosa, come via di escalation.

Alice crea un contatto

La baseline è deny. La regola 1 corrisponde via $everyone e la sua clausola withfields passa, perché nello stato after myeditors contiene Alice → consentito. Il server conferma solo il Tier 1, poi attesta la voce.

Bob (non è editor) prova a modificarlo

La regola 2 corrisponde via $everyone, ma la sua clausola withfields fallisce: nello stato before myeditors non contiene Bob → negato in locale, anche se la sua modifica prova ad aggiungerlo. Un client manomesso potrebbe inviarla, ma ogni ricevente onesto la mette in quarantena al momento della materializzazione.

Alice elimina, HR ha la precedenza

La regola 3 corrisponde via $author: la chiave di chi ha creato il documento e quella di chi firma l'eliminazione si risolvono allo stesso utente → consentito e attestato (Tier 1, resiste a un client malevolo). La regola 4 permette a qualsiasi membro del gruppo HR di modificare qualunque contatto, indipendentemente da myeditors.

Si vede così la divisione dei compiti: le regole di Tier 1 ($author, gruppo hr) sono applicate dal server e resistono a un client malevolo; le regole di Tier 2 (i controlli sul contenuto di myeditors) sono applicate da ogni client onesto e, se violate, finiscono in quarantena alla ricezione.

Il lato lettura

Controllo degli accessi in lettura

Le regole di scrittura decidono chi può modificare i dati; l'accesso in lettura decide chi può vederli, e MindooDB lo applica su due livelli, entrambi firmati dall'admin e cifrati con $publicinfos, così il server zero-trust può lavorare sui metadati che gli servono senza mai possedere la chiave del tenant.

1. Un gate di lettura/sincronizzazione a livello di database. Una baseline denyDocRead più le regole doc_read (la stessa valutazione deny-overrides-allow, rivolta a utenti, gruppi, $everyone o $admin) decidono chi può del tutto aprire e sincronizzare un database. È intrecciato direttamente nel sistema di sincronizzazione: chi perde l'accesso in lettura smette di ricevere aggiornamenti e non riesce più nemmeno ad aprire la copia locale già sincronizzata. Poiché il gate sta davanti a ogni operazione di sincronizzazione, la lettura è il gate principale per ogni database e regola anche le scritture: chi non può leggere un database non può nemmeno creare dati al suo interno (e altrimenti scriverebbe documenti che non potrebbe mai vedere).

2. La riservatezza dei documenti resta crittografica. Un documento può leggerlo solo chi ha nel proprio KeyBag (l'archivio di chiavi personale, protetto da password) una chiave che lo decifra: qui il server non prende alcuna decisione sulla lettura. La distribuzione delle chiavi è il modo in cui quelle chiavi arrivano in sicurezza alle persone giuste: una policy firmata dall'admin indica quali utenti e gruppi devono detenere ciascuna chiave, e ogni client mantiene automaticamente il proprio KeyBag allineato. È opt-in: con la chiave predefinita condivisa e senza gate di lettura, tutti possono leggere tutto, esattamente come prima.

Il gate di lettura intrecciato nella sincronizzazione

Nel punto di strozzatura sul server, lo stesso hook che valuta l'elenco degli ID di database consentiti valuta anche doc_read per il principal autenticato, contro l'ora attendibile del server, e si rifiuta di servire o di accettare invii per un database negato: gli aggiornamenti non permessi semplicemente non vengono mai consegnati. In parallelo, il percorso di apertura sul client si rifiuta di aprire un database a cui l'utente ha perso l'accesso, così un utente revocato non riesce a leggere nemmeno la propria copia sincronizzata in locale. Il database directory non passa mai dal gate (contiene proprio le policy da cui il gate dipende); l'admin è esente.

Le chiavi viaggiano cifrate per ogni destinatario

Quando una chiave viene inviata a un utente, è cifrata con la chiave pubblica (RSA) personale di quell'utente, così solo lui può estrarla: nessun altro utente, e nemmeno l'admin, può leggere la chiave. Per questo la distribuzione è cieca per l'admin: chi già detiene la chiave la incapsula per i destinatari e l'admin firma e pubblica solo il risultato. Anche un utente normale può preparare una distribuzione e passarla a un admin perché la firmi, pure a un admin che non possiede la chiave.

Le chiavi inviate mostrano i dati, quelle ritirate li nascondono

Ogni client mantiene il proprio KeyBag allineato alla policy all'avvio e dopo ogni sincronizzazione. Invia una chiave a un utente e la sua sincronizzazione successiva porta con sé i documenti che quella chiave apre: compaiono semplicemente nel database, ora leggibili. Ritira la chiave e quei documenti scompaiono: le copie locali che non si possono più decifrare vengono rimosse dal database, dalle cache e dalle viste. Promozioni, rotazioni e cambi di reparto passano automaticamente da qui.

Il vero taglio è la rotazione

Come tutela della banda, il server smette anche di consegnare dati cifrati con una chiave che un utente ha perso. Ma chi è stato rimosso e ha conservato una copia vecchia può ancora leggere quello che aveva già: il vero taglio è quindi la rotazione, cioè emettere una nuova versione della chiave solo per i destinatari rimanenti, così che ogni modifica futura usi una versione che l'utente rimosso non ha mai ricevuto.

Distribuire le app

Distribuzione di app basata su policy

Lo stesso meccanismo firmato dall'admin che distribuisce le chiavi distribuisce anche le applicazioni Haven. Un admin pubblica una policy che indica quali app offre il tenant e chi deve riceverle, e ogni client Haven riconcilia il proprio elenco locale di applicazioni con quella policy dopo la sincronizzazione della directory: così l'onboarding di un utente in un tenant installa automaticamente le app che quel tenant pubblica, e revocare l'accesso le rimuove di nuovo.

A differenza di una chiave, un'app non porta alcun segreto, quindi la distribuzione riguarda semplicemente chi riceve cosa. La definizione dell'app e i suoi metadati sono cifrati con la chiave del tenant, quindi il server zero-trust vede solo testo cifrato e instrada comunque la policy ai destinatari giusti.

Inviare a utenti e gruppi (e ritirare)

Una policy si rivolge sia a singoli utenti sia a interi gruppi. Un elenco di invio dice chi deve ricevere un'app; un elenco di ritiro la riprende. L'appartenenza ai gruppi si risolve al momento della distribuzione, quindi aggiungere o togliere qualcuno da un gruppo cambia chi riceve l'app senza toccare la policy, e in caso di sovrapposizione il ritiro ha sempre la precedenza sull'invio.

Preparata dagli utenti, firmata dall'admin

Un utente normale può preparare una nuova distribuzione — o una modifica a una esistente — e consegnarla a un admin come richiesta pronta da firmare. L'admin la esamina e firma il documento di policy; solo quella firma la rende autorevole. È identico alla distribuzione delle chiavi, quindi chi già gestisce le chiavi gestisce anche le app.

Installazione, aggiornamento e rimozione automatici

Dopo ogni sincronizzazione della directory, ogni client confronta la policy con quello che ha in locale: installa le app che ora gli spettano, aggiorna quelle di cui cambiano versione pubblicata o dettagli e rimuove ogni app a cui non ha più diritto, senza che l'utente debba muovere un dito.

Chiaramente gestita dal tenant

Un'app distribuita è contrassegnata come gestita dal tenant e mostra da quale tenant arriva. Le app gestite non possono essere modificate né rimosse dall'utente, ma solo duplicate in una copia privata per sviluppare e provare in locale, così la versione pubblicata dal tenant resta quella di riferimento.

Audit e ambito

Verificabile per progetto, onesto sui suoi limiti

Riproducibile per qualsiasi istante

Poiché ogni voce porta un tempo attendibile (receivedAt, con ripiego su createdAt per le voci solo locali) e la directory conserva una catena time-travel della propria cronologia, si può rispondere alla domanda: "l'utente X era autorizzato a modificare questo documento quando la modifica è entrata davvero nel tenant?" — e ricostruire esattamente come è cambiato nel tempo il suo accesso. La query wasAllowedAt(op, user, dbid, at) lo rende un'API di prima classe. Le violazioni di Tier 2 non svaniscono in silenzio: vengono registrate in un log di quarantena per ogni tenant, che Haven mostra nella sua vista di audit.

Ambito e non obiettivi della v1

Il livello governa sia le scritture sia le letture (a livello di documento e di chiave). Non può impedire a un client manomesso di comporre una voce in locale, ma impedisce che quella voce venga accettata nel tenant, e il gate di lettura del server impedisce ai dati non dovuti di arrivare a un client. La v1 punta sulla sincronizzazione mediata dal server come testimone. La sincronizzazione da dispositivo a dispositivo su Iroh esiste ormai, ma un peer non emette alcuna ricevuta di testimone: il dispositivo che riceve valuta da sé le regole di identità, e il server giudica di nuovo la voce quando arriva. Le ricevute di testimone emesse da un peer e un vero controllo della lettura a livello di campo (chiavi per campo) restano lavori futuri. La cronologia non viene mai ricifrata sul posto, perché le firme degli autori coprono il testo cifrato.

Vedilo all'opera
Haven - l'area di lavoro costruita su questo modello di accesso

MindooDB Haven porta la stessa cifratura end-to-end, la cronologia firmata e la governance integrata in un'area di lavoro tranquilla e multipiattaforma, compresa la vista di audit che mostra le modifiche in quarantena. Prova la beta gratuita o leggi gli approfondimenti.