Files
sessiongurad/docs/INSTALLATION.md
jbergner e104e7289f
All checks were successful
release-tag / release-image (push) Successful in 2m2s
release-main / release-images (push) Successful in 3m34s
0.4.0
2026-08-22 23:48:15 +02:00

50 KiB
Raw Blame History

SessionGuard v0.3 Installation und Konfiguration

Schritt-für-Schritt-Anleitung für den Betrieb von SessionGuard als RDS-Control-Plane zusammen mit Apache Guacamole 1.6, PocketID, Traefik, PostgreSQL und Windows Remote Desktop Session Hosts.

Diese Anleitung ist auf den aktuellen SessionGuard-v0.3-Arbeitsstand und die vorhandene Umgebung mit git.send.nrw, ts.hilden.info, guacauth.hilden.info und auth.hilden.info zugeschnitten. Alle Secrets sind Platzhalter und müssen durch eigene, zufällige Werte ersetzt werden.


1. Zielbild

Nach der Installation sieht die Umgebung logisch so aus:

Internet
   |
   v
Traefik
   |
   +----------------------+-----------------------+
   |                      |                       |
   v                      v                       v
Guacamole             PocketID              SessionGuard Master
+ SessionGuard            |                       |
Extension                 |                       +---- PostgreSQL
   |                      |                       |
   +----------------------+                       |
   |                                              |
   | Broker API                                   | Agent Heartbeats
   v                                              v
SessionGuard Master <---------------------- Windows RDS Agents
   |                                              |
   | Brokerentscheidung                           +-- RDS01
   |                                              +-- RDS02
   +----------------------------------------------+-- RDS03

Die Verantwortlichkeiten bleiben bewusst getrennt:

Komponente Aufgabe
PocketID Benutzeridentität und OIDC-Gruppen
Traefik / traefik-forward-auth TLS, Edge-Proxy und Guacamole-Header-Authentifizierung
Guacamole HTML5/RDP-Gateway
SessionGuard Guacamole Extension fragt beim Verbindungsaufbau den Broker nach dem Ziel-RDS-Host
SessionGuard Master Broker, Director, Farms, Policies, RBAC, Alerts, Audit, Session-Historie
SessionGuard Agent lokale RDS-/WTS-Steuerung, Profil-Pipeline, Templates und Telemetrie
PostgreSQL persistenter SessionGuard-Control-Plane- und Director-State
Windows RDS eigentliche Benutzer-Sitzungen

Teil A Voraussetzungen

2. Voraussetzungen prüfen

2.1 Docker-/Linux-Seite

Benötigt werden:

  • Docker Engine
  • Docker Compose v2
  • bestehender Traefik v3
  • Zugriff auf git.send.nrw
  • DNS für Guacamole, PocketID und SessionGuard
  • PostgreSQL 17 wird empfohlen

Vorhanden sind bereits:

Guacamole:       https://ts.hilden.info
Forward Auth:    https://guacauth.hilden.info
PocketID:        https://auth.hilden.info

Für SessionGuard wird in dieser Anleitung beispielhaft verwendet:

SessionGuard:    https://sessionguard.hilden.info

Dafür einen DNS-Eintrag auf denselben Traefik-Endpunkt erstellen.

2.2 Windows-Seite

Pro RDS-Host:

  • Windows Server 2019/2022/2025 x64
  • RDS Session Host installiert und funktionsfähig
  • lokaler Administrator für die Installation
  • Netzwerkzugriff zum SessionGuard Master
  • bei Profil-Sicherung: Zugriff auf den gewünschten SMB-Store
  • empfohlen: gMSA für den SessionGuard-Dienst, wenn auf SMB-Shares geschrieben werden soll

2.3 Build-Voraussetzungen

Falls der Windows-Agent lokal gebaut wird:

Go 1.23+
PowerShell 5.1+
Git

Für einen lokalen Build der Guacamole-Extension:

JDK 17
Maven 3.9+

Im normalen Gitea-CI/CD-Betrieb wird die Guacamole-Extension bereits im Docker-Build erstellt.


Teil B Secrets und PocketID

3. SessionGuard-Secrets erzeugen

Für unterschiedliche Vertrauensbeziehungen unterschiedliche Secrets verwenden.

Beispiel unter Linux:

openssl rand -base64 48
openssl rand -base64 48
openssl rand -base64 48
openssl rand -base64 48

Benötigt werden mindestens:

SESSIONGUARD_DB_PASSWORD
SESSIONGUARD_ENROLLMENT_TOKEN
SESSIONGUARD_BROKER_API_KEY
SESSIONGUARD_OIDC_CLIENT_SECRET

Die Secrets dürfen nicht wiederverwendet werden.

Insbesondere sind diese Werte voneinander zu trennen:

PocketID OIDC Client Secret       Browser -> SessionGuard
Broker API Key                    Guacamole Extension -> Master
Enrollment Token                  neuer Agent -> Master
Per-Agent Token                   Agent -> Master, wird automatisch erzeugt
PostgreSQL Password               Master -> PostgreSQL

4. PocketID für den SessionGuard Master konfigurieren

In PocketID einen neuen vertraulichen OIDC-Client nur für SessionGuard anlegen.

Beispiel:

Name:          SessionGuard Master
Client Type:   Confidential

Redirect URI:

https://sessionguard.hilden.info/oidc/callback

Scopes:

openid profile email groups

Client-ID und Client-Secret notieren.

Das Client-Secret später ausschließlich über:

SESSIONGUARD_OIDC_CLIENT_SECRET

an den Master übergeben.

4.1 Empfohlene PocketID-Gruppen

Beispielsweise:

sessionguard-admins
sessionguard-helpdesk
sessionguard-operators
sessionguard-policy
sessionguard-profile
sessionguard-auditors

Empfohlene SessionGuard-Zuordnung:

PocketID-Gruppe SessionGuard-Rolle
sessionguard-admins admin
sessionguard-helpdesk helpdesk
sessionguard-operators operator
sessionguard-policy policy_admin
sessionguard-profile profile_admin
sessionguard-auditors auditor

Für Produktion sollte rbac.groups nicht leer bleiben. Ein leeres Mapping vergibt aus Kompatibilitätsgründen weitreichendere Rechte als für einen finalen Produktionsbetrieb gewünscht.


5. PocketID für die lokalen Agent-WebUIs

Das lokale Agent-WebUI ist als Fallback vorgesehen, wenn der Master nicht erreichbar ist.

Pro Terminalserver kann ein eigener OIDC-Client verwendet werden, zum Beispiel:

https://rds01-mgmt.hilden.info/oidc/callback
https://rds02-mgmt.hilden.info/oidc/callback

Alternativ kann ein zentral verwalteter OIDC-Client mehrere explizit erlaubte Redirect-URIs enthalten, sofern dies in der eigenen PocketID-Konfiguration gewünscht ist.

Für das lokale Agent-UI nur Administratorgruppen freigeben, beispielsweise:

"admin_groups": [
  "sessionguard-admins"
]

Das Agent-WebUI selbst lauscht standardmäßig auf Port 9091. Für einen produktiven OIDC-Login sollte davor HTTPS über einen Reverse Proxy verwendet werden.


Teil C Docker-Netzwerke

6. Netzwerkstruktur härten

