Directory
The Topaz Directory stores the information required to make authorization decisions. It is flexible enough to support different access control strategies including Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Relationship-Based Access Control (ReBAC).
An authorization decision is an answer to the question "Is subject S allowed to perform action A on resource R?" In other words, authorization decisions determine whether a subject (e.g. user, group, service) has a given permission (e.g. read, write, delete) on a resource (e.g. document, folder, project, etc.).
CLI docs
The topaz
CLI contains a number of commands to manage the directory. Refer to the CLI docs for more information.
API docs
The Topaz directory supports both gRPC and REST APIs. Refer to the API docs for for information.
Concepts
Authorization Model
The authorization model specifies the object types that can participate in authorization decisions. Each object type can have relations and permissions.
Relations can be thought of as the roles that an object type supports. Permissions are the actions that can be performed on the object type, and are granted through relations.
For example, a file
object type can define the can_read
, can_write
, and can_delete
permissions,
and have these granted through the owner
, editor
, and viewer
relations.
Objects
Objects represent the participants in authorization decisions. In the context of an authorization decision one object represents a subject—an actor who performs an action—and another represents a resource—the item that subject attempts to access.
Each object has a type and the set of all available types is defined in the directory's manifest.
An object is uniquely identified by the combination of its type and a user-defined ID. For example, a user
object
may have an email address as its ID.
IDs must be unique within a type, but objects of different types are allowed to have the same ID.
To support ABAC-style policies in which authorization decision are affected by attributes of the resource being accessed or the subject performing the action (e.g. credit limit, date of birth, region), objects may include JSON properties that are stored in the directory and can be inspected by the authorizer when evaluating authorization requests.
In other cases, authorization decisions can be made purely based on relations between objects (e.g. Michael is the owner of the Sales folder) without any properties. Such objects don't need to be stored explicitly. They can simply appear as pairs of object type and ID in one or more relations.
Relations
A relation is a labeled association between a resource (source object) and a subject (target object). Each object type, defined in the directory's manifest, may specify the kinds of relations that can be created from objects of that type, and the definition of each relation type indicates the types of objects that can be used as the subjects of the relation.
For example, a file
object type my define an owner
relation that can take a user
as its subject.
See the Manifest Reference for more details about defining relations.
Permissions
A permission represents a kind of action that a subject may perform on a resource. Similar to relations, each permission is defined in the manifest as part of an object type definition.
Unlike relations, permissions cannot be assigned explicitly. They are granted indirectly by combining relations and/or other permissions using permission operators.
For example, if a file
resource has editor
and viewer
relations, it can grant a can_write
permission to anyone with
the editor
relation to the resource, and a can_read
permission to anyone who can_write
or has the viewer
relation. The example below illustrates this exact scenario.
Manifest
The manifest is a yaml file that defines the authorization model. Here is a manifest for the example above:
# yaml-language-server: $schema=https://www.topaz.sh/schema/manifest.json
---
model:
# version of the manifest file format.
version: 3
types:
user: {}
file:
relations:
owner: user
editor: user
viewer: user
permissions:
can_delete: owner
can_write: can_delete | editor
can_read: can_edit | viewer
- This manifest defines two types:
user
andfile
. - The
user
type as no relations or permissions and can only used as a subject (target) of relations. - The
file
type has three relations:owner
,editor
, andviewer
. All three can only be assigned to subjects of typeuser
. - The
file
type has three permissions:can_delete
,can_write
, andcan_read
. - The
can_delete
permission is granted to anyone who has theowner
relation to the file. - The
can_write
permission is granted to anyone with thecan_delete
permission on the file OR theeditor
relation to it. - The
can_read
permission is granted to anyone with thecan_edit
permission OR theviewer
relation to the file.
Checking Permissions and Relations
The directory provides a convenient Check
API to determine whether a subject has a given relation to or permission on a specified
resource. It simply takes:
- The type and ID of an object (the resource).
- The relation or permission to check.
- The type and ID of the subject.
The result of the call is a boolean value that indicates whether or not the subject has the specified relation or permission on the resource.
Example
With these building blocks, it's possible to construct expressions like:
- Euan is a member of the Sales-group
- Sales-folder is a parent of the Sales-plan-document
- Sales-group is a viewer of the Sales-folder
- The viewer relation includes the read permission
And answer queries like:
- Does Euan have the read permission on the Sales-plan-document ?
The Topaz directory is able to evaluate this graph query, traversing through these relations and determining the outcome.
Common Object Types
While Topaz does not have any hard-coded types, it does come with a few templates, including simple-rbac
, gdrive
, and others.
Each of these templates defines its own manifest, but these manifests share a set of common object types and relations:
- User: a principal (typically used as a subject)
- Group: a collection of users and/or other groups (can be used as a subject or object)
- Identity: a unique identifier for a user (e.g. email, PID)
These object types can be found in almost all identity providers. Topaz templates define these common types to make it easy to model a few universal patterns:
- Groups are used to model collections of users, and can be nested. This makes it easy to model authorization rules that depend on (nested) group membership.
- Identities are used to look up users. This makes it easy to look up a user by any of their unique identifiers,
including
email
, or thesub
claim that an identity provider embeds in a JWT.
User Context and Identity objects
Applications can provide an identity context in an authorization request, which is used to look up the user object associated with that identity.
For an identity context of type IDENTITY_TYPE_JWT
, the Authorizer will load an identity
object with the id
that is found in the sub
claim of the JWT.
For an identity context of type IDENTITY_TYPE_SUB
, the string passed in will be used as the id
of the identity object to load.
The Authorizer then looks up the identifier
relation to the corresponding user
object, and loads the user object,
making it available to the Policy as input.user
.
In this way, a Policy can reference properties of the user using the expression input.user.properties.<property_name>
.
Built-ins
Authorization policies can access directory contents via a set of built-ins.