Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part IX: Hierarchies and ABAC
Tags: aws, avp, authorization, cedar
Published: 2023-08-11 14:36:03

Welcome back to our series on Amazon Verified Permissions (AVP)! In the previous article we've discussed how to [integrate AVP with Cognito](https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb). 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:

```json
{
    "uid": {
        "type": "Seller",
        "id": "1"
    },
    "attrs": {
        "rating": 5,
        "department": {
            "__entity": {
                "type": "Department",
                "id": "luxury"
            }
        }
    },
    "parents": []
}
```

### AVP Format:

```json
{
    "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](https://github.com/Pigius/avp-cli) with scenario, or do it manually within the console.

## AVP-CLI approach

I've prepared the [scenario](https://github.com/Pigius/avp-cli/tree/main/scenarios/ecommerceHierarchyAndAbacScenario). 

Simply run it locally:
```bash
➜  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:

```json
{
    "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"
                    ]
                }
            }
        }
    }
}
```


![Schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onno0dy8cu99xhq2kfcz.png)

## Policy

Now we can define policy as follows:

```bash
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](https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceHierarchyAndAbacScenario/ecommerceHierarchyAndAbacScenario.json#L12), 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`


![Test Bench](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yrue0rnmpcsfrrosqls5.png)

- Leave Context untouched.

For Entities use:

```json
[
    {
        "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".


![Allow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdz8innrymvb2sjoykm7.png)

## Next steps

That's it for today. In the upcoming [article](https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-x-avp-cli-aih), 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.