Die vorhandene Umgebung verwendet das externe Netzwerk:

aio_proxy

Das funktioniert technisch. Bei Guacamole Header Authentication ist aber wichtig, dass kein nicht vertrauenswürdiger Container Guacamole direkt erreichen und selbst einen X-Guacamole-User-Header senden kann.

Empfohlen sind daher getrennte Netze:

guacamole_proxy      Traefik <-> Guacamole / ForwardAuth

guacamole_backend    Guacamole <-> guacd / PostgreSQL

sessionguard_control Guacamole <-> SessionGuard Master

sessionguard_backend SessionGuard Master <-> SessionGuard PostgreSQL

6.1 Gemeinsames privates Control-Netz erstellen

Wenn Guacamole und SessionGuard in unterschiedlichen Compose-Projekten laufen:

docker network create --internal sessionguard_control

In beiden Compose-Dateien anschließend:

networks:
  sessionguard_control:
    external: true
    name: sessionguard_control

Damit kann die Guacamole-Extension den Master intern erreichen, ohne dessen Broker-API über das Internet aufrufen zu müssen.

6.2 Optional: dediziertes Guacamole-Proxy-Netz

Besonders bei Header-Auth empfohlen:

docker network create guacamole_proxy

Traefik, traefik-forward-auth und guacamole werden an dieses Netzwerk angeschlossen. Andere Stacks sollten dort nicht Mitglied sein.

Wenn der bestehende aio_proxy von sehr vielen Containern gemeinsam verwendet wird, sollte die Umstellung auf ein dediziertes Netzwerk als Security-Hardening eingeplant werden.


Teil D Gitea CI/CD

7. CI/CD-Dateien ins Repository übernehmen

Im SessionGuard-Repository sollten vorhanden sein:

.gitea/workflows/release.yml
deploy/guacamole/Dockerfile.guacamole
guacamole-extension/

Die Pipeline erzeugt bei Push auf main:

git.send.nrw/sendnrw/<repo>:<version>
git.send.nrw/sendnrw/<repo>:latest

git.send.nrw/sendnrw/<repo>-guacamole:<version>
git.send.nrw/sendnrw/<repo>-guacamole:latest

Zusätzlich wird veröffentlicht:

sessionguard-guacamole.jar

in der Gitea Generic Package Registry.

7.1 Gitea Secrets

Im Repository mindestens hinterlegen:

DOCKER_USERNAME
DOCKER_PASSWORD

Der verwendete Account benötigt Schreibrechte auf:

  • Container Registry
  • Generic Package Registry

Später empfiehlt sich eine Trennung in eigene Package-Credentials.

7.2 Release-Versionen

Die CI verwendet:

git describe --tags --always | sed 's/^v//'

Für einen sauberen Release:

git tag v0.4.0
git push origin v0.4.0
git push origin main

Ein Commit exakt auf Tag v0.4.0 erzeugt dann:

git.send.nrw/sendnrw/sessionguard:0.4.0
git.send.nrw/sendnrw/sessionguard-guacamole:0.4.0

latest wird ebenfalls aktualisiert.

7.3 Release prüfen

docker pull git.send.nrw/sendnrw/sessionguard:0.4.0
docker pull git.send.nrw/sendnrw/sessionguard-guacamole:0.4.0

Für Produktion möglichst einen festen Versions-Tag und nicht ausschließlich latest verwenden.


Teil E SessionGuard Master

8. Verzeichnisstruktur anlegen

Auf dem Docker-Host beispielsweise:

mkdir -p /opt/sessionguard
cd /opt/sessionguard

Anlegen:

/opt/sessionguard/
├── docker-compose.yml
├── .env
└── master.json

9. .env für SessionGuard erstellen

Beispiel:

SESSIONGUARD_VERSION=0.4.0
POSTGRES_VERSION=17

TRAEFIK_NETWORK=aio_proxy
SESSIONGUARD_HOST=sessionguard.hilden.info
TRAEFIK_ENTRYPOINT=websecure
TRAEFIK_CERTRESOLVER=letsencrypt

SESSIONGUARD_DB_NAME=sessionguard
SESSIONGUARD_DB_USER=sessionguard
SESSIONGUARD_DB_PASSWORD=<SEHR_LANGES_DB_PASSWORT>

SESSIONGUARD_ENROLLMENT_TOKEN=<SEPARATES_ENROLLMENT_TOKEN>
SESSIONGUARD_BROKER_API_KEY=<SEPARATER_BROKER_API_KEY>
SESSIONGUARD_OIDC_CLIENT_SECRET=<POCKETID_SESSIONGUARD_CLIENT_SECRET>

# Optional
SESSIONGUARD_ALERT_WEBHOOK_URL=

Datei schützen:

chmod 600 .env

10. master.json erstellen

Beispiel für die vorhandene Domain:

{
  "listen": ":8080",
  "public_url": "https://sessionguard.hilden.info",
  "data_file": "/var/lib/sessionguard/master.json",
  "database_url": "",
  "enrollment_token": "SET-BY-SESSIONGUARD_ENROLLMENT_TOKEN",
  "offline_after_seconds": 30,
  "history_limit": 50000,
  "oidc": {
    "issuer": "https://auth.hilden.info",
    "client_id": "<POCKETID_SESSIONGUARD_CLIENT_ID>",
    "client_secret": "SET-BY-SESSIONGUARD_OIDC_CLIENT_SECRET",
    "redirect_url": "https://sessionguard.hilden.info/oidc/callback",
    "admin_groups": [],
    "secure_cookie": true
  },
  "rbac": {
    "default_role": "viewer",
    "groups": {
      "sessionguard-admins": ["admin"],
      "sessionguard-helpdesk": ["helpdesk"],
      "sessionguard-operators": ["operator"],
      "sessionguard-policy": ["policy_admin"],
      "sessionguard-profile": ["profile_admin"],
      "sessionguard-auditors": ["auditor"]
    }
  },
  "broker": {
    "enabled": true,
    "api_key": "SET-BY-SESSIONGUARD_BROKER_API_KEY",
    "lease_seconds": 900,
    "min_health_score": 60,
    "reconnect_existing": true,
    "single_session_per_user": true,
    "default_farm_id": ""
  },
  "alerts": {
    "enabled": true,
    "webhook_url": "",
    "cpu_percent": 90,
    "memory_percent": 90,
    "disk_free_gb": 10,
    "health_score": 50,
    "offline_seconds": 120,
    "profile_failures": 3,
    "disconnected_sessions": 20,
    "logon_duration_seconds": 30,
    "notification_min_interval_seconds": 900
  }
}

Die echten Secrets werden bewusst nicht in master.json geschrieben, sondern durch ENV-Variablen überschrieben.


11. SessionGuard Master Compose erstellen

Für die Registry-basierte Installation:

services:
  sessionguard-postgres:
    image: postgres:${POSTGRES_VERSION:-17}
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${SESSIONGUARD_DB_NAME:-sessionguard}
      POSTGRES_USER: ${SESSIONGUARD_DB_USER:-sessionguard}
      POSTGRES_PASSWORD: ${SESSIONGUARD_DB_PASSWORD:?required}
    volumes:
      - sessionguard-postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 20
    networks:
      - sessionguard_backend

  sessionguard-master:
    image: git.send.nrw/sendnrw/sessionguard:${SESSIONGUARD_VERSION:-latest}
    restart: unless-stopped
    depends_on:
      sessionguard-postgres:
        condition: service_healthy
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    environment:
      SESSIONGUARD_DATABASE_URL: postgres://${SESSIONGUARD_DB_USER:-sessionguard}:${SESSIONGUARD_DB_PASSWORD}@sessionguard-postgres:5432/${SESSIONGUARD_DB_NAME:-sessionguard}?sslmode=disable
      SESSIONGUARD_ENROLLMENT_TOKEN: ${SESSIONGUARD_ENROLLMENT_TOKEN}
      SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
      SESSIONGUARD_OIDC_CLIENT_SECRET: ${SESSIONGUARD_OIDC_CLIENT_SECRET}
      SESSIONGUARD_ALERT_WEBHOOK_URL: ${SESSIONGUARD_ALERT_WEBHOOK_URL:-}
    volumes:
      - ./master.json:/etc/sessionguard/master.json:ro
    tmpfs:
      - /tmp:size=16m,mode=1777
    networks:
      - sessionguard_backend
      - sessionguard_control
      - proxy
    labels:
      - traefik.enable=true
      - traefik.docker.network=${TRAEFIK_NETWORK}
      - traefik.http.routers.sessionguard.rule=Host(`${SESSIONGUARD_HOST}`)
      - traefik.http.routers.sessionguard.entrypoints=${TRAEFIK_ENTRYPOINT}
      - traefik.http.routers.sessionguard.tls=true
      - traefik.http.routers.sessionguard.tls.certresolver=${TRAEFIK_CERTRESOLVER}
      - traefik.http.services.sessionguard.loadbalancer.server.port=8080

networks:
  sessionguard_backend:
    internal: true
  sessionguard_control:
    external: true
    name: sessionguard_control
  proxy:
    external: true
    name: ${TRAEFIK_NETWORK:-aio_proxy}

volumes:
  sessionguard-postgres:

Wenn sessionguard_control noch nicht existiert:

docker network create --internal sessionguard_control

12. Master starten

cd /opt/sessionguard
docker compose pull
docker compose up -d

Status:

docker compose ps

Logs:

docker compose logs -f sessionguard-master

Health intern testen:

docker compose exec sessionguard-master \
  wget -qO- http://127.0.0.1:8080/healthz

Extern testen:

https://sessionguard.hilden.info

Beim ersten Login sollte PocketID erscheinen.


13. RBAC prüfen

Mindestens zwei Tests durchführen:

  1. Benutzer in sessionguard-admins anmelden.
  2. Benutzer ohne Admin-Gruppe bzw. mit Viewer-Gruppe anmelden.

Der zweite Benutzer darf keine administrativen Änderungen durchführen können.

Erst danach weitere Agents anbinden.


Teil F Guacamole mit SessionGuard Extension

14. Wichtige Korrektur der vorhandenen PocketID-/ForwardAuth-Konfiguration

In der vorhandenen .env steht:

TFA_HOST=guacauth.hilden.info

Daher muss die PocketID Redirect URI für den traefik-forward-auth-Client dazu passen:

https://guacauth.hilden.info/portals/guacamole/oauth2/callback

Ein alter Kommentar mit guac-sso.hilden.info sollte entfernt werden, damit es später nicht zu Fehlkonfigurationen kommt.

Der SessionGuard Master benötigt einen eigenen OIDC-Client. ForwardAuth- und SessionGuard-Client-Secret dürfen nicht identisch sein.


15. Guacamole-Image austauschen

Im bestehenden Compose nur beim eigentlichen guacamole-Service das Image ändern.

Vorher:

image: guacamole/guacamole:${GUACAMOLE_VERSION:-1.6.0}

Nachher:

image: git.send.nrw/sendnrw/sessionguard-guacamole:${SESSIONGUARD_VERSION:-0.4.0}

guac-init kann weiterhin das offizielle Guacamole-Image verwenden.


16. SessionGuard-Variablen zu Guacamole ergänzen

Im guacamole.environment ergänzen:

SESSIONGUARD_MASTER_URL: http://sessionguard-master:8080
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
SESSIONGUARD_BROKER_TIMEOUT_MS: "2500"

In die Guacamole .env zusätzlich:

SESSIONGUARD_VERSION=0.4.0
SESSIONGUARD_BROKER_API_KEY=<EXAKT_DERSELBE_BROKER_API_KEY_WIE_AM_MASTER>

Der Broker API Key ist kein Benutzer-Secret, sondern ein Service-to-Service-Key zwischen Guacamole-Extension und SessionGuard Master.


17. Guacamole an sessionguard_control anschließen

Beim guacamole-Service:

networks:
  - aio_proxy
  - sessionguard_control

Am Ende der Compose-Datei:

networks:
  aio_proxy:
    external: true
  sessionguard_control:
    external: true
    name: sessionguard_control

Danach kann Guacamole den Master per Docker DNS erreichen:

http://sessionguard-master:8080

Wenn Master und Guacamole in unterschiedlichen Compose-Projekten laufen, funktioniert der DNS-Name nur dann zuverlässig, wenn beide Container im gleichen externen Docker-Netz hängen und dort der Name/Alias verfügbar ist. Falls der tatsächliche Containername anders lautet, einen expliziten Alias setzen oder den tatsächlichen DNS-Namen in SESSIONGUARD_MASTER_URL verwenden.


18. Guacamole neu starten

docker compose pull guacamole
docker compose up -d guacamole

Logs prüfen:

docker compose logs -f guacamole

Die SessionGuard-Extension muss beim Guacamole-Start ohne API-/Classloader-Fehler geladen werden.


19. Header-Auth absichern

Die vorhandene Konfiguration entfernt vor ForwardAuth bereits eingehende Identitätsheader:

- traefik.http.middlewares.guac-strip-auth.headers.customrequestheaders.X-Guacamole-User=
- traefik.http.middlewares.guac-strip-auth.headers.customrequestheaders.X-Forwarded-User=
- traefik.http.middlewares.guac-strip-auth.headers.customrequestheaders.X-Authenticated-User=

und verwendet anschließend:

- traefik.http.routers.guacamole.middlewares=guac-strip-auth,guac-pocketid

Das ist richtig gedacht.

Zusätzlich sicherstellen:

  • Guacamole-Port 8080 nicht direkt veröffentlichen.
  • Guacamole nicht aus beliebigen Container-Netzen erreichbar machen.
  • aio_proxy möglichst nicht als allgemeines Netz für unzusammenhängende Stacks verwenden.
  • guacd und Guacamole-PostgreSQL nur in einem internen Backend-Netz betreiben.

Ein direkter Request eines fremden Containers an Guacamole darf nicht durch einen selbst gesetzten X-Guacamole-User authentifiziert werden können.


Teil G Windows Agent

20. Windows-Agent bauen

Der aktuelle CI-Workflow baut die Container-Images und die Guacamole-JAR, veröffentlicht aber noch nicht automatisch den Windows-Agent als Release-Artefakt.

Bis dahin Agent auf einem Buildsystem erzeugen:

git clone <SESSIONGUARD_REPOSITORY>
cd sessionguard

go mod tidy
go test ./...
go vet ./...

.\scripts\build.ps1

Ergebnis:

