# ============================================ # Apache Guacamole - Clientless Remote Desktop Gateway # ============================================ # https://guacamole.apache.org/ # Images: guacamole/guacamole:1.6.0 (web frontend) # guacamole/guacd:1.6.0 (connection proxy daemon) # # Access: https://remote.dooplex.hu (Authentik OIDC + DB login) # https://remote.home (internal) # # Architecture: # Browser → [Ingress] → guacamole (Tomcat/8080) → guacd (4822) → RDP/VNC/SSH target # guacamole ↔ PostgreSQL (shared CloudNativePG cluster) # # Database Setup (ONE-TIME, run before deploying): # 1. Create the database and user in CloudNativePG: # kubectl exec -it -n database-system postgresql-1 -- psql -U postgres # CREATE USER guacamole WITH PASSWORD ''; # CREATE DATABASE guacamole_db OWNER guacamole; # \q # # 2. Generate and apply the Guacamole schema: # kubectl run guac-initdb --rm -it --restart=Never \ # --image=guacamole/guacamole:1.6.0 \ # -- /opt/guacamole/bin/initdb.sh --postgresql > /tmp/guac-initdb.sql # # kubectl cp /tmp/guac-initdb.sql database-system/postgresql-1:/tmp/initdb.sql # kubectl exec -it -n database-system postgresql-1 -- \ # psql -U guacamole -d guacamole_db -f /tmp/initdb.sql # # 3. Create the secret: # kubectl create secret generic guacamole-secrets \ # -n kisfenyo-system \ # --from-literal=postgres-password='' \ # --from-literal=openid-client-id='' # # SSO Setup (Native OIDC): # Guacamole has built-in OpenID Connect support via environment variables. # 1. Create an OAuth2/OIDC Provider in Authentik: # - Name: Guacamole # - Authorization flow: default-provider-authorization-implicit-consent # - Client type: Public # - Redirect URI: https://remote.dooplex.hu/ # - Scopes: openid email profile # - Subject mode: Based on the User's Email # - Signing Key: Select your Authentik signing key # 2. Create an Application in Authentik: # - Name: Guacamole # - Slug: guacamole # - Provider: Guacamole # # Post-deploy: # 1. Login with default credentials: guacadmin / guacadmin # 2. Go to Settings → Connections → New Connection: # - Name: Workstation # - Protocol: RDP # - Hostname: 192.168.0.XXX (workstation LAN IP) # - Port: 3389 # - Username: # - Password: (NOT the PIN) # - Security mode: Any # - Ignore server certificate: checked # 3. Change guacadmin password! # 4. (Optional) Assign connections to OIDC users after they first log in # # Windows Prep: # - Enable Remote Desktop: Settings → System → Remote Desktop → On # - Ensure account has a password set (PIN won't work over RDP) # - Firewall: allow port 3389 from 192.168.0.0/24 # ============================================ --- # guacd - The Guacamole proxy daemon (handles RDP/VNC/SSH connections) apiVersion: apps/v1 kind: Deployment metadata: name: guacd namespace: kisfenyo-system labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacd app.kubernetes.io/version: "1.6.0" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacd template: metadata: labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacd app.kubernetes.io/version: "1.6.0" annotations: match-regex.version-checker.io/guacd: '^\d+\.\d+\.\d+$' spec: containers: - name: guacd image: guacamole/guacd:1.6.0 imagePullPolicy: IfNotPresent env: - name: TZ value: Europe/Budapest ports: - containerPort: 4822 name: guacd protocol: TCP livenessProbe: tcpSocket: port: guacd initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: tcpSocket: port: guacd initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 resources: requests: cpu: 100m memory: 256Mi limits: cpu: 2000m memory: 1Gi # Optional: mount for file transfer / drive mapping volumeMounts: - name: drive mountPath: /drive volumes: - name: drive emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: guacd namespace: kisfenyo-system labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacd app.kubernetes.io/version: "1.6.0" spec: type: ClusterIP ports: - name: guacd port: 4822 protocol: TCP targetPort: guacd selector: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacd --- # guacamole - The web frontend (Tomcat) apiVersion: apps/v1 kind: Deployment metadata: name: guacamole namespace: kisfenyo-system labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole app.kubernetes.io/version: "1.6.0" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole template: metadata: labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole app.kubernetes.io/version: "1.6.0" annotations: match-regex.version-checker.io/guacamole: '^\d+\.\d+\.\d+$' spec: containers: - name: guacamole image: guacamole/guacamole:1.6.0 imagePullPolicy: IfNotPresent env: - name: TZ value: Europe/Budapest # --- guacd connection --- - name: GUACD_HOSTNAME value: guacd.kisfenyo-system.svc.cluster.local - name: GUACD_PORT value: "4822" # --- PostgreSQL (shared CloudNativePG) --- - name: POSTGRESQL_HOSTNAME value: postgresql-rw.database-system.svc.cluster.local - name: POSTGRESQL_PORT value: "5432" - name: POSTGRESQL_DATABASE value: guacamole_db - name: POSTGRESQL_USERNAME value: guacamole - name: POSTGRESQL_PASSWORD valueFrom: secretKeyRef: name: guacamole-secrets key: postgres-password # --- Serve at / instead of /guacamole --- - name: WEBAPP_CONTEXT value: "ROOT" #--- OpenID Connect (Authentik) --- - name: OPENID_AUTHORIZATION_ENDPOINT value: "https://authentik.dooplex.hu/application/o/authorize/" - name: OPENID_JWKS_ENDPOINT value: "https://authentik.dooplex.hu/application/o/guacamole/jwks/" - name: OPENID_ISSUER value: "https://authentik.dooplex.hu/application/o/guacamole/" - name: OPENID_CLIENT_ID valueFrom: secretKeyRef: name: guacamole-secrets key: openid-client-id - name: OPENID_REDIRECT_URI value: "https://remote.dooplex.hu/" - name: OPENID_USERNAME_CLAIM_TYPE value: "preferred_username" - name: OPENID_GROUPS_CLAIM_TYPE value: "groups" - name: OPENID_SCOPE value: "openid email profile" # Show both DB login form AND OIDC button on login page - name: EXTENSION_PRIORITY value: "openid, *" # Auto-create Guacamole accounts for OIDC users - name: POSTGRESQL_AUTO_CREATE_ACCOUNTS value: "true" ports: - containerPort: 8080 name: http protocol: TCP livenessProbe: httpGet: path: / port: http initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 resources: requests: cpu: 100m memory: 512Mi limits: cpu: 1000m memory: 1Gi --- apiVersion: v1 kind: Service metadata: name: guacamole namespace: kisfenyo-system labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole app.kubernetes.io/version: "1.6.0" spec: type: ClusterIP ports: - name: http port: 8080 protocol: TCP targetPort: http selector: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: guacamole namespace: kisfenyo-system labels: app.kubernetes.io/instance: guacamole app.kubernetes.io/name: guacamole app.kubernetes.io/version: "1.6.0" annotations: cert-manager.io/cluster-issuer: letsencrypt-prod external-dns.alpha.kubernetes.io/hostname: remote.dooplex.hu,remote.home nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: 100m # WebSocket support (required for Guacamole RDP/VNC sessions) nginx.ingress.kubernetes.io/proxy-buffering: "off" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/configuration-snippet: | set $geo_allowed 0; if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; } if ($remote_addr ~ "^10\.") { set $geo_allowed 1; } if ($geoip2_country_code = "HU") { set $geo_allowed 1; } if ($geo_allowed = 0) { return 403 "Access restricted to Hungary"; } spec: ingressClassName: nginx-internal rules: - host: remote.dooplex.hu http: paths: - path: / pathType: Prefix backend: service: name: guacamole port: number: 8080 - host: remote.home http: paths: - path: / pathType: Prefix backend: service: name: guacamole port: number: 8080 tls: - hosts: - remote.dooplex.hu secretName: guacamole-tls