Access Requests

Status: Available. Access requests support just-in-time (JIT) elevation, multi-reviewer approval workflows, automatic time-based expiry, webhook notifications, and full CLI/API support. A single request can ask for whole roles, access to specific SSH nodes, or both at once. When approved, the requester's certificate is reissued for the grant window with the requested roles merged in and access to the named nodes unlocked; everything expires together at the end of one TTL.

Mezite supports just-in-time (JIT) access through an access request workflow. Instead of granting permanent elevated SSH privileges, users request temporary access only when they need it. Designated approvers review and approve (or deny) requests, and the elevated access automatically expires after a configured duration. Every step is recorded in the audit log.

Role requests vs. resource requests

There are two ways to scope a request, and they compose freely:

  • Role requests — ask for one or more roles. On approval the requester gains everything those roles grant for the duration of the request. Use this when someone needs a body of access (for example, "all production SSH").
  • Resource requests — ask for access to specific SSH nodes by name. On approval the requester gains access to exactly those nodes and nothing else. Use this when someone needs to reach one or two named hosts rather than a whole environment.

A resource request is always a strict subset of access the requester's roles already permit: a node can only be requested if one of the requester's roles names it in a request_resources clause (see RBAC Setup below). This keeps resource requests from becoming an end-run around role policy. Matching is by exact node name — there are no wildcards.


JIT Access Escalation Concept

Just-in-time access is a security pattern where users operate with minimal SSH privileges by default and request elevated access only when needed. For example, a developer might have SSH access to staging nodes at all times but must request temporary access to production nodes through an approval workflow.

  • Temporary — Elevated access has a fixed duration and expires automatically.
  • Audited — Every request, approval, denial, and expiration is recorded.
  • Approved — A designated approver must explicitly grant the request before access is activated.
  • Scoped — Requests target specific roles or specific SSH nodes, not blanket access.

Request Lifecycle

An access request moves through a defined set of states:

Request lifecycle text
create ──> pending ──> approved ──> expired
              │           │
              │           └──> revoked   (requester self-drop or admin)
              ├──> denied
              └──> cancelled            (requester or admin, while pending)

States:
  pending    — Request submitted, awaiting approver review
  approved   — Approver granted the request; elevated roles are active until expiry
  denied     — Approver rejected the request
  expired    — TTL elapsed, elevated roles automatically revoked
  cancelled  — A still-pending request was withdrawn
  revoked    — An approved request was dropped before expiry
Request flow diagram text
requester             Mezite auth service          approver
     |                        |                        |
     |-- msh request create ->|                        |
     |   (role: ssh-prod,     |-- notification ------->|
     |    reason: "deploy")   |                        |
     |                        |                        |
     |                        |<-- approve ------------|
     |                        |    (mezctl)            |
     |                        |                        |
     |<-- access granted -----|                        |
     |   (4h TTL)             |                        |
     |                        |                        |
     |   ... user SSH's ...   |                        |
     |                        |                        |
     |-- access expires ----->|                        |
     |   (automatic)          |-- audit event -------->|

Creating Requests with msh

Create access request bash
# Request access to a role
msh request create --roles=ssh-production --reason="Deploying hotfix for order processing"

# Output:
# Access request created: req_a1b2c3d4e5f6
# State:  pending
# Roles:  ssh-production
# Reason: Deploying hotfix for order processing

# Request access to a specific SSH node (the form is ssh-node:<name>)
msh request create --resource=ssh-node:web-01 --reason="Investigating incident XYZ-123"

# Output:
# Access request created: req_b2c3d4e5f6a7
# State:  pending
# Nodes:  ssh-node:web-01
# Reason: Investigating incident XYZ-123

# Request several nodes at once (repeat --resource), and mix roles with nodes
msh request create \
  --resource=ssh-node:web-01 --resource=ssh-node:web-02 \
  --reason="Rolling out config change"

# Request with a specific duration
msh request create --roles=ssh-production --duration=1h \
  --reason="Quick production check"

# List your pending and active requests. The TARGETS column shows roles and
# nodes; once a request has more than three combined targets it collapses to
# a count to keep the table readable (e.g. "1 role, 4 resources").
msh request ls
# ID                TARGETS          REASON              STATE     CREATED              EXPIRES
# req_a1b2c3d4e5f6  ssh-production   Deploying hotfix... pending   2026-03-24 10:00:00  -
# req_b2c3d4e5f6a7  ssh-node:web-01  Investigating in... pending   2026-03-24 10:05:00  -

At least one of --roles or --resource must be set; both together is allowed. Whatever you request shares a single time-to-live — when the grant expires, the roles and the node access go away together.


Reviewing Requests with mezctl

Review access requests bash
# List pending requests (as an approver). The TARGETS column shows requested
# roles and nodes, collapsing to a count past three combined targets.
mezctl access-requests ls --state=pending
# ID                REQUESTER  TARGETS          REASON              URGENCY  STATE    CREATED
# req_a1b2c3d4e5f6  alice      ssh-production   Deploying hotfix... normal   pending  2026-03-24 10:00:00
# req_b2c3d4e5f6a7  bob        ssh-node:web-01  Investigating in... high     pending  2026-03-24 10:05:00

