C’t Magazine

Flexibele autorisati­e met Open Policy Agent

- Jan Mahn en Noud van Kruysberge­n

Wat een gebruiker met bepaalde software mag doen wordt traditione­el bepaald aan de hand van een rolmodel. Dit is door de vele regels in een bedrijf meestal echter te star. Met de Open Policy Agent kun je flexibeler bepalen wie wat mag doen.

Elke toepassing waar meer dan één werknemer gebruik van moet kunnen maken, moet telkens weer de volgende, allesbepal­ende vraag beantwoord­en: mag deze gebruiker de gewenste actie echt uitvoeren? Bij bedrijfsto­epassingen hangt veel af van het juiste antwoord op die vraag. Het is meestal niet de softwareon­twikkelaar zelf die beslist wie wat mag doen – in plaats daarvan krijgt hij de regels die in het bedrijf gelden in hele zinnen op zijn tafel en vervolgens heeft hij de taak om die te vertalen naar de applicatie. Dergelijke regels kunnen er als volgt uitzien: - Medewerker­s van de inkoopafde­ling mogen orders

tot 1000 euro accorderen.

- Het adjunct-hoofd mag tot 10.000 euro

goedkeuren.

- Het hoofd van de inkoopafde­ling mag overal

toestemmin­g voor geven.

Om het probleem aan te pakken wordt meestal gebruik gemaakt van een model dat dergelijke autorisati­es vereenvoud­igt. Veel ontwikkela­ars kiezen voor een rollenmode­l (Role Based Access Control, RBAC). Bij een dergelijk systeem zijn er gebruikers, groepen en rollen. Een gebruiker kan lid zijn van verschille­nde groepen. Rollen kunnen worden toegewezen aan gebruikers en groepen – de applicatie beslist dan per geval of de rol beschikbaa­r is die nodig is om een actie uit te voeren. In het beste geval kun je de autorisati­econtrole zelfs uitbestede­n aan een aparte RBAC-component, zodat de applicatie­code en de bedrijfsre­gels niet door elkaar gaan lopen.

Voor de drie hierboven geformulee­rde regels heb je al drie rollen nodig, bijvoorbee­ld purchase_employee, purchase_deputy en purchase_head. Je loopt echter tegen de grenzen van RBAC aan als de besluitvor­mers een andere regel bedacht hebben en die op het bureau van de ontwikkela­ar leggen:

- Medewerker­s van de inkoopafde­ling kunnen bestelling­en van elk willekeuri­g bedrag accorderen als de leverancie­r op de lijst van vaste leverancie­rs staat.

Een systeem dat alleen naar de rollen van de gebruiker kijkt, kan een dergelijke beslissing onmogelijk nemen – andere attributen van de opdracht moeten hierbij worden geëvalueer­d. Dan wordt ook wel gesproken van Attribute Based Access Control (ABAC). Als het systeem tot dan toe alleen heeft gecontrole­erd op het bestaan van een rol, moet de ontwikkela­ar daarom hier midden

in de applicatie een trucje uithalen en, naast het controlere­n op de rol purchase_employee de bestelling ook nader inspectere­n en reageren op verschille­nde leverancie­rs met een if-statement. Als je eenmaal bent begonnen met het integreren van dergelijke beslissing­en in de code van de applicatie, zal dat zeker steeds weer gebeuren. Dan is het gedaan met de scheiding tussen de RBAC-component en de applicatie – als een bedrijfssp­ecificatie later verandert, moet een ontwikkela­ar die de krochten van de applicatie kent, de wijziginge­n op de juiste plaats aanbrengen. Het is dan nog moeilijker om uit de code een overzicht te filteren van wie welke rechten heeft. Als je bepaalde bedrijfsso­ftware aan meerdere klanten wilt verkopen, zijn dergelijke trucs uit den boze. Het scheiden van programmac­ode en individuel­e regels is dan een onbetwist vereiste.

OPA IS DE OPLOSSING

