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:
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 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
# 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
# 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.
# 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):
# 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 formssh-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.
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):
kind: role
metadata:
name: no-database-nodes
description: "Blocks requesting the database hosts"
spec:
allow: {}
deny:
request_resources:
- "ssh-node:/db-primary" kind: role
metadata:
name: can-approve-production
description: "Can approve production SSH access requests"
spec:
allow:
review_roles:
- ssh-production
deny: {} # 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.
# 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
- RBAC Configuration — Define the roles that can be requested.
- Audit Logging — Monitor the full access request lifecycle.
- SSO Setup — Combine SSO with access request workflows.
- SSH Access — Use JIT access for SSH to production.