SessionGuard
SessionGuard is a Go-based management layer for Windows Remote Desktop Session Hosts. It is intended for environments that use Guacamole or another access gateway and want a small subset of the operational features commonly provided by Citrix management/profile components.
Implemented MVP
- Windows service agent
- RDS/WTS session inventory
- delayed profile deletion after a real session disappears
- safety exclusions, allowed profile roots, retries, and dry-run mode
- per-user template enforcement for files, directories,
.urllinks and.lnkshortcuts - server basics: hostname, Windows version/build, uptime, RAM
- local agent dashboard
- Linux/Docker master dashboard for all agents
- outbound agent-to-master heartbeats
- bootstrap enrollment followed by per-agent bearer credentials
- per-agent policies and "apply to all agents"
- Pocket ID / generic OIDC authentication for master and local agent UI
- last-known policy continues to work if the master is unavailable
Important safety note
Profile deletion is destructive. Start with dry_run: true, verify exclusions and allowed_profile_roots, test on a non-production RDS host, and only then disable dry-run. SessionGuard calls the Windows user-profile deletion API; it does not recursively delete arbitrary profile paths itself.
Build
Requirements: Go 1.23+ and Internet access for the Go modules on the first build.
.\scripts\build.ps1
Or:
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o sessionguard-agent.exe ./cmd/agent
go build -o sessionguard-master ./cmd/master
Master deployment
- Copy
configs/master.example.jsontodeploy/master.jsonand edit it. - In Pocket ID create an OIDC client whose callback URL is
https://sessionguard.example.org/oidc/callback. - Restrict the Pocket ID client to the intended admin group and configure the same group in
admin_groups. - Put a TLS reverse proxy in front of the master.
- Start with
docker compose -f deploy/docker-compose.yml up -d --build.
The container binds the example host port only to 127.0.0.1; publish it through your reverse proxy rather than exposing plain HTTP.
Agent deployment
- Copy
configs/agent.example.jsontoconfigs/agent.jsonand edit the master URL, enrollment token and OIDC settings. - Create a Pocket ID OIDC client for the agent's management URL, for example
https://ts01-mgmt.example.org/oidc/callback. - Build the Windows agent.
- Run
scripts/install-agent.ps1from an elevated PowerShell prompt. - Keep
dry_run: trueuntil profile cleanup has been observed successfully.
The service is installed as LocalSystem by default. If a template source points to a UNC share, grant read access to the server computer account (DOMAIN\SERVER$) or change the service identity to an appropriate gMSA/service account. Do not put share passwords in the SessionGuard JSON configuration.
Example templates
[
{
"id": "support",
"kind": "url",
"target": "Desktop\\Support.url",
"url": "https://support.example.org",
"overwrite": true
},
{
"id": "erp",
"kind": "shortcut",
"target": "Desktop\\ERP.lnk",
"overwrite": true,
"shortcut": {
"target": "C:\\Program Files\\ERP\\erp.exe",
"arguments": "--terminal"
}
},
{
"id": "defaults",
"kind": "file",
"target": "AppData\\Roaming\\Example\\defaults.json",
"source": "\\\\fileserver\\templates\\defaults.json",
"overwrite": true
}
]
All target values are relative to the user's profile. Attempts to escape the profile root are rejected.
Local management during a master outage
The Windows agent continues cleanup and template work using its persisted policy. Its local web UI remains available independently of the master, provided Pocket ID is reachable. A locally saved emergency policy remains in effect until the master reconnects; if the master already has a different desired policy for that agent, the master policy is then reapplied.
Pocket ID notes
SessionGuard requests the openid, profile, email and groups scopes. Use admin_groups as a second authorization check in addition to Pocket ID's client-side allowed-group restriction. The master and agent should be served over HTTPS and secure_cookie should remain enabled.
What is intentionally not implemented yet
Full Citrix-style profile roaming/restoration is not part of v0.1. Copying an entire profile, especially NTUSER.DAT and registry-backed settings, after Windows has loaded that profile is unsafe. See docs/ARCHITECTURE.md for the recommended extension path.
Repository layout
cmd/master Linux/Docker master binary
cmd/agent Windows service binary
internal/agent agent lifecycle, cleanup, heartbeat, local UI
internal/master enrollment, dashboard, policy distribution
internal/windowsx WTS, profile and Windows server APIs
internal/templates template comparison/application
internal/auth Pocket ID / OIDC login
configs example JSON configurations
deploy Docker Compose example
scripts build/install helpers
docs architecture notes