Welcome back to our series on Amazon Verified Permissions (AVP)! In the previous article we've discussed how to integrate AVP with Cognito. Today, we're going to delve into a more advanced topic: hierarchies and entities in AVP.
Hierarchies vs Groups
In one of a previous article, we've seen how to use groups in AVP to manage permissions for a set of users. Groups are a powerful tool for simplifying permission management, especially when you have a large number of users with similar roles. For example, in our e-commerce platform, we might have a group for VIP customers who have access to preorder some products.
However, groups are not always sufficient to capture the full complexity of real-world authorization scenarios. For example, consider an e-commerce platform with a hierarchical customer structure, where permissions need to be inherited or overridden based on the customer's level in the hierarchy. In these cases, we need a more sophisticated way to model the relationships between users and resources. This is where hierarchies and entities come into play.
Entities and Attributes in AVP
In AVP, an entity is a representation of a principal, action, or resource in your application. Each entity has:
- An identifier: This includes an entity type and an entity ID. For example, for a customer entity, the entity type might be "EcommercePlatform::Customer" and the entity ID might be "Daniel".
- A set of attributes: These are properties or characteristics of the entity. For example, a customer entity might have attributes like 'purchase history' and 'loyalty level'.
- A list of parent entities: This is used to define the parent entities. In our use case we will add departments.
Cedar vs AVP Format: A Comparative Look
To better understand the differences between the Cedar and AVP formats, let's take a look at how a Seller entity from our e-commerce example would be represented in each format:
Cedar Format:
{
"uid": {
"type": "Seller",
"id": "1"
},
"attrs": {
"rating": 5,
"department": {
"__entity": {
"type": "Department",
"id": "luxury"
}
}
},
"parents": []
}
AVP Format:
{
"identifier": {
"entityType": "EcommercePlatform::Seller",
"entityId": "1"
},
"attributes": {
"rating": {
"long": 5
},
"department": {
"entityIdentifier": {
"entityType": "EcommercePlatform::Department",
"entityId": "luxury"
}
}
},
"parents": []
}
Key Differences:
Entity Representation:
Cedar: Uses uid
with type and id
to represent the entity.
AVP: Uses identifier
with entityType
and entityId
.
Attribute Types:
Cedar: Directly assigns values to attributes.
AVP: Attributes are typed, such as {"long": 5}
for the rating.
Entity Relationships:
Cedar: Uses the __entity
key inside attributes to denote relationships.
AVP: Uses the entityIdentifier
key for relationships.
Entity Naming:
Cedar: Uses concise names like "Seller".
AVP: Uses namespaced names like "EcommercePlatform::Seller".
Ecommerce example
Let's take our ongoing example of an e-commerce system where we have Sellers, Customers, Products, and now, Departments. We've used these entities in our previous blog posts as well. This time, let's imagine we're dealing with a car dealership. Our sellers are car dealers, and they have actions like selling cars, giving discounts, and ordering new cars.
We can define our entities like this:
- A Seller entity might have attributes like 'rating', and 'department'. The 'department' attribute links the Seller to a Department entity, indicating which department the seller belongs to.
- A Department entity represents different departments within the dealership, each responsible for selling certain types of cars.
- A Product (in this case, a Car) entity might have attributes like 'price', and 'department'. The 'department' attribute links the Car to a Department entity, indicating which department is responsible for selling this car.
- A Customer entity might have attributes like and 'loyalty level'. In this setup, we're going to implement two rules:
Hierarchy Rule: A seller can sell a car if the seller's department
matches the car's parent department
. This rule represents a hierarchical relationship between sellers, departments, and cars.
ABAC Rule: Moreover a seller can sell if the rating
(based on reputation) value is bigger than the specific value, as well whether the price is above some specific level. Those rules represent an attribute-based access control (ABAC) scenario where access decisions are made based on the attributes of the entities involved.
Implementation
We can either use AVP-CLI with scenario, or do it manually within the console.
AVP-CLI approach
I've prepared the scenario.
Simply run it locally:
➜ avp-cli git:(main) ✗ node index.js
Welcome to AVP CLI!
This tool is designed to help you interact with the AWS Verified Permissions (AVP) service. You can use it to create, manage, and delete policy stores, schemas, and policies.
Please ensure that you have set up your AWS credentials correctly to use this tool.
? What would you like to do? Use prepared scenarios
? Choose a scenario Ecommerce with Hierarchy and ABAC Scenario
After a couple of seconds all resources will be deployed to AWS, grab the policy store ID from the output table and navigate to the AVP Test Bench to continue.
Manual approach
Navigate to the AVP console, and create a new policy store with empty store. Open the Schema and paste it:
{
"EcommercePlatform": {
"entityTypes": {
"Department": {
"shape": {
"attributes": {
"name": {
"type": "String"
}
},
"type": "Record"
}
},
"Seller": {
"shape": {
"type": "Record",
"attributes": {
"rating": {
"type": "Long"
},
"department": {
"name": "Department",
"type": "Entity"
}
}
}
},
"Car": {
"shape": {
"attributes": {
"price": {
"type": "Long"
},
"department": {
"name": "Department",
"type": "Entity"
}
},
"type": "Record"
}
}
},
"actions": {
"Sell": {
"appliesTo": {
"resourceTypes": [
"Car"
],
"principalTypes": [
"Seller"
]
}
}
}
}
}
Policy
Now we can define policy as follows:
permit (
principal,
action in [EcommercePlatform::Action::"Sell"],
resource
)
when
{
principal.department == resource.department &&
principal.department.name == "luxury" &&
principal.rating >= 8 &&
resource.price > 1000000
};
Testing
We can either test it with AVP-CLI Test Scenario, or we can test it with Test Bench feature in AVP.
- Switch to json mode and fill it as follows:
Principal: EcommercePlatform::Seller
ID: 1
Resource: EcommercePlatform::Car
ID: porsche
Action: EcommercePlatform::Action
ID: Sell
- Leave Context untouched.
For Entities use:
[
{
"identifier": {
"entityType": "EcommercePlatform::Seller",
"entityId": "1"
},
"attributes": {
"department": {
"entityIdentifier": {
"entityType": "EcommercePlatform::Department",
"entityId": "1"
}
},
"rating": {
"long": 8
}
},
"parents": []
},
{
"identifier": {
"entityType": "EcommercePlatform::Car",
"entityId": "porsche"
},
"attributes": {
"price": {
"long": 10000000
},
"department": {
"entityIdentifier": {
"entityType": "EcommercePlatform::Department",
"entityId": "1"
}
}
},
"parents": []
},
{
"identifier": {
"entityType": "EcommercePlatform::Department",
"entityId": "1"
},
"attributes": {
"name": {
"string": "luxury"
}
},
"parents": []
}
]
Above dataset defines entities for an e-commerce platform, specifically detailing sellers, cars, and departments. It outlines a seller with a rating and department affiliation, a luxury car with its price and associated department, and a department named "luxury" to which both the seller and the car are linked.
Feel free to now test it, the decision should be "allow".
Next steps
That's it for today. In the upcoming article, I'll dive deeper into the avp-cli, exploring its capabilities and demonstrating how it can improve your AVP workflows. If there are specific topics related to Cedar or AVP you'd like me to cover, please let me know.
Top comments (0)