.\bin\sessionguard-agent.exe

und zusätzlich:

.\bin\sessionguard-master-linux-amd64

Vor Produktion sollte genau der Commit gebaut werden, aus dem auch Master und Guacamole-Image erzeugt wurden.


21. Agent-Konfiguration erstellen

Pro Server eine agent.json erstellen.

Beispiel für RDS01:

{
  "listen": ":9091",
  "public_url": "https://rds01-mgmt.hilden.info",
  "data_dir": "C:\\ProgramData\\SessionGuard",
  "master_url": "https://sessionguard.hilden.info",
  "enrollment_token": "SET-BY-SESSIONGUARD_ENROLLMENT_TOKEN",
  "heartbeat_seconds": 10,
  "oidc": {
    "issuer": "https://auth.hilden.info",
    "client_id": "<POCKETID_AGENT_CLIENT_ID>",
    "client_secret": "SET-BY-SESSIONGUARD_OIDC_CLIENT_SECRET",
    "redirect_url": "https://rds01-mgmt.hilden.info/oidc/callback",
    "admin_groups": [
      "sessionguard-admins"
    ],
    "secure_cookie": true
  },
  "policy": {
    "cleanup": {
      "enabled": true,
      "grace_seconds": 600,
      "poll_seconds": 10,
      "retry_seconds": 60,
      "dry_run": true,
      "exclude_users": [
        "Administrator",
        "DefaultAccount",
        "WDAGUtilityAccount"
      ],
      "exclude_sids": [
        "S-1-5-18",
        "S-1-5-19",
        "S-1-5-20"
      ],
      "allowed_profile_roots": [
        "C:\\Users"
      ]
    },
    "profiles": {
      "enabled": true,
      "store_root": "\\\\fileserver\\SessionGuardProfiles",
      "backup_on_logoff": true,
      "restore_on_logon": false,
      "backup_delay_seconds": 5,
      "retry_seconds": 60,
      "restore_window_seconds": 120,
      "keep_versions": 2,
      "exclude_users": [
        "Administrator"
      ],
      "exclude_sids": [
        "S-1-5-18",
        "S-1-5-19",
        "S-1-5-20"
      ],
      "folders": [
        {
          "path": "AppData\\Roaming\\Example",
          "exclude_globs": [
            "Cache/**",
            "*.tmp"
          ]
        },
        {
          "path": "Desktop"
        },
        {
          "path": "Documents"
        }
      ]
    },
    "sessions": {
      "control_enabled": true,
      "disconnected_logoff_enabled": false,
      "disconnected_timeout_seconds": 3600,
      "exclude_users": [
        "Administrator"
      ],
      "exclude_sids": [
        "S-1-5-18",
        "S-1-5-19",
        "S-1-5-20"
      ]
    },
    "templates": []
  }
}

Warum für die erste Installation restore_on_logon=false?

Der sichere Rollout ist:

  1. Backup testen.
  2. Restore manuell mit Testbenutzer validieren.
  3. Erst danach automatischen Restore aktivieren.
  4. Cleanup zunächst im Dry-Run lassen.

So existiert immer eine lokale Rückfallmöglichkeit.


22. Secrets des Agenten über Environment setzen

Empfohlen ist, sensible Werte nicht im JSON zu hinterlegen.

Der Agent unterstützt insbesondere:

SESSIONGUARD_MASTER_URL
SESSIONGUARD_ENROLLMENT_TOKEN
SESSIONGUARD_OIDC_CLIENT_SECRET

Bei einem Windows-Dienst müssen diese Werte so gesetzt werden, dass sie im Dienstkontext verfügbar sind. Alternativ kann die initiale Konfigurationsdatei mit strikten ACLs geschützt werden.

Der Installer schützt standardmäßig:

C:\ProgramData\SessionGuard

für SYSTEM und lokale Administratoren.


23. gMSA für Profil-Shares vorbereiten

Empfohlenes Dienstkonto beispielsweise:

DOMAIN\svc-sessionguard$

Das gMSA benötigt auf dem Profil-Share die erforderlichen Share- und NTFS-Rechte.

Mindestens erforderlich für Backup/Restore:

  • Lesen
  • Ordner anlegen
  • Dateien schreiben
  • Dateien ersetzen/umbenennen
  • alte Versionen entsprechend Retention löschen

Keine SMB-Passwörter in agent.json speichern.

Wenn LocalSystem verwendet wird, greift der Server gegenüber SMB typischerweise über sein Computerkonto zu, beispielsweise:

DOMAIN\RDS01$

Dann müssten entsprechend die Computerkonten auf dem Share berechtigt werden.


24. Agent installieren

Elevated PowerShell:

.\scripts\install-agent.ps1 `
  -Binary .\bin\sessionguard-agent.exe `
  -Config .\configs\agent.json

Mit gMSA:

