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.

Role anatomy yaml
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

Exact label match yaml
# Matches nodes with env=production AND team=backend
node_labels:
  env: production
  team: backend

Wildcard Match

Wildcard label match yaml
# Matches any value for the env label
node_labels:
  env: "*"

# Matches all nodes (any label, any value)
node_labels:
  "*": "*"

Multi-Value Match

Multi-value label match yaml
# Matches nodes where env is staging OR development
node_labels:
  env:
    - staging
    - development

Regex Match

Regex label match yaml
# 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:

  1. Collects all allow rules from every role assigned to the user.
  2. Collects all deny rules from every role assigned to the user.
  3. 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.

Deny overrides example yaml
# 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.

Allowed logins yaml
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 usernamealice
{{internal.traits.team}}Team trait (from SSO or user metadata)engineering
{{internal.traits.email}}User emailalice@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_ttlduration12hMaximum lifetime for user certificates
require_session_mfastring""MFA type required per-session
port_forwardingbooltrueAllow SSH port forwarding
file_copybooltrueAllow 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:

  1. Collect all roles assigned to the user.
  2. Merge all allow rules — the union of all allowed node labels and logins.
  3. Merge all deny rules — the union of all denied node labels and logins.
  4. Check if any allow rule matches the target node and requested login.
  5. Check if any deny rule matches the target node and requested login.
  6. 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.