# Show the full detail of a single request, including every requested node
mezctl access-requests show req_b2c3d4e5f6a7
# ID:                   req_b2c3d4e5f6a7
# Requester:            bob
# State:                pending
# Urgency:              high
# Reason:               Investigating incident XYZ-123
# Requested roles:      (none)
# Requested resources:  ssh-node:web-01
# Created:              2026-03-24 10:05:00

# Approve the request
mezctl access-requests approve req_a1b2c3d4e5f6

# Deny the request (with optional reason)
mezctl access-requests deny req_a1b2c3d4e5f6 --reason="Use staging environment instead"

Approving a request grants both halves together — the requested roles and the named nodes — for one shared duration. A request that asks only for resources (no roles) must be reviewed by an administrator in this release.


Time-Bound Grants

Once approved, the elevated access has a fixed time-to-live (TTL). When the TTL expires, the elevated role is automatically revoked. No manual cleanup is required.

Time-bound access lifecycle bash
# After approval, the requester's session includes the elevated role
msh status
# Cluster:     prod
# Proxy:       proxy.example.com:3080
# User:        alice
# Roles:       access, can-request-production, ssh-production
# Valid until: 2026-03-24 14:00:00 UTC (3h52m remaining)

# Production nodes are now visible and accessible
msh ls
# HOSTNAME       ROLE  STATUS  LABELS                          VERSION
# web-server-01  node  online  env=production,team=platform    0.1.0
# web-server-02  node  online  env=production,team=platform    0.1.0

# Connect normally during the access window
msh ssh --login=ubuntu web-server-01

# When the access expires, the role is automatically removed
# The next msh command will reflect the change
msh ls
# (production nodes no longer visible)

Users can also voluntarily drop elevated access early. The same cancel verb covers both pending requests (which become cancelled) and approved requests still inside their TTL (which become revoked):

Drop access early bash
# Withdraw a pending request, or revoke an active approved one
msh request cancel req_a1b2c3d4e5f6

RBAC Setup for Access Requests

Access requests are configured through role policy: a requester role declares what its holders may request, and an approver role declares what its holders may review. Two clauses control what can be requested:

  • request_roles — the roles a holder may request (role requests).
  • request_resources — the specific SSH nodes a holder may request (resource requests). Each entry is an exact node identity of the form ssh-node:<cluster>/<name>; leave the cluster empty (ssh-node:/web-01) for a node in the local cluster. A node not named by any of the requester's roles cannot be requested.
Requester role yaml
kind: role
metadata:
  name: can-request-production
  description: "Can request temporary production SSH access"
spec:
  allow:
    # May request the whole production role...
    request_roles:
      - ssh-production
    # ...and may request access to these specific nodes individually.
    request_resources:
      - "ssh-node:/web-01"
      - "ssh-node:/web-02"
  deny: {}

Both clauses honour an explicit deny side. A node named in any of the requester's deny.request_resources clauses can never be requested, even if another role allows it (deny always wins):

Carving out a node with a deny clause yaml
kind: role
metadata:
  name: no-database-nodes
  description: "Blocks requesting the database hosts"
spec:
  allow: {}
  deny:
    request_resources:
      - "ssh-node:/db-primary"
Approver role yaml
kind: role
metadata:
  name: can-approve-production
  description: "Can approve production SSH access requests"
spec:
  allow:
    review_roles:
      - ssh-production
  deny: {}
Assign roles bash
# Roles are assigned when the user is created
mezctl users create alice --roles=access,can-request-production
mezctl users create charlie --roles=access,can-approve-production

# For SSO-mapped users, attach the role names via the connector's
# claim/attribute-to-roles mapping (see the SSO guide).

Audit Trail

Every step of the access request lifecycle generates an audit event, providing a complete record of who requested what, who approved it, and when access expired.

Query access request audit events bash
# View access request events. --type takes a single event type, so query each
# stage separately (or omit --type to see everything in the window).
mezctl audit ls --type=access_request.created  --since=24h
mezctl audit ls --type=access_request.approved --since=24h
mezctl audit ls --type=access_request.denied   --since=24h
mezctl audit ls --type=access_request.expired  --since=24h

# Event types emitted across the lifecycle:
#   access_request.created
#   access_request.approved
#   access_request.denied
#   access_request.expired
#   access_request.cancelled
#   access_request.revoked

Cross-cluster nodes

A resource request can name a node in another cluster you have a trusted-cluster relationship with, using the ssh-node:<cluster>/<name> form (for example ssh-node:leaf-prod/web-01). The request is validated against that trusted-cluster relationship when it is created, and the approved scope is enforced on the remote cluster: an approval for one remote node grants access to that node only, not to other nodes in the same cluster.


Next Steps