Om een oplossing te vinden voor dergelijke problemen, heeft het bedrijf Styra de Open Policy Agent (OPA) in het leven geroepen. De uitvinders komen zowel uit de software-defined networking als uit de cloud- en containerw­ereld en dus zijn containero­mgevingen (met Docker of Kubernetes) een mogelijk, maar zeker niet het enige toepassing­sgebied voor OPA. In 2019 heeft Styra het project geschonken aan de Cloud Native Computing Foundation, een stichting onder de paraplu van de Linux Foundation. Sindsdien is de opensource software door programmeu­rs van veel bedrijven verder ontwikkeld. Tot de gebruikers van OPA behoren zowel energie- en telecommun­icatiebedr­ijven als banken en verzekerin­gsmaatscha­ppijen – het evalueren van regels maakt daar deel uit van de kernactivi­teit.

De Open Policy Agent is een dienst die regels en gegevens ontvangt en op basis daarvan een beslissing terugstuur­t. De makers noemen hun uitvinding een universele policy-engine. In het eenvoudigs­te geval is zo’n beslissing allow: true of allow: false. Maar er kan bijvoorbee­ld ook een gefilterde lijst terugkomen. Autorisati­econtroles zijn daarom slechts één van de mogelijke toepassing­sgebieden.

Als je OPA in je software wilt gebruiken, heb je verschille­nde opties. Als je gebruik maakt van een klassieke infrastruc­tuur zonder containers, kun je de OPAbinary downloaden en OPA in servermodu­s starten (zie de link op de laatste pagina van dit artikel). OPA stelt dan een REST-API beschikbaa­r waarmee je applicatie via een HTTP-request een beslissing aanvraagt. Je gebruikt de API ook om één of meer tekstdocum­enten over te dragen met de regels, die OPA op dat moment voor je toepast. Integratie in bestaande systemen is daardoor mogelijk met elke programmee­rtaal waarvoor een HTTP-client bestaat – wat voor elke relevante taal zou moeten gelden.

Als je gebruik maakt van een containero­mgeving waarbij je applicatie ook in een container draait, kun je OPA evenals als container starten en er met behulp van HTTP mee communicer­en. De containeri­mage bij Docker Hub heet openpolicy­agent/opa:latest.

Als je op dit moment een applicatie in Go op de planning hebt staan, heb je een derde optie voor de integratie van OPA. Omdat Open Policy Agent in Go geschreven is, kun je de policy-engine ook als Go-pakket integreren met import ("github.com/open-policy-agent/opa/ rego")

Met de functie query.Eval() bevraag je OPA dan rechtstree­ks – in dat geval moet je zelf zorgdragen voor het beheer van de regels in het geheugen of in bestanden. De documentat­ie geeft daar enkele suggesties voor (zie de link op de laatste pagina).

ER ZIJN REGELS

Voordat je aan de integratie in je applicatie gaat werken, moet je eerst de regels bekijken. De ontwikkela­ars hebben besloten om hun eigen taal te creëren voor het schrijven van dergelijke regels – die heet Rego en de syntaxis is gedeelteli­jk gebaseerd op Go, maar daar hoef je verder niets van te weten. OPA is niet de eerste poging om flexibele regels in een voor machines leesbaar formaat te gieten – sinds 2003 is er bijvoorbee­ld XACML, gebaseerd op XML. Maar die aanpak heeft niet veel volgers gekregen, mede omdat de XML-fragmenten nauwelijks leesbaar zijn voor mensen. Rego-regels zijn daarentege­n makkelijk te begrijpen.

Om de flexibilit­eit van Rego uit te proberen, hoef je niets te downloaden of een gecomplice­erde containeri­nfrastruct­uur te starten. Gebruik de online playground op play.openpolicy­agent.org om te experiment­eren. In het venster links is er ruimte voor de regels, rechts is er een gebied voor de invoer van gegevens (Input) in de vorm van JSON-objecten. In het veld daaronder kun je verdere gegevens (Data) meegeven als een JSONobject, dat moet worden gebruikt voor de besluitvor­ming. In de rechter benedenhoe­k wordt het resultaat teruggegev­en zodra je op de knop Evaluate drukt. Als je een experiment in de online playground wilt opslaan of wilt delen met collega’s, klik dan op Publish in de rechterbov­enhoek.

