Il least-privilege è una delle idee più antiche e affidabili della sicurezza. Concedi a un’identità esattamente l’accesso di cui ha bisogno, niente di più, e il raggio d’impatto di qualsiasi compromissione resta contenuto. Per gli account umani e per i service account di lunga durata il modello regge ragionevolmente bene: i ruoli vengono rivisti, le concessioni sono delimitate, le certificazioni degli accessi seguono una cadenza trimestrale.
Gli agenti AI rompono questo modello in sordina. A un agente vengono assegnati una credenziale, uno strumento, una connessione a un server MCP, e da quel momento il suo comportamento è dinamico. Decide a runtime quali risorse leggere, quali scrivere, quale strumento invocare di seguito. La concessione che hai messo nero su bianco il primo giorno descrive un tetto massimo, non ciò che l’agente fa. E poiché gli agenti sono produttivi, quel tetto tende a essere generoso: ruoli di database ampi, accesso in scrittura «per sicurezza», un service account condiviso tra una mezza dozzina di workflow. Il risultato è un parco di sistemi in cui l’accesso permesso e quello effettivamente utilizzato si allontanano l’uno dall’altro, in silenzio, ogni giorno.
Ricerche indipendenti del settore fotografano la portata di questo punto cieco: circa l’82% delle organizzazioni dichiara di avere agenti AI in esecuzione di cui non era a conoscenza, mentre solo il 21% circa ne mantiene un inventario in tempo reale (CSA/Token Security, n=418). Non puoi applicare il least-privilege su un parco di sistemi che non riesci a vedere.
Definire la deriva del least-privilege
Diamo a questa cosa un nome preciso. La deriva del least-privilege è il divario crescente tra l’accesso che a un agente è permesso e l’accesso che si osserva che usa. Ha due direzioni di fallimento, e solo una è evidente.
La direzione evidente è il sottoutilizzo: un agente detiene l’accesso in scrittura a una tabella su cui non ha mai scritto. È un privilegio morto, ed è un rischio che ti porti dietro senza alcun beneficio. La direzione pericolosa è il segnale inverso che ne deriva: quando l’insieme osservato contiene qualcosa che l’insieme permesso non ha mai concesso deliberatamente, c’è un’azione in corso che nessuno ha rivisto. Un job di esportazione che all’improvviso scrive su un bucket da cui aveva sempre e solo letto. Un agente che la policy aveva delimitato a uno schema e che si estende a un altro. Non sono casi esotici: sono la trama quotidiana di agenti collegati tra loro con concessioni troppo ampie.
Il motivo per cui questo è difficile, e il motivo per cui è specifico degli agenti e non degli esseri umani, è che il comportamento è generato, non configurato. Un essere umano con troppi accessi nella maggior parte dei casi non li esercita. Un agente con troppi accessi eserciterà qualsiasi cosa lo aiuti a completare il compito che ha davanti, compresi percorsi che nessuno aveva previsto. La revisione statica delle policy non riesce a stare al passo con un comportamento che cambia a ogni esecuzione.
Trasformare la deriva in un segnale rivedibile
La deriva è pericolosa solo finché resta invisibile. Il compito è trasformarla in un segnale che una persona possa rivedere, e questo richiede due cose che lavorino insieme: l’osservazione continua di ciò che gli agenti toccano davvero e un registro stabile di ciò che era loro permesso toccare.
L’osservazione deve essere read-first. Un collettore che osserva dai log, dalle tracce OpenTelemetry e dai segnali del kernel via eBPF si colloca al di fuori del percorso dati dell’agente. Non è un proxy, non blocca le chiamate, e se si guasta lo fa in modo fail-open nel senso sicuro del termine: l’agente continua a funzionare, perdi visibilità anziché disponibilità. Questa asimmetria conta: un controllo di sicurezza in grado di mandare giù la produzione è un controllo che i team disattivano in sordina. In particolare, lo strato eBPF agisce come ground truth a livello di kernel, la parte attorno a cui un agente non può fare deviazioni, ed è per questo che gli indizi a livello di protocollo come le annotazioni degli strumenti MCP (readOnlyHint, destructiveHint) vengono confermati rispetto a esso anziché ritenuti affidabili. La specifica MCP stessa afferma che quelle annotazioni non sono affidabili; sono i segnali del kernel a rendere reale la conferma.
Ciò che l’osservazione produce è una mappa degli accessi: per ciascun agente, quali risorse ha raggiunto e se ha letto (R) o letto/scritto (RW). La mappa memorizza le relazioni di accesso, non i payload, i segreti o i dati personali. La parte interessante è il confronto:
| Agente | Risorsa | Permesso | Osservato | Deriva |
|---|---|---|---|---|
| data-export-job | prod-postgres | R | R | nessuna |
| data-export-job | s3://billing-exports | R | RW | scrittura non rivista |
| report-builder | analytics-db | R | (inutilizzato) | privilegio morto |
La riga che conta è quella centrale. La policy ha concesso la lettura sul bucket di esportazione; il collettore ha osservato una scrittura. Quella singola riga è il rischio principale che la deriva del least-privilege è pensata per far emergere: un privilegio esercitato che nessuno ha rivisto, attribuito a uno specifico agente anziché a un service account condiviso, perché è proprio l’identità per agente a rendere possibili l’attribuzione e l’audit.
Applicare al momento dell’accesso, non limitarsi a registrarlo
Il rilevamento ti dice che la deriva è avvenuta. Per chiudere il cerchio vuoi che la scrittura non rivista sia un percorso negato, non uno registrato. È qui che entra in gioco la policy-as-code valutata al momento dell’accesso. Lo stesso confronto che ha segnalato la deriva diventa la regola che la previene.
Considera di vincolare il job di esportazione alla sola lettura sul database di produzione e di negare del tutto le scritture, con una violazione che blocca e avvisa anziché passare in silenzio:
agent "data-export-job" {
# Read-only on the operational database. No writes, ever.
access "prod-postgres" {
mode = "read"
deny = ["write", "delete", "ddl"]
}
# The export target the job is *supposed* to use.
access "s3://billing-exports" {
mode = "read"
}
on_violation {
action = "block" # deny the call at access time
alert = "security-oncall"
audit = "append" # write to the tamper-evident ledger
}
}
Ripercorri concretamente il prima e il dopo.
Prima. Il job di esportazione, detenendo un ruolo ampio, esegue una scrittura su s3://billing-exports. Niente lo ferma. L’azione va a buon fine, si fonde nel traffico normale e ricompare giorni dopo, se mai ricompare, come un’anomalia nella mappa degli accessi. Il divario tra permesso e osservato si è ampliato, e l’unico artefatto è una riga di log che nessuno ha letto.
Dopo. Arriva la stessa scrittura. La policy viene valutata al momento dell’accesso, vede una write su una risorsa delimitata a read e restituisce un diniego prima che l’operazione vada a segno. La violazione blocca la chiamata, lancia un avviso al turno di reperibilità e aggiunge una voce al registro di audit append-only con catena di hash. La scrittura non rivista non diventa mai una modifica non rivista. La deriva viene riconvertita, sul momento, in un percorso conforme al least-privilege.
Due proprietà mantengono tutto questo onesto. Primo, ogni consultazione privilegiata della mappa degli accessi è essa stessa sottoposta ad audit, chi ha guardato cosa, perché la mappa è sensibile e uno strumento di sicurezza che non riesce a rendere conto dei propri operatori non è degno di fiducia. Secondo, il livello di confidenza è mostrato in modo trasparente: un’azione attribuita a un agente sulla base di evidenze a livello di kernel è contrassegnata diversamente da una dedotta in modo approssimativo. Non ti viene mai chiesto di agire su una certezza fabbricata.
La conclusione
Il least-privilege non ha fallito per gli agenti AI; a fallire è stata la cadenza di revisione. Le concessioni sono troppo ampie, il comportamento è dinamico, e le certificazioni trimestrali non riescono a seguire una superficie di accesso che cambia a ogni esecuzione. La soluzione non è un proxy più pesante nel percorso critico. È un’osservazione continua e read-first che produce un confronto tra permesso e osservato, più una policy-as-code che applica il confine corretto al momento dell’accesso, così un agente con privilegi eccessivi viene individuato come segnale rivedibile molto prima di diventare un incidente.
Se vuoi vedere come il collettore, la mappa degli accessi e l’applicazione al momento dell’accesso si combinano senza collocarsi nel percorso dati dei tuoi agenti, la pagina architettura ripercorre il design, e il prodotto mostra come appare la vista permesso-osservato su un parco di sistemi reale.