Skip to content

RBAC Configuration

The RBAC feature enables restrictions of access to Terralist resources. Terralist does not have its own user management system, delegating this job to one (or more) OAuth 2.0 providers. If the provider authenticates the user, Terralist asks the provider for some metadata and takes the user as being authenticated under those claims. Depending on the provider implementation, those claims can differ.

There are two main components where RBAC configuration can be defined:

  • The server-side (global) RBAC configuration;
  • The API Key RBAC configuration;

Basic Built-in Roles

Terralist has three pre-defined roles. All roles can be extended or overridden through the server-side policy configuration.

  • role:anonymous: has access to no resources (unless specified otherwise in the server-side configuration);
  • role:readonly*: read-only access to modules, providers, and authorities (but not API keys or settings). Access to settings is policy-driven;
  • role:admin*: unrestricted access to all resources;

* This role cannot be extended.

The role:anonymous is a special role that is assigned to unauthenticated users. This role can be customized from the server-side configuration and through those modifications users are able to expose (publicly) resources from the registry. By default, this role has no grant attached.

The role:readonly and role:admin roles have baked-in default policies that are always loaded. User-provided policies are evaluated on top of these defaults.

Default Policy for Authenticated Users

When a user is authenticated in Terralist, it will be granted the role specified by the rbac-default-role configuration option, if there is no other role specified for the given user.

RBAC Model Structure

The model syntax is based on Casbin and highly inspired from the ArgoCD implementation. There are two different types of syntax: one of assigning policies, and another one for assigning users to internal roles.

Group: Used to assign users or groups to internal roles.

Syntax: g, <username/useremail/group>, <role>

  • <username/useremail/group>: The entity to whom the role will be assigned. Depending on the OAuth provider implementation those values can represent different things; Usually, the username refers to the sub claim, while the useremail and group refers to a custom claims, which might not even be supported by the provider you are using. Check the OAuth provider documentation for more details.
  • <role>: The internal role to which the entity will be assigned.

Below is a table that defines claims meaning for each OAuth provider.

Provider\Claim username useremail group
BitBucket Username User E-mail Not supported.
GitHub Username User E-mail GitHub Organization Teams slugs that the user is part of (if gh-organization configuration option is set).
GitLab Username User E-mail GitLab User Group names.
OIDC sub claim Not supported. Not supported.

Policy: Allows to assign permissions to an entity.

Syntax: p, <role/username/useremail/group>, <resource>, <action>, <object>, <effect>

  • <role/username/useremail/group>: The entity to whom the policy will be assigned
  • <resource>*: The type of resource on which the action is performed. Can be one of: modules, providers, authorities, api-keys, settings. Supports glob matching.
  • <action>*: The operation that is being performed on the resource. Can be one of: get, create, update, delete. Supports glob matching.
  • <object>*: The object identifier representing the resource on which the action is performed. Supports glob matching. Depending on the resource, the object's format will vary.
  • <effect>: Whether this policy should grant or restrict the operation on the target object. One of allow or deny.

* This attribute supports glob matching. For example, for resources * will match all resources, mod* will match only modules, while for objects my-authority/my-module/aws will match only one module, while my-authority/*/* will match all modules within the authority my-authority.

Below is a table that defines the correct object syntax for each resource group.

Resource Group Object Syntax
authorities <authority-name>
modules <authority-name>/<module-name>/<provider-name>
providers <authority-name>/<provider-name>
api-keys <scope>
settings page

API Key Scopes

Every API key has a scope — a required label that determines who can manage the key via RBAC policies.

Unlike modules or providers, API keys have no natural organizational hierarchy. The API key's UUID cannot be used in policies because it is the authentication secret itself. The scope solves this by providing a human-readable, non-sensitive identifier that can be referenced in the server-side RBAC policy.

When evaluating RBAC permissions on the api-keys resource, the scope is used as the policy object. This means you can write policies such as:

p, team-a-manager@example.com, api-keys, *, team-a, allow
p, team-b-manager@example.com, api-keys, *, team-b, allow

In this example, Team A's manager can create, view, and delete API keys scoped to team-a, but cannot touch keys scoped to team-b, and vice versa.

Scopes support glob matching, which enables hierarchical delegation. For example, a lead who oversees multiple sub-teams can be granted access to all their keys with a single policy:

p, lead@example.com, api-keys, *, team-a*, allow

This matches team-a, team-a-frontend, team-a-backend, etc.

The scope is purely organizational -- it does not affect what the API key can access. A key scoped to team-a can still have policies that grant access to resources across multiple authorities. The scope only controls who can manage the key itself.

API Key Policies

API keys carry their own RBAC policies. When authenticating with an API key, the key's inline policies are evaluated directly -- the server-side policy file is not consulted.

Each policy on an API key follows the same format as server-side policies:

  • <resource>: The resource type (modules, providers, authorities, api-keys, settings, or *)
  • <action>: The operation (get, create, update, delete, or *)
  • <object>: The object identifier (supports glob matching, same format as the table above)
  • <effect>: allow or deny

API keys can be created and managed from the Settings page in the web UI, or via the /v1/api/api-keys API endpoints. The web UI provides a form that constructs valid policies with context-sensitive object fields based on the selected resource type.

The built-in role:readonly does not grant access to the api-keys resource. To allow a readonly user to view or manage API keys, add an explicit policy such as p, <user>, api-keys, *, *, allow. The role:admin role has full access to all resources, including API keys.

Authorities Access Policies

Use explicit deny/allow policies for authorities to avoid relying on defaults.

Example:

# Deny broad authorities access by default for developer role
p, role:developer, authorities, *, *, deny

# Grant read-only access to a specific authority for authority-reader role
p, role:authority-reader, authorities, get, example-authority, allow

# Grant full authorities management to authority-admin role
p, role:authority-admin, authorities, *, *, allow

Then map identity claims (user/group/email) to those roles:

g, SSOAWS_PLATFORM, role:authority-admin
g, SSOAWS_ENGINEERING, role:authority-reader

Settings Page Access With RBAC

The Settings page capability endpoint checks RBAC permission:

  • resource: settings
  • action: get
  • object: page

Settings page access and visibility are controlled only by RBAC policy.

Migration note: if you previously used --authorized-users, convert that access list to RBAC settings/get/page policies and role mappings.

Example policies:

# Explicitly deny settings page access for developer role
p, role:developer, settings, get, page, deny

# Allow settings page access for authority-admin role
p, role:authority-admin, settings, get, page, allow