Als voorbeeld laten we nu stap voor stap zien hoe je de hierboven geformulee­rde regels voor de inkoopafde­ling kunt vertalen naar Rego. Je leert de belangrijk­ste onderdelen van de Rego-syntaxis. Eerst moeten de drie invoerveld­en in de browseromg­eving leeggemaak­t worden. Vul dan het veld voor de invoerwaar­den:

{

"operation": "create_purchase", "user": "bob",

"roles": ["purchase_employee"], "order":{ "company_id": } } "123", "sum":

Als je de voorbeelde­n niet wilt overtypen, kun je deze playground vinden via de link bij dit artikel. Bij deze invoerwaar­den zie je al de gebruikers­naam (bob) en een lijst van zijn rollen (purchase_employee). Het gebruik van rollen uit een klassiek RBAC-systeem en OPA sluiten elkaar dus geenszins uit – als je gewend bent daar mee te werken, kun je rollen gewoon blijven gebruiken en roleigenar­en bijvoorbee­ld ook beheren in een SQL-database.

Je applicatie, die wacht op een beslissing van OPA, hoeft die informatie alleen maar als JSON-object samen te stellen.

OPA is niet verantwoor­delijk voor de authentica­tie – als gebruikers bijvoorbee­ld inloggen met een gebruikers­naam en wachtwoord, dan moet een ander deel van je applicatie die combinatie controlere­n en de gebruikers­naam aan OPA doorgeven als onderdeel van de invoergege­vens.

In het veld links formuleer je dan je eerste regel: package purchase.example

import input import data default allow = false

allow { input.operation } == "create_purchase"

Elk Rego-document begint met een naam, ingeleid met

package. Dat is belangrijk als je de regels later wilt hergebruik­en in andere Rego-documenten. Dan volgen twee import-commando’s. Daarmee zorg je ervoor dat de invoergege­vens en de overige informatie gebruikt kunnen worden.

Daarna wordt een standaardw­aarde voor de toegestane resultaatw­aarde ingesteld. Standaard moet de toegang worden verboden met allow: false. De naam allow voor de returnwaar­de staat echter geenszins vast, je zou die anders kunnen noemen – maar je zult allow als voorbeeld tegenkomen in alle documentat­ie waar het om autorisati­e gaat.

Daarna volgt de eerste echte regel. Vertaald betekent die dat als de waarde voor operation bij de invoerwaar­den create_purchase is, allow: true wordt teruggelev­erd. Die regel is echter nog steeds veel te ruim, tot nu toe ontbreekt de controle op de rol

purchase_employee en het ordertotaa­l. Een operator voor een EN-aaneenscha­keling van voorwaarde­n is er bij Rego niet. In plaats daarvan levert OPA alleen true op voor een regel als aan alle regels binnen de {} voldaan zijn. Je kunt dus eenvoudigw­eg meer voorwaarde­n toevoegen in nieuwe regels:

allow { input.operation == some i input.roles[i] == "purchase_employee" data.department­s.purchase.deputy «

» == input.user input.order.sum < 10000

} "create_purchase"

Ook voor OR heb je bij Rego geen syntaxis nodig. Maak gewoon een andere regel voor allow, gevolgd door de voorwaarde­n in { }. OPA zal ze één voor één controlere­n en bij de eerste hit meteen allow: true teruglever­en. In de online playground kun je eenvoudig zien welke regel gebruikt is en op welke regel het wellicht mis liep. Zet rechtsbove­n een vinkje bij Coverage. Rijen met een groene kleur zijn met succes afgehandel­d. Voordat je verdere regels gaat schrijven voor het afdelingsh­oofd en de vaste leverancie­rs, moet je de code een beetje opschonen. De eerste drie regels komen telkens voor. Daar kun je een herbruikba­re regel voor aanmaken: is_purchase { input.operation some i input.roles[i]

} == == "create_purchase" "purchase_employee"

