DEV Community

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

Posted on • Updated on

Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XII: Terraform

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 batch authorization. Today, we will take a look at how to build AVP with one of the most popular Infrastructure as Code (IaC) tool - Terraform.

Introduction

Let's assume that we would like to recreate one of the scenarios from avp-cli in Terraform, 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:

policy store

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.

Terraform provider for AVP

In the context of AWS, a Terraform provider is a plugin that allows Terraform to interact with AWS services and resources. It provides the necessary tools and interfaces for managing the lifecycle of various AWS resources through Terraform's infrastructure as code approach.

If we check the support for the Terraform AWS Provider here (state for the date of publishing this article), we will see that the service is not yet fully supported. Last week, after more than half a year, support for creating a policy store was added. Additionally, we have the configuration to add template policies. However, the identity source is in the form of a PR draft, and there is no PR yet for the ability to create policies.

Does this mean that we currently cannot use AVP with Terraform? Not necessarily, as the Cloud Control Provider comes to our rescue.

What is cool about that provider, is that it's auto-generated straight from AWS CloudFormation schemas, meaning it's always in sync with the latest AWS features - no more waiting for manual updates!

Weekly deployments (always on Thursday) with the newest AWS enhancements. This provider taps into the AWS Cloud Control API so you can expect new AWS offerings (supported via Cloudformation) in Terraform almost as soon as they're released.

Let's build!

The example we will create is not intended for production use; it has been created for educational purposes. However, in the future, I will add more advanced projects with Terraform to the repository, also more suited for production use.

For our example, we will need two types of resources from the Terraform:

Now that we know everything, we can start building the project in Terraform. At the end, a link to the repository will be provided, which you can easily clone.

Let's assume we have a new repository, and we start with an empty main.tf file. In order to configure the provider, you will need to employ the configuration blocks shown here, while specifying your preferred region:

main.tf

terraform {
  required_providers {
    awscc = {
      source  = "hashicorp/awscc"
      version = "~> 0.68.0"
    }
  }
}

provider "awscc" {
  region = "eu-west-1"
}
Enter fullscreen mode Exit fullscreen mode

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, let's add this code to our main.tf

resource "awscc_verifiedpermissions_policy_store" "policy_store" {
  validation_settings = { mode = "STRICT" }
}
Enter fullscreen mode Exit fullscreen mode

This line declares a new resource of type awscc_verifiedpermissions_policy_store, which is provided by the AWS CC provider. The policy_store is a local name given to this resource instance, which can be used to refer to it within the Terraform configuration. We've added validation settings setup as strict.

At this point, we could easily deploy our configuration via:

AWS_PROFILE=your-profile name terraform init
AWS_PROFILE=your-profile name terraform apply
Enter fullscreen mode Exit fullscreen mode

Which will create an empty policy store with validation settings.

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 add a schema.json file to our main project directory, and then update our configuration:

resource "awscc_verifiedpermissions_policy_store" "policy_store" {
  validation_settings = { mode = "STRICT" }
  schema              = { cedar_json = file("${path.module}/schema.json") }
}
Enter fullscreen mode Exit fullscreen mode

This new line defines the schema for the policy store using the cedar_json attribute.
The file("${path.module}/schema.json") function reads the contents of a file named schema.json located in the same directory as the Terraform module (${path.module} refers to the current module's directory).

The content of this file, which should be in JSON format, is used as the schema for the policy store.

Now when we deploy changes we will schema in our policy store.

Schema

Adding policies

Now, it's time for the final step, adding policies:

Later, we can add this config to main.tf:

resource "awscc_verifiedpermissions_policy" "allow_policy" {
  policy_store_id = awscc_verifiedpermissions_policy_store.policy_store.id
  definition = {
    static = {
      statement   = file("${path.module}/allow_policy.cedar")
      description = "Allow all users to view all documents"
    }
  }
}

resource "awscc_verifiedpermissions_policy" "forbid_policy" {
  policy_store_id = awscc_verifiedpermissions_policy_store.policy_store.id
  definition = {
    static = {
      statement   = file("${path.module}/deny_policy.cedar")
      description = "Forbid user X from viewing any documents"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • The resource "awscc_verifiedpermissions_policy" "allow_policy": declares a new resource of type awscc_verifiedpermissions_policy, named allow_policy. This resource represents a policy in the AVP Policy Store (similar to the forbid_policy).
  • policy_store_id = awscc_verifiedpermissions_policy_store.policy_store.id: This line specifies the ID of the Policy Store where this policy will be created. It references the id of the previously defined awscc_verifiedpermissions_policy_store resource named policy_store.

Inside the definition block of the policy we have:

  • static: Indicates that this is a static policy definition.
  • statement = file("${path.module}/allow_policy.cedar"): The policy statement is defined in an external file named allow_policy.cedar.

The file function reads the contents of this file, which contain the policy written in Cedar policy language. This policy is expected to specify conditions under which access is allowed.

The repo for this project can be found here with proper readme. I've made small improvements to the project (adding outputs to see policy store id and region), and when you deploy it you can see:

wscc_verifiedpermissions_policy_store.policy_store: Creating...
awscc_verifiedpermissions_policy_store.policy_store: Creation complete after 1s [id=VUdm7eCYdN3xW8CeJrrVx8]
awscc_verifiedpermissions_policy.allow_policy: Creating...
awscc_verifiedpermissions_policy.forbid_policy: Creating...
awscc_verifiedpermissions_policy.allow_policy: Creation complete after 9s [id=VKo7ca1kCNHSpVhLfHgrYs|VUdm7eCYdN3xW8CeJrrVx8]
awscc_verifiedpermissions_policy.forbid_policy: Creation complete after 9s [id=VN4qXzoMRhLqxa51KY3WPr|VUdm7eCYdN3xW8CeJrrVx8]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

aws_region = "eu-west-1"
policy_store_id = "VUdm7eCYdN3xW8CeJrrVx8"
Enter fullscreen mode Exit fullscreen mode

Policies

Final words

As you can see, it's quite simple to create a basic project with AVP using Terraform. That's all for today. I encourage you to experiment on your own.

If you're interested in more TF templates, I've recreated all of the AVP-CLI scenarios in TF, you can find them here.

In the next blogpost, you can read about usage AVP with Cloudformation.

Top comments (0)