Update mit Guacamole-Extension
This commit is contained in:
@@ -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 0–100 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.
|
||||
|
||||
Reference in New Issue
Block a user