Cloud Intelligence™
Basta lottare con i permessi complessi: una boccata d'aria fresca per il tuo codice
Questa pagina è disponibile anche in English, Deutsch, Español, Français, 日本語 e Português.
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

Panoramica
Questo articolo presenta Amazon Verified Permissions (AVP) come soluzione pratica per la gestione di autorizzazioni applicative complesse, con una guida pratica basata sull'esempio AWS PetStore.
Il problema
Ti è mai capitato di trovarti di fronte a una complessità enorme cercando di gestire tutti i possibili ruoli di autorizzazione, utenti e attori del tuo prodotto SaaS? Conosci bene la fatica dei requisiti di business che cambiano, mentre cerchi di puntare ai migliori principi di sicurezza destreggiandoti tra code review e a/b test legati alle modifiche che stai cercando di implementare? E sì, il tuo SaaS gira sul cloud AWS.
Forse è arrivato il momento di fare un bel respiro e guardare le cose dall'alto!! Pensa alla tua soluzione, e poi ripensala, perché potrei mostrartene una relativamente semplice! Una che può aiutarti a gestire la complessità e a dedicare risorse ed energie a ciò che conta davvero: il tuo business e le sue esigenze!!
Questa soluzione è Amazon Verified Permissions.
Come si gestiscono di solito le autorizzazioni in un'applicazione web
Analizziamo il sistema di autorizzazione di un'applicazione web. La necessità di un sistema del genere arriva con l'evoluzione dell'applicazione. Puoi pianificarlo in anticipo (il che è meglio, come parte del design del sistema), ma dovrai comunque affrontare cambiamenti dettati dall'evoluzione dei requisiti di business. Dovrai modificare diverse parti del sistema dopo il deployment in produzione.
Perché serve un sistema del genere? Per molte ragioni:
- Vuoi permettere a determinati ruoli di vedere determinate parti dell'applicazione
- Devi limitare determinate azioni a specifici ruoli/utenti dell'applicazione
- Devi rafforzare i controlli di sicurezza e prevenire accessi non autorizzati
- La logica dei permessi finisce sparsa in tutto il codice, rendendo la manutenzione un incubo
Il tipico sistema di permessi: un groviglio inestricabile
La maggior parte dei sistemi di autorizzazione oggi assomiglia a questo — blocchi if/else sparsi in tutto il codice:
// 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;}E poi? Aggiungi un altro ruolo. Poi un altro ancora. Poi un caso speciale per i responsabili regionali. Poi una regola su chi può annullare gli ordini dopo 24 ore. Poi un nuovo requisito di business sull'accesso nel weekend. All'improvviso stai annegando in condizioni annidate, le tue code review sono brutali, ogni cambiamento nei requisiti di business diventa un deployment e metà del team discute di edge case invece di sviluppare funzionalità.
I veri punti dolenti
Esplosione dei ruoli: i tuoi 2 ruoli diventano 5, poi 10, poi ti ritrovi con manager-regionale-con-permessi-da-dipendente-di-negozio-ma-solo-nei-weekend, e nessuno riesce più a tenere traccia di chi dovrebbe avere cosa.
L'incubo delle code review: ogni modifica ai permessi richiede modifiche al codice. Gli sviluppatori passano ore a discutere la logica delle policy nelle PR invece di rilasciare funzionalità.
Testare le autorizzazioni: come si fa anche solo a testare tutte le combinazioni? Matrice di utenti × ruoli × risorse × azioni = caos. Ti sfuggono gli edge case e le cose si rompono in produzione.
Audit trail: buona fortuna a spiegare alla compliance perché quell'utente poteva accedere a quell'ordine. È sepolto nella cronologia git in 5 file diversi.
Zero flessibilità: vuoi cambiare i permessi di venerdì? Peccato — serve un deployment. Vuoi fare rapidamente il rollback di una policy? Un altro deployment.
Come gestire tutto questo con Amazon Verified Permissions
E se avessi l'opportunità di alleggerire questo fardello? E se ti dicessi che oggi esiste un servizio in grado di fare per te la maggior parte del lavoro sui permessi delle applicazioni web?
Invece di incorporare le autorizzazioni nel codice, e se le separassi completamente? E se i permessi fossero dichiarativi, versionati, centralizzati, e potessi modificarli senza rifare il deploy dell'applicazione?
È questa la promessa di Amazon Verified Permissions (AVP).
L'architettura
Ecco come funziona (a grandi linee):
- L'utente si autentica tramite AWS Cognito (o qualsiasi IdP)
- La tua API riceve la richiesta con un token JWT
- Il Lambda Authorizer intercetta la richiesta
- La Lambda costruisce una query di autorizzazione con: principal (chi), action (cosa sta facendo), resource (su cosa la sta facendo), context (attributi aggiuntivi)
- La Lambda chiama AVP con quella query
- AVP valuta le policy Cedar (un linguaggio di policy progettato per l'autorizzazione)
- AVP restituisce ALLOW o DENY
- API Gateway applica la decisione - la richiesta procede o riceve un 403
Il punto chiave: tutta la logica dei permessi vive nelle policy Cedar in AVP. Il tuo codice si limita a chiedere "è autorizzato?" e si fida della risposta.

L'esempio reale: PetStore
Ho usato il repository PetStore di AWS come applicazione di esempio, includendo la maggior parte delle funzionalità descritte, ma con alcune piccole modifiche, perché lo schema fornito non funzionava — probabilmente a causa di aggiornamenti apportati al servizio da AWS. Ricorda che è un servizio relativamente nuovo e presumo che in molte aree sia ancora in evoluzione.
Basta seguire i passaggi indicati e partire dal deployment dell'applicazione Amplify. Potrebbe chiederti di identificarti con il tuo account GitHub per clonare il repo ed effettuare il deployment nel tuo ecosistema AWS. Una volta completato il deployment, guardando il diagramma dell'architettura qui sopra, possiamo identificare i componenti e come comunicano tra loro.
La configurazione: guida passo passo
Step 1: utenti e gruppi Cognito
Come identity provider usiamo AWS Cognito. Dopo il deployment puoi accedere alla dashboard di Amazon Cognito, dove dovresti trovare lo User pool che inizia con "petstoresample": è il tuo pool ed è qui che devi creare gli utenti e i gruppi per questa applicazione.
Crea tre utenti:
Per questa PoC dobbiamo creare tre utenti. Uno deve chiamarsi esplicitamente "abhi", perché il nome è hardcoded nella funzione Lambda. Gli altri due sono più flessibili — io li ho chiamati "owner" e "visitor". Quando li crei:
- Non inviare email di verifica
- Contrassegnali come "email address verified"
- Usa password semplici (non vorrai doverle reimpostare dopo la configurazione)
Alla fine dovresti avere qualcosa del genere:

Aggiungi attributi personalizzati all'utente owner:
Non dimenticare di aggiornare l'utente "owner" con l'attributo personalizzato employmentStoreCode. Verrà usato più avanti nelle policy di Amazon Verified Permissions. Basta cliccare su "Edit" e aggiornare, in modo che gli attributi dell'utente appaiano così:

Crea i gruppi e assegna gli utenti:
Devi creare 2 gruppi e aggiungervi gli utenti. I nomi dei gruppi ("Store-Owner-Role" e "Customer") fanno parte dei token emessi da Cognito e verranno usati per il controllo degli accessi basato sui ruoli (RBAC).

L'utente "abhi" va aggiunto al gruppo "Customer" insieme all'altro utente "visitor":

E ovviamente "owner", con il tag aggiuntivo che abbiamo inserito, andrà nel gruppo "Store-Owner-Role":

Step 2: configurazione di Amazon Verified Permissions
Completata questa parte, il passo successivo è rivedere e configurare Amazon Verified Permissions. In questa parte esamineremo anche il Lambda Authorizer e l'API Gateway — sono stati deployati con lo stesso deployment Amplify, come parte dell'applicazione.
Basta cercare Amazon Verified Permissions nella barra di ricerca e creare prima di tutto un nuovo Policy store. Nel repository consigliano di partire dallo schema, ma la UI è cambiata: devi prima creare il Policy store. Puoi inserire valori a piacere, dato che alla fine useremo lo schema che fornisco io. Quindi, per semplificare le cose, puoi specificare un Empty Policy Store e chiamarlo semplicemente "PetStore".
Step 3: definisci lo schema
Questo passaggio è cruciale. Lo schema dice ad AVP quali principal, risorse, azioni e relazioni esistono nella tua applicazione. Usa questo 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" } } } }}Lo schema del progetto originale ha un piccolo problema, quindi copia invece questo nello schema del tuo Policy Store.
Step 4: crea le policy Cedar
Clicca sul Policy Store e nel pannello a sinistra vedrai il link "Policies". Cliccaci sopra e poi clicca su "Create Policy > Create static policy". Il wizard di creazione delle policy usa lo schema che abbiamo aggiunto. Usiamo policy permissive — lo scope va definito sul gruppo di partecipanti, lo scope della risorsa deve essere la risorsa specifica in cui scegli ciò che ti serve e il tipo di azione va selezionato come insieme specifico di azioni.
C'è un trucco che puoi usare per creare la policy completamente permissiva: seleziona "All principals", "All resources" e "All actions", salva la policy, poi modificala e incolla semplicemente la policy in linguaggio Cedar. È un workaround, ma devi conoscere la dichiarazione della tua policy.
Ecco le policy che ti servono per questa PoC:
Esempio RBAC — I clienti possono cercare animali ed effettuare ordini:
permit( principal in MyApplication::Group::"Customer", action in [MyApplication::Action::"SearchPets", MyApplication::Action::"PlaceOrder"], resource == MyApplication::Application::"main");Esempio ABAC — I proprietari di negozio possono accedere solo all'inventario del proprio negozio:
permit( principal in MyApplication::Group::"Store-Owner-Role", action == MyApplication::Action::"GetStoreInventory", resource == MyApplication::Application::"main")when { principal.employmentStoreCode == resource.storeId};Esempio ABAC — Gli utenti possono vedere solo i propri ordini:
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.
L'integrazione del Lambda Authorizer
La tua funzione Lambda riceve la richiesta API e deve:
- Verificare il token JWT (estrarre le informazioni dell'utente)
- Costruire una query di autorizzazione per AVP
- Chiamare l'API
isAuthorizeddi AVP - Restituire ALLOW/DENY
Ecco come si presenta (dal repo PetStore vero e proprio):
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); }};Punto chiave: il tuo codice non contiene alcuna logica dei permessi. Si limita a passare il contesto ad AVP e a fidarsi della risposta. È proprio questo il punto.
Il vero vantaggio: modifiche senza redeployment
Ed è qui che avviene la magia.
Scenario: il business ti dice "Dal mese prossimo, gli utenti Store-Owner-Role possono anche annullare gli ordini, ma solo quelli effettuati più di 24 ore fa."
Con i tradizionali permessi hardcoded:
- Modifichi il codice della Lambda
- Aggiungi una funzione
getOrderAge() - Scrivi i test per la nuova logica
- Fai il commit, apri la PR, aspetti la code review
- Qualcuno mette in discussione la tua logica, iteri
- Fai il merge, deploy in staging, test
- Fai il deploy in produzione
- Se c'è un bug, fai un altro deploy mentre il business perde soldi
Con Amazon Verified Permissions:
- Accedi alla console AVP
- Aggiungi una nuova policy Cedar (ci vogliono 2 minuti):
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};- Premi salva
- È attiva. Immediatamente. Nessun deployment. Nessuna modifica al codice. Nessun redeploy della Lambda.
Tutto qui. Il tuo codice non è cambiato. Non hai rifatto il deploy della Lambda. La regola di autorizzazione si è aggiornata in tempo reale.
RBAC + ABAC: il meglio dei due mondi
Cedar ti permette di combinare i due approcci:
Solo RBAC: "L'utente è nel gruppo Admin?" (binario, non considera gli attributi della risorsa)
Solo ABAC: "L'attributo department dell'utente corrisponde all'attributo department della risorsa?" (granulare, ma richiede molti attributi)
RBAC + ABAC (il punto di forza di Cedar): "L'utente è nel gruppo Store-Owner-Role E il suo employmentStoreCode corrisponde allo storeId della risorsa?"
permit( principal in MyApplication::Group::"Store-Owner-Role", action == MyApplication::Action::"ManageInventory", resource is MyApplication::Application)when { principal.employmentStoreCode == resource.storeId};Così ottieni il meglio di entrambi i mondi: raggruppamento basato sui ruoli + granularità basata sugli attributi.
Test e deployment
Una volta definite le policy, testale:
- Come utente
Customer: può eseguire SearchPets? ✅ Sì. Può eseguire GetStoreInventory? ❌ No. - Come utente
Store-Owner-Role: può eseguire GetStoreInventory per il proprio negozio? ✅ Sì. Per un negozio diverso? ❌ No. - Come
ownerconemploymentStoreCode=petstore-london: può accedere agli ordini di petstore-london? ✅ Sì.
Se una policy non funziona, verifica:
- Le entità sono strutturate correttamente nella Lambda?
- Il JWT dell'utente contiene i
cognito:groupscorretti? - L'attributo personalizzato è presente nel profilo utente?
- I tipi di entità nella query di autorizzazione corrispondono allo schema?
Conclusione: dall'idraulica al valore
Non avevo intenzione di scrivere questo articolo per presentare Amazon Verified Permissions come la soluzione miracolosa definitiva per la tua applicazione, ma se sei nel bel mezzo di un processo infinito di modifiche al codice della tua applicazione web basata sui ruoli perché i requisiti di business cambiano in continuazione, potresti provare a fermarti, guardare le cose dall'alto e ripensare a quello che stai facendo.
Forse questo servizio può aiutarti a risparmiare tempo e risorse, liberandoti per concentrarti sul business invece che sull'idraulica. Alla fine sembra tutta idraulica: supporta gli obiettivi di business della tua applicazione, ma non contribuisce davvero a farne crescere il valore.
Ma almeno con Amazon Verified Permissions non devi riparare le tubature ogni settimana.