Ryan Aebi
IT Architect
Autor: Ryan Aebi
In modernen Microservice und Zero-Trust Architekturen werden Zugriffsentscheidungen on the go auf jeder Komponente unabhängig voneinander gefällt. Dies birgt eine sehr grosse Herausforderung:
Der Open Policy Agent (OPA) dient als Policy Engine dazu:
In einem Autorisierungsentscheid für einen API-Call sind mehrere (logische) Komponenten beteiligt. Diese Komponenten können grob durch die folgende Grafik und Text beschrieben werden:
Neue Trends befassen sich mit Zero-Trust [2], es gibt keine zentrale Security mehr, welche alles kontrolliert.
Dabei ist das Ziel, jeden API-Call / jeden Request separat zu betrachten und so die Autorisierung in jeder Komponente und deshalb auch in jedem Zugriff durchzuführen.
Dies bedingt, dass jede Komponente einen PEP implementiert und selbstständig einen entsprechenden API-Call erlauben oder ablehnen kann.
Dadurch, dass jede Komponente selbst überprüfen muss, ob ein API-Call erlaubt werden soll oder nicht, muss jede Komponente auch fähig sein, diese Entscheidung zu fällen.
Als Micro-Service Entwickler bedeutet dies, dass nebst der Aufgabe des PEP (“ich muss einen Zugriff erlauben oder blockieren können”) ebenfalls ein PDP (“ich muss entscheiden können, ob ein Zugriff erlaubt ist”) implementiert werden muss. Dies sollte innerhalb desselben Microservices geschehen.
In der Regel führt das dazu, dass jeder Microservice seinen PDP anders implementiert und insbesondere andere Regeln und Policies als Entscheidungsgrundlage verwendet. Sprich, es gibt keinen zentralen PIP, Policies sind überall verteilt und werden unterschiedlich formalisiert.
Nebst einem massiven Governance-Overhead, um die Situation im Griff zu behalten, bedeutet dies ebenfalls, dass jede informelle Policy-Änderung zu einer Codeänderung führt:
Im Worst-Case könnte es wie nachfolgend abgebildet aussehen und dies für jeden Microservice.
Dazu kommt die Thematik der Service-Level/User-Level Authorization. Dabei geht es darum, welcher Microservice darf welche API konsumieren (what-can-do-what) und was darf ein User von einem Service/einer Applikation konsumieren (who-can-do-what). Alle diese Entscheidungen müssen pro Micro-Service, genauer pro API, implementiert werden.
Sind Sie bereit für diesen Architekturentscheid, die Mehrkosten sowie das daraus entstehende Risiko zu tragen?
In vieler Hinsicht macht es Sinn, dass in einer Zero-Trust getriebener Architektur jede Komponente einen PEP implementiert. Sowohl das Backend, der Microservice und auch die Datenbank müssen selbst verantwortlich sein, um eine Policy-Entscheidung durchsetzen zu können.
Stellen Sie sich folgendes Szenario vor:
Der Governance-Overhead besteht nicht im PEP, sondern im PDP, PIP und PAP. Eine mögliche Lösung dazu bietet der Open Policy Agent (OPA) [3].
Das Projekt OPA wurde von der Cloud Native Computing Foundation (CNCF) im April 2018 in der CNCF Sandbox und ein Jahr später in die Inkubationsphase aufgenommen [11].
Im Februar 2021 erreichte der OPA schliesslich den Status ‘graduated’, ein reservierter Begriff, welcher die CNCF an Projekte verleiht, welche eine gewisse Maturität in mehreren Bereichen erlangt haben [11].
Der OPA erlaubt es Policies als Code zu verwalten. So kann ein Git Repository (Github, Gitlab, Bitbucket, usw.) verwendet werden um Policies:
So muss nicht mehr jeder Microservice seine Policies selbst verwalten und editieren. Die Entwickler werden sogar befähigt, ihre Continuous Deployment Pipeline / Rolling Releases zu bauen, während sie den OPA / PDP einfach als Service zur Build-/Deploy- und Runtime konsumieren können. Insofern entfallen die Aufgaben von PIP (Policies werden zentral in einem Repo verwaltet) und PAP (Policies können zentral im Repo bearbeitet werden) für die Microservices.
Während die Policies in Rego geschrieben werden, übernimmt der OPA die Publikation als REST-Service. Der OPA bearbeitet den Request anhand der hinterlegten Rego-Policy und entscheidet dann entsprechend, ob der Zugriff erlaubt werden soll oder nicht. Der OPA übernimmt also die Aufgabe des Policy Decision Points (PDP), indem er Auskunft gibt, ob ein Request erlaubt ist. Das Durchsetzen des Policy-Entscheides (PEP) bleibt beim Microservice.
Eine der schönsten Eigenschaften von OPA und Rego ist, dass sie nicht auf Microservices limitiert sind. Mit Rego kann prinzipiell alles modelliert werden. So kann in einem Kubernetes-Umfeld kontrolliert werden, dass [6]:
Analog kann in einem Terraform Umfeld forciert werden:
In vielerlei Hinsicht macht es Sinn in modernen Microservice/Devops Architekturen eine mehrstufige Security umzusetzen, indem jede Komponente selbst ihren Policy Enforcement Point (PEP) implementiert. Der Open Policy Agent unterstützt dies, indem er PDP, PIP und PAP mittels zentralen Policies zur Verfügung stellt.
Da der Open Policy Agent seine Policies durch ein Source Code Repository bezieht, gibt es eine Single-Source of Truth. Es gibt kein Delta, weil Microservices ihre Policies selbst implementieren, stattdessen können diese zentral eingesehen und editiert werden. So ist es zu jedem Zeitpunkt möglich nachzuvollziehen, welche Policy deployed/aktiv war, aber auch welche Änderungen zuletzt gemacht wurden.
Zusammenfassend sind die Vorteile:
Der Open Policy Agent kann überall dort verwendet werden, wo Entscheidungen anhand einer Policy gefällt werden müssen. Die Policy-Sprache Rego ist dabei universell definiert und kann deshalb überall angewendet werden.
Ein zentrales Enabling von OPA ist, dass Policies zentral in einem Source-Code Repository geführt werden können. So werden Policies versionierbar und nachvollziehbar verwaltet. In Kombination mit einer sauberen Deployment Pipeline kann zu jedem Zeitpunkt überprüft werden, welche Policy auf welchen OPA deployed wurde, wie sie konfigurativ ausgesehen hat und so auch Policy-Entscheidungen erfassen. Dieses Zusammenspiel von Code-basierten Policies und Nachvollziehbarkeit durch Deployments eignet sich hervorragend für allfällige Audits.