RBAC

Control which Platform Orchestrator entities a member or service user can view or change.

How RBAC works

Role-based access control (RBAC) determines what members and service users can do in the Platform Orchestrator. It has four parts:

  • A permission allows one kind of operation on a Platform Orchestrator entity, such as module_write or deployment_read.
  • A role bundles one or more permissions.
  • A role assignment binds a role to a member or service user at an organization, project, or environment scope.
  • Assignments are additive. A subject receives the union of all permissions from all applicable role assignments.

This model lets you create roles for specific Orchestrator responsibilities. For example, a module maintainer can receive module_read and module_write without receiving project_write, while a deployment operator can receive deployment_read and deployment_write without being able to change modules.

Follow the principle of least privilege: grant only the permissions and scopes required for the task.

Built-in roles

The built-in roles remain available and cannot be edited or deleted. Their behavior is unchanged by granular permissions.

RoleEffective access
AdminEvery granular permission
DeployerEvery normal read permission and deployment_write
ViewerEvery normal read permission

deployment_debug_read exposes generated infrastructure code and remains Admin-only. The built-in roles are hierarchical: Admin includes Deployer, which includes Viewer.

Scopes

A role and its assignment scope are independent:

  • The role defines what the subject can do.
  • The assignment defines where the subject can do it.
Assignment scopeApplies to
OrganizationApplicable entities throughout the organization
ProjectThe project and applicable entities in its environments
EnvironmentApplicable entities in that environment

Each permission also declares the scopes where it is meaningful. For example, module_write is organization-only, project_write is effective at organization and project scope, and deployment_write is effective at all three scopes. Assigning an organization-only permission at project or environment scope does not grant organization-wide access.

The same role can contain permissions with different applicable scopes. Only the permissions applicable to an assignment’s scope take effect.

Granular permission catalog

Permission identifiers are fixed Platform Orchestrator capabilities, not arbitrary values for external applications. Use the exact identifier shown in the console or returned by listPermissions. The API catalog is authoritative and includes each permission’s display name, description, category, and applicable scopes.

Read and write permissions are independent. A *_write permission does not automatically include the matching *_read permission. Select both when the role must view and change that entity.

PermissionAllowsApplicable scopes
organization_readView organization detailsOrganization
invitation_readList pending invitationsOrganization
invitation_writeCreate, inspect, and revoke invitationsOrganization
membership_readView members and effective access assignmentsOrganization, project, environment
membership_writeAssign, replace, and remove member rolesOrganization
role_readView built-in and configurable rolesOrganization
role_writeCreate, update, and delete configurable rolesOrganization
service_user_readView service users and their role assignmentsOrganization
service_user_writeCreate, update, delete, and rotate credentials for service usersOrganization
provisioning_readRead SCIM-provisioned users and groupsOrganization
provisioning_writeCreate, update, and deprovision SCIM users and groupsOrganization
project_readView projects and their configurationOrganization, project
project_writeCreate, update, and delete projectsOrganization, project
environment_readView environments and their configurationOrganization, project, environment
environment_writeCreate, update, and delete environmentsOrganization, project, environment
environment_type_readView organization environment typesOrganization
environment_type_writeCreate, update, and delete environment typesOrganization
module_readView modules and module versionsOrganization
module_writeCreate, update, and delete modulesOrganization
module_provider_readView module providersOrganization
module_provider_writeCreate, update, and delete module providersOrganization
module_rule_readView module selection rulesOrganization
module_rule_writeCreate and delete module selection rulesOrganization
resource_type_readView available and configured resource typesOrganization
resource_type_writeCreate, update, and delete resource typesOrganization
runner_readView runners and their configurationOrganization
runner_writeCreate, update, delete, and assign runnersOrganization
runner_rule_readView runner selection rulesOrganization
runner_rule_writeCreate and delete runner selection rulesOrganization
active_resource_readView active resourcesOrganization, project, environment
deployment_readView deployments, logs, outputs, and calculated differencesOrganization, project, environment
deployment_writeCreate deployments and wait for completionOrganization, project, environment
deployment_debug_readView generated deployment infrastructure codeOrganization
metadata_key_readView deployment metadata key definitionsOrganization
metadata_key_writeCreate, update, and delete metadata key definitionsOrganization
resource_graph_readView resources produced by deploymentsOrganization, project, environment

Create a configurable role in the console

Users need role_read to view roles and the permission catalog, and role_write to create, edit, or delete configurable roles. The complete console workflow therefore requires both permissions. In Settings → Roles, the permission selector is grouped by Orchestrator entity and shows the description, identifier, and applicable scopes for every option. It accepts catalog options only.

Configurable roles can be deleted only when they have no active assignments. Changing a role changes the effective permissions of all its assignments.

Manage configurable roles with the CLI

Discover the current permission catalog before creating a role:

octl get permissions

