Just-in-time access
Let engineers ask for time-bound access to a connection, have it approved, and lose it automatically when the time is up.
With access grants alone, someone has to know who needs what and create the grant in advance. Just-in-time access turns that around. An engineer who cannot open a connection requests access for a limited time with a reason, an approver approves it, and Relay creates a grant that ends by itself. Nobody has to remember to revoke it.
Access requests are rolling out behind the access_requests feature flag, which is
enabled per organization. In the Agent Edition, turn it on with
FEATURE_FLAGS_OVERRIDE=access_requests=on on the server. With the flag off,
every access request screen, command and API call is unavailable.
How it works
- A member opens Connections and chooses Request access, or runs
relay grants request. They pick a connection or a connection group, how long they need it (up to the workspace maximum, one hour by default) and why. - The request is pending. Approvers are told in the dashboard (Approvals, with a kind filter next to query approvals), in Slack, by webhook or in Jira, depending on the workspace settings.
- An approver approves or denies it. The requester can cancel it while it is pending.
- On approval Relay creates an access grant for the requester that expires at the approval time plus the requested duration. The grant is created in the same step as the decision, so approving twice, or two approvers at once, never creates two grants.
- When the time is up the grant stops applying. Sessions the requester still has open to that connection are ended by the agent within about 30 seconds, the same way they are when a grant is revoked. The request moves to expired.
A request that nobody decides lapses after 24 hours.
If the requester already holds a grant for the same target, a new approval extends the temporary one to the later end time. A permanent grant stays permanent.
Who can request and who can approve
- Anyone who can connect in the workspace can request, for any connection or group they cannot open yet. Organization owners and admins already reach every connection and cannot request.
- Approvers are set per workspace in Approvals, Settings, Access requests: approver teams and roles (Owner also satisfies Admin), plus the integrations that hear about requests.
- With no approver teams or roles set, anyone who holds the
org.access_grants.createpermission can decide. - Segregation of duties: the person who asked can never approve or deny their own request, whatever their role, and this holds for decisions made from Slack, a webhook or Jira too.
- Reading every request in the workspace needs
org.access_requests.read; changing the settings needsorg.access_requests.manage. Both are held by admins and owners. Requesters always see their own requests and approvers see those they may decide.
The approvers, integrations and duration limits that apply to a request are recorded when it is created, so changing the settings later does not change a request already waiting.
Workspace settings
| Setting | Meaning |
|---|---|
| Longest access a request may ask for | The cap on the requested duration. Default 8 hours, at most 7 days. |
| Suggested duration | The duration used when a request names none. Default 1 hour. |
| Approver teams and roles | Who decides. Empty means holders of org.access_grants.create. |
| Integrations | Which approval integrations (see Query approvals) are told about requests and can decide them. |
An integration that access requests use cannot be deleted without detaching it first (or deleting with force).
Notifications and integrations
Slack, webhook and Jira messages say what is being asked, not a statement:
ana@example.com requests access to pg-prod for 2h: debug the nightly job- Slack posts the message with Approve and Deny buttons and updates it with the outcome and the end time. The person who clicks must be a Relay user in the organization, matched by their Slack profile e-mail, and is held to the same approver and segregation rules as in the dashboard.
- Webhook receives events named
access_request.requested,.approved,.denied,.expiredand.cancelled. The payload is the same JSON as for query approvals withkindset toaccess_grant, plustarget_type,target_nameandduration_seconds. Signed decisions are posted back the same way. - Jira opens an issue per request and decides it from the issue status.
From the CLI
relay grants request pg-prod --for 2h --reason "debug the nightly job"
relay grants request prod-dbs --group --for 30m --reason "incident 412"
relay grants requests # pending requests you may see
relay grants requests --mine --status all
relay grants approve <id> --reason "CHG-1042"
relay grants deny <id> --reason "use staging"
relay grants cancel <id>--for takes a duration such as 30m or 2h; leave it out for the workspace
default. When relay connect cannot find a connection for you, or you lose access
while connecting, the error tells you the relay grants request command to run.
Audit trail
Every step is in the workspace activity log: the request, the decision (with who decided and from where), the grant that was created, the cancellation and the expiry. Expiry is recorded once, however many control-plane replicas are running.
Plans
Just-in-time access creates access grants, so it needs the same plan as access grants and the plan feature that time-boxed grants use.