Files
pangolin/.tasks/artifacts/guacamole-research.md
Olaf b428721b07 Initial commit: cleaned project structure
- Consolidated documentation from Ralph Loop iterations
- Archived 20+ outdated/superseded files to .archive/
- Kept essential docs: OIDC integration, mobile setup, quick start
- Added operational scripts for health monitoring and backup
- Research artifacts preserved in .tasks/artifacts/

Current state:
- 3 VPS sites (fry, proton, photon) ONLINE in Pangolin
- brn-home site pending for local services (Jellyfin, etc.)
- Mobile access configuration pending

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 06:15:04 +00:00

16 KiB

Apache Guacamole OIDC Integration with Authentik - Research Report

Research Task: RESEARCH-003 Date: 2026-01-20 Objective: Comprehensive research on Apache Guacamole OIDC integration with Authentik


1. Complete List of OPENID_ Environment Variables

Required Environment Variables

For Docker installations of Apache Guacamole, the following environment variables are required:

Variable Description Example Value
OPENID_AUTHORIZATION_ENDPOINT Authorization endpoint URI from IdP https://sso.obr.sh/application/o/authorize/
OPENID_JWKS_ENDPOINT JWKS endpoint for validating ID tokens (JWTs) https://sso.obr.sh/application/o/<slug>/jwks/
OPENID_ISSUER Expected issuer for all received ID tokens https://sso.obr.sh/application/o/<slug>/
OPENID_CLIENT_ID OpenID client ID for your application From Authentik provider configuration
OPENID_REDIRECT_URI Full callback URL for Guacamole https://remote.obr.sh/guacamole/api/auth/openid-connect/callback

Optional Environment Variables

Variable Description Default Value
OPENID_ENABLED Explicitly enable the extension true (or set any OPENID_ variable)
OPENID_USERNAME_CLAIM_TYPE JWT claim for username email
OPENID_GROUPS_CLAIM_TYPE JWT claim for groups groups
OPENID_ATTRIBUTES_CLAIM_TYPE Comma-separated list of claims to expose as OIDC_* attributes (empty)
OPENID_SCOPE OpenID scopes to request openid email profile
OPENID_ALLOWED_CLOCK_SKEW Clock skew tolerance for token validation 30 (seconds)
OPENID_MAX_TOKEN_VALIDITY Maximum token validity period 300 (minutes/5 hours)
OPENID_MAX_NONCE_VALIDITY Maximum nonce validity period 10 (minutes)

Extension Loading Control

Variable Description Effect
EXTENSION_PRIORITY Controls authentication flow openid = auto-redirect to IdP
*,openid = show login screen first

Additional Configuration Requirement

For standalone installations (non-Docker), you must enable environment property evaluation:

# In /etc/guacamole/guacamole.properties
enable-environment-properties: true

2. Connection-Level Authentication Flow

User Authentication vs. Connection Authentication

Critical Finding: OIDC in Guacamole handles user authentication to the Guacamole web interface, NOT connection-level authentication to RDP/VNC/SSH hosts.

How It Works

  1. User logs into Guacamole via OIDC (SSO to Authentik)
  2. Guacamole creates a session for the authenticated user
  3. Connections are accessed based on permissions stored in the database extension (JDBC)
  4. Target system authentication happens separately using configured credentials

The Credential Passthrough Problem

With LDAP Authentication (Works)

User → LDAP login → Guacamole stores credentials → RDP connection
        ↓
    ${GUAC_USERNAME} and ${GUAC_PASSWORD} available

With OIDC Authentication (Does NOT Work)

User → OIDC login → Guacamole gets token only → RDP connection
        ↓
    ${GUAC_PASSWORD} is NOT available (password never sent to Guacamole)

Parameter Tokens Available

Token LDAP Auth OIDC Auth Notes
${GUAC_USERNAME} ✓ Available ✓ Available Username from claim
${GUAC_PASSWORD} ✓ Available ✗ NOT Available Password never leaves IdP

OIDC Attribute Passthrough

The OPENID_ATTRIBUTES_CLAIM_TYPE variable allows exposing JWT claims as OIDC_* parameters:

# Example: Expose custom claims
OPENID_ATTRIBUTES_CLAIM_TYPE=workstationName,department,employeeId

This creates connection parameters:

  • ${OIDC_workstationName}
  • ${OIDC_department}
  • ${OIDC_employeeId}

Use Case: Dynamic connection routing based on user attributes, NOT credential passthrough.


3. MFA Flow with TOTP Passthrough

Guacamole's TOTP Support

Apache Guacamole supports TOTP (Time-based One-Time Password) as a second authentication factor.

TOTP Authentication Flow

