Cloud Intelligence™
Schluss mit dem Kampf gegen komplexe Berechtigungen: Frischer Wind für Ihren Code
Diese Seite ist auch in English, Español, Français, Italiano, 日本語 und Português verfügbar.
About Dima Kramskoy
Solutions architect who takes ideas from zero to proven. With over 20 years of software engineering, I build PoCs and MVPs on AWS that prove the path before you commit — spanning GenAI, DevOps, and FinOps. Off the clock: live-fire cooking, fishing, the outdoors, and applying Extreme Ownership to everything.
My personal pagePerfectScale™ for Kubernetes
Ready to optimize?
Get your free Kubernetes savings analysis

Überblick
Dieser Beitrag stellt Amazon Verified Permissions (AVP) als praktische Lösung für die Verwaltung komplexer Anwendungsautorisierung vor – mit einem Praxis-Walkthrough anhand des AWS-PetStore-Beispiels.
Das Problem
Kennen Sie das? Sie versuchen, alle möglichen Autorisierungsrollen, Nutzer und Akteure Ihres eigenen SaaS-Produkts unter einen Hut zu bringen – und die Komplexität wächst Ihnen über den Kopf. Ihnen ist der Schmerz vertraut, wenn sich Business-Anforderungen ändern und Sie die passenden Security-Prinzipien im Blick behalten müssen, während Sie gleichzeitig Code-Reviews und A/B-Tests zu den anstehenden Änderungen jonglieren? Und ja, Ihr SaaS läuft in der AWS-Cloud.
Dann ist es Zeit, tief durchzuatmen und einen Schritt zurückzutreten!! Denken Sie über Ihre Lösung nach – und dann noch einmal. Denn ich kann Ihnen vielleicht eine vergleichsweise einfache zeigen! Eine, die Ihnen hilft, Komplexität in den Griff zu bekommen und Ihre Ressourcen und Energie in das zu stecken, was wirklich zählt: Ihr Business und dessen Anforderungen!!
Diese Lösung heißt Amazon Verified Permissions.
Wie Autorisierung in Webanwendungen üblicherweise gehandhabt wird
Schauen wir uns das Autorisierungssystem einer Webanwendung genauer an. Der Bedarf an einem solchen System entsteht mit der Weiterentwicklung der Anwendung. Sie können es im Voraus planen (was als Teil Ihres Systemdesigns die bessere Variante ist), aber Änderungen aufgrund sich wandelnder Business-Anforderungen kommen trotzdem auf Sie zu. Sie werden verschiedene Teile Ihres Systems anpassen müssen, nachdem es bereits in Produktion ist.
Warum braucht es so ein System überhaupt? Aus vielen Gründen:
- Bestimmte Rollen sollen nur bestimmte Bereiche Ihrer Anwendung sehen dürfen
- Bestimmte Aktionen müssen für einzelne Rollen/Nutzer Ihrer Anwendung eingeschränkt werden
- Sie müssen Sicherheitskontrollen verschärfen und unbefugten Zugriff verhindern
- Ihre Berechtigungslogik verteilt sich über die gesamte Codebasis und macht die Wartung zum Albtraum
Das typische Berechtigungssystem: ein heilloses Durcheinander
Die meisten Autorisierungssysteme sehen heute ungefähr so aus – verstreute if/else-Blöcke im gesamten Code:
// The typical nightmare in your Lambda or Node.js service:boolean userAuthorizedForOrder(Order order, User user) { if (user.storeId == order.storeId) { if (user.roles.contains("store-owner")) { return true; // store owners can access their own store's orders } else if (user.roles.contains("customer")) { if (user.id == order.customerId) { return true; // customers can only see their own orders } } } return false;}Und dann? Sie fügen eine weitere Rolle hinzu. Dann noch eine. Dann einen Sonderfall für Regionalmanager. Dann eine Regel, wer Bestellungen nach 24 Stunden stornieren darf. Dann eine neue Business-Anforderung zum Wochenendzugriff. Plötzlich ertrinken Sie in verschachtelten Bedingungen, Ihre Code-Reviews werden zur Qual, jede Änderung der Business-Anforderungen bedeutet ein Deployment, und das halbe Team streitet über Edge Cases, statt Features zu bauen.
Wo es wirklich wehtut
Rollen-Explosion: Aus 2 Rollen werden 5, dann 10, und irgendwann gibt es den Regionalmanager-mit-Filialmitarbeiter-Rechten-aber-nur-am-Wochenende – und niemand blickt mehr durch, wer was haben sollte.
Code-Review-Albtraum: Jede Berechtigungsänderung erfordert Codeänderungen. Entwickler diskutieren stundenlang über Policy-Logik in PRs, statt Features auszuliefern.
Autorisierung testen: Wie testet man überhaupt alle Kombinationen? Matrix aus Nutzern × Rollen × Ressourcen × Aktionen = Chaos. Edge Cases werden übersehen, in Produktion geht etwas kaputt.
Audit-Trail: Viel Glück dabei, der Compliance zu erklären, warum dieser eine Nutzer auf jene Bestellung zugreifen konnte. Das steckt irgendwo in der Git-Historie, verteilt über 5 verschiedene Dateien.
Null Flexibilität: Sie wollen Berechtigungen an einem Freitag ändern? Pech gehabt – das bedeutet ein Deployment. Sie wollen eine Policy schnell zurückrollen? Wieder deployen.
So gelingt es mit Amazon Verified Permissions
Was wäre, wenn Sie diese Last vereinfachen könnten? Was, wenn ich Ihnen sage, dass es inzwischen einen Service gibt, der Ihnen den Großteil der Arbeit rund um Berechtigungen in Webanwendungen abnimmt?
Statt die Autorisierung fest in Ihren Code einzubacken – was wäre, wenn Sie sie vollständig auslagern? Was, wenn Berechtigungen deklarativ, versioniert und zentralisiert wären und Sie sie ohne erneutes Deployment Ihrer Anwendung ändern könnten?
Genau das verspricht Amazon Verified Permissions (AVP).
Die Architektur
So funktioniert es im Überblick:
- Der Nutzer authentifiziert sich über AWS Cognito (oder einen beliebigen IdP)
- Ihre API empfängt den Request mit einem JWT-Token
- Der Lambda Authorizer fängt den Request ab
- Lambda baut eine Autorisierungsanfrage mit: Principal (wer), Action (was getan wird), Resource (womit), Context (zusätzliche Attribute)
- Lambda ruft AVP mit dieser Anfrage auf
- AVP wertet Cedar-Policies aus (eine speziell für Autorisierung entwickelte Policy-Sprache)
- AVP liefert ALLOW oder DENY zurück
- API Gateway setzt die Entscheidung durch – der Request geht weiter oder erhält 403
Die zentrale Erkenntnis: Die gesamte Berechtigungslogik lebt in Cedar-Policies in AVP. Ihr Code fragt nur "Ist das autorisiert?" und vertraut der Antwort.