.\scripts\install-agent.ps1 `
  -Binary .\bin\sessionguard-agent.exe `
  -Config .\configs\agent.json `
  -GmsaAccount "DOMAIN\svc-sessionguard$"

Der Installer:

  • kopiert die Binary nach C:\Program Files\SessionGuard
  • legt den State unter C:\ProgramData\SessionGuard ab
  • installiert den Windows-Dienst SessionGuardAgent
  • aktiviert Delayed Auto Start
  • konfiguriert automatische Service-Recovery
  • startet den Dienst

25. Agent prüfen

Get-Service SessionGuardAgent

Erwartet:

Status: Running

Falls erforderlich Windows Event Log bzw. Dienst-Logs prüfen.

Anschließend Master öffnen:

https://sessionguard.hilden.info

Der Server sollte nach Enrollment/Heartbeat in der Serverliste erscheinen.

Ein Agent, der nach offline_after_seconds keinen Heartbeat gesendet hat, wird im Director als offline dargestellt.


26. Lokales Agent-WebUI veröffentlichen

Das Agent-WebUI lauscht standardmäßig:

http://RDS01:9091

Produktiv nicht direkt öffentlich ins Internet stellen.

Empfohlen:

Management-Netz / Reverse Proxy / TLS
          |
          v
http://RDS01:9091

Windows Firewall beispielsweise nur für die Reverse-Proxy-IP öffnen:

New-NetFirewallRule `
  -DisplayName "SessionGuard Agent UI" `
  -Direction Inbound `
  -Action Allow `
  -Protocol TCP `
  -LocalPort 9091 `
  -RemoteAddress <REVERSE_PROXY_IP>

Teil H Farms, Tags und Broker

27. Erste Farm anlegen

Im Master-WebUI unter:

Farms & Broker

Beispiel:

Name: Office
ID:   wird erzeugt bzw. im UI angezeigt

Optional Required Tags:

role=office
environment=production

Farm aktivieren.


28. Agents taggen und einer Farm zuordnen

Server im Master auswählen.

Unter Serversteuerung beispielsweise:

Maintenance Mode: Online

Tags:
role=office
environment=production
location=hilden

Optional Farm-ID explizit hinterlegen.

Die explizite Zuordnung hat gegenüber automatisch aus Tags ermittelten Farm-Zuordnungen eine höhere Policy-Relevanz.


29. Server-Modi verstehen

Online

Neue Sitzungen:       erlaubt
Reconnect:            erlaubt

Drain

Neue Sitzungen:       nicht auf diesem Host
Reconnect bestehend:  erlaubt

Verwenden vor Updates/Wartung.

Maintenance

Neue Sitzungen:       blockiert
Reconnect:            blockiert

Bestehende Windows-Sitzungen werden durch das Umschalten allein nicht automatisch beendet.

Restart when drained

Aktivieren:

Neu starten sobald leer

Dann:

  1. Host auf Drain.
  2. Keine neuen Sessions mehr.
  3. Bestehende Sessions laufen aus.
  4. Bei 0 Benutzersitzungen wird ein Restart-Kommando erzeugt.
  5. Nach Neustart Agent-Health prüfen.
  6. Host wieder auf online setzen.

30. Broker-Grundeinstellungen

In master.json:

"broker": {
  "enabled": true,
  "api_key": "SET-BY-SESSIONGUARD_BROKER_API_KEY",
  "lease_seconds": 900,
  "min_health_score": 60,
  "reconnect_existing": true,
  "single_session_per_user": true,
  "default_farm_id": ""
}

Empfohlen für das vorhandene Profilmodell:

reconnect_existing = true
single_session_per_user = true

Damit versucht SessionGuard zuerst, einen Benutzer auf seine vorhandene aktive/getrennte Sitzung zurückzuführen.

Das reduziert gleichzeitige Profilzustände desselben Benutzers auf mehreren Hosts.


Teil I Guacamole Published Resources

31. Brokered Desktop in Guacamole anlegen

In Guacamole eine normale RDP-Verbindung anlegen.

Beispielname:

Office Desktop

Beim RDP Hostname keinen festen RDS-Host eintragen, sondern:

${SESSIONGUARD_HOST}

RDP-Port bleibt normalerweise:

3389

Die bisherige RDP-Credential-Konfiguration bleibt unverändert. SessionGuard entscheidet über den Zielhost, ersetzt aber nicht automatisch die Windows-Anmeldeinformationen.


32. Passende Resource in SessionGuard anlegen

Im Master-WebUI unter:

Published Resources

Beispiel:

Name:                       Office Desktop
Typ:                        desktop
Farm:                       Office
Guacamole Connection Name:  Office Desktop
Enabled:                    ja

Wenn möglich langfristig die Guacamole Connection-ID verwenden, da sie gegenüber Umbenennungen stabiler ist. Connection-Namen müssen eindeutig bleiben.

SessionGuard priorisiert beim Matching:

Resource-ID
-> Guacamole Connection-ID
-> Guacamole Connection-Name

Doppelte aktive Zuordnungen werden abgelehnt.


33. RemoteApp veröffentlichen

Guacamole-Verbindung:

hostname:        ${SESSIONGUARD_HOST}
remote-app:      ${SESSIONGUARD_REMOTE_APP}
remote-app-dir:  ${SESSIONGUARD_REMOTE_APP_DIR}
remote-app-args: ${SESSIONGUARD_REMOTE_APP_ARGS}

SessionGuard Resource zum Beispiel:

Name:             Sage
Typ:              remoteapp
Farm:             ERP
Remote App:       ||Sage
Remote App Dir:   C:\Program Files\Sage
Remote App Args:  <optional>

Die RemoteApp muss auf allen Hosts der betreffenden Farm konsistent bereitgestellt sein.


34. Broker-Funktion testen

Test 1 neue Sitzung

  1. Zwei RDS-Hosts auf online.
  2. Beide in derselben Farm.
  3. Beide Health Score >= min_health_score.
  4. Testbenutzer verbindet sich über die brokered Guacamole-Verbindung.
  5. Im Master prüfen, welcher Host ausgewählt wurde.
  6. Broker-Lease prüfen.

Test 2 Reconnect

  1. Benutzer trennt die RDS-Sitzung.
  2. Benutzer öffnet dieselbe Guacamole Resource erneut.
  3. SessionGuard muss denselben RDS-Host zurückgeben.

Test 3 Drain

  1. RDS01 auf drain setzen.
  2. Neuer Benutzer darf nicht neu auf RDS01 platziert werden.
  3. Benutzer mit vorhandener Sitzung auf RDS01 darf dort reconnecten.

Test 4 Maintenance

  1. RDS01 auf maintenance setzen.
  2. Keine neuen Broker-Verbindungen nach RDS01.
  3. Auch vorhandener Reconnect darf nicht dorthin gebrokert werden.

Teil J Profil-Pipeline

35. Profil-Store vorbereiten

Beispiel:

\\fileserver\SessionGuardProfiles

SessionGuard synchronisiert bewusst nur ausgewählte Profil-Unterordner.

Geeignete Beispiele:

Desktop
Documents
AppData\Roaming\Hersteller\Produkt

Nicht konfigurieren:

NTUSER.DAT
UsrClass.dat
komplettes C:\Users\<user>
Registry-Hives
EFS-Schlüsselmaterial
Windows-interne Profilstrukturen

36. Profilordner konfigurieren

Im Policy-Editor des Master-WebUIs:

Profil-Sicherung & Wiederherstellung

Beispiel:

Store Root:                \\fileserver\SessionGuardProfiles
Backup nach Logoff:        ja
Restore bei Logon:         zunächst nein
Backup-Verzögerung:        5 Sekunden
Retry:                     60 Sekunden
Restore-Fenster:           120 Sekunden
Historische Versionen:     2

Profilordner beispielsweise:

Desktop
Documents
AppData\Roaming\Example

Exclude-Globs für einen Ordner:

Cache/**
*.tmp

37. Backup zuerst ohne Cleanup-Risiko testen

Zunächst:

Backup:               aktiviert
Restore:              deaktiviert
Cleanup:              aktiviert
Cleanup Dry-Run:      aktiviert
Auto-Logoff:          deaktiviert

Testablauf:

  1. Testbenutzer anmelden.
  2. Testdatei in einen synchronisierten Ordner schreiben.
  3. Benutzer sauber abmelden.
  4. Master öffnen.
  5. Aktivitäts-/Profiljob-Log prüfen.
  6. SMB-Store prüfen.
  7. Sicherstellen, dass ein current-Snapshot vorhanden ist.
  8. Dry-Run-Eintrag für geplanten Cleanup prüfen.

Wichtig:

Schlägt das Backup fehl, darf SessionGuard das lokale Profil nicht löschen.


38. Restore aktivieren

Erst nach erfolgreichem Backup-Test:

Restore bei Logon = aktiviert

Test:

  1. Testbenutzer abmelden.
  2. Gesicherte Datei lokal gezielt verändern/entfernen, ohne den Backup-Store zu verändern.
  3. Benutzer erneut anmelden.
  4. Prüfen, dass der letzte current-Snapshot innerhalb des Restore-Fensters eingespielt wurde.
  5. Master-Aktivitätslog prüfen.

Der Restore arbeitet als Merge und nicht als vollständiger Profil-Mirror.


39. Cleanup produktiv aktivieren

Erst wenn Backup und Restore mehrfach erfolgreich getestet wurden:

Cleanup Dry-Run = aus

Empfohlener Startwert:

Grace: 600 Sekunden

Pipeline:

Logoff
  |
  +-- Backup Delay
  |
  +-- Backup nach staging
  |
  +-- Benutzer erneut aktiv? -> Abbruch
  |
  +-- staging -> current
  |
  +-- Cleanup Grace
  |
  +-- finaler WTS-Recheck
  |
  +-- DeleteProfileW

Ein Reconnect blockiert gefährliche Operationen.


Teil K Disconnect Auto-Logoff

40. Getrennte Sitzungen zunächst beobachten

Im Director prüfen:

  • welche Anwendungen häufig getrennt bleiben
  • typische Disconnect-Dauer
  • ob bestimmte Service-/Admin-Benutzer ausgeschlossen werden müssen

Dann Timeout definieren, zum Beispiel:

3600 Sekunden = 1 Stunde

41. Auto-Logoff aktivieren

Policy:

Sitzungssteuerung erlauben:                 ja
Getrennte Sitzungen automatisch abmelden:   ja
Disconnect Timeout:                         3600

Wichtig:

Der automatische Logoff verwendet dieselbe Nachbearbeitung wie ein manueller Logoff:

Disconnected
   |
Timeout erreicht
   |
WTSLogoffSession
   |
Profil-Backup
   |
Cleanup Grace
   |
Profil-Cleanup

Damit wird ein Benutzerprofil nicht einfach gelöscht, bevor die Sicherung abgeschlossen wurde.


Teil L Templates

42. Templates konfigurieren

Im Policy-Editor können folgende Typen angelegt werden:

Datei
Ordner
URL-Verknüpfung
Windows .lnk

URL-Beispiel

ID:       support-url
Typ:      URL
Ziel:     Desktop\Support.url
URL:      https://support.example.org
Overwrite: ja

Datei von SMB

ID:       settings-file
Typ:      Datei
Ziel:     AppData\Roaming\Example\defaults.json
Quelle:   \\fileserver\sessionguard-templates\defaults.json
Overwrite: ja

Windows Shortcut

ID:          company-shortcut
Typ:         Shortcut
Ziel:        Desktop\Fachanwendung.lnk
Target:      C:\Program Files\Example\app.exe
Description: Fachanwendung
Overwrite:   ja

Templates werden geprüft und nur bei Bedarf erzeugt/aktualisiert.


Teil M Director und Session-Steuerung

43. Director prüfen

Der Master zeigt pro Server unter anderem:

Online/Offline
Maintenance Mode
Health Score
CPU
RAM
Systemdisk
RDP Listener
Profile Store
aktive Sitzungen
getrennte Sitzungen
Profiljobs
Cleanupjobs
Prozesse

Pro Session:

Session-ID
Benutzer
Status
Logon-Zeit
Idle-Zeit
Clientname
Clientadresse

44. Sitzung steuern

Je nach RBAC-Rolle sind verfügbar:

Nachricht senden
Trennen
Abmelden
Prozess beenden

Prozessbeendigung wird zusätzlich gegen PID-Wiederverwendung abgesichert, indem der Agent PID und Session-ID vor TerminateProcess erneut verifiziert.

Administrative Aktionen werden im Audit-Log protokolliert.


Teil N Policies und Rollback

45. Policy-Ebenen

Die Policy-Priorität lautet:

Agent Override
    > explizite Farm-Zuordnung
    > zentral/tagbasiert ermittelte Farm
    > globale Policy

Empfehlung:

  • globale Baseline für alle RDS-Hosts
  • Farm-Policy für Office/ERP/etc.
  • Agent-Override nur für begründete Ausnahmen

46. Policy-Änderungen ausrollen

Für Änderungen zunächst einen Canary-Host verwenden.

Beispiel:

  1. Policy nur auf RDS03 anwenden.
  2. mindestens mehrere echte Logons/Logoffs beobachten.
  3. Director, Profiljobs und Alerts prüfen.
  4. danach auf Farm oder alle Server ausrollen.

Das WebUI bietet:

Für diesen Server speichern
Auf alle anwenden
Editor neu laden

47. Policy-Rollback

Unter:

Policy-Historie & Rollback

alte Revision auswählen und:

Rollback

verwenden.

Der Rollback löscht die Historie nicht, sondern erzeugt eine neue aktuelle Revision auf Basis der gewählten älteren Version.


Teil O Alerts und Monitoring

48. Alert-Grenzwerte konfigurieren

Beispiel:

"alerts": {
  "enabled": true,
  "cpu_percent": 90,
  "memory_percent": 90,
  "disk_free_gb": 10,
  "health_score": 50,
  "offline_seconds": 120,
  "profile_failures": 3,
  "disconnected_sessions": 20,
  "logon_duration_seconds": 30,
  "notification_min_interval_seconds": 900
}

Damit werden unter anderem überwacht:

Agent offline
CPU hoch
RAM hoch
Disk knapp
Health Score zu niedrig
Profilfehler
zu viele getrennte Sessions
langsame beobachtete Logons

49. Webhook konfigurieren

Optional:

SESSIONGUARD_ALERT_WEBHOOK_URL=https://example.org/sessionguard-webhook

SessionGuard sendet JSON-Webhooks.

Die Webhook-Zustellung ist Best Effort und ersetzt kein unabhängiges Infrastrukturmonitoring.


50. Prometheus-Metriken

Der Master stellt bereit:

/metrics

und Health:

/healthz

Beide Endpunkte in das bestehende Monitoring integrieren.


Teil P PostgreSQL und Backup

51. PostgreSQL sichern

SessionGuard speichert dort unter anderem:

Agents
Farms
Resources
Broker-Leases
Policy-State
Policy-Historie
Audit
Session-Historie
Alerts

Regelmäßiges Backup beispielsweise mit pg_dump:

docker compose exec -T sessionguard-postgres \
  pg_dump -U sessionguard -d sessionguard -Fc \
  > sessionguard-$(date +%F).dump

Das Profil-Share wird nicht in PostgreSQL gespeichert und muss separat gesichert werden.


52. Master-HA beachten

v0.3 ist als Single-Active-Master ausgelegt.

Der Master hält einen PostgreSQL Advisory Lock. Ein zweiter aktiver Master gegen dieselbe DB soll dadurch nicht gleichzeitig als Control Plane arbeiten.

Für manuellen Failover:

  1. alten Master stoppen bzw. dessen Ausfall sicher feststellen
  2. PostgreSQL-Verfügbarkeit prüfen
  3. Ersatz-Master gegen dieselbe DB starten
  4. /healthz prüfen
  5. Agent-Heartbeats prüfen
  6. Broker-Test durchführen

Kein Active/Active-Deployment konfigurieren.


Teil Q Produktions-Rollout

53. Empfohlene Rollout-Reihenfolge

Phase 1 Infrastruktur

  • SessionGuard PostgreSQL bereitstellen
  • SessionGuard Master bereitstellen
  • HTTPS/Traefik konfigurieren
  • PocketID OIDC testen
  • RBAC testen
  • PostgreSQL-Backup testen

Phase 2 erster Agent

  • einen Canary-RDS-Host wählen
  • Agent installieren
  • Heartbeat prüfen
  • Director-Telemetrie prüfen
  • Cleanup Dry-Run aktiv lassen
  • Auto-Logoff deaktiviert lassen

Phase 3 Guacamole Broker

  • SessionGuard-Guacamole-Image deployen
  • Extension-Startup prüfen
  • Canary-Farm erstellen
  • eine Published Resource erstellen
  • ${SESSIONGUARD_HOST} in Guacamole verwenden
  • neue Sitzung testen
  • Reconnect testen

Phase 4 zweite RDS-Node

  • zweiten Agent hinzufügen
  • gleiche Farm
  • Broker-Verteilung testen
  • Drain testen
  • Maintenance testen
  • Restart when drained testen

Phase 5 Profile

  • Profil-Backup aktivieren
  • Backup mehrfach testen
  • SMB-Ausfall simulieren
  • sicherstellen, dass Cleanup bei Backupfehler blockiert bleibt
  • Restore aktivieren
  • Restore mehrfach testen
  • Reconnect während Backup testen
  • erst danach Cleanup Dry-Run deaktivieren

Phase 6 Session Lifecycle

  • Disconnect-Dauer beobachten
  • sinnvollen Timeout festlegen
  • Ausschlussbenutzer festlegen
  • Auto-Logoff aktivieren
  • Backup-Pipeline nach Auto-Logoff prüfen

Phase 7 breite Einführung

  • weitere Farms anlegen
  • weitere RDS-Hosts aufnehmen
  • Policies zentralisieren
  • Alerts anbinden
  • Monitoring anbinden
  • Betriebsdokumentation/Notfallzugang dokumentieren

Teil R Funktionstests vor Produktivfreigabe

54. Mindest-Testmatrix

Broker

  • neue Verbindung wird auf gesunden Online-Host gelegt
  • Benutzer reconnectet auf seinen vorhandenen Host
  • Drain blockiert neue Sessions
  • Drain erlaubt Reconnect
  • Maintenance blockiert Brokerzugriff
  • Farm-Isolation funktioniert
  • Lease-Race bei zwei fast gleichzeitigen Verbindungsversuchen funktioniert

Session Control

  • Nachricht
  • Disconnect
  • Logoff
  • getrennte Sessions gesammelt abmelden
  • Prozess beenden
  • Audit-Eintrag vorhanden

Profile

  • normaler Backup-Job
  • Restore
  • Snapshot-History
  • SMB-Ausfall
  • Reconnect während Backup
  • Reconnect unmittelbar vor Cleanup
  • Cleanup Dry-Run
  • echter Cleanup erst nach erfolgreichem Backup

Director

  • Logon erscheint
  • Disconnect erscheint
  • Reconnect erscheint
  • Logoff erscheint
  • Prozesse sichtbar
  • CPU/RAM/Disk sichtbar
  • Agent Offline Alert funktioniert

Security

  • Viewer kann nicht administrieren
  • Helpdesk-Rechte sind begrenzt
  • Operator kann Maintenance/Sessions steuern
  • Policy Admin kann Policy ändern/rollbacken
  • fremder Container kann Guacamole nicht per gefälschtem X-Guacamole-User umgehen

Teil S Updates

55. Master aktualisieren

Vorher PostgreSQL sichern.

Dann neuen Tag setzen, beispielsweise:

SESSIONGUARD_VERSION=0.4.0

Update:

docker compose pull sessionguard-master
docker compose up -d sessionguard-master

Prüfen:

docker compose logs --tail=200 sessionguard-master

und:

/healthz
OIDC Login
Dashboard
Agent Heartbeats
Broker

56. Guacamole Extension aktualisieren

Gleichen SessionGuard-Release-Tag verwenden:

SESSIONGUARD_VERSION=0.4.0

Dann:

docker compose pull guacamole
docker compose up -d guacamole

Guacamole-Logs unmittelbar prüfen.

Master und Guacamole-Extension sollten möglichst aus demselben SessionGuard-Release stammen.


57. Windows Agents aktualisieren

Pro Farm in Wellen:

  1. Host auf drain setzen.
  2. Sitzungen auslaufen lassen.
  3. optional restart_when_drained verwenden.
  4. neuen Agent-Build kopieren/installieren.
  5. State unter C:\ProgramData\SessionGuard erhalten.
  6. Dienst prüfen.
  7. Heartbeat/Health im Master prüfen.
  8. Host wieder online setzen.
  9. nächster Host.

Installer erneut ausführen:

.\scripts\install-agent.ps1 `
  -Binary .\bin\sessionguard-agent.exe `
  -Config .\configs\agent.json `
  -GmsaAccount "DOMAIN\svc-sessionguard$"

