Skip to main content
Prime feature only
This feature is only available with a Prime subscription. See plans or contact sales.

Backstage RBAC

Role-based access control (RBAC) in kubriX Backstage is built on the Backstage RBAC backend plugin. It uses a layered permission model combining a CSV policy file with optional conditional policies.


Layered Permission Model

Permissions are organized in three layers. Each layer adds capabilities on top of the previous one.

Layer 1: role:default/authenticated  →  all logged-in users
Layer 2: role:default/kubrixdemo → viewers group (reserved for future viewer-specific permissions)
Layer 3: role:default/kubrixdev → editors + kubrix groups (advanced developer features)

Superusers (configured in permission.rbac.admin.superUsers) bypass all policies and always get ALLOW.

Layer 1 — Authenticated (all users)

Every authenticated user gets the following permissions:

PermissionAction
catalog-entityread
catalog.entity.readread
catalog.location.readread
catalog.entity.createcreate
catalog.entity.refreshupdate
scaffolder-templateread
scaffolder-actionuse
scaffolder.task.readread
scaffolder.task.createcreate
scaffolder.task.canceluse

Layer 3 — kubrixdev (editors / kubrix)

Members of group:default/editors or group:default/kubrix additionally get:

PermissionAction
catalog-entityupdate
catalog.location.createcreate
catalog.location.deletedelete
scaffolder.template.managementuse
kubernetes.clusters.readread
kubernetes.resources.readread
kubernetes.proxyuse
bulk-importuse
kyverno.*read
argocd.view.readread
policy-entity.*read / create / update / delete
announcement.entity.*create / update / delete
mssv.view.readread

Group → Role Mappings

Group memberships are mapped to roles in the CSV policy file (rbac-policy.csv). All groups also inherit Layer 1 via an explicit mapping to role:default/authenticated:

# All groups get Layer 1 baseline
g, group:default/viewers, role:default/authenticated
g, group:default/editors, role:default/authenticated
g, group:default/kubrix, role:default/authenticated
g, group:default/admins, role:default/authenticated

# Layer 2 (viewers)
g, group:default/viewers, role:default/kubrixdemo

# Layer 3 (editors / kubrix / admins)
g, group:default/editors, role:default/kubrixdev
g, group:default/kubrix, role:default/kubrixdev
g, group:default/admins, role:default/kubrixdev
note

The Backstage RBAC plugin only applies CSV p lines to roles that have a source: csv-file origin. Adding explicit g lines for every group ensures the role is created with the correct source. Using defaultRole in config creates the role with source: configuration, which conflicts with CSV policies and prevents them from being applied.


Template Visibility

By default, all authenticated users can read all catalog entities including Templates (Layer 1). When conditional policies are enabled, Template visibility is filtered per user:

  • Non-Template entities — always readable by all authenticated users
  • Template entities — readable only if the user is an owner or the template has the kubrix.io/visibility: shared annotation

Making a Template Visible to All Users

Add the annotation to your template's catalog-info.yaml or template.yaml:

metadata:
annotations:
kubrix.io/visibility: shared

Restricting a Template to a Specific Group

Set the template's owner to the group that should have access:

spec:
owner: group:default/editors

Only members of that group will see and be able to execute the template. Superusers always see all templates.

Access Matrix Example

TemplateOwnerSharedviewerseditorsadmins
docs-templategroup:default/kubrixyesALLOWALLOWALLOW
docs-template2group:default/editorsnoDENYALLOWALLOW
docs-template3group:default/viewersnoALLOWDENYALLOW (superuser)
docs-template4group:default/adminsnoDENYDENYALLOW

Configuration

Enabling Conditional Policies

In your *values*.yaml, set the path to the conditional policies file:

appConfig:
permission:
rbac:
conditionalPoliciesFile: /opt/app-root/src/rbac/conditional-policies.yaml

The file is automatically mounted from the conditional-policies ConfigMap via a projected volume. The ConfigMap is generated from rbac.conditionalPolicies in the Helm values.

Helm Values Structure

rbac:
# If true: Helm render fails when conditionalPolicies is empty.
# If false: silently skips the ConfigMap (no conditional policies applied).
enforceConditionalPolicies: false

conditionalPolicies:
# Key = logical name for Helm map merging. Not visible to Backstage.
# Multiple entries are rendered as YAML multi-document (separated by ---).
authenticated-catalog-read:
result: CONDITIONAL
roleEntityRef: role:default/authenticated
pluginId: catalog
resourceType: catalog-entity
permissionMapping:
- read
conditions:
anyOf:
- not:
rule: IS_ENTITY_KIND
resourceType: catalog-entity
params:
kinds:
- Template
- rule: IS_ENTITY_OWNER
resourceType: catalog-entity
params:
claims:
- $ownerRefs
- rule: HAS_ANNOTATION
resourceType: catalog-entity
params:
annotation: kubrix.io/visibility
value: shared

Adding Custom Conditional Policies

Because rbac.conditionalPolicies is a Helm map (not a list), customer values files are deep-merged automatically. Add new entries in your customer values without repeating the base policies:

# values-customer.yaml
rbac:
conditionalPolicies:
my-custom-policy:
result: CONDITIONAL
roleEntityRef: role:default/kubrixdev
pluginId: catalog
resourceType: catalog-entity
permissionMapping:
- read
conditions:
rule: HAS_LABEL
resourceType: catalog-entity
params:
label: my-team/restricted

Helm merges this with the base authenticated-catalog-read entry. Both policies are written into the single conditional-policies.yaml file separated by ---.


Volume Mount

The CSV policy file and conditional policies file are both mounted via a projected volume that combines two ConfigMaps into a single directory:

extraVolumes:
- name: rbac-policy
projected:
defaultMode: 420
sources:
- configMap:
name: rbac-policy
- configMap:
name: conditional-policies
optional: true # skipped gracefully if enforceConditionalPolicies=false
extraVolumeMounts:
- name: rbac-policy
mountPath: /opt/app-root/src/rbac
tip

optional: true on the conditional-policies ConfigMap source ensures the pod starts without error even when no conditional policies are configured.


Disabling Conditional Policies

To run without conditional policies (all users see all templates):

rbac:
enforceConditionalPolicies: false
conditionalPolicies: {}

And comment out conditionalPoliciesFile in appConfig.permission.rbac.

note

Simply commenting out conditionalPoliciesFile while the database still holds previously written conditional policies will not remove them. The plugin only clears DB entries when it reads the file on startup and finds them removed. To fully clear, either delete and recreate the Backstage database or use the RBAC REST API to delete conditions manually.


File Reload

With policyFileReload: true, the RBAC plugin watches both the CSV and conditional policies files for changes and reloads without a pod restart:

appConfig:
permission:
rbac:
policyFileReload: true

This applies to both rbac-policy.csv and conditional-policies.yaml.