Namespace-scoped permissions

Combining Flux's namespace primitive with RBAC — patterns for tenant-restricted roles and the gaps where namespaces don't isolate.

Flux permissions are colon-delimited strings with * wildcards. For workflows, the second segment is the namespace: workflow:{namespace}:{name}:{verb}. That gives you a place to anchor tenant or environment isolation in custom roles. This page collects the patterns that work, plus the resource families where the namespace segment is absent and a single role accidentally crosses tenants.

What namespaces do scope

Workflow permissions are the one family that carries {namespace} as a real segment. Routes under /workflows/{namespace}/{workflow_name}/... build the required permission from the request path (see flux/server.py):

required = f"workflow:{wf.namespace}:*:register"
required = f"workflow:{namespace}:{workflow_name}:read"
required = f"workflow:{namespace}:{workflow_name}:run"

AuthService._collect_required_permissions does the same for nested workflows and task-level execute checks. A role granting workflow:tenant-a:*:* covers register, read, run, and task execution inside tenant-a — and only there.

Patterns

Tenant-restricted developer

Registers, runs, and reads any workflow inside their namespace, plus schedules:

flux roles create dev-tenant-a \
  --permissions "workflow:tenant-a:*:*" \
  --permissions "schedule:*:manage" \
  --permissions "schedule:*:read"

workflow:tenant-a:*:* covers all task-level execute checks too because the terminal * matches any remaining segments (see _wildcard_match in flux/security/identity.py).

Tenant-restricted operator

Run, read, and cancel workflows in one namespace; observe executions across the cluster:

flux roles create op-tenant-a \
  --permissions "workflow:tenant-a:*:run" \
  --permissions "workflow:tenant-a:*:read" \
  --permissions "execution:*:read"

The execution:*:read line is the catch — see What namespaces do not scope.

Cross-tenant viewer

Read everywhere, write nowhere. The built-in viewer role already covers this (workflow:*:*:read, execution:*:read, schedule:*:read, plus agent / config / service reads). Clone it if you need a custom variant.

What namespaces do not scope

Workflows are the only family that route the namespace into the required permission string. Everything else uses fixed top-level shapes:

FamilyPermission shapeNamespace segment?
workflowworkflow:{ns}:{name}:{verb}Yes
scheduleschedule:*:read, schedule:*:manageNo
executionexecution:*:readNo
agentagent:*:{verb}No
configconfig:*:read, config:*:manageNo
serviceservice:*:{verb}No
workerworker:*:*No
adminadmin:{area}:{verb} (roles, principals, secrets, metrics)No

Consequences:

Provisioning a tenant-restricted user

End-to-end, for an API-key principal:

# 1. Custom role.
flux roles create dev-tenant-a --permissions "workflow:tenant-a:*:*"

# 2. Service-account principal.
flux principals create \
  --type service \
  --subject dev-tenant-a-bot \
  --external-issuer flux \
  --display-name "tenant-a dev bot" \
  --role dev-tenant-a

# 3. API key.
flux principals api-key create <principal-id> --name ci

# 4. Distribute the key as FLUX_API_KEY.

For OIDC principals, attach the role through your IdP claim mapping or via [flux.security.oidc] default_user_roles so new sign-ins land on the namespace-scoped role instead of viewer.

Failure modes

The wildcard string is the whole isolation primitive. If a resource family does not put the namespace in its permission shape, namespaces will not isolate it.