Teil T Troubleshooting

58. Agent erscheint nicht im Master

Prüfen:

Master URL korrekt?
DNS vom RDS-Host?
HTTPS-Zertifikat vertrauenswürdig?
Enrollment Token identisch?
Firewall/Proxy?
SessionGuardAgent läuft?

PowerShell:

Get-Service SessionGuardAgent
Test-NetConnection sessionguard.hilden.info -Port 443

Master-Logs:

docker compose logs -f sessionguard-master

59. Guacamole meldet Brokerfehler

Prüfen:

SessionGuard Master erreichbar?
SESSIONGUARD_BROKER_API_KEY identisch?
Guacamole und Master im sessionguard_control Netzwerk?
Farm aktiviert?
Resource aktiviert?
Resource korrekt mit Guacamole Connection gemappt?
mindestens ein gesunder Online-Host in Farm?

Netzwerk prüfen:

docker network inspect sessionguard_control

Guacamole-Logs:

docker compose logs -f guacamole

60. Broker findet keinen Server

Prüfen:

Farm enabled?
Agent online?
Agent in Farm?
Required Tags erfüllt?
Maintenance Mode = online?
Health Score >= min_health_score?
Resource zeigt auf richtige Farm?

Ein Host auf drain ist nur für Reconnects geeignet, nicht für neue Benutzer.