┌─────────────────────────────────────────────────────────────┐
│ 1. User attempts to log in                                  │
│    ↓                                                         │
│ 2. Primary authentication (OIDC/LDAP/Database)              │
│    ↓                                                         │
│ 3. If successful, TOTP extension checks for enrolled device │
│    ├─ Device enrolled: Prompt for TOTP code                 │
│    └─ No device: Force enrollment (QR code scan)            │
│    ↓                                                         │
│ 4. User enters 6-digit code from authenticator app          │
│    ↓                                                         │
│ 5. If code validates: Grant access                          │
│    └─ If code fails: Deny access                            │
└─────────────────────────────────────────────────────────────┘

TOTP Extension Configuration

Extension File: guacamole-auth-totp-*.jar

Environment Variables (Docker):

Variable Description Default
TOTP_ISSUER Issuer name shown in authenticator app Apache Guacamole
TOTP_DIGITS Number of digits in TOTP code 6
TOTP_PERIOD Time period for code validity 30 (seconds)
TOTP_MODE TOTP generation mode sha1

Layered Authentication: OIDC + TOTP

Prerequisites:

  • Database authentication extension (JDBC) installed for key storage
  • OIDC extension for primary authentication
  • TOTP extension for second factor

Flow:

  1. User → Authentik (OIDC with MFA at IdP level) → Guacamole login
  2. Guacamole → TOTP challenge (separate from Authentik MFA)
  3. User → Enters TOTP code → Access granted

Important Limitation: Duo vs. TOTP with SSO

From official documentation:

"Guacamole's Duo support cannot currently be used alongside single sign-on (SSO). If you need both MFA and SSO, you must use your SSO provider's own Duo integration or use TOTP instead of Duo."

MFA Architecture Options

Option A: MFA at IdP Level (Authentik)

User → Authentik (with TOTP/WebAuthn) → Guacamole
Pros: Single MFA enforcement point, better UX
Cons: No Guacamole-level MFA control

Option B: MFA at Guacamole Level

User → Authentik (no MFA) → Guacamole TOTP → Access
Pros: Guacamole controls second factor
Cons: Users authenticate twice (SSO + TOTP)

Option C: Dual MFA (Most Secure)

User → Authentik (with MFA) → Guacamole TOTP → Access
Pros: Defense in depth, two independent factors
Cons: Potential user friction

4. RDP NLA Compatibility with SSO

What is RDP NLA?

Network Level Authentication (NLA) is a security feature in RDP that requires authentication before establishing a full remote desktop session.

The Fundamental Incompatibility

Critical Finding: OIDC SSO and RDP NLA have a credential passthrough problem.

Why It Doesn't Work

┌──────────────────────────────────────────────────────────┐
│ OIDC Flow (No Password to Guacamole)                    │
├──────────────────────────────────────────────────────────┤
│ User → Authentik → JWT Token → Guacamole                │
│                                                          │
│ RDP NLA Requirement (Needs Actual Password)             │
│                                                          │
│ Guacamole → Windows Server (NLA) → ??? No password ???  │
└──────────────────────────────────────────────────────────┘

The Problem:

  • OIDC authentication means the user's password never reaches Guacamole
  • RDP NLA requires a username/password for NTLM or Kerberos authentication
  • ${GUAC_PASSWORD} token is empty when using OIDC

Confirmed by Community Evidence

From mailing list discussions:

"When using OpenID Connect (or SAML, or CAS without the ClearPass extension) for Guacamole login, the user's password is not shared between the Identity Provider (IdP) and Guacamole, meaning the ${GUAC_PASSWORD} variable will not be available for use in RDP connections."

Current Status of FreeRDP NLA Support

Guacamole uses FreeRDP for RDP connections. Key limitations:

  1. NTLM-only NLA: FreeRDP currently only supports NTLM variant of NLA
  2. No Kerberos NLA: Kerberos NLA support is in development
  3. Protected Users Group: Users in AD "Protected Users" group cannot authenticate via NTLM NLA

Workarounds and Solutions

Solution 1: Disable NLA on Target Systems

Pros: Simple, works immediately
Cons: Reduced security, Microsoft discourages this

Solution 2: Credential Prompting

Leave RDP username/password blank → User prompted during connection
Pros: Works with OIDC
Cons: Users log in twice (SSO + RDP prompt)

Solution 3: Pre-configured Shared Accounts

Store RDP credentials in Guacamole connection config
Pros: Single sign-on UX maintained
Cons: Shared accounts, loses per-user audit trail
LDAP auth → ${GUAC_PASSWORD} available → RDP NLA works
Pros: Credential passthrough works
Cons: Loses SSO benefits, security regression

Solution 5: Custom Authentication Extension

Community Solution: guacamole-auth-header-password

# Example: Pass credentials via HTTP headers
http-username-header=OIDC_REMOTE_USER
http-password-header=OIDC_access_token  # Not a real password
http-groups-header=OIDC_CLAIM_sdDesktopProjects

Note: This doesn't solve the password problem but shows extension architecture.

Solution 6: CAS with ClearPass (Alternative SSO)

Apache Guacamole 0.9.14+ includes CAS credential pass-through
using "ClearPass" which allows ${GUAC_USERNAME} and ${GUAC_PASSWORD}
tokens with SSO

