Update mit Guacamole-Extension
All checks were successful
release-tag / release-image (push) Successful in 2m5s
release-main / release-images (push) Successful in 5m5s

This commit is contained in:
2026-08-22 15:19:17 +02:00
parent 0f4a234f52
commit 7972ed7e38
45 changed files with 6448 additions and 402 deletions

View File

@@ -1,51 +1,176 @@
# SessionGuard architecture
# SessionGuard 0.3 Architecture
## Components
## Purpose
- **Agent (Windows service):** watches RDS/WTS sessions, applies user-profile templates, schedules profile cleanup, exposes a local management UI, and sends outbound heartbeats to the master.
- **Master (Linux/Docker):** receives enrollments and heartbeats, stores the latest server snapshots, provides a consolidated dashboard, and distributes per-agent or bulk policies.
- **Pocket ID:** authenticates administrators through OIDC. The master and each independently usable agent UI have their own callback URL.
SessionGuard separates the functions commonly bundled into a Citrix deployment into components that can be independently replaced:
## Connection model
- **PocketID/OIDC**: administrator identity and group claims.
- **Traefik / forward-auth**: trusted ingress for Guacamole.
- **Apache Guacamole**: browser gateway and RDP transport.
- **Windows RDS**: Windows session runtime.
- **SessionGuard Master**: broker, Director, policy control plane, history, alerting and command queue.
- **SessionGuard Agent**: Windows/RDS integration, profile lifecycle, templates, telemetry and local fallback administration.
Agents initiate HTTPS calls to the master. There is no requirement for the master to open an inbound management connection to a terminal server. Enrollment uses a bootstrap secret once; the master then returns an agent-specific bearer token and stores only its SHA-256 hash.
SessionGuard intentionally does not implement a new remote-display protocol.
## Profile cleanup state machine
## Network model
1. The agent polls WTS sessions.
2. A session that was present in the previous persisted snapshot and disappears is treated as logged off.
3. If no other session with the same SID exists, the profile is scheduled for cleanup after `grace_seconds`.
4. If the SID appears again before the deadline, cleanup is cancelled.
5. Immediately before deletion, the allowed-root rule and active-session rule are checked again.
6. Deletion uses the Windows `DeleteProfileW` API. Failures are retried.
Agents initiate all master communication:
The agent persists the previous session set and pending cleanup jobs so a service restart does not normally lose a logout transition.
```text
Agent --HTTPS heartbeat--> Master
<-- policy + commands--
-- results + telemetry-->
```
## Template engine
The master does not open SMB/RPC/WMI/WinRM management sessions to RDS hosts. This keeps the Windows hosts behind normal firewall/NAT boundaries and makes master outages less disruptive.
Targets are always relative to the resolved user profile path. Supported types:
Guacamole reaches only the broker API using a dedicated API key:
- `directory`: ensure a directory exists.
- `file`: write inline content/base64 content or copy a source file (including a UNC path).
- `url`: create an Internet Shortcut (`.url`).
- `shortcut`: create or update a Windows Shell Link (`.lnk`) and compare its key properties before changing it.
```text
Guacamole extension --HTTP(S) + bearer key--> /api/v1/broker/tokens
```
Templates are evaluated on a newly observed user session and again when a policy revision changes.
That API key is separate from agent enrollment credentials and PocketID secrets.
## Policy precedence
## Master persistence
- The agent starts with its local configured/persisted policy.
- A master policy for an agent becomes authoritative once received.
- If the master is unavailable, the last policy remains active and can be edited locally.
- When the master reconnects and still has a different desired policy, the master's policy wins.
Production mode uses PostgreSQL.
## Deliberate non-goal in v0.1: full roaming-profile replacement
### `sessionguard_state`
A complete restore of a Windows user profile from a share is not implemented. Restoring `NTUSER.DAT`, registry state, and profile files after the Windows profile has already been loaded is race-prone and can corrupt state. Citrix Profile Management operates much deeper in the logon/logoff lifecycle than a normal post-logon service loop.
Single JSONB control-plane document containing relatively small mutable state:
A future profile provider should therefore either:
- agents and last snapshots
- farms
- published resources
- leases
- policy versions/control state
- active alerts
1. synchronize only explicitly selected user-data directories, or
2. integrate with a supported pre-profile-load mechanism / profile-container technology.
### `sessionguard_audit`
The current design keeps this concern separate from cleanup and template enforcement rather than pretending that copying a profile directory after logon is equivalent.
Append-only administrative and command audit events. Indexed by time and actor.
### `sessionguard_session_history`
Append-only Director session history. Indexed by time, lower-cased username and agent ID.
History retention is bounded by `history_limit`. This avoids rewriting a permanently growing history document on every agent heartbeat.
JSON-file storage remains supported when `database_url` is empty. It is intended for development, migration and small single-node installations, not a HA master.
### Single-active-master guard
v0.3 is intentionally single-active-master. A dedicated PostgreSQL connection holds a session-level advisory lock for the lifetime of the Master, and control-plane writes verify that lock is still held. A second Master against the same database refuses to start. This prevents accidental split-brain; it is not a claim of seamless HA/failover.
## Agent state
Persistent agent state under `data_dir` contains:
- enrolled agent ID/token
- last accepted policy
- pending cleanup/profile jobs
- disconnected-session timers
- command deduplication/results
- profile status
- bounded event history
- bounded logon telemetry
The service can therefore continue cleanup/profile/session policy during a master outage using the last accepted policy.
## Session event model
The Windows service subscribes to service session-change notifications and also polls WTS. Immediate notifications wake the worker; polling is the reconciliation mechanism.
The agent records:
- session ID
- user/domain/SID
- state
- client name/address where available
- logon/connect/last-input timestamps
- disconnected-since timestamp
- idle seconds
The master compares consecutive snapshots and emits history events such as `logon`, `reconnect`, `disconnect`, `state_change`, `logoff`, and `logon_ready`.
## Broker model
Broker selection is entirely master-side and never modifies the Guacamole database.
A request contains the authenticated username plus Guacamole connection ID/name or an explicit SessionGuard resource/farm. The master resolves the resource and farm, then follows the placement algorithm documented in `BROKER.md`.
The response contains tokens rather than Guacamole-specific mutable state. The extension injects them into the current user context immediately before the connection parameters are resolved.
## Policy hierarchy
Policy precedence:
1. explicit agent desired policy
2. policy of a farm explicitly listed in the agent's `farm_ids`, in configured order
3. policy of a centrally matching farm (`agent_ids` or `required_tags`), deterministic farm-ID order
4. global policy
5. agent's local policy if no master desired policy applies
Master policy changes are versioned. Rollback creates a new revision derived from the selected historical version, so history remains append-only rather than being rewritten.
## Command model
Administrative actions are queued on the master and delivered through the next heartbeat:
```text
UI -> Master command queue -> heartbeat response -> Agent -> WTS/Win32 -> result -> heartbeat -> audit
```
Commands have IDs, creation time, expiry time and actor. The agent remembers recently executed IDs to avoid duplicate execution if a heartbeat is retried.
Supported command families include:
- message session
- disconnect session
- logoff session
- terminate process
- restart server after drain
## Maintenance states
- `online`: new and existing connections allowed.
- `drain`: no new broker placements; existing sessions may reconnect.
- `maintenance`: neither new placement nor reconnect is allowed.
With `restart_when_drained`, the master queues a restart only once the agent reports zero user sessions.
## Health model
The agent calculates a 0100 health score from local checks. Current checks include:
- CPU pressure
- memory pressure
- system-disk free space
- local RDP listener reachability
- profile-store reachability when profile sync is enabled
The broker excludes hosts below `broker.min_health_score` for new sessions. Alerts have independent thresholds.
## Failure behavior
### Master unavailable
- Existing Windows sessions continue.
- Agent keeps its last accepted policy.
- Profile jobs and disconnect timers continue.
- Local agent UI remains usable if its OIDC provider is reachable.
- New Guacamole broker requests fail because authoritative farm placement is unavailable. Do not silently fall back to an arbitrary RDS host if duplicate-profile protection matters.
### PostgreSQL unavailable
Master writes fail rather than pretending state was persisted. Existing master in-memory state may still answer reads, but operators should treat the master as degraded and restore DB connectivity.
### Profile share unavailable
Backup/restore jobs retry within their configured semantics. A failed backup blocks cleanup. Restore stops retrying after the configured restore window rather than injecting files into an already-running desktop later.
### Agent unavailable
It is removed from new broker placement after `offline_after_seconds`. Offline alerts use their own threshold.