Ein Host auf maintenance wird auch für Reconnect nicht verwendet.


61. Profil-Backup schlägt fehl

Prüfen:

  • Dienstkonto des Agenten
  • Share-Rechte
  • NTFS-Rechte
  • DNS zum Fileserver
  • SMB-Erreichbarkeit
  • freier Speicher
  • gesperrte Dateien
  • Pfad in store_root

Mit gMSA besonders wichtig: Tests müssen im Kontext des Dienstkontos betrachtet werden, nicht nur mit dem eigenen Admin-Account.

Bei Backupfehler darf der Cleanup nicht fortgesetzt werden.


62. Restore wird nicht ausgeführt

Prüfen:

restore_on_logon=true?
current Snapshot vorhanden?
SMB erreichbar?
Benutzer/SID ausgeschlossen?
Restore-Fenster überschritten?
Agent während Logon aktiv?

Ein Restore, der das konfigurierte Restore-Fenster überschritten hat, wird bewusst nicht verspätet in eine bereits laufende Sitzung injiziert.


63. OIDC Redirect-Fehler

Die Redirect URI muss Zeichen für Zeichen zum PocketID-Client passen.

Master:

https://sessionguard.hilden.info/oidc/callback

ForwardAuth entsprechend der vorhandenen ENV:

https://guacauth.hilden.info/portals/guacamole/oauth2/callback

Agent beispielsweise:

https://rds01-mgmt.hilden.info/oidc/callback

Außerdem public_url, redirect_url, DNS und TLS prüfen.


64. PostgreSQL startet nicht

docker compose logs sessionguard-postgres

Prüfen:

SESSIONGUARD_DB_PASSWORD gesetzt?
Volume beschreibbar?
Disk voll?
PostgreSQL-Volume aus inkompatibler Major-Version?

