Wardengate

Administer

Session policies

Policies decide whether a session is allowed. Session policies decide what the session can do once it is up: how long, how idle, which side channels are open, which risky commands are blocked. This is the layer where most of your production-safety guardrails live.

Shape of the resource

Session policy is a section on the same Policy resource that already decides who gets to connect. Keeping them together means you never end up with an access rule that forgot its session constraints.

apiVersion: wardengate/v1
kind: Policy
metadata:
  name: prod-ssh-engineer
  organization: acme
spec:
  principals: { groups: ["sre", "platform-eng"] }
  targets:   { assetGroup: "prod-linux" }
  protocols: ["ssh"]
  accounts:  ["deploy"]
  session:
    idleTimeout: 10m
    maxDuration: 4h
    maxConcurrent: 2
    clipboard: read-only
    fileTransfer:
      sftp: true
      scp: false
      maxBytes: 200MB
    ssh:
      allowedSubsystems: ["sftp"]
      forwardAgent: false
      forwardX11: false
      portForwarding: none
    killOn:
      idle: true
      policyChange: warn
      anomaly: terminate

Idle timeout and max duration

Idle timeout kicks in when no keystrokes or protocol traffic flow for the configured window. Max duration is an unconditional cap — even an engaged session is cut when the wall clock says so. The defaults we recommend:

  • 15 minutes idle for interactive shells.
  • 4 hours max duration for day-to-day operator sessions.
  • 60 minutes for approval-gated break-glass sessions.
  • 8 hours for read-only database query sessions where long-running analytical queries are normal.

Both timers emit a warning banner 60 seconds before cut so users can save work; the banner is non-blocking.

Concurrent session caps

Caps are evaluated per user, per target, and per policy. A cap of two on maxConcurrent means one operator cannot open 50 tabs to the same host — which is less about courtesy and more about blast radius, since a runaway script multiplies your exposure.

Clipboard and file transfer

Clipboard controls apply to browser-based sessions. The four modes are off, read-only (operator can paste into the session, nothing leaves), write-only (operator can copy out; nothing in), and full. The right default for production SSH or RDP is read-only.

File transfer is orthogonal. You can allow SFTP but block SCP (a common pattern because SFTP produces cleaner audit records), cap per-session bytes, and block specific extensions.

fileTransfer:
  sftp: true
  scp: false
  maxBytes: 200MB
  deniedExtensions: [".sh", ".py", ".ps1"]
  direction: upload-only
  perFileMaxBytes: 50MB

SSH subsystem and forwarding

SSH has a long list of side channels. Each of them is turned off by default and must be explicitly allowed in policy:

  • allowedSubsystems sftp is usually the only thing you want. Avoid letting users spin up arbitrary subsystems.
  • forwardAgent — agent forwarding is a pivot waiting to happen. Leave it off.
  • forwardX11 — off for the same reason.
  • portForwarding — one of none, local, remote, both. Default to none. Open local forwarding only when the target requires it for a well-understood reason.

RDP device redirection

RDP has more side channels than SSH and they are all on by default in a stock Windows install. The session policy lets you disable each selectively.

rdp:
  drives: false
  printers: false
  smartCards: true
  audio: inbound-only
  usb: false
  clipboard: read-only
  mouse: true
  keyboard: true

Drive redirection is the big one. An RDP session with drive mapping is effectively a two-way file-copy channel without any of the audit handles a policy on SFTP would give you. Turn it off unless you have a concrete, argued-for use case.

Database query caps

For DB protocols, session policy goes beyond the transport. You can cap rows returned, bytes streamed, query duration, and (with a warning banner) block statements that match a regex.

database:
  maxRows: 100000
  maxBytes: 256MB
  maxQuerySeconds: 600
  readOnly: true
  blocked:
    - pattern: "(?i)^drop +table"
      action: block
    - pattern: "(?i)^update +.*\\bwhere\\b"
      action: warn

Do not rely on these regexes as a security boundary. A determined operator can write a DROP that evades a naive pattern. Use them as a guardrail that slows accidents; keep the real safety on the DB side with role scoping and read-replicas.

Kill-switch and anomaly termination

An OrgAdmin or Auditor can terminate any live session from the console or the CLI. The session can also be cut automatically on anomaly — Wardengate produces a per-session anomaly score from command cadence, output entropy, and protocol idiosyncrasies, and the policy can set a threshold at which the gateway simply drops the connection.

wgctl session terminate s-2f7c91 --reason "confirmed incident"
# sends TERM to the session, waits 3s, then RST if still alive.

Evaluation order

A user may match several policies. Session-level constraints combine with a "most restrictive wins" rule: the shortest idle timeout applies, the smallest concurrent cap applies, the union of all deny rules applies, the intersection of all allow lists applies. This makes it safe to stack policies — a baseline plus a per-team tightening plus a per-target override.

Inheritance through asset groups

Session constraints attached to an asset group flow into every matching target. A new target tagged env=prod,data=pii inherits whatever the pii-assets asset group defines — no need to edit each policy on onboard.

Dry-run mode

Turn on dryRun: true on any constraint and it logs but does not enforce. Operators see a banner explaining what would have been blocked. Run a new restriction in dry-run for a week before flipping it live; the report will tell you which teams need a heads-up.

Related