Create, inspect, replace, and delete a configurable role:

octl create role \
  --set display_name="Module Maintainer" \
  --set-json '{"permissions":["module_read","module_write"]}'

octl get roles
octl get role 11111111-1111-1111-1111-111111111111

octl update role 11111111-1111-1111-1111-111111111111 \
  --set display_name="Module and Provider Maintainer" \
  --set-json '{
    "permissions": [
      "module_read",
      "module_write",
      "module_provider_read",
      "module_provider_write"
    ]
  }'

octl delete role 11111111-1111-1111-1111-111111111111

An update replaces both the display name and the complete permission set.

Manage configurable roles with Terraform or OpenTofu

Provider v1.1.0 and later can manage configurable roles and read the permission catalog:

data "platform-orchestrator_permissions" "available" {}

resource "platform-orchestrator_role" "module_maintainer" {
  display_name = "Module Maintainer"
  permissions = [
    "module_read",
    "module_write",
  ]
}

The permissions argument is authoritative. Removing an identifier from the configuration removes it from the role. Existing roles can be imported by UUID. See the Terraform Registry role documentation  for the complete schema.

Create a configurable role with the API

The examples use PO_API_URL, PLATFORM_ORCHESTRATOR_TOKEN, and ORG_ID environment variables. See API authentication for setup.

1. Discover valid permissions

Do not guess permission identifiers. Read the current catalog:

curl "${PO_API_URL}/orgs/${ORG_ID}/permissions" \
  -H "Authorization: Bearer ${PLATFORM_ORCHESTRATOR_TOKEN}"

An abbreviated response looks like this:

{
  "items": [
    {
      "id": "module_read",
      "display_name": "View modules",
      "description": "View modules and module versions.",
      "category": "Modules",
      "level": "read",
      "scopes": ["organization"]
    },
    {
      "id": "module_write",
      "display_name": "Manage modules",
      "description": "Create, update, and delete modules.",
      "category": "Modules",
      "level": "manage",
      "scopes": ["organization"]
    }
  ]
}

The level field preserves built-in-role compatibility. Use the permission id and scopes fields when building and assigning a configurable role.

2. Create the role

This payload creates a role that can view and change modules, but cannot write projects or other entity types:

curl -X POST "${PO_API_URL}/orgs/${ORG_ID}/roles" \
  -H "Authorization: Bearer ${PLATFORM_ORCHESTRATOR_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{
    "display_name": "Module Maintainer",
    "permissions": ["module_read", "module_write"]
  }'

Unknown permission identifiers, duplicates, and malformed payloads return 400 Bad Request.

3. Update the role

PUT /orgs/{orgId}/roles/{roleId} replaces the display name and the entire permission list. Include every permission the role should retain:

curl -X PUT "${PO_API_URL}/orgs/${ORG_ID}/roles/${ROLE_ID}" \
  -H "Authorization: Bearer ${PLATFORM_ORCHESTRATOR_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{
    "display_name": "Module and Provider Maintainer",
    "permissions": [
      "module_read",
      "module_write",
      "module_provider_read",
      "module_provider_write"
    ]
  }'

Omitting a previously assigned permission removes it from the role.

Assign the role with the API

Role assignments use the role UUID returned by the create or list-roles API, not a permission identifier.

Members

Replace a member’s assignments with PUT /orgs/{orgId}/users/{userId}/memberships. A role membership uses "subject_type": "role", places the role UUID in subject, and optionally sets scope:

{
  "memberships": [
    {
      "subject_type": "role",
      "subject": "11111111-1111-1111-1111-111111111111"
    },
    {
      "subject_type": "role",
      "subject": "22222222-2222-2222-2222-222222222222",
      "scope": "project:33333333-3333-3333-3333-333333333333"
    },
    {
      "subject_type": "role",
      "subject": "22222222-2222-2222-2222-222222222222",
      "scope": "env:44444444-4444-4444-4444-444444444444"
    }
  ]
}

Omit scope for an organization assignment. Use project:<project-uuid> for a project assignment and env:<environment-uuid> for an environment assignment.

Service users

Replace a service user’s assignments with PUT /orgs/{orgId}/service-users/{serviceUserId}:

{
  "roles": [
    {
      "id": "11111111-1111-1111-1111-111111111111"
    },
    {
      "id": "22222222-2222-2222-2222-222222222222",
      "scope": "project:33333333-3333-3333-3333-333333333333"
    }
  ]
}

Both assignment endpoints use replace-all semantics. First read the current assignments, then send the complete desired list; omitted assignments are removed.

Compatibility with existing configurable roles

Existing roles that contain legacy aggregate values such as read_all, write_all, or manage_all continue to authorize exactly as before and can still be edited. These compatibility values are intentionally absent from the permission catalog and are not offered when creating new roles. Replace them with granular permissions when you next refine the role.

Top