Requires: CAS server instead of OIDC

Azure AD / Entra Joined Systems

Additional Complexity:

  • Azure AD Joined (Entra-joined) systems may require web-based authentication
  • Guacamole cannot pass through the web sign-in mechanism
  • Hybrid joined (Azure AD + Domain joined) systems work better

From community reports:

"Hybrid joined systems with NLA enabled are working fine with Guacamole/RDP"

Best Practice Architecture:

  1. Use OIDC for Guacamole authentication (SSO to Authentik)
  2. Configure RDP connections with one of:
    • Option A: Dedicated service accounts (stored in connection config)
    • Option B: Prompt users for RDP credentials (UX compromise)
    • Option C: Disable NLA on internal trusted network segments only
  3. Implement connection-level access control via Authentik groups
  4. Enable audit logging to track connection access (even with shared accounts)

5. Authentik-Specific Configuration Notes

Authentik Provider Setup

Provider Type: OAuth2/OpenID Connect Client Type: Confidential Scopes: openid, email, profile

Critical Authentik Settings

  1. Redirect URI:

    https://remote.obr.sh/guacamole/api/auth/oidc/callback
    
  2. Token Validity:

    Max 300 minutes (5 hours) - Guacamole limitation
    
  3. Signing Key:

    authentik Self-signed Certificate
    

Username Claim Configuration

Two Options:

OPENID_USERNAME_CLAIM_TYPE=sub
  • Pros: Immutable, unique identifier
  • Cons: Not human-readable (UUIDs)
  • Important: Disable "Allow users to change username" in Authentik

Option B: Use preferred_username

OPENID_USERNAME_CLAIM_TYPE=preferred_username
  • Pros: Human-readable usernames
  • Cons: May change if user updates profile
  • Requires: Custom property mapping in Authentik

Custom Property Mapping for Usernames

In Authentik: Create Scope Mapping to expose custom username attribute

# Example: Map custom field to preferred_username claim
{
  "preferred_username": user.attributes.get("guacamole_username", user.username)
}

Pre-creating Admin User

Best Practice: Create admin user in Guacamole database before enabling OIDC

-- Insert user matching Authentik username
INSERT INTO guacamole_entity (name, type)
VALUES ('admin@example.com', 'USER');

-- Grant admin permissions
INSERT INTO guacamole_user_permission (entity_id, permission)
VALUES ((SELECT entity_id FROM guacamole_entity WHERE name='admin@example.com'), 'ADMINISTER');

6. Key Takeaways and Recommendations

Confirmed Capabilities

✓ OIDC authentication to Guacamole web interface works well with Authentik ✓ Username passthrough (${GUAC_USERNAME}) available with OIDC ✓ Custom JWT claims can be exposed as ${OIDC_*} parameters ✓ TOTP MFA can be layered on top of OIDC authentication ✓ Groups from Authentik can control connection access

Critical Limitations

✗ Password passthrough (${GUAC_PASSWORD}) does NOT work with OIDC ✗ RDP NLA requires passwords, creating incompatibility with OIDC SSO ✗ No per-connection SSO (OIDC only authenticates to Guacamole, not target systems) ✗ Duo MFA cannot be used with SSO (use TOTP instead)

For Pangolin/Authentik/Guacamole Integration:

  1. Primary Authentication: OIDC to Authentik (SSO)
  2. MFA Strategy: MFA at Authentik level (TOTP/WebAuthn)
  3. RDP Authentication:
    • Service accounts for automated access
    • User prompting for per-user audit requirements
    • NLA disabled on trusted internal segments (if acceptable)
  4. Database Extension: Required for connection storage and TOTP keys
  5. Group Mapping: Use OPENID_GROUPS_CLAIM_TYPE=groups to control access

Environment Variable Template for Pangolin

# Authentik OIDC Integration
OPENID_AUTHORIZATION_ENDPOINT=https://sso.obr.sh/application/o/authorize/
OPENID_JWKS_ENDPOINT=https://sso.obr.sh/application/o/guacamole/jwks/
OPENID_ISSUER=https://sso.obr.sh/application/o/guacamole/
OPENID_CLIENT_ID=<from_authentik_provider>
OPENID_REDIRECT_URI=https://remote.obr.sh/guacamole/api/auth/oidc/callback

# Claim Configuration
OPENID_USERNAME_CLAIM_TYPE=preferred_username
OPENID_GROUPS_CLAIM_TYPE=groups
OPENID_SCOPE=openid email profile

# Token Settings
OPENID_MAX_TOKEN_VALIDITY=300
OPENID_ALLOWED_CLOCK_SKEW=30

# Extension Loading
EXTENSION_PRIORITY=openid
OPENID_ENABLED=true

# Enable environment variables in guacamole.properties
enable-environment-properties: true

References


Research Completed: 2026-01-20 Task: RESEARCH-003 Status: Complete