Das Praxisbeispiel: PetStore
Als Beispielanwendung habe ich das PetStore-Repository von AWS verwendet, inklusive der meisten beschriebenen Features – allerdings mit kleinen Anpassungen, da das mitgelieferte Schema nicht funktionierte. Vermutlich liegt das an Updates, die AWS am Service vorgenommen hat. Bedenken Sie: Es ist ein relativ neuer Service, und ich gehe davon aus, dass er in vielen Bereichen noch in Arbeit ist.
Folgen Sie einfach den angegebenen Schritten und beginnen Sie mit dem Deployment der Amplify-Anwendung. Möglicherweise müssen Sie sich mit Ihrem GitHub-Konto identifizieren, um das Repo zu ziehen und in Ihr AWS-Ökosystem zu deployen. Nach dem Deployment lassen sich anhand des Architekturdiagramms oben die Komponenten und ihre Kommunikation untereinander nachvollziehen.
Die Einrichtung – Schritt für Schritt
Schritt 1: Cognito-Nutzer und -Gruppen
Als Identity Provider nutzen wir AWS Cognito. Nach dem Deployment öffnen Sie Ihr Amazon-Cognito-Dashboard und finden dort den User Pool, dessen Name mit "petstoresample" beginnt. Das ist Ihr Pool – hier legen Sie die Nutzer und Gruppen für diese Anwendung an.
Legen Sie drei Nutzer an:
Für diesen PoC brauchen wir drei Nutzer. Einer muss zwingend "abhi" heißen, da dieser Name in der Lambda-Funktion hartkodiert ist. Die anderen beiden sind flexibler – ich habe sie "owner" und "visitor" genannt. Beim Anlegen gilt:
- Keine E-Mail-Verifizierungen versenden
- Die Nutzer als "email address verified" markieren
- Einfache Passwörter verwenden (Sie wollen sie nach dem Setup nicht zurücksetzen müssen)
Am Ende sollte es ungefähr so aussehen:

Fügen Sie dem Nutzer owner benutzerdefinierte Attribute hinzu:
Vergessen Sie nicht, den Nutzer "owner" mit dem benutzerdefinierten Attribut employmentStoreCode zu aktualisieren. Dieses wird später in den Policies von Amazon Verified Permissions verwendet. Klicken Sie einfach auf "Edit" und passen Sie die Attribute so an, dass sie folgendermaßen aussehen:

Gruppen anlegen und Nutzer zuweisen:
Sie müssen 2 Gruppen anlegen und die Nutzer diesen Gruppen zuordnen. Diese Gruppennamen ("Store-Owner-Role" und "Customer") sind Teil der von Cognito ausgestellten Tokens und werden für die rollenbasierte Zugriffskontrolle (RBAC) verwendet.

Der Nutzer "abhi" muss zusammen mit dem Nutzer "visitor" in die Gruppe "Customer" aufgenommen werden:

Und der "owner" mit dem zusätzlich hinzugefügten Attribut kommt natürlich in die Gruppe "Store-Owner-Role":

Schritt 2: Amazon Verified Permissions einrichten
Dieser Teil ist abgeschlossen. Als Nächstes prüfen und konfigurieren wir Amazon Verified Permissions. Dabei schauen wir uns auch den Lambda Authorizer und das API Gateway an – beide wurden im Rahmen desselben Amplify-Deployments als Teil der Anwendung bereitgestellt.
Navigieren Sie einfach über das Suchfeld zu Amazon Verified Permissions und legen Sie zunächst einen neuen Policy Store an. Im Repository wird empfohlen, mit dem Schema zu starten, aber die UI hat sich geändert – Sie müssen zuerst den Policy Store erstellen. Die Angaben dabei sind zweitrangig, denn am Ende verwenden wir ohnehin das Schema, das ich hier bereitstelle. Wählen Sie der Einfachheit halber einen leeren Policy Store und geben Sie ihm den Namen "PetStore".
Schritt 3: Das Schema definieren
Dieser Schritt ist entscheidend. Das Schema teilt AVP mit, welche Principals, Ressourcen, Aktionen und Beziehungen in Ihrer Anwendung existieren. Verwenden Sie dieses Schema:
{ "MyApplication": { "actions": { "GetOrder": { "appliesTo": { "principalTypes": ["User"], "resourceTypes": ["Order"] } }, "GetStoreInventory": { "appliesTo": { "principalTypes": ["User"], "resourceTypes": ["Application"] } }, "ListOrders": { "appliesTo": { "principalTypes": ["User"], "resourceTypes": ["Application"] } }, "PlaceOrder": { "appliesTo": { "principalTypes": ["User"], "resourceTypes": ["Application"] } }, "SearchPets": { "appliesTo": { "principalTypes": ["User"], "resourceTypes": ["Application"] } } }, "entityTypes": { "Application": { "memberOfTypes": [], "shape": { "attributes": { "storeId": {"type": "String"} }, "type": "Record" } }, "Order": { "memberOfTypes": [], "shape": { "attributes": { "owner": { "name": "User", "type": "Entity" }, "storeId": { "type": "String" } }, "type": "Record" } }, "Pet": { "memberOfTypes": [], "shape": { "attributes": { "owner": { "name": "User", "type": "Entity" }, "storeId": { "type": "String" } }, "type": "Record" } }, "Group": { "memberOfTypes": [], "shape": { "attributes": {}, "type": "Record" } }, "User": { "memberOfTypes": ["Group"], "shape": { "attributes": { "employmentStoreCode": {"type": "String"} }, "type": "Record" } } } }}Das Schema im Originalprojekt hat einen kleinen Fehler – kopieren Sie daher stattdessen dieses Schema in Ihren Policy Store.
Schritt 4: Cedar-Policies erstellen
Klicken Sie auf den Policy Store; im linken Bereich finden Sie den Link "Policies". Klicken Sie darauf und anschließend auf "Create Policy > Create static policy". Der Assistent zur Policy-Erstellung nutzt das zuvor hinzugefügte Schema. Wir arbeiten mit permissiven Policies – der Geltungsbereich sollte auf die Gruppe der Beteiligten festgelegt werden, der Ressourcen-Scope muss die konkrete Ressource sein, bei der Sie auswählen, was Sie benötigen, und als Aktionstyp muss ein spezifisches Set von Aktionen ausgewählt werden.
Ein kleiner Trick: Erstellen Sie zunächst eine vollständig permissive Policy mit "All principals", "All resources" und "All actions", speichern Sie sie, bearbeiten Sie sie anschließend und fügen Sie die Policy einfach in Cedar-Syntax ein. Das ist ein Workaround – Sie müssen Ihre Policy-Deklaration allerdings kennen.
Hier die Policies, die Sie für diesen PoC benötigen:
RBAC-Beispiel – Kunden dürfen Haustiere suchen und Bestellungen aufgeben:
permit( principal in MyApplication::Group::"Customer", action in [MyApplication::Action::"SearchPets", MyApplication::Action::"PlaceOrder"], resource == MyApplication::Application::"main");ABAC-Beispiel – Store-Besitzer dürfen nur auf das Inventar ihres eigenen Stores zugreifen:
permit( principal in MyApplication::Group::"Store-Owner-Role", action == MyApplication::Action::"GetStoreInventory", resource == MyApplication::Application::"main")when { principal.employmentStoreCode == resource.storeId};ABAC-Beispiel – Nutzer dürfen nur ihre eigenen Bestellungen einsehen:
permit( principal in MyApplication::Group::"Customer", action == MyApplication::Action::"GetOrder", resource is MyApplication::Order)when { principal == resource.owner};Cloud bill shouldn't be a mystery
One platform for AI and Cloud optimization.
Die Lambda-Authorizer-Integration
Ihre Lambda-Funktion empfängt den API-Request und muss:
- Das JWT-Token verifizieren (Nutzerinformationen extrahieren)
- Eine Autorisierungsanfrage für AVP aufbauen
- Die
isAuthorized-API von AVP aufrufen - ALLOW/DENY zurückgeben
So sieht das aus (aus dem tatsächlichen PetStore-Repo):
const AWS = require('aws-sdk');const avp = new AWS.Service({ apiConfig: require('./verifiedpermissions.json')});
const { CognitoJwtVerifier } = require("aws-jwt-verify");const jwtVerifier = CognitoJwtVerifier.create({ userPoolId: process.env.USERPOOLID, tokenUse: "id", clientId: process.env.APPCLIENTID});
const policyStoreId = process.env.POLICYSTOREID;
exports.handler = async (event) => { // Extract and verify the JWT token const token = event.headers["Authorization"]; let payload;
try { payload = await jwtVerifier.verify(token); var groups = payload["cognito:groups"] || [];
// Build the principal entity (the user) var userEntity = { "identifier": { "entityType": "MyApplication::User", "entityId": payload["cognito:username"] }, "attributes": { "employmentStoreCode": { "string": payload["custom:employmentStoreCode"] == null ? "" : payload["custom:employmentStoreCode"] } }, "parents": [] };
// Add groups as parent entities (for group membership) groups.forEach((group) => { userEntity.parents.push({ "entityType": "MyApplication::Group", "entityId": group }); });
// Build the authorization query let entities = { entityList: [userEntity] };
// Add resource entities based on the action addResourceEntities(entities, actionMap[event.httpMethod + event.resource], event.pathParameters);
// Call AVP let authQuery = { policyStoreId, principal: { "entityType": "MyApplication::User", "entityId": payload["cognito:username"] }, action: { "actionType": "MyApplication::Action", "actionId": actionMap[event.httpMethod + event.resource] }, resource: buildResource(actionMap[event.httpMethod + event.resource], event.pathParameters), entities };
const authResult = await avp.isAuthorized(authQuery).promise();
if (authResult.decision == 'ALLOW') { return buildResponse(200, 'Authorized', authResult); } else { return buildResponse(403, "You are not authorized to perform this action.", authResult); } } catch(err) { console.log(err); return buildResponse(403, "Error: " + err); }};Das Wichtigste: Ihr Code enthält keinerlei Berechtigungslogik. Er übergibt lediglich den Kontext an AVP und vertraut der Antwort. Genau darum geht es.
Der eigentliche Vorteil – Änderungen ohne Redeployment
Und hier passiert die eigentliche Magie.
Szenario: Ihr Business sagt: "Ab nächstem Monat dürfen Nutzer mit der Store-Owner-Role auch Bestellungen stornieren – aber nur solche, die vor mehr als 24 Stunden aufgegeben wurden."
Mit klassischen, hartkodierten Berechtigungen:
- Sie ändern den Lambda-Code
- Sie fügen eine
getOrderAge()-Funktion hinzu - Sie schreiben Tests für die neue Logik
- Sie committen, erstellen einen PR und warten auf das Code-Review
- Jemand stellt Ihre Logik infrage, Sie iterieren
- Sie mergen, deployen auf Staging, testen
- Sie deployen in Produktion
- Gibt es einen Bug, deployen Sie erneut – während das Business Geld verliert
Mit Amazon Verified Permissions:
- Sie loggen sich in die AVP-Konsole ein
- Sie fügen eine neue Cedar-Policy hinzu (dauert 2 Minuten):
permit( principal in MyApplication::Group::"Store-Owner-Role", action == MyApplication::Action::"CancelOrder", resource is MyApplication::Order)when { principal.employmentStoreCode == resource.storeId && resource.age > 1440 // minutes};- Auf Speichern klicken
- Fertig – die Änderung ist sofort live. Kein Deployment. Keine Codeänderung. Kein Lambda-Redeploy.
Das war's. Ihr Code hat sich nicht geändert. Ihr Lambda wurde nicht neu deployt. Die Autorisierungsregel wurde in Echtzeit aktualisiert.
RBAC + ABAC: Das Beste aus beiden Welten
Cedar erlaubt die Kombination beider Ansätze:
RBAC allein: "Ist der Nutzer in der Admin-Gruppe?" (binär, berücksichtigt keine Ressourcenattribute)
ABAC allein: "Stimmt das department-Attribut des Nutzers mit dem department-Attribut der Ressource überein?" (feingranular, erfordert aber viele Attribute)
RBAC + ABAC (die Stärke von Cedar): "Ist der Nutzer in der Gruppe Store-Owner-Role UND stimmt sein employmentStoreCode mit der storeId der Ressource überein?"
permit( principal in MyApplication::Group::"Store-Owner-Role", action == MyApplication::Action::"ManageInventory", resource is MyApplication::Application)when { principal.employmentStoreCode == resource.storeId};So erhalten Sie das Beste aus beiden Welten: rollenbasierte Gruppierung plus attributbasierte Granularität.
Testen & Deployment
Sobald Ihre Policies stehen, testen Sie sie:
- Als
Customer-Nutzer: Funktioniert SearchPets? ✅ Ja. Funktioniert GetStoreInventory? ❌ Nein. - Als
Store-Owner-Role-Nutzer: Funktioniert GetStoreInventory für den eigenen Store? ✅ Ja. Für einen anderen Store? ❌ Nein. - Als
ownermitemploymentStoreCode=petstore-london: Ist der Zugriff auf Bestellungen von petstore-london möglich? ✅ Ja.
Wenn eine Policy nicht funktioniert, prüfen Sie:
- Sind Ihre Entitäten in der Lambda-Funktion korrekt strukturiert?
- Enthält das JWT des Nutzers die richtigen
cognito:groups? - Ist das benutzerdefinierte Attribut im Nutzerprofil hinterlegt?
- Stimmen die Entitätstypen in Ihrer Autorisierungsanfrage mit Ihrem Schema überein?
Fazit: Weniger Klempnerarbeit, mehr Wertschöpfung
Ich wollte mit diesem Beitrag Amazon Verified Permissions nicht als ultimative Wunderwaffe für Ihre Anwendung präsentieren. Aber wenn Sie sich in einem endlosen Prozess wiederfinden, in dem Sie den Code Ihrer rollenbasierten Webanwendung ständig anpassen, weil sich die Business-Anforderungen so häufig ändern, lohnt es sich, kurz innezuhalten, einen Schritt zurückzutreten und zu hinterfragen, was Sie da eigentlich tun.
Vielleicht hilft Ihnen dieser Service, Zeit und Ressourcen zu sparen und sich auf das Business statt auf die Klempnerarbeit zu konzentrieren. Denn am Ende ist das alles Klempnerarbeit – sie unterstützt zwar die Geschäftsziele Ihrer Anwendung, steigert aber nicht wirklich deren Wert.
Aber mit Amazon Verified Permissions reparieren Sie zumindest nicht jede Woche die Rohre.