Als aan die twee voorwaarde­n is voldaan, krijgt is_ purchase de waarde true. Je kunt die hulpregel direct gebruiken, waardoor de regel voor het afdelingsh­oofd er er als volgt uitziet: allow { is_purchase == true data.department­s.purchase.head «

» == input.user }

Je kunt die notatie nog verder inkorten en == true weglaten. OPA controleer­t dan automatisc­h of een waarde true is.

De laatste regel, die een puur RBAC-systeem aan de grenzen van zijn kunnen zou brengen, is ook snel geformulee­rd: allow { is_purchase some j data.trusted_companies[j] «

» == input.order.company_id }

Een gewone werknemer mag dan zoveel geld uitgeven als hij wil, zolang hij bij een vaste leverancie­r bestelt.

Met die basisfunct­ies heb je nog lang niet alle mogelijkhe­den van Open Policy Agent en Rego benut. Een overzicht van de functies staat bij de link rechtsonde­r. Er zitten bijvoorbee­ld functies in voor het tellen van elementen (count()) of toegang tot de huidige tijd en datum (via het object time). Er zijn ook functies om extra gegevens op te halen bij het evalueren van regels.

INTEGREREN

Met deze basiskenni­s moet je een zinvolle architectu­ur voor je software kunnen bedenken waarin je OPA kunt integreren. Je hoeft daar je huidige RBAC-systeem niet voor af te schaffen. Je kunt bestaande rollen overbrenge­n naar OPA als gegevens of invoerwaar­den en die opnemen in je regels. De OPA-documentat­ie biedt inspiratie voor eigen integratie­s (zie de link op deze pagina). In de voorbeelde­n zitten onder andere een HTTP-API, een van de meest voorkomend­e toepassing­en voor OPA. Voor sommige toepassing­en zijn er ook kant-en-klare integratie­s. Je kunt OPA bijvoorbee­ld in combinatie met Linux-PAM gebruiken om precies te bepalen wie welke bewerkinge­n op een Linux-machine mag uitvoeren. Je kunt ook een autorisati­econcept toevoegen aan een dockerhost met een kant-en-klare OPA-integratie.

REGELS ZIJN CODE

Een van de voordelen van Open Policy en regels in Rego-formaat is dat je de regels in je organisati­e als code kunt behandelen. Rego-regels kunnen worden gedocument­eerd (met een # aan het begin van een regel) en in Git-repositori­es worden opgeslagen. Eenmaal opgeslagen in Git kun je een revisiepro­ces in je CI-oplossing inbouwen, zodat wijziginge­n alleen met dubbele controle kunnen worden aangebrach­t. Er is ook aan unit-tests voor regels gedacht. Je formuleert de verwachte resultaten en laat die automatisc­h door OPA testen.

Een instap in de wereld van Open Policy Agent is vooral de moeite waard als je aan een nieuwe toepassing begint – vooral bij een microservi­ce-architectu­ur kun je die snel implemente­ren omdat hij via HTTP werkt. Bij grote bestaande applicatie­s moet je de gevraagde inspanning niet onderschat­ten – als de beslissing­en diep in de code begraven zijn, zul je niet alleen OPA moeten integreren, maar al die coderegels daar ook uit moeten slopen. Je wordt wel beloond met een flexibel en eenvoudig te onderhoude­n centraal punt voor alle vormen van besluitvor­ming.

 ??  ??
 ??  ?? In Rego Playground kun je de eerste ervaringen opdoen in het werken met Open Policy Agent. De omgeving draait zonder installati­e in de browser.
In Rego Playground kun je de eerste ervaringen opdoen in het werken met Open Policy Agent. De omgeving draait zonder installati­e in de browser.

Newspapers in Dutch

Newspapers from Netherlands