DEV Community

Cover image for Authorization and Amazon Verified Permissions: A New Way to Manage Permissions - Part IV - Schema
Daniel Aniszkiewicz for AWS Community Builders

Posted on • Updated on

Authorization and Amazon Verified Permissions: A New Way to Manage Permissions - Part IV - Schema

In our previous article, we explored Amazon Verified Permissions (AVP), a fully managed, serverless service that simplifies managing, enforcing, and monitoring application permissions. AVP leverages Cedar, an open-source policy language developed by AWS, to define fine-grained, attribute-based access control policies.

A key component of AVP is the schema, which defines the structure of our authorization system and forms the basis for writing policies in AVP. In this article, we delve deeper into the AVP schema, exploring its basics, its importance, and how we can enhance it.

Understanding the Basics of AVP Schema

An AVP schema consists of three main components: namespaces, entity types, and actions.

  • Namespaces group related entity types and actions together, helping to organize our schema and prevent naming conflicts.
  • Entity types represent the objects in our system to which we want to control access. They can be anything from users and roles to resources like files, databases, and services.
  • Actions represent the operations that can be performed by or on the entities. They can be standard operations like read, write, and delete, or any custom operation relevant to our application.

These components define the "vocabulary" we use to write our policies in AVP. They specify what entities exist in our system, what actions they can perform, and how they are grouped together.

In our previous blog post, we defined a basic schema for an e-commerce scenario. Let's revisit it:

