RBAC Configuration
Mezite uses role-based access control (RBAC) to govern who can SSH into which nodes. Roles define allow and deny rules that match against node labels, specify allowed OS logins, and set session options. This guide covers the role system in depth: structure, label matching, deny-overrides-allow semantics, template variables, built-in roles, and practical examples.
Role Structure
A Mezite role has three main sections: allow, deny, and
options. The allow and deny sections specify which nodes a
user can or cannot access. Options control session behavior.
kind: role
metadata:
name: example-role
description: "Human-readable description of this role"
spec:
options:
# Maximum session TTL for users with this role
max_session_ttl: 12h
# Whether to require MFA for SSH sessions
require_session_mfa: ""
# Allow port forwarding
port_forwarding: true
# Allow SCP/SFTP file transfers
file_copy: true
allow:
# Label selectors — which nodes this role grants access to
node_labels:
env: staging
# Which OS logins are permitted
logins:
- ubuntu
- deploy
# Access request permissions (optional)
request:
roles:
- ssh-production
max_duration: 4h
# Review (approve) permissions (optional)
review_requests:
roles:
- ssh-production
deny:
# Deny rules override allow rules
node_labels:
sensitivity: restricted
logins:
- root Label-Based Matching
Labels are key-value pairs attached to nodes via the agent configuration. Roles grant or deny SSH access based on label selectors.
Exact Match
# Matches nodes with env=production AND team=backend
node_labels:
env: production
team: backend Wildcard Match
# Matches any value for the env label
node_labels:
env: "*"
# Matches all nodes (any label, any value)
node_labels:
"*": "*" Multi-Value Match
# Matches nodes where env is staging OR development
node_labels:
env:
- staging
- development Regex Match
# Matches nodes where team starts with "eng-"
node_labels:
team: "^eng-.*$" When multiple labels are specified, all must match (AND logic). When multiple values are specified for a single label, any can match (OR logic).
Deny Overrides Allow
Mezite uses a deny-overrides-allow evaluation model. When a user has multiple roles, the system:
-
Collects all
allowrules from every role assigned to the user. -
Collects all
denyrules from every role assigned to the user. - Grants access only if at least one allow rule matches AND no deny rule matches.
This means a single deny rule in any role will block access, even if other roles explicitly allow it. Use deny rules sparingly and intentionally.
# Role A: allows SSH to all production nodes
kind: role
metadata:
name: ssh-all-production
spec:
allow:
node_labels:
env: production
logins:
- ubuntu
- deploy
deny: {}
---
# Role B: denies SSH to PCI nodes
kind: role
metadata:
name: deny-pci
spec:
allow: {}
deny:
node_labels:
compliance: pci
logins:
- root
- ubuntu
- deploy
# If a user has both Role A and Role B:
# - They CAN access env=production nodes (allowed by A)
# - They CANNOT access compliance=pci nodes (denied by B)
# - A production node with compliance=pci is DENIED (deny wins) Allowed Logins
The logins field in a role specifies which OS-level usernames
the Mezite user can authenticate as on remote nodes. The login requested at
connection time (via
msh ssh --login=) must appear in the allow.logins list and must not appear in the deny.logins list.
spec:
allow:
node_labels:
env: production
logins:
- ubuntu
- deploy
- "{{internal.traits.username}}" # Dynamic: maps to Mezite username
deny:
logins:
- root # Never allow root, even if another role permits it Template Variables
Roles support template variables that are expanded at evaluation time. This allows you to write generic roles that adapt to each user based on their identity and traits (often sourced from SSO).
| Variable | Description | Example Value |
|---|---|---|
{{internal.traits.username}} | Mezite username | alice |
{{internal.traits.team}} | Team trait (from SSO or user metadata) | engineering |
{{internal.traits.email}} | User email | alice@example.com |
{{internal.traits.logins}} | Allowed logins from SSO claims | ["alice", "ubuntu"] |
Template variable usage yaml kind: role
metadata:
name: team-scoped-ssh
description: "SSH access scoped to the user's team nodes"
spec:
allow:
# Only access nodes labeled with the user's team
node_labels:
team: "{{internal.traits.team}}"
# Login as the user's own username
logins:
- "{{internal.traits.username}}"
deny: {}
When a user with team=platform trait uses this role, the label
selector expands to team: platform, restricting them to
nodes owned by their team.
Session Options
The options section of a role controls session behavior. When
a user has multiple roles, the most restrictive option value wins.
Option Type Default Description max_session_ttlduration 12hMaximum lifetime for user certificates require_session_mfastring ""MFA type required per-session port_forwardingbool trueAllow SSH port forwarding file_copybool trueAllow SCP and SFTP file transfers
Restrictive session options yaml kind: role
metadata:
name: ssh-restricted
spec:
options:
max_session_ttl: 4h
require_session_mfa: "totp"
port_forwarding: false
file_copy: false
allow:
node_labels:
env: production
sensitivity: high
logins:
- ubuntu
deny:
logins:
- root
Built-in Roles
Mezite ships with three built-in roles that cover common access
patterns. You can assign these directly or use them as templates for
custom roles.
admin
Full SSH access to all nodes and all administrative functions. Intended
for platform operators.
Built-in: admin yaml kind: role
metadata:
name: admin
spec:
allow:
node_labels:
"*": "*"
logins:
- root
- "{{internal.traits.username}}"
# Can approve access requests for any role
review_requests:
roles:
- "*"
deny: {}
access
Standard user SSH access. Can connect to nodes matching their labels but
cannot perform administrative actions or log in as root.
Built-in: access yaml kind: role
metadata:
name: access
spec:
allow:
node_labels:
"*": "*"
logins:
- "{{internal.traits.username}}"
deny:
logins:
- root
auditor
Read-only access to audit logs and session recordings. Cannot SSH into
nodes directly.
Built-in: auditor yaml kind: role
metadata:
name: auditor
spec:
allow:
# No node access — only audit permissions
audit:
events: ["*"]
sessions: ["*"]
deny:
node_labels:
"*": "*"
Creating Roles with mezctl
Use mezctl to create, update, and manage roles.
Role management commands bash # Create a role from a YAML file
mezctl roles create ssh-production.yaml
# List all roles
mezctl roles ls
# NAME TYPE DESCRIPTION
# admin builtin Full cluster access
# access builtin Standard user access
# auditor builtin Audit log and session access
# ssh-production custom SSH access to production nodes
# View a specific role
mezctl roles show ssh-production
# Update a role
mezctl roles update ssh-production.yaml
# Delete a role
mezctl roles delete ssh-production
# Assign roles to a user
mezctl users update alice --set-roles=access,ssh-production
# Add a role without replacing existing ones
mezctl users update alice --add-roles=ssh-staging
# Remove a role
mezctl users update alice --remove-roles=ssh-staging
Example Role Definitions
SSH to Production (Non-Root)
ssh-production.yaml yaml kind: role
metadata:
name: ssh-production
description: "SSH access to production nodes, non-root"
spec:
options:
max_session_ttl: 8h
allow:
node_labels:
env: production
logins:
- ubuntu
- deploy
deny:
logins:
- root
node_labels:
sensitivity: restricted
Team-Scoped Access with Template Variables
ssh-team-scoped.yaml yaml kind: role
metadata:
name: ssh-team-scoped
description: "SSH access restricted to the user's team nodes"
spec:
options:
max_session_ttl: 12h
allow:
node_labels:
team: "{{internal.traits.team}}"
logins:
- "{{internal.traits.username}}"
- ubuntu
deny:
logins:
- root
Staging-Only with File Copy Disabled
ssh-staging-readonly.yaml yaml kind: role
metadata:
name: ssh-staging-readonly
description: "SSH to staging, no file transfers or port forwarding"
spec:
options:
max_session_ttl: 4h
port_forwarding: false
file_copy: false
allow:
node_labels:
env: staging
logins:
- ubuntu
deny: {}
Requestable Production Access
can-request-production.yaml yaml kind: role
metadata:
name: can-request-production
description: "Can request temporary production SSH access"
spec:
allow:
# No direct node access — only request permissions
request:
roles:
- ssh-production
max_duration: 4h
reason_required: true
deny: {}
Role Evaluation Order
When a user attempts to SSH into a node, Mezite evaluates roles in this
order:
- Collect all roles assigned to the user.
-
Merge all
allow rules — the union of all allowed node labels
and logins.
-
Merge all
deny rules — the union of all denied node labels
and logins.
-
Check if any allow rule matches the target node and requested login.
-
Check if any deny rule matches the target node and requested login.
- Grant access only if step 4 is true and step 5 is false.
Debugging Role Evaluation
Debug role evaluation bash # Show all roles and effective permissions for a user
mezctl users show alice --verbose
# USERNAME: alice
# ROLES: access, ssh-production
#
# EFFECTIVE SSH ACCESS:
# ALLOW: env=production (logins: ubuntu, deploy)
# DENY: logins: root
# Test if a user can access a specific node
mezctl access check --user=alice --resource=node/web-server-01 --login=ubuntu
# ALLOWED: yes (matched role: ssh-production)
mezctl access check --user=alice --resource=node/web-server-01 --login=root
# DENIED: login "root" denied by role "access"
Next Steps
- SSH Access — Apply SSH-specific RBAC policies.
- Access Requests — Set up approval
workflows for elevated access.
- SSO Setup — Map SSO attributes to Mezite
roles automatically.
- Audit Logging — Monitor role evaluation
in audit logs.