Mach5 Role Patterns (Glob Syntax)
This document defines the glob-style authorization pattern language used by the Mach5 authorization system.
Mach5 uses a glob-like syntax to define permissions for namespaces, stores, indexes, pipelines, etc.
Each role is a pattern, not a literal string.
Examples:
namespace:*/index:*/read
store:*/create
namespace:default/connection:iceberg/update
These patterns are compiled to safe, anchored regular expressions and matched against required permission strings.
Special Characters
| Character | Meaning | Example | Matches |
|---|---|---|---|
* | Wildcard segment (zero or more characters except / or :) | namespace:* | namespace:prod |
? | Single wildcard character | index:?/read | index:a/read |
\X | Literal X (escape) | \* | literal * |
\\ | Literal backslash | \\ | \ |
Important: Backslash does not become part of the output. It only means “treat the next character literally.”
Backslash Escaping Rules
| Input | Interpreted As | Notes |
|---|---|---|
\* | literal * | not a wildcard |
\? | literal ? | not a wildcard |
\\ | literal backslash | needed if resource names contain \ |
| any other character | treated literally | auto-escaped for regex |
EXACT behavior of escaped characters:
namespace:a\\c matches "namespace:a\c"
namespace:a\*c matches "namespace:a*c"
namespace:a\?c matches "namespace:a?c"
If a user wants the actual backslash, they must double-escape it:
\ --> \\
Examples (Good vs Bad Patterns)
Good
namespace:*/index:*/read
namespace:default/index:products/update
store:*/delete
namespace:a\\b/read (literal backslash)
namespace:a\*b/read (literal *)
Bad (invalid escapes)
namespace:default\ trailing backslash does nothing
namespace:\*foo\ incomplete escape
Security Notes
- Role patterns cannot inject arbitrary regex (fully escaped).
- Only
*and?have wildcard meaning. - All resource names are 100% safe, even if containing
.+()$[]{}etc.
Overview - Authorization Pattern Specification
This specification applies to patterns used in roles such as:
namespace:*/connection:*/create
store:*/delete
storeroute:*/read
namespace:*/entity:*/*
It describes exactly how patterns behave, how wildcard characters work, and how escaping is handled.
A role pattern is a glob-like string that matches entire permission identifiers such as:
namespace:default/entity:customer/read
namespace:prod/connection:prod-s3/update
Patterns are converted to anchored regular expressions of the form:
^<converted-pattern>$
Meaning: the pattern must match the full permission string exactly.
Glob Syntax
The pattern language consists of:
| Symbol | Meaning |
|---|---|
* | wildcard segment (matches any string except / and :) |
? | wildcard matching exactly one character |
\* | literal * |
\? | literal ? |
\\ | literal backslash |
| any other character | treated literally (auto-escaped for regex) |
1. * Wildcard Segment
* matches any non-empty string without crossing / or : boundaries.
Equivalent regex:
[^/:]*
Examples:
| Pattern | Matches | Does Not Match |
|---|---|---|
namespace:* | namespace:abc | namespace:abc/def |
namespace:events_*/* | namespace:events_log/read | namespace:system_log/read |
namespace:events_user/update | namespace:system_user/read | |
entity:* | entity:customer | entity: |
2. ? Single Character Wildcard
? matches exactly one character.
Equivalent regex:
.
Examples:
| Pattern | Matches | Does Not Match |
|---|---|---|
namespace:he?lo | namespace:hello, namespace:hezlo | namespace:helo |
store:? | store:a | store:ab |
3. Escaping Special Characters
The escape character is \.
| Literal You Want | Pattern Syntax |
|---|---|
* | \* |
? | \? |
| \ | \\ |
All escaped characters are treated literally.
Examples:
| Pattern | Matches |
|---|---|
namespace:my\*file | namespace:my*file |
entity:version\?2 | entity:version?2 |
path:folder\\name | path:folder\name |
4. Literal Characters
All other characters including regex metacharacters are escaped using regex::escape().
This makes the system regex-safe.
Literal characters include:
. + ( ) [ ] { } ^ $ | /
Example:
Pattern:
namespace:file.(name)[test]{v}+ok
Matches:
namespace:file.(name)[test]{v}+ok
Only that exact string.
5. Anchoring
Every compiled regex is anchored:
^pattern$
Thus:
| Pattern | Matches | Does Not Match |
|---|---|---|
namespace:* | namespace:abc | xnamespace:abcx |
entity:*/* | entity:abc/read | entity:abc/read/extra |
This prevents partial-match privilege escalation.
6. Trailing Backslash Rule
If a pattern ends with a single \, it is treated as a literal backslash.
Example:
Pattern --> Text
namespace:hello\ --> namespace:hello\
Examples
Permission Examples
namespace:default/entity:customer/create
namespace:default/entity:customer/read
namespace:test/entity:item42/update
store:mystore/delete
Pattern Examples
| Pattern | Matches | Reason |
|---|---|---|
namespace:*/entity:*/* | namespace:default/entity:customer/read | last * matches read |
store:*/delete | store:mystore/delete | typical action pattern |
storeroute:\?/* | storeroute:?/create | literal ? using \? |
Summary Table
| Token | Meaning |
|---|---|
* | segment wildcard (zero or more chars, no / or :) |
? | single-char wildcard |
\* | literal * |
\? | literal ? |
\\ | literal \ |
| all others | literal (regex-escaped) |
| anchored | full-string match |
Role Patterns: /admin Access
The /admin suffix allows a user to gain full recursive access to all resources. This complements your existing fine-grained roles:
- Namespaced entities:
namespace:*/index:*,namespace:*/script:*,namespace:*/warehouse:*, etc.
- Non-namespaced entities:
store:*,storeroute:*, etc.
The /admin suffix recursively covers all entities without needing to assign each role individually.
Syntax /admin suffix
namespace:<namespace-pattern>/admin
namespace:*/admin // matches all namespaces
namespace:prod/admin // matches only the "prod" namespace
- Grants full access to all entities under the namespace, including:
- Namespaced entities:
index,script,warehouse,materializedview,notebook,connection, ingestpipeline, etc.
- Namespaced entities:
- Must appear at the very end of the role string (unescaped).
- Wildcards
*?are allowed in namespace names.
Example:
| Role Pattern | Effective Access |
|---|---|
namespace:*/admin | All entities (index, script, warehouse, etc.) in all namespaces |
namespace:prod/admin | All entities in the prod namespace only |
store:*/admin | All CRUD access on all stores |
Important Rules
/adminmust appear unescaped at the end of the role string.- Escaping the slash (
\/admin) disables recursion and matches the literal string. - Namespace-level
/admingrants full access to all namespaced entities. - Works alongside existing granular roles for selective access.
- Wildcards
*may be used to match multiple namespaces.
Examples
| Role Pattern | Matches Example Entities | Notes |
|---|---|---|
namespace:*/admin | namespace:prod/index:idx/read | Full recursive access for all namespaced entities |
namespace:prod/admin | namespace:prod/script:script1/update | Full access only in prod namespace |
namespace:prod/connection:main/admin | namespace:prod/connection:main/read | Full access for that namespace, and that connection entitity |
namespace:*\/admin | namespace:prod/admin | Only literal match, recursion disabled. Avoid this pattern |
admin | All entities across all namespaces | Super-admin full access for everything |
Summary
- Use
/adminfor full recursive access to entities. - Namespace-level
/admin= full access across the namespace. - Wildcards
*may be used to cover multiple namespaces. - Escaping the slash disables recursion. Avoid such pattern
- Works alongside existing fine-grained roles to allow selective access.
Real-World Role Examples (Namespaces, Entities, and Actions)
This section provides concrete, real-world example values that match each of the authorization patterns currently stored in Keycloak or can be added as needed. Examples are grouped by domain (namespace, store, storeroute, license, index, etc.).
Each example demonstrates:
- realistic namespace names
- realistic entity names
- CRUD operations
- multi-segment resource paths
- how wildcards expand in practice
All examples assume the standard Mach5 permission format:
entity:<name>/<action>
namespace:<name>/entity:<name>/<action>
1. Admin
Role: admin
Matches everything (^.*$).
Examples (all allowed):
namespace:default/index:products/read
store:mystore/delete
license/metered/data/read
namespace:analytics/notebook:model-trainer/update
Role: /admin suffix
Full recursive access within the entity or namespace.
Examples:
namespace:default/admin --> all entities in default namespace
store:*/admin --> full CRUD on store
namespace:analytics/*:*/admin --> all entities in analytics namespace
namespace:*/index:*/admin --> all indexes in all namespaces
2. Namespace-level Roles
These roles apply to operations on a namespace itself.
namespace:*/create
Examples matching:
namespace:default/create
namespace:prod/create
namespace:analytics/create
namespace:test-env/create
namespace:*/read
Examples:
namespace:default/read
namespace:prod/read
namespace:research/read
namespace:*/delete
Examples:
namespace:legacy/delete
namespace:unused/delete
3. Store Roles
These roles do not involve namespaces.
store:*/create
Examples:
store:mystore/create
store:customer-cache/create
store:*/read
store:mystore/read
store:transactions/read
store:*/delete
store:temp-store/delete
store:data-lake/delete
4. Store Route Roles
These roles do not involve namespaces.
storeroute:*/create
storeroute:route-a/create
storeroute:bulk-ingest/create
storeroute:*/read
storeroute:route-a/read
storeroute:nightly-sync/read
storeroute:*/delete
storeroute:route-a/delete
storeroute:backup/delete
5. License Roles
These roles do not involve namespaces.
license/*/data/read
license/status/data/read
license/metered/data/read
6. Connections (namespace-scoped)
Pattern format:
namespace:<ns>/connection:<conn>/<action>
namespace:*/connection:*/create
namespace:default/connection:snowflake/create
namespace:prod/connection:kafka/create
namespace:*/connection:*/read
namespace:default/connection:iceberg/read
namespace:research/connection:bigquery/read
namespace:*/connection:*/update
namespace:dataeng/connection:gcs/update
namespace:*/connection:*/delete
namespace:test/connection:s3/delete
namespace:*/connection:*/test/read
Test connection
This role is to allow testing the connection parameters when creating or editing a connection.
namespace:dev/connection:local-s3/test/read
7. Ingest Pipelines
Pattern format:
namespace:<ns>/ingestpipeline:<name>/<action>
Examples:
namespace:default/ingestpipeline:order-events/create
namespace:default/ingestpipeline:order-events/read
namespace:analytics/ingestpipeline:etl-job/update
namespace:prod/ingestpipeline:bulk-loader/delete
8. Materialized Views
Pattern format:
namespace:<ns>/materializedview:<name>/<action>
namespace:default/materializedview:sales-daily/create
namespace:default/materializedview:sales-daily/read
namespace:prod/materializedview:customer-agg/update
namespace:test/materializedview:temp/delete
9. Notebooks
Pattern format:
namespace:<ns>/notebook:<name>/<action>
namespace:default/notebook:model-trainer/create
namespace:ml/notebook:experiment-12/read
namespace:ml/notebook:experiment-12/update
namespace:ml/notebook:obsolete/delete
10. Scripts
Pattern format:
namespace:<ns>/script:<name>/<action>
namespace:default/script:migration/create
namespace:default/script:migration/read
namespace:dataflow/script:cleanup/update
namespace:dataflow/script:cleanup/delete
11. Warehouses
Pattern format:
namespace:<ns>/warehouse:<name>/<action>
namespace:prod/warehouse:s3/create
namespace:prod/warehouse:s3/read
namespace:prod/warehouse:s3/update
namespace:prod/warehouse:s3/delete
12. Index Aliases
Pattern format:
namespace:<ns>/indexalias:<name>/<action>
namespace:default/indexalias:customers/create
namespace:default/indexalias:customers/read
namespace:default/indexalias:customers/update
namespace:default/indexalias:customers/delete
13. Indexes
Pattern Format:
namespace:<ns>/index:<name>/<action>
CRUD on index itself
namespace:default/index:products/create
namespace:default/index:products/read
namespace:default/index:products/update
namespace:default/index:products/delete
Full access on all indexes in default namespace:
namespace:default/index:*/admin
Roles Coverage Guide
| Role Pattern | Coverage / Description | Notes |
|---|---|---|
admin | Full access to all resources (namespaced & non-namespaced) | Super-admin role |
namespace:<N>/admin | Full recursive access to all entities in namespace <N> | Namespace-scoped admin |
| Including index, script, warehouse, notebook, materialized view, connection, pipeline, etc. | ||
namespace:*/admin | Same as above but applies to all namespaces | Global namespace admin |
namespace:<N>/connection:<C>/admin | Full access to connection <C> in namespace <N> | Connection-scoped admin |
Non-namespaced roles (e.g., store:*/admin) | Grants access only to specified resource types | Non-namespaced resource admin |
namespace:<N>/... (normal roles without /admin) | Scoped access only to the specific resource/action defined | Least-privilege access |
Escaped admin suffix (e.g., namespace:*\/admin) | Literal match only; no recursive admin access | Avoid unless literal suffix is intended |
Usage Recommendations
-
Super admin: Use
adminfor super-admin users needing access to everything in all namespaces and non-namespaces. -
Namespace-level /admin: Use
namespace:<namespace>/adminto grant full access within a single namespace, ideal for team leads or environment owners. -
Entity-level /admin: Use
namespace:<namespace>/connection:<connection>/adminto give full access to a particular namespace entity. -
Granular roles: Use specific roles (e.g.,
namespace:<ns>/index:*/read,store:*/delete) when least-privilege access is desired using the actionscreate,read,updateanddelete. Usenamespace:analytics/*:*/readto grant read only access for the namespace analytics, ideal for viewer only user like business analyst. -
Avoid escaped
/admin(\/admin):