PostgreSQL Major Upgrades nicht durch simples Austauschen von 17 auf eine spätere Major-Version durchführen; dafür das normale PostgreSQL-Upgradeverfahren verwenden.


Teil U Empfohlene Produktionswerte

65. Startwerte

Diese Werte sind ein sinnvoller Ausgangspunkt, müssen aber zur eigenen Umgebung passen:

Einstellung Startwert
Agent Heartbeat 10 s
Agent offline nach 30 s
Broker Lease 900 s
Broker min. Health 60
Profil Backup Delay 5 s
Profil Retry 60 s
Restore Window 120 s
Snapshot History 2
Cleanup Grace 600 s
Cleanup Poll 10 s
Cleanup Retry 60 s
Disconnect Auto-Logoff zunächst aus
Disconnect Timeout später z. B. 3600 s
CPU Alert 90 %
RAM Alert 90 %
Disk Alert < 10 GB
Alert Repeat Minimum 900 s

Teil V Go-Live-Checkliste

66. Go-Live

Vor dem breiten Rollout müssen alle Punkte erfüllt sein:

  • SessionGuard Master nur per HTTPS administrierbar
  • getrennte Secrets für DB/OIDC/Broker/Enrollment
  • RBAC-Gruppen eingerichtet
  • PostgreSQL-Backup erfolgreich getestet
  • SessionGuard Master Restore-Verfahren dokumentiert
  • Guacamole Header-Auth kann nicht direkt aus fremden Netzen umgangen werden
  • Guacamole Extension lädt fehlerfrei
  • Brokered Desktop funktioniert
  • Reconnect Affinity funktioniert
  • Drain funktioniert
  • Maintenance funktioniert
  • mindestens zwei RDS-Hosts in einer Canary-Farm getestet
  • Agent-Dienst Recovery getestet
  • Profil-Backup mehrfach erfolgreich
  • Profil-Restore mehrfach erfolgreich
  • SMB-Ausfall getestet
  • Reconnect während Profil-Backup getestet
  • Cleanup Dry-Run überprüft
  • echter Profil-Cleanup nur nach erfolgreichem Backup aktiviert
  • Auto-Logoff separat getestet
  • Audit-Log geprüft
  • Alerts geprüft
  • /healthz überwacht
  • /metrics überwacht
  • Break-Glass-RDP-Zugang dokumentiert
  • Upgrade- und Rollback-Verfahren dokumentiert

67. Empfohlene Reihenfolge für diese konkrete Umgebung

Für die vorhandene Guacamole/PocketID-Installation würde ich genau so vorgehen:

1. sessionguard.hilden.info in DNS anlegen
2. separaten PocketID OIDC Client für SessionGuard erstellen
3. RBAC-Gruppen in PocketID erstellen/zuweisen
4. sessionguard_control Docker-Netz erstellen
5. SessionGuard PostgreSQL + Master deployen
6. OIDC/RBAC im Master prüfen
7. einen RDS-Canary auswählen
8. Agent dort installieren
9. Director/Health prüfen
10. Office-Canary-Farm erstellen
11. Guacamole auf sessionguard-guacamole:<version> umstellen
12. Guacamole mit sessionguard_control verbinden
13. eine neue Guacamole-Testconnection mit ${SESSIONGUARD_HOST} erstellen
14. passende Published Resource in SessionGuard erstellen
15. Broker-Verbindung testen
16. Disconnect/Reconnect testen
17. zweiten Canary-RDS-Host hinzufügen
18. Load Placement testen
19. Drain/Maintenance testen
20. Profil-Backup testen
21. Restore testen
22. Cleanup Dry-Run beobachten
23. Cleanup aktivieren
24. Disconnect Auto-Logoff aktivieren
25. danach schrittweise die restlichen RDS-Hosts aufnehmen

Damit wird nicht gleichzeitig Gateway, Broker, Profilmanagement und Session-Lifecycle produktiv umgestellt. Jede Schicht kann einzeln validiert und bei Problemen zurückgenommen werden.


68. Wichtige Betriebsgrenzen

SessionGuard ersetzt in diesem Stand nicht:

  • ICA/HDX
  • den Windows RDS Session Host
  • einen vollständigen Windows Profile Provider wie FSLogix/UPM
  • Active/Active-Master-HA
  • die eigentliche RDP-Credential-Authentifizierung

SessionGuard übernimmt stattdessen gezielt:

Broker
Reconnect Affinity
Farms
Drain / Maintenance
Director
Session Control
Profile Folder Lifecycle
Templates
Policies
RBAC
Audit
Alerts

Guacamole bleibt das Gateway und Windows bleibt die Session Runtime.


69. Relevante Projektdateien

Im Repository:

README.md
configs/master.example.json
configs/agent.example.json
deploy/docker-compose.yml
deploy/.env.example
deploy/guacamole/Dockerfile.guacamole
deploy/guacamole/docker-compose.sessionguard.example.yml
deploy/guacamole/CI-CD.md
scripts/build.ps1
scripts/install-agent.ps1
docs/ARCHITECTURE.md
docs/BROKER.md
docs/DIRECTOR.md
docs/GUACAMOLE.md
docs/OPERATIONS.md
docs/PROFILE-LIFECYCLE.md
docs/RBAC.md
docs/SECURITY.md
docs/TESTING.md

Diese Anleitung sollte zusammen mit docs/TESTING.md als Go-Live-Grundlage verwendet werden.

SessionGuard-managed RemoteApps (v0.4)

This mode is intended for RD Session Hosts where you want SessionGuard Agents to maintain the local RemoteApp allow-list instead of manually publishing the same alias on every farm member. It uses the documented Terminal Services WMI provider in root\CIMv2\TerminalServices. Administrator rights are required for changes; the normal SessionGuard Windows service account must therefore retain its existing local system/administrative privileges.

Before enabling it for a production farm, verify the provider on a canary RDS host:

Get-WmiObject `
  -Namespace 'root\cimv2\TerminalServices' `
  -Class Win32_TSPublishedApplication `
  -Authentication PacketPrivacy |
  Select-Object Alias,Path,PathExists,CommandLineSetting

An empty result is valid when no RemoteApps are published. A class/provider error means this SessionGuard mode should not be enabled on that host until the Windows RDS installation is corrected.

In Master → Apps & Desktops, create/edit a Resource:

Type:                         RemoteApp
Farm:                         <target farm>
RemoteApp Alias:              ||Sage
Agent-managed publication:    enabled
Executable:                   C:\Program Files\Sage\Sage.exe
Command-line policy:          deny / allow / require

The executable must exist at the configured path on each eligible farm member. The Agent reconciles on desired-state changes and periodically thereafter. The Master UI shows per-host readiness. A managed RemoteApp remains unavailable on any host that has not yet reported a healthy synchronized registration.

SessionGuard only removes aliases that the same Agent originally created and recorded as owned. Existing manually published RemoteApps are discovered and can be adopted for desired-state checks, but are not deleted when management is later disabled. Canary-test this behavior on the exact Windows Server version used in your environment.

Because v0.4 changes the heartbeat protocol to version 4, upgrade Master and Agents as one coordinated rollout. A v0.3 Agent will be rejected by a v0.4 Master with a protocol-version mismatch until upgraded.