Wardengate

Operate

Session management

A session is the live brokered connection between a human (or a service principal) and a target. Wardengate tracks every session through its full lifecycle — requested, approved, opened, active, idle, closing, closed — and exposes that state over the CLI, the REST API, and the operator console. This page is the reference for the people watching sessions in flight.

Listing active sessions

The canonical command prints one line per session with its sess_ ID, the actor, the target, the protocol, the gateway that owns the connection, and the elapsed time. The list is cluster-wide by default — you do not need to query each gateway.

wgctl session list

SESSION             ACTOR               TARGET               PROTO  GW        AGE
sess_a91c7f20bb48   alice@corp          web-01.prod          ssh    gw-us-1   00:14:22
sess_c8144e90ab17   bob@corp            billing-ro.prod      pg     gw-us-2   00:02:48
sess_21f3b7910a2d   svc_deploy          win-dc01.prod        rdp    gw-us-1   00:31:07

Useful flags: --actor, --target, --protocol, --idle-gt 5m, and -o json for scripting. The REST equivalent is GET /api/v1/sessions?state=active.

Session details

Drill into a single session to see the full access-decision trail: the policy that admitted the connection, the MFA method used, any approvals that fired, the client IP and geolocation, the gateway hop, and the target account that was injected. This is the record you hand to an auditor who asks “why did this connection happen?”

wgctl session show sess_a91c7f20bb48

session       sess_a91c7f20bb48
state         active
actor         alice@corp (group:sre)
client        198.51.100.24  (Los Angeles, US)  wgctl/1.6.1
target        web-01.prod (10.10.4.20:22)
account       deploy  (vault/ssh/deploy-prod)
protocol      ssh  pty=xterm-256color  80x24
policy        prod-ssh-write  (approved by carol@corp, 00:14:08 ago)
mfa           webauthn (YubiKey 5C)
recording     full  (chunk 3/∞, 412 KB)
gateway       gw-us-1 (10.64.0.12)
started       2026-04-20T18:41:02Z
idle          00:00:04

Force-terminating a session

Termination is a first-class operator action — not a side effect of “kill the gateway pod.” The control plane sends a targeted close to the owning gateway, which flushes any buffered recording frames and then severs both legs of the brokered connection. The user sees their client disconnect immediately.

wgctl session terminate sess_a91c7f20bb48 \
  --reason "policy review - suspected off-hours access"

terminated sess_a91c7f20bb48 at 2026-04-20T18:55:31Z
recording  sealed (chunks=7, bytes=918644, sha256=3f0b...)

The --reason field is required for any forced termination and lands on the audit event tied to the session. For mass cutoff (compromised credential, IdP sync gone bad, contractor offboarded mid-shift) combine with --actor or a target selector:

wgctl session terminate --actor mallory@corp --reason "credential revoked"
wgctl session terminate --target-tag env=prod --protocol ssh --reason "maintenance window"

Live shadowing

Shadowing attaches a read-only observer to an already-running session. For SSH and database sessions the shadow renders the PTY or the query stream in a terminal; for RDP it opens a browser tab streaming the framebuffer at low bitrate. The observed user is not notified silently — the policy that authorised the session decides whether shadowing surfaces a banner, stays covert for security investigations, or is blocked outright.

wgctl session shadow sess_a91c7f20bb48

[shadow] attached read-only at 00:14:22 of sess_a91c7f20bb48
[shadow] observer: carol@corp  banner=visible
[shadow] detach with Ctrl-] q

Shadowing itself creates its own audit event and is captured in the recording access log — the same machinery that tracks after-the-fact playback. Multiple observers can attach at once; the session owner can see how many shadows are present in the client banner when banners are enabled.

Concurrent session limits

Concurrency is enforced at four levels. The most specific match wins, and a denial at any level short-circuits the connection before a target account is ever touched.

ScopeKnobTypical value
ActormaxSessionsPerUser3 interactive
TargetmaxSessionsPerTarget5 for shared jump hosts
Policyconcurrency.max1 for break-glass
Gateway poolgateway.maxActive500 per replica

When a limit is reached, new connection attempts are denied with a structured error containing the offending scope, so your chat-bot or CI runner can report “target at capacity” distinctly from “policy denied.”

Reconnect behavior

Networks drop. Wardengate distinguishes between three reconnect modes and the policy decides which one applies.

  • resume — the original session is paused and kept alive for a bounded grace period (default 120s). Reconnecting within the window re-attaches the same PTY or RDP buffer and continues the recording chunk. The session ID is preserved.
  • reauth — the client may come back but must re-enter MFA. A new session is opened; the previous one is sealed. Typical for admin-critical policies.
  • strict — no reconnect. A dropped TCP means the work is done. Use this for break-glass and for any policy where session bookends matter to auditors.

Ownership and handoff

A session is always owned by exactly one actor — the one whose identity was evaluated by policy. Handoff is the explicit act of transferring ownership to another authorised principal, recorded as a first-class audit event. This matters for on-call: when the primary engineer hands an incident to the secondary, the secondary’s identity appears on every subsequent command rather than silently reusing the original session.

wgctl session handoff sess_a91c7f20bb48 --to dan@corp \
  --reason "shift change, incident INC-4412"

handoff requested -> dan@corp
  dan@corp must accept within 5m with: wgctl session accept sess_a91c7f20bb48
sess_a91c7f20bb48  previous owner: alice@corp  new owner: dan@corp (pending)

Handoff requires both parties to hold a policy that permits the target and account. If the incoming owner’s policy is more restrictive, any in-flight command filters re-evaluate under the stricter set on acceptance.

Idle disconnect mechanics

Idle is measured as the time since the last meaningful user input, not since the last TCP packet. Keystrokes, RDP mouse motion with modifier keys, and explicit protocol-level pings all reset the counter; keepalives injected by the client do not. For database sessions, idle is the gap between queries — background connection pools do not count.

The default idle timeout is 15 minutes, overridable per policy. When a session goes idle, Wardengate first emits a session.idle_warning audit event and an in-band banner; the connection is severed only if the user does not respond within the grace window. This keeps legitimate long-running operations (large rsync, slow query) from being cut mid-flight while still bounding unattended shells.

Operator console walkthrough

The Sessions view in the admin console mirrors the CLI. The left rail lets you pin filters (by environment tag, by protocol, by policy) as saved queries. Each row expands to the same detail panel the CLI renders, plus three action buttons: Shadow, Handoff, and a red Terminate button that asks for a reason before firing. The timeline on the right stitches together the policy decision, the MFA challenge, any approvals, command-filter hits, and recording events, so you can see at a glance whether a session is behaving normally.

A compact Live strip at the top shows aggregate counters — active sessions, sessions waiting on approval, sessions idle > 10 minutes, sessions pinned by a shadow observer — so a SOC analyst can keep the tab open as an at-a-glance monitor.

Related