RBAC

4 min read

Orkestra never auto-creates permissions. Every right your operator has is generated from your Katalog, reviewed by you, committed to source control, and applied explicitly. Nothing is hidden inside the Helm chart.


How it works

Orkestra reads your Katalog and derives the minimal set of permissions required to do exactly what you declared. Both steps below run entirely offline — no cluster required.

Step 1: preview the permissions

ork validate --full

Shows every RBAC rule that will be requested, broken down per CRD and per component (runtime and gateway). This is the review step — you see exactly what the bundle will contain before any YAML is written.

Step 2: generate the bundle

ork generate bundle

If your file is named katalog.yaml or komposer.yaml, --file is optional — Orkestra finds it automatically. For any other name:

ork generate bundle -f my-katalog.yaml -o bundle.yaml

The bundle is a multi-document YAML stream. Review it, commit it, apply it:

kubectl apply -f bundle.yaml

What the bundle contains

Namespace
ServiceAccount     orkestra              (runtime)
ServiceAccount     orkestra-gateway      (gateway)
ServiceAccount     orkestra-cc           (control center)
ClusterRole        orkestra              (runtime rules only)
ClusterRoleBinding orkestra
ClusterRole        orkestra-gateway      (gateway rules only)
ClusterRoleBinding orkestra-gateway
ConfigMap          orkestra-katalog      (embedded katalog YAML)

Three separate ServiceAccounts, each with its own ClusterRole. The control center gets only a ServiceAccount — it has no direct cluster access.


Derived permissions, not wildcards

Traditional operators often ship with:

- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

This grants every API access to the operator process. Orkestra replaces it with rules derived directly from what you declared in the Katalog:

- apiGroups: ["platform.orkestra.io"]
  resources: ["websites", "databases"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["platform.orkestra.io"]
  resources: ["websites/status", "databases/status"]
  verbs: ["get", "update", "patch"]

Only the API groups you declared. Only the resource kinds those groups produce. Only the verbs those resources need. Status subresources get a narrower verb set — delete is never granted on them.

Built-in Kubernetes resources (Deployments, Services, ConfigMaps, etc.) only appear in the rules if your Katalog actually uses them. If your operator creates no Deployments, the runtime has no apps/deployments permission.


Runtime vs gateway — permissions are separate

The runtime and gateway run as separate processes with separate credentials. Their permissions do not overlap.

Runtime (orkestra ClusterRole) is scoped to what the reconciler needs:

WhatPermissions
Your CRDsFull CRUD + watch on main and /status subresource
Built-in resources used in your KatalogFull CRUD + watch (only those declared)
Kubernetes leasesget, create, update — for leader election
Eventscreate, patch — for status reporting

Gateway (orkestra-gateway ClusterRole) is scoped to what admission and certificate management needs:

WhatPermissions
ValidatingWebhookConfigurationsget, list, watch, create, update, patch, delete
MutatingWebhookConfigurationssame (only if mutation rules are enabled)
Secretsget, create, update — for TLS certificate storage
Namespacesget, patch — for deletion-protection label management
CustomResourceDefinitionspatch — for CA bundle injection (only if conversion is enabled)

A compromise of the gateway cannot read or modify your CRs. A compromise of the runtime cannot touch webhook configurations.


Permissions scale with your Katalog

Gateway permissions are only generated if the features that need them are declared. Runtime permissions only include built-in resources your Katalog actually uses.

Katalog featureAdded to
Each CRD you declareRuntime — CRUD on that group/resource
Deployments, Services, etc. in onCreateRuntime — only the kinds you use
Validation rulesGateway — validatingwebhookconfigurations
Mutation rulesGateway — mutatingwebhookconfigurations
Deletion protectionGateway — namespaces get/patch
Conversion webhooksGateway — customresourcedefinitions patch (CA bundle)
TLS / certificatesGateway — secrets

If you declare no validation rules, the gateway ClusterRole has no admissionregistration.k8s.io entries at all.


Generating for specific components

By default ork generate bundle includes all three components. Use --for to generate only what you need:

# Runtime only
ork generate bundle --for runtime

# Gateway only
ork generate bundle --for gateway

# Runtime and control center, no gateway
ork generate bundle --for runtime,cc

Valid values: runtime (alias run), gateway (alias gw), cc (aliases controlcenter, control-center).

This is useful when deploying components to different clusters or namespaces, or when rotating credentials for one component without touching the others.


Rerun after Katalog changes

Whenever you add a new CRD or resource type, run ork validate --full first to see exactly which permissions are being added or removed, then regenerate:

ork validate --full          # review the diff in permissions
ork generate bundle -o bundle.yaml
kubectl apply -f bundle.yaml

The bundle output is deterministic — it diffs cleanly in GitOps workflows and PRs.


GitOps compatibility

The generated bundle is a plain Kubernetes YAML file. It works with any GitOps tool (Flux, ArgoCD, Helm, plain kubectl apply). Lint it, diff it in PRs, require approval before it reaches the cluster. No cluster-admin access required at any point.