Skip to main content

Directory Resources

Resources provide a means to manage arbitrary data objects inside the Aserto directory, which are managed (created, updated and deleted) outside the scope a policy. Like data.json files which reside inside a policy, resources are JSON data objects, managed as key-value pairs.

Resource objects are loaded on-demand, in contrast to data.json files which are materialized into the data namespace when the policy is loaded and remain memory-resident for the duration of the policy lifetime. Concretely this means that a policy (rule) interacting with data managed in a resource object, will load the data when needed, using the res.get(<keyname>) built-in function, present in the Aserto Authorizer.

As noted earlier resources objects are managed out-of-band of the policy, where data.json files and their content are managed as part of the policy (as code) lifecycle.

Managing Resource Objects

Resource objects can be managed using the Aserto CLI or using the directory gRPC APIs.

Resource related Aserto CLI commands:

directory (d) list-res    list resources
directory (d) get-res get resource
directory (d) set-res set resource
directory (d) del-res delete resource

A resource can be a simple single value. The below example shows creating, getting and deleted a boolean resource object named is_it_dark_outside:

aserto d set-res is_it_dark_outside --value true

aserto d get-res is_it_dark_outside
{
"is_it_dark_outside": true
}

aserto d del-res is_it_dark_outside

Using the is_it_dark_outside resource inside a rego policy:

package policies.demo

default is_dark_outside = false

is_dark_outside {
res.get("is_it_dark_outside")
}
note

Note: The reason for specifying default is_dark_outside = false clause is to cover the case when the resource key value is not defined or found, which would result in an undefined value. This in turn would results in an undefined outcome of the rule.

Handling complex JSON objects

A resource can also contain a complex JSON object, source from a file or stdin. For example, consider the following JSON file:

demo.json

{
"user_roles": {
"alice": [
"admin"
],
"bob": [
"employee",
"billing"
],
"eve": [
"customer"
]
},
"role_grants": {
"customer": [
{
"action": "read",
"type": "dog"
},
{
"action": "read",
"type": "cat"
},
{
"action": "adopt",
"type": "dog"
},
{
"action": "adopt",
"type": "cat"
}
],
"employee": [
{
"action": "read",
"type": "dog"
},
{
"action": "read",
"type": "cat"
},
{
"action": "update",
"type": "dog"
},
{
"action": "update",
"type": "cat"
}
],
"billing": [
{
"action": "read",
"type": "finance"
},
{
"action": "update",
"type": "finance"
}
]
}
}

To load the JSON fragment inside the demo.json file using the Aserto CLI into a resource objects with the demo key name, use the following command:

aserto directory set-res demo --file ./demo.json

To list resources in the directory:

aserto directory list-res

Organizing resource objects is a design decision based on the use case, the expected update frequency and object size. For example we can shred the demo.json file into four segments: user_roles, role_grants, employee and billing if these need to be updated independently, or if data size and therefore memory footprint would become important.

Here's an example of a Rego policy that would use the demo resource object:

package app.rbac

import future.keywords.in

# By default, deny requests.
default allow = false

# Allow admins to do anything.
allow {
user_is_admin
}

# Allow the action if the user is granted permission to perform the action.
allow {
# Find grants for the user.
some grant
user_is_granted[grant]

# Check if the grant permits the action.
input.action == grant.action
input.type == grant.type
}

# user_is_admin is true if...
user_is_admin {
# "admin" is among the user's roles as per data.user_roles
"admin" in res.get("demo").demo.user_roles[input.user]
}

# user_is_granted is a set of grants for the user identified in the request.
# The `grant` will be contained if the set `user_is_granted` for every...
user_is_granted[grant] {
# `role` assigned an element of the user_roles for this user...
some role in res.get("demo").demo.user_roles[input.user]

# `grant` assigned a single grant from the grants list for 'role'...
some grant in res.get("demo").demo.role_grants[role]
}

Using the rule with the input:

{
"user": "bob",
"action": "read",
"object": "id123",
"type": "dog"
}

Would result in:

[
{
"x": {
"allow": true,
"user_is_granted": [
{
"action": "read",
"type": "cat"
},
{
"action": "read",
"type": "dog"
},
{
"action": "read",
"type": "finance"
},
{
"action": "update",
"type": "cat"
},
{
"action": "update",
"type": "dog"
},
{
"action": "update",
"type": "finance"
}
]
}
}
]

You can list resource related gRPC APIs using the list command with a grep filter. For example:

❯ grpcurl authorizer.prod.aserto.com:8443 list aserto.authorizer.directory.v1.Directory | grep -i resource

aserto.authorizer.directory.v1.Directory.DeleteResource
aserto.authorizer.directory.v1.Directory.GetResource
aserto.authorizer.directory.v1.Directory.ListResources
aserto.authorizer.directory.v1.Directory.SetResource

The describe command can be used to get the detailed description of the gRPC function signature:

❯ grpcurl authorizer.prod.aserto.com:8443 describe aserto.authorizer.directory.v1.Directory.GetResource


aserto.authorizer.directory.v1.Directory.GetResource is a method:
rpc GetResource ( .aserto.authorizer.directory.v1.GetResourceRequest ) returns ( .aserto.authorizer.directory.v1.GetResourceResponse );