Simplify the way you manage authorization in your apps with Amazon's verified permissions - now publicly available
When creating a new application or integrating an existing one into a new environment, properly implementing user authentication and authorization requires significant work. You would have built your authentication system in the past, but today, you can use an external identity provider such as Amazon Cognito. However, the authorization logic is usually implemented in code.
This may start by assigning all users a role for their function. However, these authorizations become more complex over time. The number of roles grows as the authorizations also become more detailed. New use cases create the need for customized permissions. For example, one user may share a document with another user in a different role, or a support agent may require temporary access to a customer account to resolve a problem. Managing permissions in code is error-prone and a significant challenge when auditing permissions and deciding who has access to what, predominantly when these permissions are expressed across applications and using multiple programming languages.
At re:Invent 2022, the developers introduced a preview version of Amazon Verified Permissions, a detailed permissions management and authorization service for your applications that can be used at any scale. Amazon Verified Permissions centralizes permissions in a policy store and helps developers authorize user actions in their applications. In the same way that an identity provider simplifies authentication, the policy store enables authorizations to be managed consistently and scalable.
Amazon Verified Permissions defines detailed permissions using Cedar, an open-source policy language and software development kit (SDK) for access control. You can specify a schema for your authorization model regarding master types, resource types, and valid actions. This way, when a policy is created, it is validated against your authorization model. You can simplify the creation of similar policies by using templates. Changes to the policy store are audited so you can see who made the changes and when.
You can then link your applications to Amazon Verified Permissions via the AWS SDK to authorize access requests. The relevant rules are retrieved and evaluated for each authorization request to determine whether the action is allowed. You can replay these authorization requests to confirm that the permissions work as intended.
As of today, the authors are pleased to announce that the Amazon Verified Permissions service is generally available with new capabilities and a simplified user interface in the AWS management console.
Let's see how you can use this in practice.
Creating a Policy Store with Amazon Verified Permissions
In the Amazon Verified Permissions console, select Create Policy Store. A policy store is a logical container where policies and schemas are stored. Authorization decisions are therefore made based on all policies in the policy store.
You can use different methods to configure a new policy store. For example, you can start with a guided setup, a sample policy shop (such as a photo-sharing application, an online shop, or a task manager), or an empty policy shop (recommended for advanced users). Select Guided Setup, enter the namespace for your scheme (MyApp), and select Next.
Resources are objects on which security actors can act. In your application, you have users (principals) who can create, read, update and delete documents (resources). Start by defining the Documents resource type.
Enter a name for the resource type and add the two required attributes:
- owner (String) to specify who owns the document.
- isPublic (Boolean) to denote public documents that anyone can read.
Specify four actions for the Document resource type:
- DocumentCreate
- DocumentRead
- DocumentUpdate
- DocumentDelete
Enter User as the name of the root type that will use these actions on Documents. Then select Next.
You will now configure the master user type. You can use a custom configuration to integrate an external identity source but use the Amazon Cognito user pool you created earlier. Select Connect user pool.
In the dialog box, select the AWS region where the user pool is located, enter the user pool ID, and select Connect.
Now that the Amazon Cognito user pool is connected, you can add another level of protection by validating client application IDs. Do not use this option for now.
In the Principal attributes section, select the attributes you intend to use for attribute-based access control in your policies. Select the sub (subject) used to identify the end user according to the OpenID Connect specification. You can select more attributes. For example, use email_verified in a policy to give permission only to Amazon Cognito users whose email addresses have been verified.
As part of the policy store creation, create the first policy that gives the danilop user access to read the doc.txt document.
In the following code, the console allows you to preview the resulting policy using Cedar.
permit(
principal == MyApp::User::"danilop",
action in [MyApp::Action::"DocumentRead"],
resource == MyApp::Document::"doc.txt"
) when {
true
};
Finally, select Create Policy Store.
Adding permissions to the policy store
After creating the policy store, select Policies in the navigation pane. From the Create policy drop-down list, select Create static policy. A static policy contains all the information you need to evaluate it. Your second policy is to allow any user to read public documents. By default, everything is prohibited, so in Policy Effect, select Permit.
In Policy scope, leave All principals and All resources checked and select the DocumentRead action. In the Policy section, change the when condition clause to restrict permissions to resources where isPublic equals true:
permit (
principal,
action in [MyApp::Action::"DocumentRead"],
resource
)
when { resource.isPublic };
Enter a policy description and select Create policy.
For your third policy, create another static policy to allow full access to the document owner. Again, in the Policy Effect area, select Permit, and in the Policy scope, leave All principals and All chosen resources. In this case, also leave All actions selected.
In the Policy section, change the conditional clause when to restrict permissions to resources where the owner is equal to the sub-principal:
permit (principal, action, resource)
when { resource.owner == principal.sub };
In your application, you need to allow read access to certain users who are not owners of the document. To simplify this, create a policy template. Policy templates allow you to create policies from a template that uses placeholder symbols for some of their values, such as a security entity or resource. Substitution symbols in a template are keywords starting with the ?.
In the navigation pane, select Policy templates and then Create policy template. Enter a description and use the following policy template content. Using this template, you can specify the values of the substitution symbols ?principal and ?resource.
permit(
principal == ?principal,
action in [MyApp::Action::"DocumentRead"],
resource == ?resource
);
Finish creating the policy template. Now use the template to simplify policy creation. Select Policies in the navigation pane and then Create a template-linked policy in the Create policy dropdown list. Select the policy template you just created and click Next.
To grant the user (danilop) access to a specific document (new-doc.txt), simply pass the following values (note that MyApp is the namespace of the policy store):
For the Principal: MyApp::User:: "danilop"
For the Resource: MyApp::Document:: "new-doc.txt"
Finish creating the rules. Now it's time to test that the rules work as expected.
Testing the rules in the console
You can use AWS SDKs to run the authorization request in your applications. The console allows you to simulate what your applications would do. Select the Test Bench in the navigation pane. To simplify testing, use Visual mode. Alternatively, you can use the same JSON syntax as in the SDKs.
As Principal, pass the user janedoe. As Resource, use the requirements.txt file. This is not a public document (isPublic has a false value); the owner attribute equals sub janedoe. For the action, select MyApp::Action:: "DocumentUpdate".
By running an authorization request, you can pass Additional entities with more information about the security entities and resources associated with the request. However, leave this section blank for now.
Select Run authorisation request at the top to see the decision based on the current rules. As expected, the decision is allowed. Here, you can also see which policy was satisfied by the authorisation request. In this case, the policy allows full access to the document owner.
You can also test other values. If you change the document owner and action to DocumentRead, the decision is deny. If you then set the resource attribute isPublic to true, the decision is allow, because there is a policy that allows all users to read public documents.
Handling groups in Permissions
Administrative users in your application need to be able to delete any document. To do this, create a role for administrators. First, select Schema in the navigation pane and then Edit Schema. In the list of entity types, select Add New. Use Role as the Type name and add it. Then select User in the entity types and edit it to add the Role as parent. Save the changes and Create the following policy:
permit (
principal in MyApp::Role::"admin",
action in [MyApp::Action::"DocumentDelete"],
resource
);
Run an authorization request in the testbench to see if the user jeffbarr can delete (DocumentDelete) the resource doc.txt. As he is not the resource's owner, the request is rejected.
Now, in Additional entities, add an entity MyApp::User with jeffbarr as the identifier. As a parent, add the MyApp::Role entity with admin as the identifier and confirm. The console warns that the MyApp::Role:: "admin" entity is referenced but not included in the additional entity data. Add it and resolve this issue.
Re-run the authorization request, which is now allowed because, according to the additional entities, the principal (jeffbarr) is an administrator.
Using Amazon Verified Permissions in Your Application
I can run authorization requests in my applications using the isAuthorised API action (or isAuthrizedWithToken if the principal is from an external identity source).
For example, the Python code below uses the AWS SDK for Python (Boto3) to check if the user has read access to a document. The authorization request uses the policy store you just created.
Python
Run this code and, as expected, the output will be consistent with the tests run earlier.
Availability and costs
The Amazon Verified Permissions service is available in all commercial AWS regions, excluding regions in China.
With Amazon Verified Permissions, you only pay for what you use based on the number of authorization requests and API calls made on the service. For more information, see the Amazon Verified Permissions service price list.
Using Amazon Verified Permissions, you can configure detailed permissions using the Cedar policy language and simplify the code of your applications. This way, permissions are maintained in a centralized repository and are easier to audit. Read more about how the authors built Cedar with automated reasoning and differential testing.