Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blogpost we've learned about usage AVP with IaC Terraform. Today, we will cover the topic of how to use AVP with Cloudformation.
Introduction
Cloudformation (IaC) does not need to be introduced to anyone, plus if you read the previous blogpost, the terraform provider (CC) we used is based on Cloudformation. Moreover, you will notice a lot of similarities, after all, we are implementing the same scenario, but with a different tool.
All the Cloudformation references you can check here.
Let's assume that we would like to recreate one of the scenarios from avp-cli in Cloudformation, for example, the documents scenario. This is a basic scenario with a document management platform schema and two policies (Allow all users to view all documents
and Forbid user X from viewing any documents
).
To recreate this, we need:
A policy store, which is a container for our policies. In such a container, we keep all policies, as well as the schema. It's important to remember that later when using AVP for authorization requests, we send requests against a specific policy store.
A schema is the structure of all available entities for a given policy store. In short, it defines what entities are available for our authorization system, including available actions, principals, and resources. The schema not only informs us about the available entities but also validates the correctness of authorization requests.
Finally, we will also need to add our policies.
Let's build!
The code for today's blog post can be found here.
The example we will create is not intended for production use; it has been created for educational purposes. However, in the future, In the next weeks, I will try to recreate all scenarios from avp-cli to Cloudformation. It will be in this repository, as well as a couple of more advanced, production-wise examples.
For our example, we will need two types of resources from the Cloudformation:
Now that we know everything, we can start building the project with Cloudformation.
Let's start with empty avp.yaml
for our Cloudformation configuration.
AWSTemplateFormatVersion: "2010-09-09"
Description: >
IaC for AVP
Resources:
We've started from adding AWSTemplateFormatVersion
to tell CloudFormation which template version we're adhering to. The Description
part refers to the overall description of the template.
Now we can focus on the Resources
section where we declare the AWS resources you want CloudFormation to create or manage.
Create a policy store
Now our focus will be to add a configuration for a policy store. First, we need to define the validation_settings
. It specifies the validation setting for this policy store. In our use-case, we would like to be strict
as we will add schema and check the validation of our authorization requests.
PolicyStore:
Type: AWS::VerifiedPermissions::PolicyStore
Properties:
Description: "Policy store for the documents scenario"
ValidationSettings:
Mode: STRICT
We're declaring a resource of type AWS::VerifiedPermissions::PolicyStore
, which represents a container in AVP where we will store policies. The Description
nested within Properties gives our policy store a description. Moreover, we've added validation settings setup as strict.
Now if we deploy it, we will have an empty policy store with a validation mode setup as strict.
Adding Schema
Now we want to add a schema, which you can find here. As you can see, it is a JSON file that we need to have. Let's update the configuration
...
PolicyStore:
Type: AWS::VerifiedPermissions::PolicyStore
Properties:
Description: "Policy store for the documents scenario"
ValidationSettings:
Mode: STRICT
Schema:
CedarJson: |
{
"DocumentManagementPlatform": {
"entityTypes": {
"User": {
"shape": {
"type": "Record",
"attributes": {}
}
},
"Document": {
"shape": {
"type": "Record",
"attributes": {}
}
}
},
"actions": {
"View": {
"appliesTo": {
"principalTypes": ["User"],
"resourceTypes": ["Document"]
}
},
"Edit": {
"appliesTo": {
"principalTypes": ["User"],
"resourceTypes": ["Document"]
}
}
}
}
}
This way, we've added a schema to our policy store.
Policy Store ID
Before we jump into the policies, we need to tackle one important thing in our template. We would like to know the ID of our policy store, so we can easily find it, and check our Policy Store, or pass it to the resources that will use it (for instance Lambda function which will make requests to AVP later on).
So to have it, we need to use Cloudformation Outputs
which specifies the values that are returned whenever you view your stack's properties.
We can easily add it like:
...
Outputs:
PolicyStoreId:
Description: "Identifier of the Amazon Verified Permissions policy store."
Value: !Ref PolicyStore
The actual !Ref directive within Value is an intrinsic function used to retrieve the ID of a resource defined in the same template. In our case, !Ref PolicyStore
gets the ID of the PolicyStore resource created by the stack.
Adding policies
Now, it's time for the final step, adding policies:
Now we can add:
AllowPolicy:
Type: AWS::VerifiedPermissions::Policy
Properties:
PolicyStoreId: !Ref PolicyStore
Definition:
Static:
Description: "Allow all users to view all documents"
Statement: |
permit (
principal,
action in [DocumentManagementPlatform::Action::"View"],
resource
);
DenyPolicy:
Type: AWS::VerifiedPermissions::Policy
Properties:
PolicyStoreId: !Ref PolicyStore
Definition:
Static:
Description: "Forbid user X from viewing any documents"
Statement: |
forbid(
principal == DocumentManagementPlatform::User::"xyz",
action in [DocumentManagementPlatform::Action::"View"],
resource
);
- The
Type: AWS::VerifiedPermissions::Policy
is used for creating two policies. - As any policy is part of that policy store, we needed to reference the Policy Store ID.
- For the
Definition
, we've usedstatic
, which indicates that the policy is static – it's not dynamically created from a template but is rather a fixed definition. - For the
Statement
we just need to pass the definition in Cedar language.
The whole file will look like this:
AWSTemplateFormatVersion: "2010-09-09"
Description: >
IaC for AVP
Resources:
PolicyStore:
Type: AWS::VerifiedPermissions::PolicyStore
Properties:
Description: "Policy store for the documents scenario"
ValidationSettings:
Mode: STRICT
Schema:
CedarJson: |
{
"DocumentManagementPlatform": {
"entityTypes": {
"User": {
"shape": {
"type": "Record",
"attributes": {}
}
},
"Document": {
"shape": {
"type": "Record",
"attributes": {}
}
}
},
"actions": {
"View": {
"appliesTo": {
"principalTypes": ["User"],
"resourceTypes": ["Document"]
}
},
"Edit": {
"appliesTo": {
"principalTypes": ["User"],
"resourceTypes": ["Document"]
}
}
}
}
}
AllowPolicy:
Type: AWS::VerifiedPermissions::Policy
Properties:
PolicyStoreId: !Ref PolicyStore
Definition:
Static:
Description: "Allow all users to view all documents"
Statement: |
permit (
principal,
action in [DocumentManagementPlatform::Action::"View"],
resource
);
DenyPolicy:
Type: AWS::VerifiedPermissions::Policy
Properties:
PolicyStoreId: !Ref PolicyStore
Definition:
Static:
Description: "Forbid user X from viewing any documents"
Statement: |
forbid(
principal == DocumentManagementPlatform::User::"xyz",
action in [DocumentManagementPlatform::Action::"View"],
resource
);
Outputs:
PolicyStoreId:
Description: "Identifier of the Amazon Verified Permissions policy store."
Value: !Ref PolicyStore
Deployment
Now that we have everything, let's try to deploy our template.
Navigate to the AWS console, and open Cloudformation service. Inside the Cloudformation service in the AWS console, press Create a new stack
with the option With existing resources (import resources)
. Use the Template is ready
.
Overall, we have 3 options for deploying our Cloudformation, either by storing it in S3 (if you use SAM or Serverless Framework you will be aware of that), you can upload it (which we will use), or you can deploy it from your repo. Here is a great article on that.
This time, use the Upload a template file
option.
- Attach the
avp.yaml
file and then forStack name
create a name, you can leave the rest of the configuration unchanged.
If we check the Designer
option it will look like this:
- Attach the
avp.yaml
file and then forStack name
create a name, you can leave the rest of the configuration unchanged. Review a stack, accept capabilities, and deploy.
After a couple of minutes everything will be deployed. In the resources tab, you can see 3 resources (AVP policy store, and 2 access policies), and in the output section, you will AVP policy store ID, which you can grab and check the resources in the AVP service.
Feel free to grab the Policy Store ID and check it in AVP.
Final words
As you can see, it's quite simple to create a basic project with AVP using Cloudformation.
If you're interested in more Cloudformation templates, I've recreated all of the AVP-CLI scenarios in CF, you can find them here. In the next blogpost we will tackle AVP getting started feature.
That's all for today. I encourage you to experiment on your own.
Top comments (0)