{
  "EcommercePlatform": {
    "entityTypes": {
      "Customer": {
        "shape": {
          "type": "Record",
          "attributes": {}
        }
      },
      "Product": {
        "shape": {
          "type": "Record",
          "attributes": {}
        }
      }
    },
    "actions": {
      "View": {
        "appliesTo": {
          "principalTypes": ["Customer"],
          "resourceTypes": ["Product"]
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In this schema, we have a namespace called "EcommercePlatform". Under this namespace, we've defined two entity types: "Customer" and "Product". We've also defined an action called "View", which can be performed by "Customer" entities on "Product" entities.

This is a simple example, but it provides a good starting point for understanding how schemas work in AVP. In the following sections, we'll explore how to make our schema more advanced by including context and adding groups.

Including Context in the Schema

In many real-world scenarios, the decision to allow or deny access might depend not only on the entities involved but also on some context. For example, in an e-commerce platform, we might want to restrict certain actions based on the region from where the customer is accessing the platform.

To include context in our schema, we can add a "context" field to the "appliesTo" section of our actions. Here's how we can modify our "View" action to include a context that specifies the customer's region:

"View": {
    "appliesTo": {
        "principalTypes": [
            "Customer"
        ],
        "resourceTypes": [
            "Product"
        ],
        "context": {
            "type": "Record",
            "attributes": {
                "region": {
                    "name": "region",
                    "type": "String",
                    "required": true
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this modified schema, the "View" action now includes a context that expects a "region" attribute. This attribute can then be used in our policies to make more granular access decisions.

Difference Between Context in Cedar and AVP

It's important to note that the way context is represented in Cedar and AVP is slightly different. In Cedar, the context is represented as a simple JSON object, like this:

{
    "region": "US"
}
Enter fullscreen mode Exit fullscreen mode

In AVP, however, the context is represented as a JSON object with typed fields, like this:

{
    "region": {
        "string": "US"
    }
}
Enter fullscreen mode Exit fullscreen mode

This difference in representation allows AVP to support a wider range of context types and to enforce type safety in the policies.

Adding Context to Our Schema in the AWS Console

To add the context to our schema in the AWS console, follow these steps:

Navigate to the AWS Console and open the Amazon Verified Permissions (AVP) service.

  • In the AVP dashboard, click on the name of the policy store that contains the schema you want to modify.
  • In the policy store details page, click on the "Schema" tab.
  • In the schema editor, you'll see a visual representation of your schema. Find the "Actions" section and click on the "View" action.
  • A panel will open on the right side of the screen showing the details of the "View" action. Click the "Edit" button at the top of this panel.
  • In the "Context attributes" section, click the "Add attribute" button.
  • A new row will appear in the "Context attributes" table. In the "Name" field, enter "region". In the "Type" field, select "String". Check the "Required" checkbox.
  • Click the "Save" button at the top of the panel to save your changes.

You've successfully added a context attribute to your schema using the visual mode in the AWS Console. Now, when you write policies for the "View" action, you can include conditions based on the "region" context attribute.

Context

Adding Groups to the Schema

In many scenarios, it's easier to define policies for groups, instead of multiple individual principals. For instance, in our e-commerce platform, we might have a group of VIP customers who are entitled to special privileges, such as early access to new products or exclusive discounts. To handle this, we can add a new entity type to our schema to represent customer groups.

Here's how our schema would look after adding a "CustomerGroup" entity type and making "Customer" a member of "CustomerGroup":

{
    "EcommercePlatform": {
        "entityTypes": {
            "Product": {
                "shape": {
                    "type": "Record",
                    "attributes": {}
                }
            },
            "Customer": {
                "memberOfTypes": [
                    "CustomerGroup"
                ],
                "shape": {
                    "type": "Record",
                    "attributes": {}
                }
            },
            "CustomerGroup": {
                "shape": {
                    "type": "Record",
                    "attributes": {
                        "name": {
                            "type": "String",
                            "required": true
                        }
                    }
                }
            }
        },
        ...
    }
}
Enter fullscreen mode Exit fullscreen mode

In this updated schema, we've added a new entity type called "CustomerGroup". This entity type has a single attribute, "name", which is a required string. The "memberOfTypes" field in "Customer" indicates that a "Customer" is a member of the "CustomerGroup" entity type. This means that a customer can belong to one or more customer groups.

Now, let's see how to add this updated schema to the AWS Console.

Adding Groups to Our Schema in the AWS Console

To add the "CustomerGroup" entity type to our schema in the AWS Console, follow these steps:

Navigate to the AVP console and select the "Schema" section:

  • Click on the "Edit Schema" button.
  • Click on the "Add new entity type" button.
  • In the "Type name" field, enter "CustomerGroup".
  • Click on the "Add an attribute" button.
  • In the "Attribute name" field, enter "name".
  • In the "Attribute type" field, select "String".
  • Check the "Required" checkbox.
  • Click on the "Save" button to save the changes.

To make "Customer" a member of "CustomerGroup", follow these steps:

  • In the "Entity types" section, click on the "Customer" entity type.
  • Click on the "Edit" button.
  • In the "Member of types" field, select "CustomerGroup" from the dropdown menu.
  • Click on the "Save" button to save the changes.

Now, we can use this updated schema to define more complex policies that take into account both the customer's region and their membership in customer groups.

CustomerGroup

Sum-up and next steps

The full schema could be found here:

{
    "EcommercePlatform": {
        "actions": {
            "Delete": {
                "appliesTo": {
                    "principalTypes": [
                        "Customer"
                    ],
                    "resourceTypes": [
                        "Product"
                    ]
                }
            },
            "Edit": {
                "appliesTo": {
                    "principalTypes": [
                        "Customer"
                    ],
                    "context": {
                        "attributes": {},
                        "type": "Record"
                    },
                    "resourceTypes": [
                        "Product"
                    ]
                }
            },
            "View": {
                "appliesTo": {
                    "resourceTypes": [
                        "Product"
                    ],
                    "context": {
                        "type": "Record",
                        "attributes": {
                            "region": {
                                "type": "String",
                                "name": "region",
                                "required": true
                            }
                        }
                    },
                    "principalTypes": [
                        "Customer"
                    ]
                }
            },
            "Create": {
                "appliesTo": {
                    "resourceTypes": [
                        "Product"
                    ],
                    "principalTypes": [
                        "Customer"
                    ]
                }
            }
        },
        "entityTypes": {
            "Product": {
                "shape": {
                    "attributes": {},
                    "type": "Record"
                }
            },
            "CustomerGroup": {
                "memberOfTypes": [
                    "Customer"
                ],
                "shape": {
                    "attributes": {
                        "name": {
                            "required": true,
                            "type": "String"
                        }
                    },
                    "type": "Record"
                }
            },
            "Customer": {
                "memberOfTypes": [],
                "shape": {
                    "attributes": {},
                    "type": "Record"
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

We've explored how to add context to our schema, allowing us to make authorization decisions based on additional information such as the region from which a customer is accessing our platform. We've also looked at how to add groups to our schema, enabling us to manage permissions for sets of users more efficiently.

In the next article, we'll take our exploration of AVP a step further by introducing the Test Bench. The Test Bench is a feature of AVP that allows us to test our policies before deploying them. This can help us catch any potential issues or gaps in our authorization system, ensuring that our policies work exactly as intended.

Stay tuned!

Top comments (0)