mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-10 17:47:13 +00:00
e79883224f
### RDP NTLM default
New [rdp] config section with default_auth_pkg. The resolver in
session.rs walks entry value -> config default -> hardcoded "ntlm".
Kerberos/Negotiate are still selectable per-entry or via the config
override, but the default is NTLM because Kerberos needs a KDC
reachable via DNS (often over TCP) and its failure mode is a silent
RDP hang that looks exactly like an unrelated network issue.
Existing entries and Guacamole-imported entries that stored
auth_pkg = None now resolve to NTLM automatically. Admins who do
run Kerberos-integrated hosts can set default_auth_pkg =
"kerberos" or "negotiate" in config.toml to restore the old
behaviour.
UI: the entry modal's NLA dropdown now says "Server default (NTLM)"
instead of "Default (negotiate)" so the behaviour matches the
label. Added an explicit "Negotiate (Kerberos first, NTLM fallback)"
option for completeness.
5 unit tests cover the resolver matrix (entry wins, empty entry
falls through, no entry falls through, empty config default falls
through, server default wins when entry is None).
### Connections tree persistence
Folder expansion state and the selected folder are now persisted
to localStorage, so reopening the page / logging back in no longer
collapses the whole tree or snaps you back to the alphabetical
first folder.
- `rustguac_connections_expanded`: {scope|path: true} map, saved
on every toggleFolder() and on the auto-expand-on-subfolder-
create path.
- `rustguac_connections_selected`: {scope, path}, saved on every
selectedFolder assignment (click, new folder, new subfolder,
delete-to-null, move entry).
On page load, loadFolders() now chains: fetch top-level folders ->
restoreExpandedTree() walks saved keys shallowest-first so deeper
paths can resolve via findFolder() after their ancestors populate
subfolderCache -> try restoring saved selection -> fall back to
the current auto-select-first behaviour only if nothing restored.
Stale keys (deleted folders, ACL-revoked folders) are dropped
opportunistically during the restore walk. Per-browser, not
per-user; try/catch wraps every storage call so private-mode / quota
errors degrade silently to the pre-persistence behaviour.
281 lines
13 KiB
TOML
281 lines
13 KiB
TOML
# rustguac — example configuration
|
||
#
|
||
# All settings are optional and have sensible defaults.
|
||
# Copy this file to config.toml and adjust as needed.
|
||
#
|
||
# Usage:
|
||
# rustguac --config config.toml serve
|
||
|
||
# ─── Server ───────────────────────────────────────────────────────────────────
|
||
|
||
# Address and port to listen on.
|
||
# Default: "127.0.0.1:8089" (loopback only — safe for development).
|
||
# For production behind a reverse proxy, use "127.0.0.1:8089".
|
||
# To listen on all interfaces: "0.0.0.0:443" (with TLS) or "0.0.0.0:8089".
|
||
listen_addr = "127.0.0.1:8089"
|
||
|
||
# Address of the guacd daemon (Guacamole protocol server).
|
||
# Default: "127.0.0.1:4822"
|
||
guacd_addr = "127.0.0.1:4822"
|
||
|
||
# Directory for session recording files (.guac format).
|
||
# Default: "./recordings"
|
||
# DEPRECATED: use [recording] section below. Kept for backwards compatibility.
|
||
recording_path = "./recordings"
|
||
|
||
# Directory containing static web files (HTML, JS, CSS).
|
||
# Default: "./static"
|
||
static_path = "./static"
|
||
|
||
# Path to the SQLite database (admins, OIDC users, auth sessions).
|
||
# Default: "./rustguac.db"
|
||
db_path = "./rustguac.db"
|
||
|
||
# Title shown in the browser tab and page header.
|
||
# Default: "rustguac"
|
||
site_title = "rustguac"
|
||
|
||
# ─── Session Timeouts ─────────────────────────────────────────────────────────
|
||
|
||
# Seconds before a pending session expires (no WebSocket connection yet).
|
||
# Default: 60
|
||
session_pending_timeout_secs = 60
|
||
|
||
# Maximum duration for active sessions in seconds.
|
||
# Sessions running longer than this are automatically terminated.
|
||
# Default: 28800 (8 hours). Set to 0 to disable.
|
||
session_max_duration_secs = 28800
|
||
|
||
# OIDC auth session TTL in seconds. After this period, users must
|
||
# re-authenticate via their identity provider.
|
||
# Default: 86400 (24 hours)
|
||
# auth_session_ttl_secs = 86400
|
||
|
||
# ─── Session Limits ──────────────────────────────────────────────────────────
|
||
|
||
# Maximum concurrent sessions (all types). Default: 500. Set to 0 for unlimited.
|
||
# max_sessions = 500
|
||
|
||
# Maximum concurrent sessions per user. Default: 50. Set to 0 for unlimited.
|
||
# max_sessions_per_user = 50
|
||
|
||
# Seconds to keep completed sessions in memory before cleanup.
|
||
# Session history in SQLite is not affected. Default: 300 (5 minutes).
|
||
# session_cleanup_delay_secs = 300
|
||
|
||
# ─── Browser Sessions (Xvnc + Chromium) ──────────────────────────────────────
|
||
|
||
# Path to the Xvnc binary (from tigervnc-standalone-server).
|
||
# Default: "Xvnc"
|
||
xvnc_path = "Xvnc"
|
||
|
||
# Path to the Chromium binary.
|
||
# Default: "chromium"
|
||
chromium_path = "chromium"
|
||
|
||
# X display number range for Xvnc instances.
|
||
# Each web browser session gets its own display (:100 = port 6100, etc.).
|
||
# Default: 100–199 (up to 100 concurrent web sessions).
|
||
display_range_start = 100
|
||
display_range_end = 199
|
||
|
||
# ─── Connection Allowlists (CIDR) ────────────────────────────────────────────
|
||
#
|
||
# Control which hosts sessions can connect to. Each is a list of CIDR ranges.
|
||
# Hostnames are resolved and checked against the allowlist.
|
||
# Default for all three: ["127.0.0.0/8", "::1/128"] (localhost only).
|
||
|
||
# SSH session targets
|
||
ssh_allowed_networks = ["127.0.0.0/8", "::1/128", "10.0.0.0/8", "192.168.0.0/16"]
|
||
|
||
# RDP session targets
|
||
rdp_allowed_networks = ["127.0.0.0/8", "::1/128", "10.0.0.0/8", "192.168.0.0/16"]
|
||
|
||
# Web browser session URL hosts
|
||
# Use ["0.0.0.0/0", "::/0"] to allow any host.
|
||
web_allowed_networks = ["127.0.0.0/8", "::1/128"]
|
||
|
||
# ─── Trusted Proxies ────────────────────────────────────────────────────────
|
||
#
|
||
# CIDRs of reverse proxies whose X-Forwarded-For header should be trusted.
|
||
# When a connection comes from a trusted proxy, the first IP in
|
||
# X-Forwarded-For is used as the client IP in audit logs and rate limiting.
|
||
# Default: [] (empty — always use socket address)
|
||
|
||
# trusted_proxies = ["127.0.0.0/8", "::1/128"]
|
||
|
||
# ─── TLS ──────────────────────────────────────────────────────────────────────
|
||
#
|
||
# Enables HTTPS for clients and optionally TLS for the guacd connection.
|
||
# Omit the entire [tls] section to run plain HTTP (for development or
|
||
# when behind a TLS-terminating reverse proxy).
|
||
#
|
||
# Generate a self-signed cert:
|
||
# rustguac generate-cert --hostname your-hostname.example.com --out-dir ./tls
|
||
|
||
# [tls]
|
||
# # HTTPS certificate and private key
|
||
# cert_path = "/opt/rustguac/tls/cert.pem"
|
||
# key_path = "/opt/rustguac/tls/key.pem"
|
||
#
|
||
# # Trust this certificate for the guacd TLS connection (optional).
|
||
# # When set, rustguac connects to guacd over TLS.
|
||
# # The same self-signed cert can serve both purposes.
|
||
# # Omit for plain TCP to guacd.
|
||
# guacd_cert_path = "/opt/rustguac/tls/cert.pem"
|
||
|
||
# ─── OIDC (Single Sign-On) ───────────────────────────────────────────────────
|
||
#
|
||
# Enables OpenID Connect authentication. Works with any OIDC provider:
|
||
# Authentik, Keycloak, Okta, Azure AD, Google, etc.
|
||
#
|
||
# The client_secret can also be set via the OIDC_CLIENT_SECRET environment
|
||
# variable, which takes precedence over this config file. Recommended for
|
||
# production (Docker secrets, systemd EnvironmentFile, etc.).
|
||
#
|
||
# When OIDC is configured, the web UI shows a login button. API key auth
|
||
# continues to work alongside OIDC.
|
||
|
||
# [oidc]
|
||
# issuer_url = "https://authentik.example.com/application/o/rustguac/"
|
||
# client_id = "your-client-id"
|
||
# client_secret = "your-client-secret" # or set OIDC_CLIENT_SECRET env var
|
||
# redirect_uri = "https://your-host/auth/callback"
|
||
#
|
||
# # Role assigned to new users on first login.
|
||
# # Options: "admin", "poweruser", "operator", "viewer"
|
||
# # Default: "operator"
|
||
# default_role = "operator"
|
||
#
|
||
# # OIDC claim name containing group memberships (default: "groups").
|
||
# groups_claim = "groups"
|
||
#
|
||
# # Extra OIDC scopes to request beyond openid/email/profile.
|
||
# extra_scopes = ["groups"]
|
||
#
|
||
# # Custom CA certificate (PEM) for verifying the OIDC provider.
|
||
# # Use this when your IdP uses a private or internal CA not in the system trust store.
|
||
# # ca_cert = "/etc/ssl/private/internal-ca.pem"
|
||
#
|
||
# # Skip TLS certificate verification for OIDC connections (default: false).
|
||
# # WARNING: Only use for debugging — exposes client_secret and tokens to MITM attacks.
|
||
# # tls_skip_verify = false
|
||
|
||
# ─── Vault / Address Book ──────────────────────────────────────────────────
|
||
#
|
||
# Enables the Vault-backed address book. Connection entries (SSH, RDP, Web)
|
||
# are stored in HashiVault or OpenBao KV v2. Credentials never reach the
|
||
# browser — the server reads them from Vault and creates sessions directly.
|
||
#
|
||
# Authentication uses AppRole. The secret_id is provided via the
|
||
# VAULT_SECRET_ID environment variable.
|
||
#
|
||
# Vault KV v2 path structure:
|
||
# <base_path>/shared/<folder>/<entry> — shared across instances
|
||
# <base_path>/instance/<name>/<folder>/<entry> — instance-specific
|
||
# <folder>/.config — folder metadata (allowed_groups, description)
|
||
|
||
# [vault]
|
||
# addr = "https://vault.example.com:8200"
|
||
# mount = "secret" # KV v2 mount (default: "secret")
|
||
# base_path = "rustguac" # base path under mount (default: "rustguac")
|
||
# role_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||
# # namespace = "my-ns" # optional, Vault Enterprise / OpenBao namespaces
|
||
# # instance_name = "prod-1" # optional, enables instance-scoped entries
|
||
# # tls_skip_verify = false # skip TLS cert verification (dev only, default: false)
|
||
|
||
# ─── Recording ──────────────────────────────────────────────────────────────
|
||
#
|
||
# Controls session recording and automatic rotation.
|
||
# If omitted, recordings are enabled with no automatic cleanup.
|
||
# The path can also be set via the top-level recording_path key
|
||
# (the [recording] section takes precedence).
|
||
|
||
# [recording]
|
||
# path = "./recordings" # recording directory (default: "./recordings")
|
||
# enabled = true # master switch (default: true)
|
||
# max_disk_percent = 80 # delete oldest when disk usage exceeds % (0 = disable)
|
||
# max_recordings = 0 # global max recording count (0 = unlimited)
|
||
# rotation_interval_secs = 300 # how often to check rotation (seconds, default: 300)
|
||
|
||
# ─── Theme ────────────────────────────────────────────────────────────────────
|
||
#
|
||
# Customize the web UI appearance. Pick a built-in preset and optionally
|
||
# override individual colors. Users can switch themes in the browser via
|
||
# the theme switcher (persisted in localStorage).
|
||
#
|
||
# Built-in presets: aurora (default), dark, light, high-contrast, terminal,
|
||
# nord, corporate, jaguar
|
||
#
|
||
# All color values are CSS color strings (hex, rgb(), hsl(), named colors).
|
||
|
||
# [theme]
|
||
# preset = "aurora" # built-in preset to use as the base
|
||
# logo_url = "/logo.svg" # custom logo URL (shown on login + nav)
|
||
#
|
||
# # Override individual colors on top of the preset:
|
||
# # primary_color = "#e94560"
|
||
# # accent_color = "#5bc0be"
|
||
# # bg_color = "#1a1a2e"
|
||
# # surface_color = "#16213e"
|
||
# # text_color = "#e0e0e0"
|
||
# # text_muted = "#aaa"
|
||
# # border_color = "#333"
|
||
# # input_color = "#0f3460"
|
||
# # primary_hover = "#c73652"
|
||
# # accent_hover = "#4aa3a1"
|
||
# # text_dim = "#888"
|
||
# # text_on_primary = "#fff"
|
||
# # btn_disabled = "#555"
|
||
# # status_pending = "#f0c040"
|
||
# # status_active = "#5bc0be"
|
||
# # status_completed = "#888"
|
||
# # status_error = "#e94560"
|
||
# # status_expired = "#666"
|
||
|
||
# ─── Drive / File Transfer ──────────────────────────────────────────────────
|
||
#
|
||
# Enables file transfer for RDP (drive redirection) and SSH (SFTP) sessions.
|
||
#
|
||
# RDP: A per-session directory under drive_path is mounted as a virtual drive
|
||
# visible in the remote Windows session (e.g. "Shared Drive" in Explorer).
|
||
# SSH: SFTP file transfer directly between browser and target SSH server.
|
||
# No files stored on the rustguac server for SSH sessions.
|
||
#
|
||
# SECURITY: For RDP drive storage, use the LUKS options below to encrypt the
|
||
# drive_path volume. The encryption key is stored in Vault and the volume is
|
||
# only unlocked while rustguac is running.
|
||
|
||
# [drive]
|
||
# enabled = true
|
||
# drive_path = "/mnt/rustguac-drives" # mount point / base dir for per-session storage
|
||
# drive_name = "Shared Drive" # name shown in remote RDP session
|
||
# allow_download = true # allow downloading files from remote
|
||
# allow_upload = true # allow uploading files to remote
|
||
# cleanup_on_close = true # delete session drive dir on session end
|
||
# retention_secs = 0 # delay before cleanup (0 = immediate)
|
||
#
|
||
# # LUKS encryption (optional, requires Vault)
|
||
# # The install script can set this up interactively.
|
||
# luks_device = "/opt/rustguac/drives.luks" # LUKS container file
|
||
# luks_name = "rustguac-drives" # device-mapper name
|
||
# luks_key_path = "rustguac/luks-key" # Vault KV path for encryption key
|
||
|
||
# ──────────────────────────────────────────────────────────────────
|
||
# RDP defaults
|
||
# ──────────────────────────────────────────────────────────────────
|
||
#
|
||
# Applied to every RDP session unless the address book entry (or the
|
||
# ad-hoc connect request) overrides the same field.
|
||
#
|
||
# default_auth_pkg: NLA/CredSSP authentication package. Rustguac
|
||
# defaults to "ntlm" because Kerberos requires a KDC reachable via
|
||
# DNS (usually over TCP) and its failure mode is a silent hang.
|
||
# Set to "kerberos" if you actually run AD-integrated hosts with
|
||
# Kerberos working. "negotiate" means Kerberos-first with NTLM
|
||
# fallback and is also prone to the silent-hang failure mode.
|
||
# Leave commented to accept the "ntlm" default.
|
||
|
||
# [rdp]
|
||
# default_auth_pkg = "ntlm"
|