Update mit Guacamole-Extension
This commit is contained in:
9
deploy/.env.example
Normal file
9
deploy/.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
POSTGRES_VERSION=17
|
||||
TRAEFIK_NETWORK=aio_proxy
|
||||
SESSIONGUARD_DB_NAME=sessionguard
|
||||
SESSIONGUARD_DB_USER=sessionguard
|
||||
SESSIONGUARD_DB_PASSWORD=generate-a-long-random-password
|
||||
SESSIONGUARD_ENROLLMENT_TOKEN=generate-a-long-random-token
|
||||
SESSIONGUARD_BROKER_API_KEY=generate-a-separate-long-random-token
|
||||
SESSIONGUARD_OIDC_CLIENT_SECRET=pocketid-sessionguard-client-secret
|
||||
SESSIONGUARD_ALERT_WEBHOOK_URL=
|
||||
@@ -1,14 +1,60 @@
|
||||
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:?SESSIONGUARD_DB_PASSWORD is 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:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
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_ENROLLMENT_TOKEN is required}
|
||||
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY:?SESSIONGUARD_BROKER_API_KEY is required}
|
||||
SESSIONGUARD_OIDC_CLIENT_SECRET: ${SESSIONGUARD_OIDC_CLIENT_SECRET:?SESSIONGUARD_OIDC_CLIENT_SECRET is required}
|
||||
SESSIONGUARD_ALERT_WEBHOOK_URL: ${SESSIONGUARD_ALERT_WEBHOOK_URL:-}
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
volumes:
|
||||
- ./master.json:/etc/sessionguard/master.json:ro
|
||||
- sessionguard-data:/var/lib/sessionguard
|
||||
tmpfs:
|
||||
- /tmp:size=16m,mode=1777
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
networks:
|
||||
- sessionguard_backend
|
||||
- proxy
|
||||
|
||||
networks:
|
||||
sessionguard_backend:
|
||||
internal: true
|
||||
proxy:
|
||||
external: true
|
||||
name: ${TRAEFIK_NETWORK:-aio_proxy}
|
||||
|
||||
volumes:
|
||||
sessionguard-data:
|
||||
sessionguard-postgres:
|
||||
|
||||
56
deploy/guacamole/CI-CD.md
Normal file
56
deploy/guacamole/CI-CD.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Gitea CI/CD for the SessionGuard Guacamole extension
|
||||
|
||||
The workflow `.gitea/workflows/release.yml` publishes three artifacts on every
|
||||
push to `main`:
|
||||
|
||||
1. `git.send.nrw/sendnrw/<repo>:<version>` - SessionGuard Master
|
||||
2. `git.send.nrw/sendnrw/<repo>-guacamole:<version>` - Guacamole with the
|
||||
SessionGuard broker extension preinstalled
|
||||
3. `sessionguard-guacamole.jar` in the Gitea Generic Package Registry under
|
||||
`<repo>-guacamole-extension/<version>`
|
||||
|
||||
Both container images also receive the `latest` tag.
|
||||
|
||||
## Required secrets
|
||||
|
||||
The workflow reuses the existing secrets:
|
||||
|
||||
- `DOCKER_USERNAME`
|
||||
- `DOCKER_PASSWORD`
|
||||
|
||||
The account needs write access to both the OCI/container registry and the
|
||||
Gitea Package Registry. If these permissions should be separated, create
|
||||
`PACKAGE_USERNAME` and `PACKAGE_TOKEN` secrets and use those in the package
|
||||
upload step.
|
||||
|
||||
## Compose
|
||||
|
||||
Instead of the stock Guacamole image, use the CI-built image:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
guacamole:
|
||||
image: git.send.nrw/sendnrw/sessionguard-guacamole:${SESSIONGUARD_VERSION:-latest}
|
||||
environment:
|
||||
SESSIONGUARD_MASTER_URL: http://sessionguard-master:8080
|
||||
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
|
||||
SESSIONGUARD_BROKER_TIMEOUT_MS: "2500"
|
||||
```
|
||||
|
||||
Keep all existing Guacamole/PostgreSQL/header-auth environment variables and
|
||||
Traefik labels unchanged.
|
||||
|
||||
## Versioning
|
||||
|
||||
`fetch-depth: 0` is important. The release version is determined with:
|
||||
|
||||
```sh
|
||||
git describe --tags --always | sed 's/^v//'
|
||||
```
|
||||
|
||||
A commit tagged `v0.3.0` therefore publishes `0.3.0`; later commits are named
|
||||
like `0.3.0-1-g0123456` until the next tag.
|
||||
|
||||
The extension Dockerfile no longer hardcodes `sessionguard-guacamole-0.3.0.jar`.
|
||||
Maven may therefore change the project version without requiring a Dockerfile
|
||||
change.
|
||||
18
deploy/guacamole/Dockerfile.guacamole
Normal file
18
deploy/guacamole/Dockerfile.guacamole
Normal file
@@ -0,0 +1,18 @@
|
||||
ARG GUACAMOLE_VERSION=1.6.0
|
||||
|
||||
FROM maven:3.9-eclipse-temurin-17 AS extension-build
|
||||
WORKDIR /src
|
||||
COPY guacamole-extension/pom.xml ./pom.xml
|
||||
COPY guacamole-extension/src ./src
|
||||
RUN mvn -B -DskipTests package \
|
||||
&& JAR="$(find target -maxdepth 1 -type f -name 'sessionguard-guacamole-*.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' | head -n 1)" \
|
||||
&& test -n "$JAR" \
|
||||
&& cp "$JAR" /tmp/sessionguard-guacamole.jar
|
||||
|
||||
# This target is used by CI to export the extension as a standalone JAR.
|
||||
FROM scratch AS extension-artifact
|
||||
COPY --from=extension-build /tmp/sessionguard-guacamole.jar /sessionguard-guacamole.jar
|
||||
|
||||
# Default/final image: stock Guacamole plus the SessionGuard broker extension.
|
||||
FROM guacamole/guacamole:${GUACAMOLE_VERSION} AS guacamole
|
||||
COPY --from=extension-build /tmp/sessionguard-guacamole.jar /etc/guacamole/extensions/sessionguard-broker.jar
|
||||
50
deploy/guacamole/README.md
Normal file
50
deploy/guacamole/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# SessionGuard + Guacamole 1.6 integration
|
||||
|
||||
The `sessionguard-guacamole` extension does **not** authenticate users. It decorates the `UserContext` produced by Guacamole's existing providers and asks the SessionGuard broker for connection parameter tokens at connect time.
|
||||
|
||||
## 1. Build Guacamole with the extension
|
||||
|
||||
Use `Dockerfile.guacamole` instead of the stock image directly. It builds `guacamole-extension/` with Maven and copies the JAR to `/etc/guacamole/extensions/`.
|
||||
|
||||
The Guacamole container needs these additional environment variables:
|
||||
|
||||
```yaml
|
||||
SESSIONGUARD_MASTER_URL: http://sessionguard-master:8080
|
||||
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
|
||||
SESSIONGUARD_BROKER_TIMEOUT_MS: "2500"
|
||||
```
|
||||
|
||||
Use a private Docker network between Guacamole and SessionGuard Master where possible. The broker API key is independent from the agent enrollment token and PocketID client secret.
|
||||
|
||||
## 2. Configure Guacamole RDP connections
|
||||
|
||||
For a brokered desktop connection set the RDP hostname to:
|
||||
|
||||
```text
|
||||
${SESSIONGUARD_HOST}
|
||||
```
|
||||
|
||||
For a brokered RemoteApp resource, these SessionGuard tokens can be used as connection parameters:
|
||||
|
||||
```text
|
||||
hostname: ${SESSIONGUARD_HOST}
|
||||
remote-app: ${SESSIONGUARD_REMOTE_APP}
|
||||
remote-app-dir: ${SESSIONGUARD_REMOTE_APP_DIR}
|
||||
remote-app-args: ${SESSIONGUARD_REMOTE_APP_ARGS}
|
||||
```
|
||||
|
||||
The extension identifies a SessionGuard resource by Guacamole connection ID or connection name. Create the corresponding mapping in SessionGuard under **Published Resources**. Unmapped Guacamole connections receive no SessionGuard tokens and remain untouched; this lets brokered and static/admin connections coexist.
|
||||
|
||||
## 3. Broker behavior
|
||||
|
||||
1. Existing matching RDS session in the requested farm wins (if reconnect is enabled).
|
||||
2. Otherwise a valid SessionGuard user lease is reused.
|
||||
3. Otherwise only online, `online`-mode farm members above `min_health_score` are considered.
|
||||
4. Candidates are scored by health, active/disconnected sessions, CPU and memory pressure.
|
||||
5. `drain` blocks new allocations but allows reconnects; `maintenance` blocks both.
|
||||
|
||||
With `single_session_per_user=true`, the lease key is global per username. With it disabled, leases are scoped by user + farm + resource.
|
||||
|
||||
## 4. Header-auth boundary
|
||||
|
||||
If Guacamole uses `HTTP_AUTH_HEADER=X-Guacamole-User`, untrusted traffic must not be able to reach Guacamole directly and supply that header. Keep the reverse proxy/header scrubber as the only trusted ingress path. Prefer a dedicated proxy network instead of sharing Guacamole's port with unrelated containers.
|
||||
29
deploy/guacamole/docker-compose.sessionguard.example.yml
Normal file
29
deploy/guacamole/docker-compose.sessionguard.example.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
# Merge these changes into the existing Guacamole stack.
|
||||
# Build context must point at the SessionGuard repository root.
|
||||
services:
|
||||
guacamole:
|
||||
image: sessionguard-guacamole:${SESSIONGUARD_VERSION:-0.3.0}
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/guacamole/Dockerfile.guacamole
|
||||
args:
|
||||
GUACAMOLE_VERSION: ${GUACAMOLE_VERSION:-1.6.0}
|
||||
environment:
|
||||
# Existing Guacamole variables stay unchanged.
|
||||
SESSIONGUARD_MASTER_URL: http://sessionguard-master:8080
|
||||
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
|
||||
SESSIONGUARD_BROKER_TIMEOUT_MS: "2500"
|
||||
networks:
|
||||
- aio_proxy
|
||||
- sessionguard_control
|
||||
|
||||
sessionguard-master:
|
||||
# Your SessionGuard master may be in another compose project. If so, attach
|
||||
# it to this external network and use its Docker DNS name above.
|
||||
networks:
|
||||
- sessionguard_control
|
||||
|
||||
networks:
|
||||
sessionguard_control:
|
||||
name: sessionguard_control
|
||||
internal: true
|
||||
Reference in New Issue
Block a user