Beslisrecords, tien van tien. Een architectuurbeslissing per stuk, uit een beheerst AI-agentplatform dat ik als prototype ontwierp en bouwde voor de Nederlandse lokale overheid.
De situatie
Deze vond ik tijdens het bouwen, niet bij review, en dat is precies waarom hij in de reeks zit.
Elke identiteitsbron in het platform loste een principal op, en elk daarvan zette het principal-type hard op “user”. Een aanroeper die binnenkwam via een service-credential, zonder mens erachter, werd opgelost, geauthenticeerd en geregistreerd als mens. Het record had het niet mis over wie de credential hield. Het had het mis over wat voor soort ding dat was.
Het gevolg was niet abstract. Een component die data over tenants heen moest oplossen had geen mens die rechtmatig de principal voor die aanroep kon zijn, dus er was geen “user” om op te lossen. In plaats van het identiteitsmodel te repareren, had de eerdere versie van het ontwerp die component naar een andere host geduwd waar identiteit anders werkte. In die host sloegen zijn sessies de receipts over, de budgetchecks over, en de goedkeuringspoort over. De schuld stond vastgelegd in een codecommentaar. Niet in de architectuur, niet in het risicoregister, in een commentaar.
Dat is wat een identiteitsgat doet. Het kondigt zichzelf niet aan als beveiligingsprobleem. Het presenteert zich als een component die ergens anders moet wonen, en dat ergens anders heeft minder controls.
Josef K. van Kafka kwam nooit te weten wie hem had aangeklaagd. Onze logs hadden het omgekeerde probleem: ze wisten precies wie alles had gedaan, en het was altijd “user”.
De beslissing
Een workload mag een eigen niet-menselijke principal hebben en daaronder handelen. Agents en diensten zijn principals, dezelfde categorie als gebruikers, en het record behandelt ze als zodanig. Vier voorwaarden.
Onderscheidbaar in het record, niet slechts geannoteerd. Het principal-type is een veld dat elke control leest, geen tag waar iemand later op kan filteren. Beleid, goedkeuring, budget en bewijs zien allemaal “dit is een machine” als volwaardig feit.
Onafhankelijk van elk menselijk account intrekbaar. De workload-principal intrekken stopt de workload. Het stopt niet, en wordt niet gestopt door, de toegang van enig mens.
Nooit een permanente credential. Workload-principals hebben kortlevende, uitgegeven credentials die aan de identiteit van de workload zijn gebonden. Er is geen langlevende sleutel.
Weigering als standaard wanneer geen principal wordt opgelost. Als een aanroeper zich meldt en niets wordt opgelost, mens of machine, is het antwoord nee. Niet “user”, niet “anoniem”, nee.
Wat ik afwees, en waarom
Alleen on-behalf-of. Elke machineaanroep draagt een menselijke principal voor wie hij handelt, en de machine zelf heeft geen identiteit. Dit is het gangbare patroon en voor de meeste aanroepen is het juist. Het faalt voor het geval over tenants heen, omdat sommige resoluties helemaal geen rechtmatig menselijk pad hebben: er is geen enkele persoon die beide kanten mag zien. Met alleen on-behalf-of blijft die component voor altijd in de onbeheerste host. De bypass wordt permanent, by design.
Een workload-credential met beperkte scope zonder principal. Geef de workload een credential met een smalle scope, maar modelleer hem niet als actor. Dat is autoriteit zonder identiteit. Het kost hetzelfde als een volledige principal, je moet hem nog steeds uitgeven, roteren en intrekken, en het levert niets van het record op. Het bewijsregister zou een scope laten zien en geen actor.
Wat het kost
Een nieuw autoriteitsoppervlak. Aan machine-principals kunnen dingen worden toegekend, en de set van dingen die hun kan worden toegekend is een nieuw beleidsdomein met een eigen review. En een confused-deputy-risico: een workload-principal met eigen autoriteit kan door een aanroeper met minder autoriteit worden aangezet om namens die aanroeper te handelen met de rechten van de workload. Dat moet worden begrensd, door het beleid van de workload ook de oorspronkelijke principal te laten evalueren naast de eigen, en het prototype begrenst dat voor het tool-call-pad en nog niet voor het retrieval-pad.
Een gegevensbeschermingsvraag wordt actueel. Zodra een machine-actor inwonerdata verwerkt onder een eigen identiteit, wordt de vraag wie verwerkingsverantwoordelijke is voor die verwerking niet langer beantwoord met “de mens die klikte”. Voor een gemeente is dat een echte vraag die een echt antwoord vereist, en het prototype stelt hem zonder hem te beslechten.
Wat het niet doet
Auditors winnen het onderscheid pas als records daadwerkelijk gaan verschillen. Machine-principals in het schema modelleren doet niets totdat er records zijn met beide typen erin, en controls die zich op elk anders gedragen. Tot de eerste machine-principal is uitgegeven en handelt, is het veld een belofte.
Het identiteitsmodel is aangepast en het hard gecodeerde type verwijderd. De component die naar de andere host was geduwd, was nog niet teruggehaald toen het prototype pauzeerde. Het commentaar staat er nog, nu wijzend naar een beslisrecord in plaats van naar niets.
Als je een ding meeneemt
Zoek in je identiteitscode de plek die het principal-type zet. Als het een constante is, heb je ergens een aanroeper die geen mens heeft geauthenticeerd terwijl je records iets anders zeggen. Vind die aanroeper voordat je het commentaar vindt.
Onze identiteitslaag zei “user” tegen alles wat aanklopte. Computer says yes blijkt de veel slechtere sketch.
Verwijzingen
De knipogen en citaten in dit stuk, met hun herkomst:
- Franz Kafka, The Trial (1925): Josef K., arrested without ever learning the charge.
- Little Britain (BBC, 2003-2006): “Computer says no”, Carol Beer at the desk.
- #Beslisrecords
- #AI-governance
- #Architectuur

Rutger Hemrika
AI-strategie en -governance voor sectorsoftware. Schrijft vanuit bouwen, niet vanuit slides; elke claim draagt een bewijsniveau.