# Kasm Workspaces Documentation > Reference documentation for Kasm Workspaces 1.19.0 (the latest stable release). Version: 1.19.0 Complete documentation for Kasm Workspaces 1.19.0 (the latest stable release), with every page inlined in a single document for offline/one-shot ingestion. ## Secure Architecture for DoD & Federal Use # Architecture To meet various DoD and NIST guidance, the following architecture guidance should be followed for US Federal and DoD deployments. This architecture is also recommended for clients needing to meet other industry compliance such as [SOC](https://www.aicpa-cima.com/resources/landing/system-and-organization-controls-soc-suite-of-services) or [ISO/IEC 27001](https://www.iso.org/isoiec-27001-information-security.html). The Web App role servers, database servers, and Agent Role servers should each be on different subnets with a firewall between them. The Web App Role servers should be placed in a DMZ, instead of inside the enclave. The agents can be placed in the enclave on-premise or in the cloud where needed. Firewall rules should be used to limit where user traffic from containers can go, according to DoD allow by exception policy. ## Reverse Proxy The Web App Role servers should not be directly publicly exposed. Instead, there should be a [reverse proxy](../how-to/networking/reverse-proxy.mdx) in front of the servers that meets the various DoD requirements, such as DoS rate limiting, Web Application Firewall (WAF), and other requirements. DoD/Federal networks typically have an F5 or other appliance in the security stack dedicated to providing reverse proxy services to resources inside the network. These appliances are typically capable of providing access to internal resources using different methods and they have vendor specific terminology for those methods. However, the appliance must be configured to act as a standard reverse proxy with WAF features enabled. ## WAF Rules Web Application Firewalls (WAF) should be used to mitigate various risks. WAFs can induce issues with false positives, so alerts should be investigated and the rules should be tweaked as needed. WAFs generally allow you to specify whether the body of the request should be inspected, or just the request URL and headers. Inspection of just the URL and headers is generally safe with standard OWASP rules. Body inspection can cause issues, especially with user uploads and downloads. --- ## Kasm Connection Proxies: RDP, SSH, and VNC Gateway # Connection Proxies The Connection Proxy component is the gateway between users and resources they want to access that utilize RDP, SSH or traditional VNC. Container based desktops and apps do not utilize the Connection Proxy component. The proxy role is comprised of 3 different containers, which have different responsibilities. Connection proxies are automatically registered with the Kasm deployment when [installing](../tutorials/install/multi-server-install.mdx) the Connection Proxy component on a server. For Kubernetes deployments, Kasm will always show a single instance of each component type. ![Connection Proxies](/img/connection_proxies/connection_proxies.webp) ## Components ### Guacamole (GUAC) Kasm utilizes a custom compiled build of Apache guacd in combination with our own micro service for controlling guacd. Guacd is used for web-native connections to backend RDP, VNC, and SSH servers. Kasm spawns 1 guacd service per core on the system and automatically load distributes sessions between the services, providing for better use of system resources on multi-core systems. Administrators can override this default of 1 guacd service per core by using the `--guac-cluster-size N` flag on installation, where N signifies the number of guacd instances you wish to be running on the system. ### RDP Gateway Added in Kasm Workspaces 1.16.0, the RDP Gateway provides a proxy capability allowing users to use a client-side RDP thick client to connect to Kasm Windows workspaces. This provides several features that are not possible with Kasm's web native RDP access method, including smart card, USB, and webcam passthrough from the user's client machine into the Kasm session while maintaining Kasm's DLP protections. Windows, Linux, ChromeOS, and macOS clients are supported, however the instructions to configure a seamless experience differ by OS. See [Auto-Opening RDP Files](../how-to/workspaces-sessions/server-workspace/auto-open-rdp-file.mdx) for more details. Kasm Technologies has tested the Microsoft client on Windows and macOS and the XtraLogic client on ChromeOS, however any RDP client software should be compatible. The chosen client must support the desired features; for instance, not all clients support smart card passthrough. ### RDP HTTPS Gateway The RDP HTTPS Gateway allows for RDP connections to traverse over HTTPS, primarily used to facilitate connections through enterprise security firewalls and other security devices. The RDP HTTPS Gateway follows the [Microsoft Remote Desktop Gateway Server Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/b68cd6a0-999f-46cf-9038-4d4b3afbc7c3). The Kasm RDP HTTPS Gateway does not understand the RDP protocol itself, but rather tunnels the underlying RDP protocol through web based transport. Because this component does not understand RDP, it is used in conjunction with the **RDP Gateway** covered in the above section. ## RDP Native Connections By default, when a client connects to a Kasm session with an RDP client, it will come first to the **RDP HTTPS Gateway**, then to the **RDP Gateway**, and finally to the destination server. Administrators can disable the **RDP Gateway** or the **RDP HTTPS Gateway** to reduce overhead, however, there are consequences for disabling either. Disabling the **RDP HTTPS Gateway** will mean clients will connect to Kasm using the RDP protocol, which may not be allowed through some firewalls that are not in your control. If this is not an issue in your environment, or the environments where clients will connect from, then this may be a good way of increasing the performance of the connection proxy server and thus improving user experience. Admins can uncheck the **Enable RDP HTTPS Gateway** setting in [Zone Settings](../how-to/infra-autoscale/deployment-zones.mdx#defining-zone-configurations) to achieve this. Conversely, the **RDP Gateway** can be disabled by the administrator by unchecking the **Enable RDP HTTPS Gateway DLP** option in the [Zone Settings](../how-to/infra-autoscale/deployment-zones.mdx#defining-zone-configurations). RDP traffic will then directly flow from the **RDP HTTPS Gateway** to the destination server, without traversing the **RDP Gateway** component which facilitates DLP and SSO features. Disabling the **RDP Gateway** can significantly reduce bandwidth consumption and improve end-user experience with the following drawbacks: * [Data Loss Prevention](../how-to/security/data-loss-prevention.mdx) controls will not be enforced by Kasm. These include settings such as allowing clipboard, uploads, and downloads. Many of these settings can also be enforced through Windows Group Policy. * [SSO](../how-to/workspaces-sessions/server-workspace/windows/authentication.mdx) is only supported when the RDP traffic goes through the **RDP Gateway**. Without the **RDP Gateway** users will get prompted to input credentials. Smartcard authentication into Windows will continue to work with the **RDP HTTPS Gateway DLP** disabled. * Static credentials assigned to a server in Kasm are not passed through in RDP sessions when the **RDP Gateway** is disabled. * Microsoft RemoteApp support with the **RDP Gateway** disabled is not a supported configuration. ## Architecture ![Architecture](/img/multi_install/multiple_install.png) The above diagram shows the architecture and user flow of traffic. For Kasm guac sessions, when a user connection to a remote session comes in, shown in light blue, the request can optionally be load balanced between multiple web app servers. The Web App server queries the database for a list of potential connection proxy servers that are responsible for the Kasm Deployment Zone that the requested server is in. The Web App service goes down the list of connection proxies in random order and performs a health check. The user's HTTPS connection is then proxied to the first connection proxy server \(light purple line\), in the request zone, that succeeds the health check. This sequence of events ensures resiliency in the event of networking or server issues with a single connection proxy. For Kasm RDP gateway sessions, when a user connection to a remote session comes in, shown in light blue, the request can optionally be load balanced between multiple web app servers. The Web App server queries the database for a list of potential RDP gateway connection proxy servers that are responsible for the Kasm Deployment Zone that the requested server is in. The Web App service goes down the list of RDP gateway connection proxies in random order and performs a health check. When a healthy server is found the Web App server builds an RDP file targeting the selected RDP gateway server and presents it to the user's browser for download. The user's RDP client then makes a connection over HTTPS(443) or 3389, depending on if the RDP HTTPS Gateway is enabled, to the Kasm RDP gateway service \(dark blue line\), which is then proxied to the RDP target. This sequence of events ensures resiliency in the event of networking or server issues with a single RDP gateway connection proxy. When the connection from the user enters either the RDP gateway or guac connection proxy, it performs an authentication request up to the Web App Role server \(light purple line\) to authenticate the user, authorize that the user has access to the requested server, and to download connection details for the server. The connection proxy then performs an RDP connection to the remove server \(green line\). Single server deployments have all roles installed on a single server. For multi-server deployments, you should consider deploying at least 2 connection proxy servers per Kasm deployment zone. Kasm will automatically load balance users and provide automatic fail-over should one stop responding. --- ## Kasm Workspaces Kubernetes Deployment Options # Kubernetes Deployment Options When deploying Kasm Workspaces on Kubernetes, the Helm chart covers the core services but not everything. Which additional components you need to provision depends on what session types you want to support and how many zones you are running. --- ## Service Roles Kasm Workspaces is composed of four service roles. Each role can be deployed independently, and larger deployments typically spread them across separate hosts for performance and isolation. ### App Includes: NGINX, API, Manager The App role is the control plane for a zone. It handles authentication, session orchestration, and all administrative UI and API functions. Every zone requires exactly one App instance. The App role should be deployed close to the database, as it is the only role that communicates directly with it. ### Connection Proxy Includes: NGINX, Guacamole, RDP Gateway, RDP HTTPS Gateway The Connection Proxy role routes browser-based RDP, VNC, and SSH connections to external workloads. It is the gateway for any non-Docker session type. For best performance it should be deployed close to the target workloads (Windows VMs, Linux RDP hosts, etc.) it proxies. ### Dedicated Proxy Includes: NGINX (kasm_proxy) The Dedicated Proxy role is a standalone zone-local relay that directs end-users to the correct Kasm Agent for container sessions. Rather than routing KasmVNC session traffic through the App role, a Dedicated Proxy handles that routing locally within the zone, reducing latency. In standard deployments, session routing for container sessions is handled by the built-in proxy in the App role — no Dedicated Proxy is needed. The standalone Dedicated Proxy (`--role proxy`) is an alternative to that built-in routing, providing a zone-local relay. It is most beneficial when an additional zone is geographically distant from the primary zone. ### Agent Includes: Docker runtime, Kasm Agent service, kasm_proxy The Agent role runs containerized desktop and application sessions. Each Agent also runs a local `kasm_proxy` for routing its own sessions. Agents are always deployed outside of Kubernetes on standard Docker hosts and are never included in the Helm chart. Each zone needs its own Agent pool — Agents are not shared across zones. --- ## What the Helm Chart Deploys ### Single-Zone Deployment The Helm chart bundles the **App**, **Connection Proxy**, and **Dedicated Proxy** roles into the cluster. This covers all session routing for the primary zone out of the box. | Role | Deployed by Helm | Notes | |---|---|---| | App | Yes | API, Manager, built-in PostgreSQL | | Connection Proxy | Yes | Guacamole, RDP Gateway, RDP HTTPS Gateway | | Dedicated Proxy | Yes | Proxies KasmVNC traffic to Agents | | Agent | **No** | Must be provisioned separately | To support container sessions in a single-zone deployment, you only need to add Agents. RDP and VNC sessions work immediately via the bundled Connection Proxy. ### Multi-Zone Deployment When you define multiple zones in `my-values.yaml`, the Helm chart deploys the full set of roles for the **primary zone** (first in the list) but only the **App role** for each additional zone. Proxy and Agent components for additional zones must be provisioned externally via the [multi-server installation guide](../tutorials/install/multi-server-install). | Role | Primary Zone | Additional Zones | |---|---|---| | App | Helm (in cluster) | Helm (in cluster, one per zone) | | Connection Proxy | Helm (in cluster) | **External** — deploy if supporting RDP/VNC | | Dedicated Proxy | Helm (in cluster) | **External** — deploy for container session performance | | Agent | **External** | **External** — deploy if supporting container sessions | --- ## Choosing What to Deploy Use the table below to determine which external components to provision for each additional zone. The primary zone requires no external components unless you are adding Agents. | Container sessions | RDP / VNC sessions | External components needed (per additional zone) | |---|---|---| | No | No | None | | Yes | No | Agent; Dedicated Proxy *(optional — reduces latency)* | | No | Yes | Connection Proxy | | Yes | Yes | Agent, Connection Proxy; Dedicated Proxy *(optional — reduces latency)* | :::note Agents are required for any zone that runs container sessions, including the primary zone. The Dedicated Proxy is optional: without it, container session traffic routes through the App role's built-in proxy rather than a zone-local relay — sessions work, but potentially with higher latency. A Dedicated Proxy is most beneficial when additional zones are geographically distant from the primary zone. ::: --- ## Related Resources - [Install Kasm on Kubernetes](../tutorials/install/kubernetes) — step-by-step Helm installation - [Multi-Zone Proxies with Kubernetes](../how-to/kubernetes/multi_zone_proxies) — provision Connection and Dedicated Proxies for additional zones - [Multi-Server Installation Guide](../tutorials/install/multi-server-install) — install individual roles on external VMs - [Connection Proxies](./connection-proxies) — deeper explanation of how the Connection Proxy role works --- ## Plugin Management: Update, Rollback, Reinstall # Plugin Management Kasm utilizes Docker Engine Plugins to provide some of its capabilities. For example, the Kasm Network Plugin drives the sidecar network for [customized workspace egress](../how-to/networking/egress/index.mdx). Although they are hosted on the same registries as container images, plugins are treated differently by Docker and have different workflows for maintenance. Notably, the system can't simply **pull** a plugin to update it. ## Automated Updates Kasm automatically attempts to upgrade Kasm Docker plugins with rolling identifiers in their names (see the "Determining Alias" section below). This will happen every time the Kasm service is started (via `sudo systemctl start kasm`), along with the `pull` for rolling service images. The script will only update a given plugin if there are no other active system components using it, such as containers or docker networks. A ledger file is maintained for each plugin modified by this script. The file records information about each installed version. ### Rollback If a plugin upgrade needs to be rolled back, it can be accomplished through one of Kasm's provided scripts. The snippet below will reinstall the most recent previous version of the plugin; if you upgraded from version A to version B, rollback would target version A. Rolling back a plugin will pin the plugin to the rollback version. This removes the rolling tag from the plugin; it will no longer be automatically updated when the Kasm service starts. ```yml sudo systemctl stop kasm # Determine the name of the plugin, as seen in the output of # sudo docker plugin ls plugin_name= sudo /opt/kasm/bin/utils/upgrade_plugins --rollback --name "$plugin_name" ``` If the last stable version cannot be determined, the script will not modify the plugin. In that event, you should browse the plugin's repository and determine which version you would like to install. Use that tag as the `--version` in the "Reinstallation" section below. ## Reinstallation Kasm provides a script that will install an arbitrary version of a Kasm Docker plugin present on the system. ### Determining Name Use `sudo docker plugin ls` to determine the names of Kasm Docker plugins. ### Determining Version (Tag) Plugin tags can be viewed on the source registry. Alternatively, you can use the following script to query for the lastest patch-level tag found on the registry. In the snippet, we query for the plugin used by the sidecar network, for the latest x86_64 version of the 1.2 plugin release. ```yml sudo /opt/kasm/bin/utils/plugin_helper 'kasmweb/kasm-network-plugin:amd64-1.2' --latest ``` * Use `arm64` for ARM architecture systems * The tag must provide the architecture, but can specify `Major.Minor` versions (e.g. `1.2`), just Major version (e.g. `1`), or omit the version entirely ### Determining Alias Alias is optional. Provide a plugin alias if you want the installed plugin to use a Name different than the registry reference. The plugin used by the egress feature has an alias of `kasmweb/sidecar:{tag}` Providing an alias that matches `/-rolling.*$/` will tell kasm to automate updates to this plugin, even if the registry reference isn't a rolling tag. Don't mix and match "rolling"! ### Script Execution Basic usage: ```yml sudo systemctl stop kasm # Determine the name of the plugin, as seen in the output of # sudo docker plugin ls plugin_name= sudo /opt/kasm/bin/utils/upgrade_plugins --reinstall --name "$plugin_name" --version "$plugin_version" --alias "$plugin_alias" ``` ## Force Upgrade To force upgrade a Kasm Docker plugin to the latest version, use the following script. ```yml sudo systemctl stop kasm # Determine the name of the plugin, as seen in the output of # sudo docker plugin ls plugin_name= sudo /opt/kasm/bin/utils/upgrade_plugins --name "$plugin_name" ``` This always pulls down the latest image from the registry, even if it is the same as the currently installed version. --- ## Patterns --- ## Reference Architecture 1: Single Server # (RA1) Single Server Architecture Explained The Single Server architecture, designated **RA1**, is often described as the simplest way to deploy Kasm Workspaces. That description is accurate from an operational perspective. It is misleading from an architectural perspective. RA1 is not a reduced version of the platform, it is a **collapsed version** of the platform. Every logical role that exists in the most sophisticated multi-region Kasm deployment also exists in RA1. The Web App, the Database, the Agent, the Connection Proxy, and the session delivery infrastructure are all present. What is absent in RA1 is the **separation between those roles**. Understanding RA1 is therefore less about understanding the diagram, which shows a single server, and more about understanding **what disappears when all roles are collapsed** onto one machine and what the consequences of that collapse are. --- ## Reference Architecture 1 ![Kasm Workspaces RA1 Single Server Architecture Diagram](/img/reference_architecture/ra1.png) --- ## The Primary Load Balancer Each Kasm Web App role includes an NGINX container `kasm_proxy` that serves as a required front-end to internal services. While this component is integral to system operation, organizations may enhance their security posture by either hardening this configuration or deploying Kasm Workspaces **behind an enterprise-grade reverse proxy or load balancer**. Enterprise security solutions can provide **advanced protections** such as Web Application Firewall (WAF) capabilities, DDoS mitigation, and Zero Trust access controls. Additionally, SSL/TLS offloading can centralize traffic management and **reduce processing overhead on backend Kasm services**, improving both performance and resource efficiency. All user interactions, authentication, session initiation, and workspace streaming enter the environment through a single public endpoint, the Primary Load Balancer. This abstraction presents the deployment as **a unified service**, regardless of the underlying architecture. For production deployments, a **network load balancer** is the recommended approach. --- ## The Defining Characteristic: Role Collapse In more advanced Kasm architectures, responsibilities are distributed to separate infrastructure tiers. In RA1, all roles run on the same host, **share the same compute resources**, and are **exposed through the same network identity**. This creates a system with: - **No internal network topology** between roles - **No trust boundaries** between roles - **No independent scaling** of any role The architecture still behaves like Kasm. Sessions are authenticated, workspaces are provisioned, containers are launched, and sessions are streamed. The absence of role separation means that **none of the structural protections** that larger architectures provide are present. A resource spike in the Agent tier, where workspace containers consume CPU and memory, directly affects the Web App tier on the same host. A database failure is simultaneously a **control plane failure**, a **session provisioning failure**, and a **state persistence failure**, because all three functions share the same machine. --- ## The Illusion of Simplicity RA1 feels simple because there is **one hostname**, **one server**, and **one deployment unit**. Internally, the system is performing: - **API orchestration** - **Session scheduling** - **Container execution** - **Protocol translation** - **State persistence** These functions are not simplified in RA1. They are co-located. **RA1 reduces deployment complexity, not architectural complexity.** This distinction matters because it shapes how RA1 should be evaluated. An Enterprise Architect who concludes that Kasm is architecturally simple because RA1 appears simple has misinterpreted what they are looking at. RA1 is the architecture that results when all boundaries are deliberately removed. Its simplicity is a consequence of **collapsed boundaries**, not of an inherently simple system. --- ## Two Session Types, One Control Plane RA1 supports two fundamentally different session types that share a control plane but **diverge after session creation**. **Containerized workspaces** are launched on external Docker Agents and delivered as ephemeral containers. These sessions benefit directly from the distributed execution model: capacity for containerized workspaces **scales with the number of Agent nodes** registered to the control plane. **Remote system access sessions** connect to existing Windows, Linux, and macOS systems via RDP, VNC, or SSH. These sessions are mediated through the Connection Proxy on the control plane server, which **translates legacy protocols** into browser-native streams. The execution target is an existing system, not a container provisioned by Kasm. Both session types share the **same authentication flow** and the **same control plane**. The difference lies in where execution occurs and what infrastructure hosts it. --- ## The Control Plane and Execution Plane Share a Boundary In distributed architectures, the **control plane** makes decisions and the **execution plane** carries them out. Separating them allows each to scale, fail, and be maintained independently. In RA1, the Web App role decides where to run a session, and the Agent role executes that session, but both exist **on the same machine**. There is no network boundary between decision-making and execution. There is no resource isolation between orchestration and workload. The system loses its ability to separate the responsibility for decisions from the capacity to execute them. This becomes visible under load. As user concurrency increases, workspace containers compete for the same CPU and memory that the Web App API and the database require to function. In a distributed architecture, **Agent load is isolated from control plane load**. In RA1, they are the same load on the same hardware. --- ## The Database: State Without Isolation Even in RA1, the database remains the **single source of truth** for user sessions, configuration, and authentication state. Its role is not simplified in any architectural sense. It stores exactly the same data it would store in an RA3 or RA4 deployment. What changes in RA1 is that the database **shares its compute, memory, and failure domain** with every other role on the system. In larger architectures, the database occupies a dedicated, isolated segment. In RA1, **the most critical component in the system has no isolation** from any other component. This is the most significant architectural property of RA1 from a resilience perspective. :::warning In RA1, any failure is a total failure. A hardware failure, a kernel panic, an out-of-memory condition, or a network disruption affects every role simultaneously. ::: --- ## DNS and Identity: A Single Point of Truth RA1 typically uses a **single public hostname**, for example `kasm.example.com`. This hostname represents the Web App, the Proxy, and the session endpoint simultaneously. Because everything is on one server: - **Browser origin rules** are trivially satisfied - **TLS configuration** requires only a single certificate for a single hostname - **No cross-domain considerations** exist This simplicity makes RA1 the clearest environment in which to observe how Kasm behaves when **identity, transport, and execution share a single domain**. The DNS and TLS requirements that become more complex in distributed architectures are visible here in their simplest possible form. Even at this scale, TLS must match the configured hostname, WebSocket origin must match, and the Proxy Hostname must resolve identically. These requirements **do not relax** in RA1: they are simply easier to satisfy because everything resolves to one address. --- ## What RA1 Reveals About Kasm's Design Philosophy Despite its limitations as a production architecture, RA1 reveals the **core design philosophy** of the platform clearly: **The system is inherently multi-role.** Even when collapsed onto a single host, distinct responsibilities exist and are executed by distinct services. The architecture does not disappear in RA1: the boundaries between roles are simply not enforced by physical or network separation. **The browser is the universal client.** All access is mediated through web-native protocols regardless of the complexity of the underlying execution environment. RA1 makes this particularly clear because there is no complex proxy topology to obscure the basic relationship between browser and platform. **Sessions are ephemeral workloads.** Workspaces are created and destroyed on demand in RA1 exactly as they are in RA4. The ephemerality of sessions is not a feature of large-scale deployments: it is a property of how the platform works at every scale. **The control plane governs everything.** All decisions about authentication, session placement, and policy evaluation originate from the Web App role, even when that role is co-located with everything else. --- ## RA1 in the Deployment Progression RA1 occupies a **specific and intentional position** in the deployment progression. It is the starting point, the baseline for understanding, and the architecture that exposes what must change to achieve resilience. | **What RA1 Lacks** | **What It Teaches** | |---|---| | **Isolation between roles** | Why role separation is the foundation of all resilience improvements | | **Independent scaling of any tier** | Why statelessness of the Web App role is architecturally significant | | **Database resilience** | Why the database is the single most critical HA investment | | **Any partial failure mode** | Why the difference between control plane and session plane failures matters | RA1 is not an endpoint, it is a point of departure. It demonstrates a complete Kasm system in its most compressed form: control plane, execution plane, transport, and state all co-located, sharing a **single identity**, a **single failure domain**, and a **single boundary**. From an enterprise perspective, the key realization is this: **RA1 is designed for understanding, not resilience.** Because once you understand what RA1 lacks, you understand exactly why the rest of the architecture exists. --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Reference Architecture 2: Single Server Control Plane with External Agents # (RA2) Single Server Control Plane with External Docker Agents Architecture Explained The RA2 architecture is frequently described as RA1 with more servers. That description is accurate about the hardware involved. It is misleading about what changes architecturally. RA2 is the **first meaningful separation of responsibility** in Kasm Workspaces. It introduces the most fundamental structural distinction the platform makes: the separation between **decision-making and execution**. In RA1, the same machine both decides where a session runs and runs it. In RA2, the control plane still decides, but the **execution happens elsewhere**. This is not a configuration change. It is the beginning of a **distributed system**. --- ## Reference Architecture 2 ![Kasm Workspaces RA2 Single Server Control Plane with External Agents Architecture Diagram](/img/reference_architecture/ra2.png) --- ## The Primary Load Balancer Each Kasm Web App role includes an NGINX container `kasm_proxy` that serves as a required front-end to internal services. While this component is integral to system operation, organizations may enhance their security posture by either hardening this configuration or deploying Kasm Workspaces **behind an enterprise-grade reverse proxy or load balancer**. Enterprise security solutions can provide **advanced protections** such as Web Application Firewall (WAF) capabilities, DDoS mitigation, and Zero Trust access controls. Additionally, SSL/TLS offloading can centralize traffic management and **reduce processing overhead on backend Kasm services**, improving both performance and resource efficiency. All user interactions, authentication, session initiation, and workspace streaming enter the environment through a single public endpoint, the Primary Load Balancer. This abstraction presents the deployment as **a unified service**, regardless of the underlying architecture. For production deployments, a **network load balancer** is the recommended approach. --- ## From Consolidated to Distributed In RA1, everything happens in one place. In RA2, one change fundamentally alters the system's character: **the Agent function moves to external nodes**. The **control plane remains centralized**. The single Kasm server in RA2 still contains the Web App, the Database, and the Connection Proxy. It is still the authoritative core of the system, handling authentication, policy evaluation, session scheduling, and state persistence. From the browser's perspective, the entire platform **still appears as a single endpoint** with a single identity. But the **execution plane has become distributed**. External Docker Agents run on separate infrastructure, host containerized workspace sessions, and provide scalable compute capacity no longer constrained by the resources available on the control plane server. | **Role** | **RA1 Location** | **RA2 Location** | |---|---|---| | **Web App** | Single server | Single server (unchanged) | | **Database** | Single server | Single server (unchanged) | | **Connection Proxy** | Single server | Single server (unchanged) | | **Docker Agent** | Single server | **External Docker Agent nodes** | The architectural consequence of this separation is that **workloads no longer run where decisions are made**. The system has acquired the most basic property of a distributed architecture: different functions occurring on different machines, coordinated through a defined interface. --- ## Three Traffic Flows Define the Architecture Reading RA2 correctly requires understanding it as a **system of flows** rather than a collection of components. The **control plane flow** handles authentication and orchestration. This flow runs between the user's browser and the single Kasm control plane server. The user authenticates, requests a workspace, and receives session connection details. This flow is **entirely contained** within the control plane server. The **execution flow** handles workload instantiation. When the control plane selects an external Agent for a session, it instructs that Agent to provision a container. This flow runs between the **control plane server and the external Agent nodes** over internal network paths. The **session plane flow** handles workspace streaming. Once a container is running on an external Agent, the user's browser connects to it through the Connection Proxy on the control plane server. This flow runs from the user's browser, through the **control plane server's proxy**, to the external Agent hosting the container. Understanding RA2 is understanding how these three flows **diverge after session creation**. --- ## Two Session Types, One Control Plane RA2 supports two fundamentally different session types that share a control plane but **diverge after session creation**. **Containerized workspaces** are launched on external Docker Agents and delivered as ephemeral containers. These sessions benefit directly from the distributed execution model: capacity for containerized workspaces **scales with the number of Agent nodes** registered to the control plane. **Remote system access sessions** connect to existing Windows, Linux, and macOS systems via RDP, VNC, or SSH. These sessions are mediated through the Connection Proxy on the control plane server, which **translates legacy protocols** into browser-native streams. The execution target is an existing system, not a container provisioned by Kasm. Both session types share the **same authentication flow** and the **same control plane**. The difference lies in where execution occurs and what infrastructure hosts it. --- ## Asymmetrical Failure Behavior RA2 introduces something RA1 cannot provide: **asymmetrical failure behavior**. When an **Agent node fails** in RA2, only the sessions running on that specific Agent are interrupted. Users on other healthy Agents continue working unaffected. New sessions are scheduled to remaining healthy Agents automatically. When the **control plane server fails**, no new sessions can be created, authentication fails for new connections, and the entire management interface becomes unavailable. Existing sessions already streaming between a browser and an Agent may continue briefly, because the session plane is database-independent mid-stream, but they **cannot be re-authenticated** and will eventually terminate. :::info **RA2 is partially resilient, not highly available.** Organizations that require control plane fault tolerance need RA3 or higher. RA2 is appropriate for capacity expansion beyond a single server and for environments where control plane downtime during maintenance windows is acceptable. It should **not** be treated as a production-grade HA architecture. ::: --- ## What RA2 Reveals About Kasm's Design Philosophy RA2 exposes several core principles of the Kasm design that RA1 cannot demonstrate, because RA1 collapses everything into one place. **Centralized control with distributed execution** is not just a scaling pattern. It is the foundational structure of the platform. The control plane governs everything: it authenticates, authorizes, schedules, and records. **The execution plane does exactly what it is told and nothing more.** **Zero trust mediation is architecturally enforced**, not configured. Users cannot connect directly to workloads because the architecture does not provide a path for them to do so. The Connection Proxy is the only path, and it validates every connection against the control plane. **Sessions are disposable and location-independent.** When a container runs on an external Agent in a different part of the data center, the user's experience is identical. The location of execution is an **infrastructure detail that the architecture deliberately abstracts away**. --- ## RA2 in the Architectural Progression RA2 demonstrates that the execution plane can be distributed without any fundamental change to the control plane. It also reveals what remains unresolved: control plane redundancy, database resilience, and proxy distribution. For an Enterprise Architect, the key realization RA2 offers is this: **RA2 is where infrastructure stops being a collection of servers and starts becoming a coordinated system of roles.** Once that shift happens, the question that follows naturally is: if the execution plane can be distributed, why not the control plane as well? --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Reference Architecture 3: Single-Zone Multi-Server # (RA3) Single-Zone Multi-Server Architecture Explained The RA3 architecture is the point in the Kasm deployment progression where the platform's design philosophy is **fully expressed in a single-region topology**. This completes the role separation that RA2 begins and adds the redundancy mechanisms that transform each separated role from a potential single point of failure into a resilient, independently managed tier. RA3 is the architecture **most production enterprise deployments should be running**. It is also the foundation that RA4 extends without fundamentally changing. Everything RA4 does is add geographic distribution of the session plane on top of an RA3 control plane. Understanding RA3 means understanding not just the component topology, but the reasoning that produced each architectural decision within it. --- ## Reference Architecture 3 ![Kasm Workspaces RA3 Single Zone Multi Server Architecture Diagram](/img/reference_architecture/ra3.png) --- ## The Primary Load Balancer Each Kasm Web App role includes an NGINX container `kasm_proxy` that serves as a required front-end to internal services. While this component is integral to system operation, organizations may enhance their security posture by either hardening this configuration or deploying Kasm Workspaces **behind an enterprise-grade reverse proxy or load balancer**. Enterprise security solutions can provide **advanced protections** such as Web Application Firewall (WAF) capabilities, DDoS mitigation, and Zero Trust access controls. Additionally, SSL/TLS offloading can centralize traffic management and reduce processing overhead on backend Kasm services, improving both performance and resource efficiency. All user interactions, authentication, session initiation, and workspace streaming enter the environment through a single public endpoint, the Primary Load Balancer. This abstraction presents the deployment as **a unified service**, regardless of the underlying multi-node architecture. A critical requirement of the Primary Load Balancer is **continuous backend health awareness**. The Kasm Web App exposes a `/api/__healthcheck` endpoint that verifies both application availability and database connectivity. If a Web App instance becomes unable to reach the database, it is automatically marked unhealthy and removed from traffic routing. For production deployments, a **network load balancer** is the recommended approach. Unlike DNS round-robin, which relies on TTL expiration and may continue routing traffic to failed nodes for 90–300 seconds, a network load balancer performs active health checks and reroutes traffic to healthy instances within seconds, ensuring higher availability and a more reliable user experience. --- ## Private Load Balancer One of the subtler architectural decisions is the use of a **private load balancer** within each zone. The private load balancer is positioned between the Web App nodes on one side, and the Agent and Connection Proxy nodes on the other. This design establishes an internal routing path for control-plane traffic, ensuring it remains within the private network. As a result, control traffic does not traverse the external load balancer interface, improving both efficiency and security. --- ## The Web App Tier: Statelessness as an Architectural Superpower The Web App tier is the **control plane** of the RA3 deployment. Multiple Web App servers run behind the Primary Load Balancer, forming an HA cluster that makes the control plane resilient. The property that makes horizontal scaling of the Web App tier straightforward is **statelessness**. No session state lives inside the Web App process. Everything is delegated to the database. Any Web App instance can be removed from the cluster at any time **without affecting users** interacting with other instances. A Web App server that needs patching is drained from the load balancer, patched and rebooted, and returned to the cluster with **no user-facing interruption**. The recommended minimum for production RA3 Web App high availability is **N+1**: one more Web App server than needed to serve peak load. An organization expecting 500 concurrent users might require 2 Web App servers at peak. N+1 means deploying **3**, providing both failure tolerance and maintenance flexibility simultaneously. **Every instance is active and capable of serving any request.** There is no primary or secondary designation, no active-passive relationship. --- ## Database The database sits in a **dedicated segment, isolated** awar from the internet-facing infrastructure boundary. This placement reflects the database's distinct security requirements and its role as the **only stateful component** in the entire deployment. When the database is unavailable, the entire platform is **operationally blocked**. No component in the Web App tier can perform its core function without database access. This is the single most consequential availability dependency in the entire deployment, and it is the one that most frequently receives insufficient attention. | **Redundancy Approach** | **Mechanism** | **Suitable For** | |---|---|---| | **AWS RDS Multi-AZ** | Synchronous standby; automatic failover | Cloud deployments on AWS | | **AWS Aurora PostgreSQL** | Multi-primary compatible clustering | High-throughput cloud deployments | | **Cloud-provider equivalents** | Varies by provider | Azure, GCP, OCI managed PostgreSQL | | **Self-managed replication with Patroni** | PostgreSQL streaming replication; automated failover | On-premises and private cloud | | **Single containerized instance** | None | Small teams, development and proof-of-concept | > **Warning:** Kasm ingests platform logs into the database by default. At scale with hundreds of concurrent sessions, this log volume can reach **tens of gigabytes** within days under default retention settings. For larger deployments, forwarding logs to an external SIEM and **disabling Kasm's internal log retention** both reduces storage requirements and removes I/O load that competes with operational queries. This is a critical configuration and a **production readiness requirement** at enterprise scale. --- ## Docker Agents Docker Agents are the compute nodes that provision and host containerized workspace sessions. Agent redundancy follows a straightforward principle: **the more Agents in the zone, the smaller the impact of any single Agent failure**. When an Agent fails, sessions on that node are interrupted. Users reconnect, receiving a **fresh container on a surviving Agent**. Sessions on other Agents continue unaffected. New sessions are routed to healthy Agents automatically. > **Warning:** Autoscaling requires that the **Upstream Auth Address** zone setting be correctly configured before autoscaling is enabled. Newly provisioned Agent virtual machines must be able to reach the Web App API to register with the zone. If the Upstream Auth Address points to an internal IP or a **single Web App server hostname** rather than the load balancer, autoscaled Agents may fail to register silently. The virtual machine provider provisions the VM, but **Kasm never sees a successful check-in**, and capacity does not increase when needed. This is the **most common autoscaling failure mode** in enterprise deployments. --- ## The Ephemeral Container Model The ephemerality of containers is not a tradeoff: it is a **feature of the security model** that also simplifies the HA calculus. In traditional VDI, a **compromised persistent desktop remains compromised** until discovered and remediated. The compromise may persist for days or weeks while an attacker maintains access. In a Kasm container session, the container is **destroyed at session end**, taking any compromise with it. The next session starts from a **clean, verified image**. For HA purposes, the ephemerality of containers means there is **no persistent data at risk** when an Agent fails. A failed Agent takes nothing meaningful with it. The recovery operation is a **session restart**, not a virtual machine restoration procedure. **The security benefit and the operational benefit are consequences of the same decision.** --- ## The Connection Proxy Tier: Gateway for Legacy Infrastructure The Connection Proxy tier in RA3 provides web-native access to existing infrastructure: **Windows servers, Linux systems, macOS machines**, and any endpoint accessible via RDP, VNC, or SSH. It is an **optional** role; deployments that use only containerized workspaces are delivered through the Agent role. A common enterprise pattern is **hybrid delivery**: containerized browser workspaces for secure web browsing alongside Connection Proxy-mediated **RDP access for Windows line-of-business applications** that require a full Windows environment. --- ## RA3 as a Direct Expression of Zero Trust RA3's architectural structure is not merely an engineering convenience. It is a **direct expression of Zero Trust principles** at the infrastructure level. - The **database** sits in an isolated segment with no public interface. Only the Web App tier can reach it. - The **Docker Agents** sit behind an internal Private Load Balancer with no public exposure. Users reach sessions through the proxy path, **never directly to the container**. - The **Connection Proxy tier** translates legacy protocols into WebSocket before they reach the user's browser, eliminating the need to expose RDP, VNC, or SSH ports to the public internet. - The **Primary Load Balancer** is the single controlled entry point where traffic inspection and WAF rules can be applied uniformly. Each of these is an expression of the same principle: **minimize the attack surface, enforce access through controlled choke points, and ensure that compromise in one component cannot be leveraged to attack another**. The architecture does not trust that users connect from managed endpoints. It does not trust that the network outside the deployment boundary is clean. It trusts **only the session token** that the control plane issues, and it validates that token at every session connection. This is what distinguishes RA3 from a collection of virtual machines running VDI software: it is an architecture designed around the assumption that **trust must be earned at every boundary, not assumed at the perimeter**. --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Reference Architecture 4: Multi-Zone Multi Server # (RA4) Multi-Zone Multi-Server Architecture Explained Every previous architecture in the Kasm progression solves for **resilience within a single region**. RA4 answers a different question: what happens when the users themselves are distributed across the globe? That question exposes a problem that no amount of single-region redundancy can resolve. **Control plane traffic**, which includes authentication, session provisioning, and policy evaluation, must flow to wherever the Kasm Web App and its database reside. **Session plane traffic**, the live pixel stream that constitutes the user's workspace experience, is sensitive to **round-trip latency** between the user and the infrastructure relaying it. In a single-region deployment, both types of traffic travel to the same place. For a user on the other side of the world, this is the source of a degraded experience that **no configuration change can fix**, because the underlying problem is the speed of light across fiber. RA4 resolves this problem by **separating the two planes geographically**. The control plane remains centralized in a primary region. The session plane is distributed to secondary regions physically close to the users they serve. A user in London authenticates through the central control plane and then receives a session stream **from infrastructure in London**. The authentication adds a one-time latency cost. The session itself runs at local speeds. > **Every component placement, every load balancer, every zone definition, and every DNS record in RA4 is an expression of this single organizing idea: separate the control plane from the session plane so each can be optimized independently.** --- ## Reference Architecture 4 ![Kasm Workspaces RA4 Multi Zone Multi Server Architecture Diagram](/img/reference_architecture/ra4.png) --- ## The Primary Load Balancer Each Kasm Web App role includes an NGINX container `kasm_proxy` that serves as a required front-end to internal services. While this component is integral to system operation, organizations may enhance their security posture by either hardening this configuration or deploying Kasm Workspaces **behind an enterprise-grade reverse proxy or load balancer**. Enterprise security solutions can provide **advanced protections** such as Web Application Firewall (WAF) capabilities, DDoS mitigation, and Zero Trust access controls. Additionally, SSL/TLS offloading can centralize traffic management and **reduce processing overhead on backend Kasm services**, improving both performance and resource efficiency. All user interactions, authentication, session initiation, and workspace streaming enter the environment through a single public endpoint, the Primary Load Balancer. This abstraction presents the deployment as **a unified service**, regardless of the underlying multi-node architecture. A critical requirement of the Primary Load Balancer is **continuous backend health awareness**. The Kasm Web App exposes a `/api/__healthcheck` endpoint that verifies both application availability and database connectivity. If a Web App instance becomes unable to reach the database, it is automatically marked unhealthy and removed from traffic routing. For production deployments, a **network load balancer** is the recommended approach. Unlike DNS round-robin, which relies on TTL expiration and may continue routing traffic to failed nodes for 90–300 seconds, a network load balancer performs active health checks and reroutes traffic to healthy instances within seconds, ensuring higher availability and a more reliable user experience. --- ## Private Load Balancer One of the subtler architectural decisions is the use of a **separate private load balancer** within each zone. The private load balancer is positioned between the Web App and Dedicated Proxy nodes on one side, and the Agent and Connection Proxy nodes on the other. This design establishes an internal routing path for control-plane traffic, ensuring it remains within the private network. As a result, control traffic does not traverse the external load balancer interface, improving both efficiency and security. --- ## The Two-Region Structure The RA4 diagram shows two distinct geographic regions. Understanding how they differ structurally is the key to understanding the architecture. **Region 1 is the primary region.** It hosts the control plane for all zones: the Web App nodes for Zone 1 and Zone 2 all reside here, along with the **PostgreSQL database**. Region 1 also hosts Zone 1's session infrastructure, because Zone 1 users are geographically local and do not benefit from session plane distribution. **Region 2 is the secondary region.** It is structurally identical. It hosts a **Dedicated Zone Proxy**, **Docker Agents**, and **Connection Proxies** for legacy protocol connections. **It does not host a Web App instance or any database infrastructure.** > **Note:** The placement of all zones' Web App nodes inside Region 1 is one of the most **architecturally significant decisions in RA4**, and one that surprises architects who expect each zone to have its own independent control plane. The reason is the **database dependency**: a Web App instance in Region 2 querying a database in Region 1 would add **80 to 120 milliseconds** to every query, compounding across multiple sequential queries per interaction to produce **multi-second control plane latency**. This is structurally unacceptable regardless of available bandwidth between regions. --- ## Why All Web App Instances Live in Region 1 The Web App role issues **synchronous, blocking database queries** for every user interaction. Authentication requires a database lookup. Session provisioning requires a database write. Policy evaluation requires a database read. **These operations cannot tolerate cross-continental database latency.** The solution RA4 adopts is to accept the **one-time latency cost of control plane traffic** for users in remote regions, while **eliminating the sustained latency cost of session traffic** by routing it to regional infrastructure. The one-time authentication latency is noticeable but not disruptive. Sustained session latency is directly experienced as **lag in every keystroke and mouse movement**. --- ## The Dedicated Zone Proxy The Dedicated Zone Proxy is the component that makes RA4 possible. It is a **session relay**; it accepts WebSocket connections from users' browsers and relays the session stream to the appropriate Agent. The Dedicated Proxy does not provision sessions (that is the Web App's job), does not authenticate users (that is the database's job via the Web App), and does not run workspaces (that is the Agent's job). It does exactly one thing: relay the session stream between the user and the Agent, at regional proximity. :::info What the Dedicated Proxy Does The Dedicated Proxy’s only responsibility is to relay session traffic between the user and the Agent or Connection Proxy at regional proximity. ::: The Dedicated Proxy does not provision sessions (that is the Web App's job), does not authenticate users (that is the database's job via the Web App), and does not run workspaces (that is the Agent's job). It does exactly one thing: relay the session stream between the user and the Agent, at regional proximity. ```mermaid sequenceDiagram actor U as User (Region 2 - London) participant Z2_LB as Zone 2 Public UI LB (Region 1) participant Z2_WA as Zone 2 Web App (Region 1) participant DB as PostgreSQL (Region 1) participant Z2_SESS_LB as Zone 2 Session LB (Region 2) participant Z2_PROXY as Dedicated Zone Proxy (Region 2) participant Z2_AG as Docker Agent (Region 2) rect rgb(253, 237, 236) Note over U,DB: Control Plane - Cross-region (~100ms RTT, one-time) U->>Z2_LB: HTTPS Login / Workspace request Z2_LB->>Z2_WA: Route request Z2_WA->>DB: Validate credentials and provision session DB-->>Z2_WA: Session token + proxy endpoint Z2_WA-->>U: Session token + Session LB address end rect rgb(213, 245, 227) Note over U,Z2_AG: Session Plane - Local to Region 2 (~5ms RTT, persistent) U->>Z2_SESS_LB: WSS connect Z2_SESS_LB->>Z2_PROXY: Route to proxy Z2_PROXY->>Z2_WA: Validate session token Z2_WA-->>Z2_PROXY: Token valid Z2_PROXY->>Z2_AG: Relay session stream Z2_AG-->>Z2_PROXY: Pixels, input, audio Z2_PROXY-->>U: Live session (low latency) end Note over Zone 2_Web App: Web App exits data path after token validation. ``` The token validation step, where the Dedicated Proxy contacts the Web App's **Upstream Auth Address** to verify the session token, is the one moment during session streaming where Region 2 touches Region 1. It happens once at session connection time, not continuously during the session. After validation, the session stream runs entirely within Region 2's infrastructure. This is why the **Upstream Auth Address** zone setting is so critical in RA4. It tells the Dedicated Zone Proxy in Region 2 where to send token validation requests. It must resolve to the Region 1 Web App load balancer's public address — not an internal IP, not a single Web App server hostname. If any Web App instance in the HA cluster fails, the **Upstream Auth Address** should continue resolving to the load balancer, which routes validation requests to remaining healthy instances. > **Warning:** The **Upstream Auth Address** zone setting is critical in RA4. It must resolve to the **Region 1 Web App load balancer's public address**, not an internal IP and not a single Web App server hostname. If any Web App instance in the HA cluster fails, the **Upstream Auth Address** should continue resolving to the load balancer, which routes validation requests to **remaining healthy instances**. --- ## Search Alternate Zones and Regional Failure The **Search Alternate Zones** setting governs what happens when a regional zone loses capacity entirely. For RA4 deployments where zones represent **geographic preferences**, this means a Region 2 capacity failure results in Region 2 users receiving sessions from Region 1 or Region 3 with higher latency, rather than a hard failure. For deployments where zones represent **compliance or tenant isolation boundaries**, this setting **must be disabled**. A zone boundary representing a PCI-scoped network segment or a classified enclave must not be crossed during overflow routing. A **capacity error is the correct behavior** when the alternative is a silent boundary violation. --- ### Database Tier Resilience A database failure is a global platform failure. | Approach | RPO | Failover | |---|---|---| | Managed HA (RDS Multi-AZ, Azure Flexible HA) | Near-zero | Automatic (~60 seconds) | | Self-managed Patroni | Near-zero | Automatic | | Cross-region async replica | Minutes (replication lag) | Manual promotion | ### Intra-Zone Resilience Each zone follows the same HA patterns as RA3 component tiers. | Zone Component | Minimum | Failure Impact | |---|---|---| | Dedicated Proxy nodes | 2 behind internal LB | One fails: active sessions on that proxy lost; others continue | | Agent nodes | 2+ | One fails: sessions on that Agent lost; new sessions use healthy Agents | | Connection Proxy nodes | 2 | One fails: legacy sessions lost; new sessions route to healthy proxy | Dedicated Proxy nodes are lightweight (kasm_proxy only, no DB or container runtime) and economical to deploy in pairs. ### RA4 HA Summary | Failure Scenario | Impact | Recovery | |---|---|---| | One Web App node fails | Brief management disruption; session streams unaffected | Automatic: LB routes around it | | Database fails (managed HA) | ~60 second platform unavailability | Automatic promotion | | One zone's Dedicated Proxy fails | Active sessions on that proxy lost; zone remains functional | Automatic: LB routes to remaining proxies | | Complete zone failure | Zone users lose sessions; all other zones unaffected | Zone users reassignable to another zone if policy permits | | Central Web App region fails | All zones lose auth and session launch | Requires secondary cluster or recovery from backup | --- ## Operational Complexity RA4 is the most operationally complex Kasm architecture. Treat these as deployment prerequisites, not post-deployment enhancements. | Requirement | Why | |---|---| | **Centralized observability** with zone-tagged logs and metrics | Zone-specific failures appear as intermittent global problems without zone tagging | | **Automated certificate management** | A certificate expiry in one zone causes a zone-scoped outage; wildcard certs plus automation prevent this | | **Per-zone configuration documentation** | Each zone's six settings must be documented and version-controlled independently | | **Image pre-loading across all zone Agents** | Staggered image cache state causes zone-specific workspace launch failures | | **WAN path monitoring** | Upstream Auth reliability from each remote zone to the central cluster must be actively monitored | --- ## When to Use RA4 | Requirement | RA4 Capability | |---|---| | Users in multiple regions requiring regional session proximity | Zone-specific Dedicated Proxy and Agent nodes deliver regional streaming | | Data residency: session compute must stay within a geographic boundary | Zone-per-region with Agents restricted to compliant infrastructure | | Regional failure must not cause a global outage | Zone isolation: zone failure is regional degradation only | | Single global administrative interface | Central Web App cluster manages all zones from one console | | Scaling from RA3 with proven multi-server operations | RA4 extends RA3; existing central infrastructure is unchanged | --- *This document completes the Kasm Workspaces Reference Architecture series. Return to the **Planning and Design Concepts** document for the foundational concepts underlying all four reference architectures.* --- ## Kasm Workspaces: Database and Web App Placement # Database and Web App Placement Constraint This principle warrants its own section because it is one of the most overlooked architectural constraints in multi-server Kasm deployments, and violations are typically discovered only after deployment when platform performance is already degraded. The constraint is simple and absolute: :::warning Important Every Web App node must be provisioned as physically and topologically close to the database as possible. ::: Close means same data center, same availability zone, or same cloud region: any configuration where the round-trip network latency between a Web App node and the database server is measured in **single-digit milliseconds**, not tens or hundreds of milliseconds. --- ## Why the Latency Math Matters The `kasm_api` and `kasm_manager` services issue many **sequential, blocking database queries** during normal operations. Sequential and blocking are the critical terms here. These are not fire-and-forget asynchronous calls. They are synchronous calls where **each step in a workflow waits for the previous database response** before proceeding. Consider a user launching a workspace in a deployment where the Web App is in US-East and the database is in APJ-West. The round-trip latency between those regions is approximately **100 to 150 milliseconds**. If a single workspace launch requires ten sequential database queries, the database interaction alone contributes **1,000 to 1,500 milliseconds** of latency to that user's session startup. At enterprise scale with many concurrent workspace launches, this compounding effect degrades the entire control plane **for all users across all zones simultaneously**. The degradation is not local to the users who are geographically distant from the database: it affects every user whose session creation happens to be processed during a period of high database query load. :::warning Control plane latency caused by distant database placement does not manifest as a localized problem affecting specific users. It manifests as systemic platform sluggishness affecting all users simultaneously. Symptoms including slow session launches, slow admin UI responses, and timeout errors can be attributed to many causes. Administrators who observe these symptoms should **verify database round-trip latency** before investigating other causes. ::: --- ## Dedication Proxy Role for Geographic Distribution The instinctive response to serving remote users is to place Web App nodes closer to those users. This instinct is wrong in the Kasm architecture. The control plane must remain co-located with the database. The correct architectural response to serving remote users is to place **Dedicated Proxy nodes** in each region. **Dedicated Proxy nodes** have no database dependency. They run a single service, `kasm_proxy`, which relays session traffic between the user's browser and the Agent. The proxy's only interaction with the control plane is a single Upstream Auth HTTPS call at session connect time to validate the session token. For a trans-continental path, this one-time call adds approximately **100 to 200 milliseconds** at connection establishment. After that single validation, the session streams entirely within the remote region at local latency for the entire duration of the session. --- ## The Practical Implication for Capacity Planning The database co-location constraint means Web App nodes and the database should be treated as a **single logical unit** from a placement perspective, even when they run on separate physical servers. In cloud deployments, this means both should be in the **same availability zone** rather than simply the same region: | **Network Path** | **Typical Round-Trip Latency** | |---|---| | **Intra-availability-zone** | Sub-millisecond | | **Intra-region, cross-availability-zone** | 1 to 5 milliseconds | | **Cross-region** (even nearby regions) | **Tens of milliseconds or higher** | Single-digit millisecond round-trip latency between the Web App and the database is not an aspiration. It is the operating condition **the control plane was designed for**. Deployments that operate outside this condition will experience control plane performance that degrades predictably with load, in a way that cannot be remediated by adding more Web App nodes or increasing database resources. The database co-location constraint is one of the most reliable **leading indicators of production success** in enterprise Kasm deployments. Organizations that plan for it before deployment avoid a class of performance problems that are expensive to diagnose and require infrastructure changes to resolve. --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Kasm Workspaces: Deployment Zones # Understanding Deployment Zones Architects encountering Kasm Workspaces Deployment Zones for the first time often treat zone configuration as a **late-stage** administrative task, something to revisit after the platform is running. That approach leads to a predictable class of problems, sessions routing to the wrong geographic tier, RDP connections failing through firewalls, cookie-scoped authentication breaking in portal integrations, and load balancing decisions that work **against user experience** rather than for it. Zones are not an administrative overlay. They are the mechanism through which Kasm's control plane and session plane separation **is expressed in a global deployment**. Every zone setting is a direct statement about how those two planes relate to each other and to the users they serve. --- ## What a Zone Actually Represents A Zone is a **logical boundary** that groups Kasm services sharing a common network context. That context might be geographic, organizational, or regulatory. The zone mechanism is neutral about which concern drives its definition, but it is not neutral about the architectural implications that follow. | **Zone Use Case** | **Zone Purpose** | |---|---| | **Geographic distribution** | Route users to Agents closer to them for lower latency | | **Security enclave separation** | Isolate workloads by classification level or tenant | | **Network segment isolation** | Scope sessions to permitted egress paths per segment | | **Workspace restriction** | Limit which workspace types are available in which network | :::warning Zones are created at Web App installation time and the zone topology must be understood and planned, not improvised after the platform is in production. ::: --- ## The Zone Settings: What Each One Actually Governs Zone settings are primarily concerned with the **session plane**. Zone configuration is how the session plane is told where it actually lives **from the perspective of the client browser**. The distinction between where infrastructure physically lives and where the browser thinks it lives is the source of **most zone misconfiguration** in enterprise deployments. --- ### Zone Name and Zone Assignment The Zone Name setting carries structural weight beyond its appearance as a simple text label. Every Web App service instance **declares its zone membership** through its configuration. Every Kasm node that checks in with a Manager **inherits that Manager's zone assignment automatically**. **Labels** extend zone assignment with fine-grained targeting. Labels are key-value tags applied to servers and Agents within a zone. Workspaces specify **Include Labels or Exclude Labels** to control which infrastructure their sessions are permitted to use. This is the primary mechanism for **workspace-to-enclave binding**, ensuring that high-sensitivity workspaces only provision on Agents within a specific zone regardless of what capacity other zones have available. --- ### Search Alternate Zones: Availability vs. Isolation **Search Alternate Zones** governs what happens when all Agents within the user's current zone are full or unavailable. The decision to enable or disable this setting is a **policy question, not a technical one**. When zones represent **geographic regions**: enabling is almost always correct. A user whose nearest data center is temporarily at capacity should receive a slightly higher-latency session from an alternate zone rather than **a hard failure**. When zones represent **security enclaves or regulatory boundaries**: disabling may be architecturally mandatory. If a zone represents a PCI-scoped network segment, allowing session overflow into a general-purpose zone would be a **compliance violation**. The failure mode, a capacity error, is the **correct behavior** when the alternative is a boundary violation. :::tip The default is **Enabled**, which encodes an implicit assumption that zones are geographic, not regulatory. Organizations deploying zones for **compliance or tenant isolation** should consciously evaluate whether this default aligns with their security policy before going to production. ::: --- ### Prioritize Static Agents: Managing Hybrid Compute Pools **Prioritize Static Agents** governs how the Manager selects between manually registered agents and dynamically provisioned autoscaled agents when both are available in the same zone. Enabling it ensures **sunk-cost on-premises infrastructure** is consumed before **variable-cost cloud infrastructure** is activated. This is financially rational in most hybrid deployments. Disabling it may be appropriate only when cloud Agents have **superior performance characteristics** that justify preferential use. --- ### Proxy Hostname: The Most Consequential Zone Setting **Proxy Hostname** is the FQDN that Kasm embeds in the session connection URL and returns to the client's browser. It is the address the browser will actually attempt to connect to for **WebSocket session traffic**. This is the **single most consequential zone setting** for multi-tier deployments. The default value `$request_host$` evaluates to the hostname used when the user accessed the Kasm Web App. For single-region deployments where the Web App and Proxy are behind the **same load balancer on the same hostname**, this default works correctly. For **multi-region deployments with separate proxy tiers per zone**, this value must be explicitly overridden with the **zone-specific proxy FQDN**. :::warning Leaving Proxy Hostname at its default `$request_host$` in a multi-zone deployment is one of the **most common causes of session delivery failures** in enterprise deployments. The browser will attempt to connect to the Web App's hostname for session streaming rather than the zone-specific proxy hostname. The failure appears as a **session connectivity problem** rather than a configuration problem, which misleads diagnostic efforts. ::: --- ### Upstream Auth Address: The Control Plane's View of Itself **Upstream Auth Address** is the address Kasm uses to validate session authentication tokens. The default value `proxy` instructs the proxy to validate tokens against a **co-located API server**, correct for single-server deployments. In any distributed deployment, this value must be overridden with the **address of the Web App tier**. :::warning Setting the Upstream Auth Address to the **internal IP of a single Web App server** in a multi-server HA deployment is a common mistake. If that specific server is removed from the pool, proxy token validation fails **even though the overall Web App tier remains healthy**. The correct value in HA deployments is the **load balancer's FQDN**, so that token validation requests are distributed across all healthy Web App instances. ::: --- ### Allow Origin Domain: The CORS Security Boundary **Allow Origin Domain** enforces which origins are permitted to initiate WebSocket session connections to Kasm. This implements **browser-level CORS policy** for session traffic, preventing session tokens from being usable from unauthorized web origins. The default value `$request_host$` is correct for straightforward deployments. When the Web App and the session proxy are on **different hostnames**, this default produces **CORS failures** because the session connection is initiated from the Web App's hostname but the proxy evaluates the origin against its own hostname. In multi-hostname deployments, Allow Origin Domain must be set to the **Web App's public hostname** from which users actually initiate sessions. --- ### The Three Settings That Must Be Mutually Consistent The most important relationship in zone configuration is the one between **Proxy Hostname**, **Upstream Auth Address**, and **Allow Origin Domain**. All three must describe the same deployment from three different perspectives: - **Allow Origin Domain** is what origin the proxy accepts session connection requests from - **Upstream Auth Address** is what the proxy calls to validate the session token - **Proxy Hostname** is what the client's browser connects to for session traffic When these three are **mutually consistent**, sessions work. When **any one is misaligned**, the failure almost always appears as a session connectivity problem that looks deceptively like an **authentication problem**. --- ## Zone Settings Quick Reference | **Setting** | **What It Governs** | **When to Override** | |---|---|---| | **Zone Name** | Logical deployment boundary | When multiple regions, enclaves, or tenants exist | | **Allow Origin Domain** | CORS security for session connections | When Web App and proxy are on different hostnames | | **Upstream Auth Address** | Token validation target | **Any multi-server deployment** | | **Load Balance Strategy** | Resource consumption policy | Cloud: change to Most Load | | **Search Alternate Zones** | Overflow to other zones | **Disable** when zones are compliance or security boundaries | | **Prioritize Static Agents** | Static vs. autoscale preference | Disable only when cloud Agents are preferred for performance | | **Proxy Hostname** | Client-facing session plane address | **Always** in multi-zone and dedicated proxy deployments | | **Proxy Port** | Session WebSocket port | When proxy listens on non-443 port | | **Enable RDP HTTPS Gateway** | Port 443 vs. 3389 for RDP | Enable when clients connect from uncontrolled networks | | **Enable RDP HTTPS DLP** | DLP enforcement on RDP sessions | Enable when Kasm must be the DLP enforcement point | | **Restrict RDP Client IP** | Anti-replay for RDP sessions | Enable only when source IP is preserved end-to-end | --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Kasm Workspaces: DNS Design # Why DNS Is an Architectural Control In most enterprise environments, DNS is treated as **foundational but passive**: a directory that maps names to IP addresses. It is provisioned early, configured once, and rarely revisited as an architectural concern. Kasm Workspaces does not inherit this assumption. In a **web-native, Zero Trust platform** where every interaction is mediated through a browser, DNS plays a fundamentally different role. It directly governs whether: - **Browser security policies** allow session establishment - **Authentication context** can traverse system components - **WebSocket-based session streaming** succeeds In Kasm DNS is much more than just naming, it also affects system enforcement boundaries. --- ## The Browser as an Active Enforcement Engine The most important mental model shift for Enterprise Architects unfamiliar with web-native systems is recognizing that **modern browsers are not passive clients**. They are active security enforcement engines that apply strict rules around: - **Same-origin policies** - **Cookie scoping rules** - **Cross-origin request validation** - **TLS certificate trust** When a user launches a Kasm session, the browser evaluates whether connections are permitted based on **DNS-resolved hostnames**, domain relationships, and TLS certificate validity. If DNS and domain design do not align with these rules, session establishment does not degrade, it fails outright. :::note Symptoms of DNS and domain misalignment in Kasm deployments, including WebSocket connections failing, sessions not launching, and inconsistent authentication, **closely resemble firewall issues, routing problems, and load balancer misconfiguration**. Always verify DNS design and domain alignment **before** examining firewall rules or network paths. ::: --- ## Domain Relationships Define Authentication Flow The relationship between hostnames defines how identity flows through the system. **The Child Domain Model (Preferred)** When the Web App is at `kasm.example.com` and the proxy is at `proxy.kasm.example.com`: - The browser automatically sends cookies scoped to `kasm.example.com` to `proxy.kasm.example.com` - **Authentication context flows naturally** - Fewer cross-origin constraints need to be managed **The Sibling Domain Model (Complex)** When the Web App is at `kasm.example.com` and the proxy is at `proxy.example.com`: - The browser **will not automatically send** the `kasm.example.com` cookie to `proxy.example.com` - Cross-origin validation must be **explicitly configured** - Every component must agree perfectly on **Allow Origin Domain**, **Upstream Auth Address**, and TLS expectations | **Model** | **Cookie Sharing** | **Cross-Origin Config Required** | **Failure Surface** | |---|---|---|---| | **Child domain (preferred)** | Automatic | Minimal | Narrow | | **Sibling domain (complex)** | Not automatic | Extensive | **Broad** | Most enterprise Kasm deployments choose the **child domain approach** because it reduces the configuration surface area and makes failure modes easier to diagnose. --- ## DNS, TLS, and Load Balancers Form a Single System In Kasm deployments, DNS does not operate independently. It forms a **tightly coupled system** with load balancers and TLS certificates: - DNS resolves hostnames to **load balancer endpoints**, not individual server nodes - TLS certificates must be issued for the **public hostnames that browsers use** - **Internal node names are irrelevant** to the browser, which only trusts what DNS and TLS present **Wildcard certificates** covering the chosen domain hierarchy, for example `*.kasm.example.com`, are commonly used not as a convenience measure but to maintain **consistency across distributed proxy endpoints** in multi-server and multi-zone deployments. --- ## The Session Chain: Where DNS Participates at Every Step Every Kasm session depends on an **unbroken chain** of operations where DNS is present at multiple points: 1. Browser resolves the **Web App hostname** via DNS 2. Browser connects to the Web App, establishes HTTPS, and authenticates 3. The API returns a **Proxy Hostname** for session streaming 4. Browser resolves the **Proxy Hostname** via DNS 5. Browser initiates a **WebSocket connection** to the proxy 6. The proxy validates the **session token** via the Web App At every step, the hostname must resolve correctly, the certificate must match, and the origin must be permitted. **A failure at any link in this chain produces a session failure.** --- ## DNS Significance Across the Reference Architectures The role DNS plays **scales with the complexity of the deployment**. | **Architecture** | **DNS Role** | **Complexity** | **Failure Impact** | |---|---|---|---| | [**RA1** (Single Server)](architecture-patterns/ra1) | Identity: single hostname defines the entire system boundary | Low | Immediate failure | | [**RA2** (Single Server Control Plane)](architecture-patterns/ra2) | Identity plus abstraction: single public hostname; Agents are invisible to DNS | Low | Immediate if Proxy Hostname cannot resolve | | [**RA3** (Single Zone Multi-Server)](architecture-patterns/ra3) | Identity plus scaling: DNS resolves to load balancers; certificates must match public hostnames | Medium | Inconsistent behavior across sessions | | [**RA4** (Multi-Zone Multi-Server)](architecture-patterns/ra4) | **Identity plus routing plus locality:** DNS enables geographic routing and zone-aware session delivery | High | System-wide session delivery failure | **In RA4**, DNS becomes the **routing fabric of the session plane**. Each zone has its own proxy hostname that resolves to a zone-specific load balancer in a geographically distributed region. A typical RA4 DNS design: | **Hostname** | **Purpose** | **Resolves To** | |---|---|---| | `kasm.example.com` | Global control plane entry | Region 1 global load balancer | | `us.kasm.example.com` | US zone session load balancer | Region 1 session load balancer | | `eu.kasm.example.com` | EU zone session load balancer | Region 2 session load balancer | Each of these hostnames must **resolve globally**, present a **valid TLS certificate**, be included in **origin validation configuration**, and reach a **functioning proxy**. Any mismatch breaks session delivery for the affected zone. --- ## DNS as a Zero Trust Enabler Across all reference architectures, DNS supports Zero Trust principles by: - Forcing all access through **controlled endpoints** - Defining the **public identity** of each role in the system - Ensuring traffic flows through **named, managed entry points** rather than implicit network routes - In RA4 especially, enabling **secure global distribution** without exposing internal topology The deeper insight: in Kasm Workspaces, **DNS defines who the system is, TLS proves that identity is valid, and the browser enforces whether interaction is permitted**. Naming, security, and connectivity are inseparable. DNS is not just how the system is found. It is **how the system is allowed to exist**. --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Kasm Workspaces: High Availability # Understanding High Availability When Enterprise Architects evaluate a new platform for production readiness, the instinct is to ask, "Is this platform highly available?" That question is appropriate for monolithic systems but it is misplaced for Kasm Workspaces. Kasm is not a monolith. It is a **deliberately decomposed set of service roles**, each with a different function, different state characteristics, and different failure behaviors. High availability in Kasm is not a setting to enable or a tier to select. It is an outcome produced by **independently analyzing each role**. **The right questions to ask are:** - What is the **failure mode** of each role? - What is the **impact** of that failure? - What **redundancy mechanism** addresses it? --- ## Resilience Is a Role-by-Role Decision, Not a Platform-Wide Switch Legacy VDI platforms typically run management, session brokering, and delivery functions inside the same process or tier. When that tier fails, everything fails together. Recovery requires the entire system to come back up, and the **blast radius of any single failure touches every user simultaneously**. Kasm separates these concerns into **five distinct roles**. Because these roles are separated, a failure in one does not automatically cascade into all others: - An **Agent failure** interrupts only the sessions running on that Agent. Users on healthy Agents continue working. - An **Connection Proxy (CPX) failure** interrupts only the sessions running through that node. Users on healthy CPX servers continue working. - A **Web App failure** blocks new session creation but does **not terminate** sessions already streaming through an Agent. - A **Database failure** is the exception: it is the one role whose failure makes the **entire platform unavailable**, which is precisely why it demands the most serious redundancy investment. --- ## Role-by-Role: Failure Impact and Redundancy ### The Database Role: The Most Critical HA Decision The database holds **all persistent state** for the entire deployment. When it is unavailable, the Web App API cannot serve any requests, no session can be created, and no administrative operation can complete. | **Redundancy Approach** | **Mechanism** | **Suitable For** | |---|---|---| | **AWS RDS Multi-AZ** | Synchronous standby; automatic failover | Cloud deployments on AWS | | **AWS Aurora PostgreSQL** | Multi-primary compatible clustering | High-throughput cloud deployments | | **Cloud-provider equivalents** | Varies by provider | Azure, GCP, OCI managed PostgreSQL | | **Self-managed replication with Patroni** | PostgreSQL streaming replication; automated failover | On-premises and private cloud | | **Single containerized instance** | None | Small teams, development, and Proof-of-Concept | :::warning Kasm ingests logs from all platform components into the database by default. For deployments with hundreds of concurrent sessions, this log volume can reach **tens of gigabytes** under default retention settings. Organizations running enterprise-scale deployments should **forward logs to an external SIEM** and reduce Kasm's internal log retention to zero. This both reduces storage requirements and removes I/O load that competes with the operational queries HA depends on. ::: --- ### The Web App Role: Statelessness as the HA Enabler The Web App role is the **easiest tier to make redundant** because it was designed to carry **no session state of its own**. Every piece of state lives in the database. Any Web App instance can serve any request from any user, and the load balancer can route traffic to any healthy instance **without coordination between instances**. The recommended minimum for production Web App HA is **N+1**: one more Web App server than needed to serve peak load. A deployment expecting 200 concurrent sessions requires approximately 2 Web App servers at peak. N+1 means deploying **3**, providing both failure tolerance and maintenance flexibility. | **Pattern** | **Convergence Speed on Failure** | **Best For** | |---|---|---| | **DNS load balancing** | Slow: 90 to 300 seconds for TTL expiry | Outermost redundancy tier | | **Network load balancer** | Fast: seconds via active health checks | Production HA where fast failover is required | The health check endpoint at `/api/__healthcheck` is the correct target for both DNS health monitors and load balancer health probes. It validates that the Web App process can **successfully reach the database**, making it a meaningful **end-to-end health signal** rather than a shallow process check. --- ### The Agent Role: Horizontal Distribution as Fault Isolation Agent nodes are where workspace sessions execute. An Agent failure directly interrupts sessions on **that specific node only**. Several properties make this failure mode less catastrophic than it might appear: **Ephemerality:** Containers are destroyed at session end. A failed Agent takes **no persistent user data** with it. Users reconnect and receive a fresh container on a healthy Agent. **Automatic rerouting:** The Manager's health monitoring continuously tracks Agent check-ins. When an Agent stops responding, the Manager stops routing new sessions to it and **schedules them to remaining healthy Agents** automatically. **AutoScaling:** In cloud environments, the Manager can provision new Agent virtual machines when existing Agents reach capacity or when a node fails. :::warning AutoScaling requires the **Upstream Auth Address** to be explicitly configured **before** AutoScaling is enabled. New Agent virtual machines must be able to reach the Web App API to register. If the Upstream Auth Address is misconfigured, autoscaled Agents **silently fail to join the pool**, and capacity does not increase when needed. This is the **most common AutoScaling failure mode** in enterprise deployments. ::: --- ### The Connection Proxy Role: Selective Redundancy The Connection Proxy is required only when Kasm serves as a web-native gateway to **existing RDP, VNC, or SSH endpoints**. Containerized workspace sessions always use the **Agent role**. For organizations where Windows, Linux, and macOS access is a primary delivery mode, Connection Proxy redundancy follows the same **stateless horizontal scaling model** as the Web App tier: multiple instances behind a load balancer, with health checks routing traffic away from failed instances. --- ## Failure Domain Isolation Through Zone Design The **Zone model** is Kasm's primary mechanism for geographic failure domain isolation, keeping a failure in one region from cascading into another. The **Search Alternate Zones** setting determines whether Kasm will route session requests to Agents in a different zone when the assigned zone has no available capacity. | **Zone Boundary Type** | **Search Alternate Zones** | **Rationale** | |---|---|---| | **Geographic preference only** | Enable | Users benefit from fallback; no security boundary is crossed | | **Security enclave** (classification, tenant separation) | **Disable** | Cross-zone fallback would **violate the policy** the zone boundary enforces | :::tip The **default is Enabled**, which encodes an implicit assumption that zones are geographic, not regulatory. Organizations deploying zones for **compliance or tenant isolation** reasons should consciously evaluate whether this default aligns with their security policy before going to production. ::: --- ## HA Decision Summary by Role | **Role** | **Redundancy Mechanism** | **Minimum for Production HA** | **Key Failure Mode Without HA** | |---|---|---|---| | **Database** | Managed service with auto-failover or streaming replication with Patroni | Automatic failover required | Entire platform unavailable | | **Web App** | N+1 behind DNS or network load balancer | 2+ recommended | New session creation blocked; admin UI down | | **Agent** | Multiple per zone; AutoScaling in cloud | 2+ Agents per zone | Capacity reduction; sessions on failed Agent interrupted | | **Connection Proxy** | Multiple instances behind load balancer | Required only for RDP, VNC, SSH workspaces | Legacy protocol sessions terminated | | **Dedicated Proxy** | Multiple instances per zone behind load balancer | Required for multi-zone regional delivery | Sessions in affected zone interrupted | --- ## Why Ephemeral Sessions Fundamentally Simplify HA In legacy VDI, a failed host takes **persistent state** with it. Virtual machines accumulate data, configuration, and user work over weeks or months. HA requires shared storage, live migration, or backup and restore workflows that trade **data-loss risk against infrastructure cost**. In Kasm, a **failed Agent takes nothing meaningful with it**. Containers are ephemeral: they are created for a session and destroyed at session end. A failed Agent interrupts the session but cannot take persistent user data with it, because there is no persistent user data to take. The HA problem for Agents reduces to: provision enough Agents that losing one does not exhaust capacity, and provision them quickly enough through AutoScaling that sustained failures do not keep capacity depleted. The ephemeral state that eliminates persistence-based attacks also eliminates persistence-based HA complexity. Both benefits are consequences of the same architectural decision. --- *This article is part of the Kasm Workspaces Reference Architecture Explanation Series.* --- ## Reference Architecture --- ## Kasm Workspaces: Logical Architecture # Understanding the System as a Flow of Responsibility Kasm’s logical architecture is best understood as a lifecycle of intent. 1. A user initiates a session via a browser 2. The system authenticates and interprets that intent 3. A decision is made about where to run the session 4. A workload is instantiated on an available resource 5. The session is streamed back via web-native protocols Each step maps to a role. These roles represent **responsibilities in a distributed system**, not just deployable services. --- ## The Five Kasm Roles ### 1\. Web App Role (Control Plane and Orchestration Engine) **The Brain and System Boundary**The Web App role combines user interaction and orchestration into a unified control plane. * Hosts the web UI and API endpoints * Authenticates users and captures session requests * Maintains awareness of system state and capacity * Determines workload placement and execution strategy **Architectural meaning:** * Centralized control plane * Combines broker, scheduler, and API gateway **Mental model:** > This is where **intent is translated into action**. --- ### 2\. Agent Role (Optional, Container Execution Plane) **The Distributed Runtime Fabric** Agents are responsible for executing user's container workloads. * Launch containerized workspaces * Provide compute resources (CPU, memory, GPU) * Report health and capacity back to the control plane **Architectural meaning:** * Vertically and horizontally scalable execution nodes * Fully decoupled from orchestration **Mental model:** > Agents are **ephemeral workload hosts**, not persistent desktops. --- ### 3\. Connection Proxy Role (Optional, Unified Transport and Legacy Protocol Layer) **The Engine of Web-Native Session Delivery** The Connection Proxy enables Kasm’s core capability to deliver fully interactive workspace sessions to traditional endpoints (Windows, Linux, macOS) directly through a web browser. > The Connection Proxy is a **customized Guacamole-based connection handler** that encodes and proxies RDP, VNC, and SSH into WebSocket streams usable by modern browsers. Each Kasm Deployment Zone requires at least one Connection Proxy when supporting RDP, VNC, or SSH workloads. Rather than a single service, this role is composed of four tightly integrated components: --- #### kasm\_guac **Protocol Translation Core** * Built on a custom-compiled Apache guacd * Converts RDP, VNC, and SSH into web-native streams * Spawns **one guacd process per CPU core by default** * Automatically load-balances sessions across processes This design ensures efficient utilization of multi-core systems. **Interpretation:** > This is the **rendering and encoding engine** that makes remote systems browser accessible. --- #### kasm\_proxy **Session Routing and Broker Layer** * Routes client connections to the correct component * Acts as the reverse proxy for session traffic **Interpretation:** > This is the **traffic director**, ensuring sessions reach the correct execution endpoint. --- #### kasm\_rdp\_gateway **Feature-Enforcing RDP Mediation Layer** * Enables native RDP client access to Kasm sessions * Enforces: * Data Loss Prevention (clipboard, uploads, downloads) * Single Sign-On (SSO) * Credential injection * Supports advanced device redirection: * Smart cards * USB * Webcam **Interpretation:** > This layer adds **policy enforcement and enterprise-grade control** to RDP sessions. --- #### kasm\_rdp\_https\_gateway **Transport Compatibility Layer** * Tunnels RDP traffic over HTTPS * Enables traversal through restrictive firewalls * Implements Microsoft RD Gateway protocol Important distinction: * Does **not interpret RDP traffic** * Acts purely as a **secure transport wrapper** **Interpretation:** > This layer ensures **connectivity in constrained network environments**. --- #### How these components work together For browser-based sessions: ` Client → kasm_proxy → kasm_guac → Target Session ` For native RDP sessions (default path): ` Client → kasm_RDP_HTTPS_Gateway → kasm_RDP_Gateway → Target Session ` This layered design allows Kasm to: * Support both **web-native and thick-client access** * Balance **security, compatibility, and performance** --- #### Architectural meaning of the Connection Proxy role * Protocol abstraction layer * Session routing and delivery mechanism * Security enforcement boundary * Web-native translation engine **Mental model:** > The Connection Proxy transforms **any remote interaction into a controlled, browser-delivered experience**. --- ### 4\. Dedicated Proxy Role (Optional, Geo-Distributed Edge Layer) **Separating User Proximity from Control Plane Location** In standard deployments, proxy functionality resides with the Web App. At scale, this can be externalized. * Deploys proxies across geographic regions * Routes sessions through the nearest proxy to the user * Reduces latency while maintaining centralized control * Uses the Web App for authentication and orchestration **Architectural meaning:** * Edge-distributed access layer * Enables global scale without duplicating control logic **Mental model:** > The Dedicated Proxy moves the **workspace experience closer to the user**, not the control plane. --- ### 5\. Database Role (Persistence and Coordination) **The System Memory** * Stores users, configuration, sessions, and metadata * Enables stateless control plane operation * Coordinates distributed roles **Architectural meaning:** * Foundation for system consistency **Mental model:** > This is what allows a distributed system to behave consistently over time. --- ## Zero Trust Through Architectural Design Kasm enforces zero trust principles inherently: * All access is mediated through proxy layers * No direct connectivity to backend systems * Sessions are isolated and ephemeral * Control and execution planes are separated With Dedicated Proxies: * Access becomes **geo-distributed without expanding trust boundaries** --- ## Closing Kasm Workspaces redefines VDI by dissolving the dependency on persistent desktops and replacing it with: * A centralized control plane (Web App Role) * A distributed execution fabric (Agents) * A unified protocol and transport layer (Connection Proxy) * A globally scalable edge access model (Dedicated Proxy) * A persistent coordination layer (Database) Together, these roles form a system where: > **User intent is transformed into a secure, isolated, browser-delivered session, instantiated dynamically, governed centrally, and delivered globally.** --- ## Kasm Workspaces: Reference Architecture: Planning and Design # Planning and Design Concepts > **About This Article** > This series of explanation articles is written for Enterprise Architects evaluating or planning Kasm Workspaces deployments. Each article is understanding oriented: the goal is to build a durable mental model of how and why the architecture is structured the way it is. These articles are not deployment guides, configuration references, or operational runbooks. --- ## Zero Trust Workspace Delivery for the Modern Enterprise If your background includes **Citrix Virtual Apps and Desktops**, **Omnissa Horizon**, **Azure Virtual Desktop**, or **Amazon WorkSpaces**, most of what you already know about workspace architecture still applies here. Concepts like session brokering, connection gateways, and resource pools all have a counterpart in Kasm Workspaces. What differs is where the platform draws its security boundary, and that difference is worth understanding before you map your existing design patterns onto it. This article builds the conceptual foundation that makes every later architecture decision easier to reason about. Understanding why the platform is structured this way will make the configuration decisions in later articles more straightforward. --- ## The Problem Kasm Was Built to Solve Kasm Workspaces extends familiar workspace delivery concepts to address a specific, well documented enterprise problem: providing secure, reliable access to applications and desktops for users connecting from any device, on any network, while containing the risk that comes with that flexibility. It does this using standard, well established web technologies rather than a proprietary client stack: * **HTTPS**-based session delivery * **High-performance** WebSocket streaming * **Browser-native** authentication and access control * **All execution** is performed in secure infrastructure, not on endpoints * **Pixel rendering** is performed client-side in the browser * **No proprietary client software** or endpoint agent required --- ## Why Legacy VDI and VPN Models Reach Their Limits Traditional workspace delivery platforms were designed around assumptions that were reasonable at the time but have become harder to satisfy in most modern enterprises: * Users connect from **trusted networks or managed corporate endpoints** * Security enforcement occurs at the **network perimeter** * **VPN-based access** is an acceptable mechanism for remote workers Each of these assumptions is harder to guarantee in environments that support hybrid workforces, third-party contractors, unmanaged devices, or data subject to Data Loss Prevention (DLP) requirements. VPN-based access extends the internal network to the endpoint, which increases the blast radius of an endpoint compromise and creates a path for lateral movement. Legacy VDI reduces some of this risk, but it still typically depends on proprietary client software, persistent desktops that accumulate state across sessions, and trust models that treat network location as a proxy for legitimacy. Kasm Workspaces was built to close this gap: to give architects a workspace delivery model that holds up under a Zero Trust standard, where every access request is validated on its own merits regardless of where it originates, without requiring a wholesale replacement of existing identity, security, and infrastructure investments. --- ## The Architectural Principle: Execution Stays in Infrastructure The organizing principle behind Kasm Workspaces can be stated directly: > **Workloads execute in secure infrastructure environments, not on user devices.** In conventional VDI, the virtual machine is a full, persistent environment, and client software on the endpoint renders its output. The endpoint remains a meaningful participant: it can hold client certificates, run a proprietary protocol stack, and retain session data. In Kasm Workspaces, the endpoint functions as a display device. Its role is limited to rendering a pixel stream delivered from infrastructure the organization controls. The endpoint does not execute the application, does not touch the underlying data directly, and does not retain session state once the session ends. | **Architectural Advantage** | **What It Means in Practice** | |---|---| | **Reduced endpoint attack surface** | A compromised endpoint cannot compromise the workspace, because execution happens entirely in infrastructure | | **Isolation of untrusted content** | Code, files, and browser activity run inside an ephemeral container that is destroyed at session end | | **Centralized execution control** | Policy is enforced in infrastructure, independent of endpoint state or management enrollment | | **Elimination of persistent state** | Sessions are disposable by design, removing the kind of persistent foothold that Advanced Persistent Threats (APTs) rely on | --- ## Web-Native, Standards-Based Delivery Web-native has a precise meaning here. It does not describe a product with a web interface layered on top of a proprietary protocol stack. It describes a delivery architecture where every component, from session origin to browser rendering, runs on standard, open web technologies, with no proprietary protocol in the user-facing path. That distinction matters operationally: it is what keeps firewall rules simple and keeps the platform interoperable with the identity, logging, and security tooling you already run. When a user authenticates to Kasm Workspaces, the entire session lifecycle runs over **HTTPS** and **WebSocket**: | **Step** | **What Happens** | **Technology** | |---|---|---| | **1** | User navigates to the Kasm URL in any modern browser | HTTPS | | **2** | Browser authenticates against `kasm_api` via identity provider | HTTPS REST, SAML, or OIDC | | **3** | `kasm_manager` schedules a container on an available Agent node | Internal API | | **4** | Browser opens a WebSocket stream via `kasm_proxy` to the container | WebSocket over HTTPS | | **5** | Session is rendered client-side inside the browser tab | HTML5 Canvas | | **6** | Session ends; container is destroyed; no persistent state remains | Docker lifecycle | The practical result is a simple, auditable network requirement: the complete user-facing firewall rule is a single outbound allow on port 443. There is no VPN client to install, no persistent tunnel to maintain, and no proprietary protocol handshake to support. The browser's native security sandbox becomes part of the session security boundary by design. The single-port requirement applies to traffic between end users and the Kasm platform. Internal component networking uses standard protocol ports: **TCP 5432** for PostgreSQL, **TCP 3389** for RDP to legacy targets, **TCP 22** for SSH, and **TCP 5900** for VNC. These are intra-infrastructure paths, not user-facing firewall requirements. For legacy protocols such as RDP, VNC, and SSH, Kasm does not stream those protocols directly to the browser. The Connection Proxy role translates them server-side into a browser-renderable WebSocket stream before delivery. From the browser's perspective, every session arrives over the same HTTPS and WebSocket path, which means existing network monitoring and inspection tools continue to work as expected. --- ## Zero Trust Alignment: Architecture as Security Policy Zero Trust is an architectural approach built on one foundational assumption: breach is possible, so containment matters as much as prevention. Kasm Workspaces is designed at the architecture level to support the controls a Zero Trust standard requires, rather than adding those controls on top of an existing design. | **Zero Trust Control** | **How Kasm Implements It** | |---|---| | **Least Privilege Access** | Users receive a session, not network access. Access is scoped to the specific workspace policy assigned to them | | **Micro-segmentation** | Each session container has its own Linux kernel namespace. Sessions cannot communicate with each other at the network layer | | **Elimination of Implicit Trust** | Each session is individually authenticated and authorized. There is no persistent authenticated tunnel that carries over between sessions | | **Attack Surface Reduction** | The session container is destroyed on logout, removing all residual state. The browser sandbox is the outermost boundary | | **Embedded DLP** | Clipboard access, file upload, and file download are configurable per workspace policy, enforced at the session boundary regardless of endpoint state | In many traditional VDI environments, DLP is added on top of the system through endpoint agents, network inspection appliances, and after-the-fact monitoring. All of these approaches share the same dependency: they rely on the endpoint and network being in a known, trusted state. In Kasm Workspaces, DLP is a property of how sessions are delivered, applied uniformly across managed and unmanaged devices alike. --- ## The Two Traffic Planes One of the most useful distinctions to internalize in Kasm Workspaces is the separation between two different types of traffic. Every topology and placement decision in this reference architecture series traces back to this separation. | **Characteristic** | **Control Plane** | **Session Plane** | |---|---|---| | **Content** | Authentication, policy evaluation, session orchestration, workspace lifecycle | Live pixel stream, keyboard and mouse input, clipboard events, file transfer | | **Bandwidth profile** | Low: primarily API call volume | High: approximately 5 to 15 Mbps per active session | | **Latency sensitivity** | Database query latency: slow queries degrade launch times for all users at once | Network round-trip between the proxy and the user's browser: high latency produces visible display lag | | **Database dependency** | **Yes**: multiple sequential, blocking queries per operation | **None**: zero database interaction during an active session stream | | **Handled by** | Web App role | Kasm Agent role or Connection Proxy role | These two planes pull infrastructure in opposite directions in any distributed deployment: * **Control plane traffic** anchors the Web App role near the database. Placing the Web App role far from the database introduces latency that degrades the experience for every user in every zone at once. * **Session plane traffic** benefits from proxy nodes placed as close as possible to end users. A Kasm Dedicated Proxy node can sit in a geographically remote region with no control plane penalty, because it has zero database dependency. This distinction is the practical justification for the Dedicated Proxy role, and the reason a multi-zone deployment can support global geographic distribution without needing a full control plane replica in every region. --- ## The Five Service Roles and Their Responsibilities Kasm Workspaces uses a role-based architecture. A role is a collection of services with a defined responsibility boundary. Roles can be co-located on a single server, as in a single-server deployment, or distributed across many servers, as in larger multi-server deployments. The same role definitions apply either way. | **Role** | **Key Services** | **TCP Port** | **Zone-Assigned** | **Database Dependency** | |---|---|---|---|---| | **Web App** | `kasm_api`, `kasm_manager`, `kasm_proxy` | 443 | Yes | **Critical** | | **Database** | `kasm_db` (PostgreSQL) | 5432 | No | N/A | | **Agent** | `kasm_agent`, `kasm_proxy`, container runtime | 443 | Yes | **None** | | **Connection Proxy** | `kasm_guac`, `kasm_rdp_gateway`, `kasm_rdp_https_gateway`, `kasm_proxy` | 22, 443, 3389, 5900 | Yes | **None** | | **Dedicated Proxy** | `kasm_proxy` | 443 | Yes | **None** | Understanding these roles as a system, rather than as individual services, is the key to reading any Kasm reference architecture diagram correctly. --- ## The Deployment Patterns Kasm architectures grow through progressive separation of concerns. Each stage adds resilience, scalability, and architectural clarity. This is not a forced upgrade path: each stage is appropriate for a specific scale and fault-tolerance requirement, and many organizations run successfully at an earlier stage indefinitely. | **Architecture** | **DB Proximity** | **Zone Count** | **Fault Tolerance** | **Primary Use Case** | |---|---|---|---|---| | [**RA1:** Single Server](architecture-patterns/ra1) | Automatic (same host) | 1 | None | POC, dev/test, small teams, edge sites | | [**RA2:** Single Server Control Plane + External Agents](architecture-patterns/ra2) | Automatic (co-located) | 1 | Agent tier only | Capacity expansion, legacy access in remote networks | | [**RA3:** Single Zone Multi-Server](architecture-patterns/ra3) | Deliberate (same DC or region) | 1 | All roles | Enterprise: Single region | | [**RA4:** Multi-Zone Multi-Server](architecture-patterns/ra4) | Deliberate (same DC or region) | 1 per region | All roles + zone isolation | Enterprise: Global multi-region | The transitions between stages are additive rather than a replacement. Moving from RA2 to RA3 means separating the database onto a dedicated server and adding a second Web App node behind a load balancer. Moving from RA3 to RA4 means defining additional zones with region-specific infrastructure, while keeping the Web App role and database anchored at the central site. Architecture selection is driven by session concurrency, fault tolerance, and geographic distribution requirements. The choice of hypervisor or cloud provider does not determine which reference architecture to select. --- ## What This Means for Your Evaluation None of the roles, planes, or deployment patterns above require you to set aside your existing standards. Kasm Workspaces is designed to integrate with the identity providers, logging systems, and infrastructure platforms your organization already runs, and to scale from a single-server proof of concept to a global, multi-region deployment using the same underlying architecture. Each reference architecture in this series documents a proven, supportable pattern used in production today, so you can select the stage that matches your current requirements and grow into the next one when you need it, without redesigning the platform from scratch. *Proceed to the following sections that build on these foundations.* --- ## Kasm Workspaces Sizing and Deployment Guide # Sizing and Deployment Guide This guide covers sizing requirements and deployment guidance for the Kasm Workspaces platform and assumes a distributed architecture with separate API, database, and agent components. For single server deployments, use the guidance provided in the agent sizing section. For all componenets, maximum concurrent Kasm sessions is the metric that should be used when sizing. Some use cases will have lots of total users with a small number of concurrent users while others will have more concurrent sessions than total users (more than 1 session per user). In all cases, the maximum concurrent session count should be the metric used when considering sizing requirements. ## Web App Role The web app server role is comprised of several containerized services: API, Manager, Share, and proxy. The API server is responsible for taking API calls from users and potentially external services using the developer API. The manager service is responsible for managing clusters of agents and auto scaling new agents in the cloud if configured. The web app server role is both vertically scalable (adding more CPUs and RAM) and horizontally scalable (adding more web app servers). ### Redundancy For large deployments, it is recommended to have N+1 redundancy for the web app servers. This ensures ease of maintenance, allowing administrators to bring down a server for patching, without effecting users. ### Sizing Concurrent sessions are used for deployment size recommendations, so while you may be using a named user license, you still need to understand your concurrent session requirements in order to size your deployment appropriately. There are two deployment architectures that can be used, which have drastically different sizing requirements for the Web App Server role, Standard and Direct-to-Agent. The standard deployment architecture has all traffic traverse the web app servers that are responsible for each respective zone. The Direct-to-Agent workflow has client API calls going to the Web App servers while the desktop rendering goes directly to the server hosting the application container. Direct-to-agent is only applicable to containerized desktop/app sessions and does not apply to Servers connected to via RDP. | Deployment | Server Specifications | Concurrent Sessions | |-----------------|---------------------------|---------------------| | Standard | 4 CPUs, 4GB RAM, 80 GB HD | 70 to 150 | | Direct-to-Agent | 4 CPUs, 4GB RAM, 80 GB HD | 300 to 500 | The range of concurrent sessions a single server can support is highly dependent on the use case. Administrators supporting an online gaming service would be on the low end of the spectrum while more moderate uses like remote work or browser isolation could expect to be near the high end of the spectrum. An administrator expecting to support up to 200 concurrent sessions for a remote work use case, in a standard deployment architecture, would need 3 servers using the N+1 redundancy recommendation. With 3 API servers, the administrator could expect to support up to 450 concurrent users. If the administrator needs to remove one for maintenance, the deployment would still be able to support up to 300 concurrent sessions, still within the desired capacity. ### Load Balancing Load distribution to different deployed web app servers can be accomplished via DNS load balancing or using a network load balancer such as an F5 or cloud load balancer. #### DNS Load Balancing With DNS load balancing, there is an A record for the same domain name pointing to each web app servers. Health checks can be used to automatically remove the DNS entry should the corresponding web app server become unresponsive. DNS load balancing offers a simple solution that requires no additional components between users and the backend servers. This simplifies the architecture and significantly reduces the cost of providing resilient services. There are many services and physical devices on premise that can provide DNS load balancing with health checks. AWS Route 53 is one example. You don’t need to host Kasm in AWS to use Route 53. Route 53 can provide public DNS services for resources on-premise or even in other cloud providers. The disadvantage to using DNS based load balancing is slow convergence on failure. Even with the most aggressive settings of10 seconds between health checks and 3 consecutive failures, will result in at least 30 seconds to recognize the failure. At this point the DNS record is removed, however, clients will not get the update until the TTL has expired. A typical TTL in AWS is 5 minutes, however, it can be set as low as 60 seconds. Therefore, the best case scenario is that on failure some clients will be down for at least 90 seconds. #### Network Load Balancer Another option is to use a network load balancer, either a physical on-premise load balancer such as an F5 or a cloud based load balancer. In either case, the load balancer is placed between the users and the web app servers and distributes the load between all the web app servers. Load balancers typically use health checks to determine if an upstream server is offline. These health checks can be passive, such as looking at the TCP sessions or HTTP return codes of traffic. Active health checks can also be used, which actively make HTTP calls to a specific path and expect a configured HTTP status code. Network load balancers have the advantage of providing convergence within seconds after a failure. They can also try multiple upstream web app servers for a single request, meaning users typically wouldn’t notice a web app server going down. The disadvantage is that it complicates the architecture with additional components between the end users and the backend servers. The load balancers can also go down and require maintenance as well. Which usually means maintaining N+1 redundancy and using DNS load balancing to balance the traffic to the load balancers. Network load balancers may be required for some organizations as they provide many other potential benefits: \* Single entry point for all publicly served websites for the organization \* Web Application Firewall (WAF) \* SSL inspection \* Data Loss Prevention \* Anti-virus \* Logging of all traffic at the enterprise level \* Other advanced security features #### Health Checks Wether using DNS load balancing, network load balancers, or both, health checks are imperative to ensuring failover and alerting. Kasm has a built in health check located at /api/\_\_healthcheck, which checks the operational status of the API server and the API server’s access to the database. If the API returns a non HTTP 200 series status code, the health check failed. AWS Route 53 can be configured with email alerts on failure, in addition to removing the associated A record. When the health check starts returning healthy, the A record will be re-enabled. For network load balancers the premise is the same, upstream servers will automatically be removed/added as their health check changes. ### Maintenance It is recommended to have a scheduled maintenance window, however, Web App servers can be gracefully taken offline without affecting users. This would require removing the selected server from the load balancing mechanism. For DNS load balancing, that would mean removing the A record. For network load balancers that would mean removing the selected server from the upstream list of servers and applying the configuration change, to each load balancer. After the server has been patched and rebooted, the DNS record or upstream change can be reverted. For DNS load balancing, it can take a while for users requests to stop coming into the server. The amount of time needed is determined by the TTL of the DNS record and potentially DNS architecture at the user's site which cache DNS records for longer than the configured TTL. Therefore, if DNS load balancing is used, it is recommended to monitor the traffic going through the API server before starting maintenance activities. ## Database Role By default, Kasm uses a Postgres container on the database role server. ### PostgreSQL Kasm utilizes the latest version of Postgres 16.x and uses a simple containerized version in the default installation. Larger deployments may choose to use an external PostgreSQL database. The minimum requirements for PostgreSQL in general are minimal, however, we recommend at least 2 CPUs and 4 GB of RAM. These minimum requirements will handle deployments into the hundreds of concurrent users. The database server can be vertically scaled to increase performance of larger deployments. Disk space requirements are more complicated. Kasm collects logs from all components and by default keeps debug logs for 4 hours and all other logs 7 days. These logs are ingested into the database and used by the dashboard and logging panels of the UI. For larger installations it is highly recommended to configure Kasm to forward logs to an Enterprise class SIEM solution, such as Splunk and set the Kasm log retention period to 0, effectively disabling database logs. With the default log retention settings, the database will use between 250 to 550MB for a single server install. Deployments with hundreds of concurrent users can easily use several tens of gigabytes of storage with default log retention settings. Smaller deployments with less than around 50 concurrent sessions can rely on Kasm’s built-in logging mechanisms, with a healthy database volume of around 150GB on the higher end of the spectrum. Deployments larger than this should use an external SIEM solution and set log retention to 0. If disabling the built in logging is not an option, monthly database maintenance should be performed to ensure AUTO VACUUMs are being performed and the space is being released back to the operating system. #### Postgres Compatible Databases Kasm supports using [AWS RDS](https://aws.amazon.com/rds/) and [AWS Aurora](https://aws.amazon.com/rds/aurora/postgresql-features/) Postgres database. Other Postgres compatible solutions, such as CockroachDB may work but are not officially supported by Kasm Technologies. Solutions such as AWS RDS provide added benefits of ease of maintenance, scalability, redundancy/failover, and automated backups. #### Redundancy and Backups Due to the criticality of the database to Kasm operations, it is important to carefully consider database redundancy and backups. At a minimum, regular backups of the database should be performed. See the Kasm documentation on performing [backups](../how-to/infra-autoscale/database.mdx) and [restorations](../how-to/infra-autoscale/database.mdx) of the database. The simplest form of redundancy is automated scheduled backups using a cron job, which are transferred to a remote location (NFS/S3,etc) and are able to be restored on a standby server in case of a failure of the primary database. For a solution that provides high availability, see the [PostgreSQL documentation](https://www.postgresql.org/docs/16/high-availability.html) for HA deployments. #### Sizing The following sizing recommendation is for sizing a the system backing the Postgres database. The standard Kasm deployment uses a single database server, however, RDS and other Postgres compatible PaaS deployments are supported. | Server Specifications | Concurrent Sessions | |---------------------------|---------------------| | 4 CPUs, 4GB RAM, 80 GB HD | 50 to 200 | | 4 CPUs, 8GB RAM, 100 GB HD | 200 to 500 | | 8 CPUs, 8GB RAM, 150 GB HD | 500 to 1000 | ## Agent Role The agent servers are responsible for hosting containers for user desktops/apps. These servers have high CPU, RAM, and disk requirements that are heavily dependent on the specific use case. ### Redundancy User sessions are automatically spread to available agents. When an agent goes offline or does not respond, new sessions are directed to healthy agents within the same zone that meet the requirements needed to fullfil the requested Workspace. Existing sessions may be interrupted until the agent is brought back online. ### Sizing Concurrent sessions are used for deployment size recommendations, so while you may be using a named user license, you still need to understand your concurrent session requirements in order to size your deployment appropriately. Agents only support container based Workspace sessions, so ensure you are sizing only for expected container based Workspaces sessions. The number of user sessions each agent can run depends on the Workspaces being deployed on that agent and the [Agent Settings](../how-to/infra-autoscale/docker-agent.mdx). The Agent Settings allow the administrator to override how many CPUs and RAM that Kasm uses to calculate how many sessions an agent can take. This allows the administrator to oversubscribe the agents. Each Workspace definition can be configured with a different CPU count and RAM amount. The below table assumes each Workspace running on the agent has the identical specifications configured. | Workspace Specs | Agent Size | Agent Overrides | Concurrent Sessions | |------------------|--------------------|---------------------|---------------------| | 2 CPUs, 4 GB RAM | 16 CPUs, 64GB RAM | N/A | 8 | | 4 CPUs, 4 GB RAM | 16 CPUs, 64GB RAM | 96 CPUs, 80GB RAM | 20 | | 4 CPUs, 4 GB RAM | 32 CPUs, 128GB RAM | 192 CPUs, 192GB RAM | 48 | For container workspaces that will have session recording enabled, one additional CPU should be assigned to the workspace to handle the session recording encoding workload. In the first example, there is no agent override configured. For each session on the agent, there are 2 CPUs subtracted from the available resources. Since the agent physically has 16 CPUs, that means only 8 sessions could be established. This is not optimal because system still has more RAM available, and could potentially handle twice as many sessions if the CPUs were overridden to 32. The amount of overriding the CPU and RAM is dependent on how large the agent is and what the use case is. For game streaming use case, users will be using most of their resources at all times. For standard use cases, however, overriding is generally safe but requires the administrator monitor the environment and understand the baseline usage. The subsequent two rows show two more scenarios of overriding. The more sessions a single system can take, generally the more you can override, because there are more sessions on the system, each of which has RAM and CPU not being fully utilized. The final example is very aggressive and is achievable depending on the use case. It is critical that actual RAM utilization on the agents is never allowed to get near full capacity. Getting the right override requires careful monitoring of your deployment in real world usage. Use the Kasm Workspaces Admin dashboard to view RAM utilization over time, on each agent. #### Disk Space The amount of disk space required will depend on the number of concurrent users the agent is expected to host and how much data each user is expected to accumulate during their session. When a new session is created, nearly no additional space is required on the agent to provision the session. As the user adds files or uses applications like Chrome, changes to the containers file system will accumulate space. The amount of disk space that each user session will consume can vary greatly based on your use case. In addition, when session recording is enabled, each session running on the agent where the user is part of a group with session recording enabled will need additional space to store the recording while it is being encoded and uploaded to S3 buckets. **It is recommended to use a separate volume for /var/lib/docker that uses the XFS file system.** The /var/lib/docker volume should have at least 80GB of disk space as a baseline plus the number of users times the amount of space expected per user (80GB + (Users * space_per_user)). The following table provides the calculations for several scenarios. If persistent profiles are enabled and use a remote file system such as NFS, the persistent profile does not reside on the agent and thus does not count when figuring out the expected size per user. You can utilize the command `sudo docker system df -v` to see the amount of disk space utilized by each container. | Base Size | Concurrent Sessions | Max Size Per User | Total Volume Size | |-----------|---------------------|-------------------|-------------------| | 80GB | 8 | 5GB | 120 GB | | 80GB | 20 | 10GB | 280 GB | | 80GB | 48 | 12GB | 656 GB | ##### Limiting Disk Usage It is possible to place size and speed restrictions on disk usage of containers. See the [Docker Reference Docs](https://docs.docker.com/engine/reference/commandline/run/#storage-opt) for more details. If using the default overlay2 storage driver, the backing file system must be XFS for the size and speed restrictions to work. The following JSON can be placed in the Workspace definition in the Docker Run Override field. With the example in place, the user's session would be capped at 10GB of disk space. This does not include the base desktop environment or installed applications, only changes the user invokes within their environment. **Restricting space used by a user's session.** ```json {"storage_opt":{"size":"10g"}} ``` **Restricting Disk I/O with read/write bps.** ```json {"device_read_bps":[{"Path":"/dev/vda","Rate":1000000}]} ``` **Restricting Disk I/) with [relative weights](https://docs.docker.com/engine/reference/run/#block-io-bandwidth-blkio-constraint).** ```json {"blkio_weight":200} ``` ### CPU Allocation Method Workspaces supports provisioning session containers with one of two methods, **Quotas** (`--cpus`) or **Shares** (`--cpu-shares`). See [Docker Resource Contraints](https://docs.docker.com/config/containers/resource_constraints/#cpu) for more details on how Docker utilizes these flags. The default method is **Shares** and is governed by the [Global Setting](../reference/settings.mdx) **Default CPU Allocation Method**. The allocation method can also be updated on the Workspace configuration by changing the **CPU Allocation Method** in the Workspace Settings. By default, the Workspace setting is configured to **Inherit**, which means to use the Global Setting. #### Shares CPU and Cores are used interchangably is this section. Ultimately, what is being referenced is the number of Logical Processors that are presented to the system. This will vary depending on the physical processor, such as those that are multi-core or support hyper-threading. It may also vary depending on the operating enviroment (e.g Virtual Machines / Cloud Environments). When the Shares CPU Allocation Method is used, session containers are provisioned with the Docker equivalent of `--cpu-shares=`. For example, if the **Cores** setting on the Workspace is set to 2, the container would be provisioned with `--cpu-shares=2048`. When a container utilizes shares, the amount of CPU resources the container can use is weighted against other containers and their share value. Most notably, **the container is only throttled if there is CPU contention.** If there is no contention, the container can use as much as it needs. For example, on an 8 CPU machine, if the **Cores** Workspace setting is configured at 4, this will result in the container created with `--cpu-shares=4096`. - If no CPU contention exists, the container can use all 8 CPUs. - If there are 2 containers both with `--cpu-shares=4096` each with be able to us the full CPU resources if no contention exists. - If contention exists, each container will be allowed up to 50% of the CPU resources because their shares (weights) are equal. The **Shares** method is useful for maximizing the usage of CPU resources, as all containers can use as much as needed when there is no contention. For bursty workloads, this will likely result in a better overall user experience when compared to the **Quotas** method. However, user experience may not be as consistent depending on the CPU activity of other containers. #### Quotas When the **Quotas** CPU Allocation Method is used, session containers get provisioned with the Docker equivalent of `--cpus=X`. The value used is based on the **Cores** setting defined on the Workspace. This sets a ceiling for the amount of CPU resources the container can use. For example, on an 8 CPU system with the Workspace configured at 2 cores, the container will only be allowed to use up to 25% of the CPUs. This strategy may be more helpful if the desire is to provide a more consistent performance profile. It may also be helpful if Kasm is running on systems with additional applications and utilizing all available CPU resources at times is not appropriate. ### Cloud Auto-Scaling Sizing Kasm can automatically scale agents in a number of cloud service providers. The instance size of the VM to use for auto scaled agents is configured in the [VM Provider Config](../how-to/infra-autoscale/autoscale/vm-providers.mdx). Administrators can choose to use an instance size that would allow a single Kasm session to be provisioned or an instance size that would allow for many instances to be provisioned per agent. Using larger instance sizes allows for CPU and RAM oversubscribing, however, using smaller instance sizes allows for resources to be released faster as user sessions end. Administrators will need to monitor the use of the system and select a strategy that maximizes cost savings and performance for there specific use-case. For example, Kasm Technologies currently uses an instance size that can accommodate two sessions per instance for the personal SaaS product. ### Redundancy When a user creates a new session, the manager API service will select an agent and attempt to provision the container there. If the provision failed, the manger will move on to the next available agent. This ensures redundancy for creating new sessions. The manager can only use agents that have the Docker image and Docker network (if specified in the Workspace settings) available and are assigned to the correct zone. If a central container image registry is used, agents will automatically pull images down. Agents will only pull images that can be provisioned on that agent. If a Kasm Workspace is defined that is assigned a specific Docker network and that network does not exist on an agent, the agent will not pull that specific Docker image. It is recommended to reduce differences between agents within a Zone and treat all agents in a Zone as a cluster of identically configured servers. This ensures Kasm will provision new user containers evenly across the cluster of agents. For cloud deployments that auto scale, capacity is managed by Kasm. For deployments with static agents, however, capacity planning is needed. For large deployments with static agents, it is recommended to keep the number of agents at N+2. In other words, ensure the number of agents is enough to handle peek capacity if you were to loose 2 agents. This allows for both maintenance and for the loss of 1 agent. If an agent were to go offline or be disabled by an administrator, Kasm will automatically send new sessions to the remaining agents. For existing sessions, it is not possible to provide redundancy if the system they are on goes down. However, there are additional resiliencies built in. The agent service can go down and user containers will continue to operate un-interrupted. Similarly, the agent can be disabled in the Kasm admin UI and existing sessions will continue to operate. ### Maintenance For systems in the cloud with auto scaling, the AMI ID defined in the [VM Provider Config](../how-to/infra-autoscale/autoscale/vm-providers.mdx) can be updated to start using an updated AMI. It is recommended to have a testing zone or a testing Kasm deployment to test updating to a new AMI before applying to production. For deployments with static agents it is recommended to keep 1 agent disabled in rotation, for system patching. For example, if the deployment had 6 agents, the administrator would disable one, wait for all user sessions to close on that agent, then perform system patching and restart the agent. Once the agent was back up and ready, the admin would enable the agent in the Kasm UI. This process would be repeated on the next agent. This allows for administrators to keep Kasm agents updated continuously, without the need for scheduled downtime. This is the reason that N+2 redundancy for agents is recommended for larger deployments. ## Connection Proxy The connection proxy service is a customized [Guacamole](https://guacamole.apache.org/) connection handler. This encodes and proxies standard RDP, VNC, and SSH connections to a websocket format usable by a modern web browser. Each [Zone](../how-to/infra-autoscale/deployment-zones.mdx) in Kasm requires at least one connection proxy, if the zone will have servers with RDP/VNC/SSH connections. ### Redundancy and Load Balancing Kasm will automatically load balance user sessions across multiple connection proxies and it is recommended to have at least two for redundancy. Kasm checks that a connection proxy is actively working prior to directing a user session to one. This ensures automatic failover while also load balancing sessions across any number of servers per Zone. ### Maintenance When connection proxies are taken offline, either by a reboot or by shutting down the service, Kasm will stop sending sessions through the down server. This is done automatically without admin intervention, however, any user sessions currently flowing through the connection proxy will be disconnected. The clients will automatically reconnect to their session and flow through a different connection proxy. It is recommended to perform maintenance on connection proxy servers during a scheduled maintenance window, however, it is not strictly required. It is important to test your maintenance procedures in your own environment in order to understand the operational impact to users. ### Sizing The required size of the connection proxy will vary highly on the exact user usage of systems. For example, if all users are watching full screen videos within their remote Windows desktop, the connection proxy will consume approximately 1.25 CPU cores per user, without [session recording](../how-to/workspaces-sessions/sessions/session-recording.mdx) enabled. Typically, users are not all watching full screen videos or playing video games all at the same time and in fact you may find that 60% of your users are not actively engaged with a session at any given time. Users may be reading an email or document, with little to no interaction. The larger your deployment, the more slack you have to play the law of averages. Some Kasm deployments with several hundred users easily accommodate all users with two servers with 16 cores each. These deployments are business customers, where users are typically interacting with documents and emails. Your mileage will vary, it is important to monitor your own deployment's resource utilization to understand your user base's real world usage and adjust accordingly. Memory requirements for the connection proxy are modest with 4 GB of RAM being a minimum. With [session recording](../how-to/workspaces-sessions/sessions/session-recording.mdx) enabled, additional resources are required. Sessions are initially recorded in a raw format that consumes a lot of local disk space. The video segments are then encoded in a compressed video format and uploaded. The [Session Recording Queue Length](../reference/settings.mdx) global setting defines how many video clips are processed concurrently. This setting should be increased when scaling up the number of concurrent sessions each connection proxy is sized to handle. It is recommended to set the `Session Recording Queue Length` to half that of the number of cores a system has. So if a system has 16 cores, set the `Session Recording Queue Length` to 8. This setting will ensure half the resources of a single server are dedicated to recording and reserves the other 8 cores for session streaming. Session recording is enabled as a [Group Setting](../how-to/security/users-groups-mgmt/groups.mdx#group-settings), therefore, session recording may not be enabled on all user sessions, depending on your configuration. Monitor the real world usage of your environment and adjust as needed. All connection proxies should be identical in size, this is even more important when session recording is enabled. Disk usage is minimal, without session recording. With session recording enabled, you should plan for at least 1GB or disk space per concurrent session. Additionally, disk I/O can become a bottleneck with higher capacities. For cloud based deployments, check your cloud provider documentation on how to increase disk I/O if needed. **Example Specifications** The following table provides a starting point, each environment will have different requirements based on several real world factors, such as actual user desktop activity, CPU architecture and class, cloud provider, and more. | Deployment | Server Specifications | Concurrent Sessions | |---------------------------|-----------------------------|---------------------| | Without Session Recording | 8 CPUs, 4GB RAM, 80 GB HD | 32 | | With Session Recording | 16 CPUs, 8GB RAM, 112 GB HD | 32 | --- ## Architecture: Services, Agents & Sessions # System Architecture The following system roles make up the Kasm Architecture: **API Service (container: kasmweb/kasm_api)** This service contains the API endpoints used by the web application. The web application content is automatically installed as part of this service. **Manager Service (container: kasmweb/kasm_manager)** This service is responsible for monitoring the status of Agents and user sessions. Agents report to this service via an automatic check in process. **Agent Service (container: kasmweb/agent)** The agent is responsible for provisioning instances of end user session containers when requested via the web application. The Agent reports the available system resources to the manager. These Agents are represented in the Servers tab in the Administration tab of the web application. This service automatically downloads all Kasm Images defined within the application so they are available to provision new sessions on demand. **Proxy Service (container: kasm_proxy)** This container, based on nginx, is used to forward traffic to the correct service container. This container is required to be run in tandem with any of the following services: - **API Service** - **Manager Service** - **Agent Service** - **Database Services (container: kasmweb/kasm_db, kasmweb)** > Houses the postgresql Kasm application databases **Connection Proxy (container: kasmweb/kasm_guac)** This service is a custom [Guacamole](https://guacamole.apache.org/) connection handler. This encodes and proxies standard RDP, VNC, and SSH connections to a websocket format usable by a modern web browser. **Sessions – End User Sessions/Containers (container: e.g kasmweb/firefox)** End users request to create sessions that are on-demand instances of Images registered in the application. These instances are provisioned by and on the Agent. These containers house the desktop or application presented to the end user via the web application. **Workspaces** A Workspace is full desktop, single application, or a direct web link made available to users based on their group membership. In the case of desktops and applications these can be containerized workloads that are spun up on demand or direct connections to KasmVNC/RDP/VNC/SSH endpoints. Any number of Workspaces can be registered via the web application and can be customized by the administrator to add additional software and configurations. The administrator can also configure the CPU, memory and network resources available to each Workspace via the [Workspaces Settings](../how-to/workspaces-sessions/container-workspace/workspaces.mdx). By default, several Workspaces are installed and registered. --- ## Installation Requirements & Compatibility # Kasm Workspaces Requirements Kasm Workspaces can be installed in a [single server](../tutorials/install/single-server-install.mdx) or [multi server](../tutorials/install/multi-server-install.mdx) setup. ## Operating System Kasm Services and end user sessions are [docker](../reference/glossary.mdx#docker) containers. Access to the Docker registry is required for installation. Kasm Workspaces can be installed on a Virtual Machine or directly on bare metal. We do not recommend running Kasm in LXC or WSL/WSL2. Installation is supported on the following operating systems: | | | --- | | Ubuntu 22.04 / 24.04 (amd64/arm64) | | Debian 11 / 12 / 13 (amd64/arm64) | | Oracle Linux 8 / 9 (amd64/arm64) | | Red Hat Enterprise Linux 8 / 9 / 10 (amd64/arm64) | | Raspberry Pi OS (Debian) 11 / 12 / 13 (arm64) | | AlmaLinux 8 / 9 (amd64/arm64) | | Rocky Linux 8 / 9 (amd64/arm64) | | [Other](../tutorials/install/other-operating-systems.mdx) | Not all published Workspaces Docker Images are available on all architectures. Please see [Default Images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx) for the support matrix. The WireGuard kernel module is not available as a prebuilt package for EL8 aarch64. ELRepo's `kmod-wireguard` is x86_64 only, and `kernel-modules-extra` does not include `wireguard.ko` on RHEL / Rocky / AlmaLinux 8 aarch64. **Affected feature:** Egress (WireGuard) will not be available on these platforms. To enable WireGuard, install `wireguard-dkms` from EPEL after ensuring `kernel-devel` is present. Note: RHEL / Rocky / AlmaLinux 9 aarch64 ships WireGuard in the stock kernel and does not have this limitation. ## Resource Requirements Minimum Requirements | | | | :----- | :-------- | | **CPU** | 2 cores | | **Memory** | 4GB | | **Storage**| 75GB (SSD) | Kasm provides a [Sizing and Deployment Guide](sizing-operations.mdx) to aid in determining hardware specifications for large scale deployments. Although the requirements for the Kasm services are quite modest, provisioning each end-user session requires additional compute resources as specified in the [workspace](../reference/glossary.mdx#workspace) configuration. The default Kasm Workspaces are [configured](../how-to/workspaces-sessions/container-workspace/workspaces.mdx) to require 2768MB of memory and 2 cores. Sessions will not be provisioned if the minimum resources requirements on the [agent](../reference/glossary.mdx#agent) are not met. Storage requirements are related directly to using the default set of Workspaces optionally downloaded during installation. Kasm can only assess the available storage space within the volume where the default docker directory (/var/lib/docker) exists. If you have unallocated free space in a different volume and want to use it for Kasm, you can extend your root volume to incorporate this unallocated space. If not enough space is available in Docker's storage directory (default /var/lib/docker) this can potentially block the entire installation and lead to undesired behavior. Please review the partition layout for the host operating system and ensure this requirement is met. When using a custom set of Workspaces this storage requirement can vary. ## Swap Partition Administrators can configure sessions to provision with any amount of cpu or memory allocations by editing the in the [Kasm Workspace Settings](../how-to/workspaces-sessions/container-workspace/workspaces.mdx). However, even a host with more than enough system memory can run into stability issues without enabling a swap partition. For this reason, the Kasm installation recommends a swap partition to be present. Install Swap partition for best stability of end user sessions. For additional details on docker resource constraints see the following link: [Docker Resource Constraints](https://docs.docker.com/config/containers/resource_constraints/) ### Creating a Swap Partition During installation users will be prompted to create a swap partition if none are present. Following this menu a swap partition of any size can be defined depending on the needs of the deployment. To skip this check pass the `--no-swap-check` installation flag. To automate this process the `--swap-size` installation flag can be passed with a number in megabytes for the resulting swap partition. Example: ``` sudo bash kasm_release/install.sh --accept-eula --swap-size 8192 ``` This will create an 8 gigabyte swap partition during Kasm Workspaces installation and assuming the installation is unattended bypass the License prompt. For general information on swap partitions check out the [Ubuntu Documentation](https://help.ubuntu.com/community/SwapFaq) ## Docker and Docker Compose Installation of Kasm will fail if `docker` exists on the machine with a version unsupported by Kasm. However, if `docker-compose` exists with an unsupported version, it will be automatically replaced by the installer with a compatible version. It is recommended that you install Kasm on a single-purpose machine and let the installer install the `docker` and `docker compose` programs. Below are the minimum requirements. Minimum Version Requirements | | | | :----------------- | :--------- | | **docker** | \>= 28.5.2 | | **docker compose** | \>= 2.40.2 | Run the following commands to check the versions of the programs if installed. ```bash sudo docker --version sudo docker info | grep "Docker Compose" ``` ## End User Requirements End-users access the Kasm Workspaces via the web ui. Most modern browsers are supported. | **Browsers** | | --- | | Chrome 92+ | | Edge 92+ | | Firefox 95+ | | Safari 15.4+ | **Caveats** - Audio is not supported on mobile browsers. - Seamless Clipboard ( Copying and Pasting without using the control panel ) is only supported on Chrome and Chromium-based client browsers. --- ## Custom Branding in Kasm Workspaces: Application & Session # Custom Branding Administrators may choose to add custom branding to their Kasm deployment. ## Application Branding Kasm allows administrators to define multiple branding configurations that are chosen by the system based on the URL hostname the users accesses the system with. Changes to branding may take up to 90 seconds to be apply since certain requests are cached by the system. When regularly changing and testing branding settings it is best to use the following steps to observe the changes: - Wait 90 seconds after the configuration change is made. - Logout of the Kasm UI. - Navigate the browser to the login page, and do a hard refesh of the page (Typcially CTRL+F5) or clear the browser cache. - Login and verify changes. This feature is available in Kasm Workspaces Enterprise. **Branding Configs** can be defined in the UI by an administrator under **Settings** -> **Branding**. | **Name** | **Description** | | :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | The name for the configuration. | | **Hostname** | The hostname of the URL used to access the Kasm deployment is used to map the appropriate branding config. | | **Favicon Logo URL** | URL for the favicon logo image, this image is also used for the global PWA icon, icons must be square for the PWA to be installable. | | **Admin Dashboard Logo URL** | URL for the logo shown in the sidebar on the admin pages. | | **User Dashboard Logo URL** | URL for the logo shown on the user dashboard, this is often the same as the admin dashboard logo, but doesn't have to be. | | **Launcher Background URL** | URL for the background image for the Workspaces launcher. See [Default Backgrounds](branding.mdx#default-backgrounds) for a list of available default images. | | **HTML Title** | HTML document title, this is also set as the global PWA title. | | **Login Caption** | Caption displayed under the login logo. | | **Login Logo URL** | URL for the login logo image. If a custom logo is used, the phrase "Powered By Kasm" will be displayed under the new logo. | | **Login Splash Background URL** | URL for the login splash background image. | | **Username Input Label** | Label for the username input field on the login page. | | **Loading Session Text** | The text to display while the user is connecting to a session. | | **Joining Session Text** | The text to display while the user is joining a shared session. | | **Destroying Session Text** | The text to display when the session is being destroyed. | | **Default** | If the configuration is set to Default, this system will use this configuration if the URL hostname does not match another config. | ## Session Branding The default background used within a session container can be adjusted by [Building a Custom Image](../workspaces-sessions/container-workspace/customization/building-images.mdx) or [Using File Mapping to Change the Default Background of a Workspace](../workspaces-sessions/file-mappings.mdx#using-file-mapping-to-change-the-default-background-of-a-workspace). **Background** The background can be changed by replacing the following file. Recommended resolution: 1920x1080 px. ```Bash /usr/share/backgrounds/bg_default.png ``` **Casting Branding** It's also possible to set the background on casting links by changing the **Launcher Background URL** on the [casting](../workspaces-sessions/sessions/session-casting.mdx) page. ## Default Backgrounds Workspaces includes a number of default backgrounds by default. Below is a preview of the images and the relative urls that can be used in the configurations. --- ## System Export Configuration # Exporting System Configurations The export interface provides four distinct export modes, each suited to different use cases. All exports produce a password-protected AES256 ZIP file containing an `export_data.yaml` file with the exported configuration data. To access the export interface: 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab. 4. Select "Export Configuration" ## Export Modes ### Complete Data Set A full system backup containing all configuration tables. Use this mode for disaster recovery or system restore. * **Import behavior:** Replaces ALL existing data. This is a destructive operation. * Supports [UUID tokenization](#uuid-tokenization) (optional). * Exports all configuration tables (excluding logs and license data). ### Partial Data Set A selective export allowing you to choose specific database tables. Use this mode for targeted operations where only certain configuration data is needed. * **Import behavior:** Data is merged additively with existing system data. * Supports [UUID tokenization](#uuid-tokenization) (optional). * Includes [table selection](#table-selection) to choose which tables to export. #### Table Selection Click "Show" to expand the list of exported tables. By default, all tables are exported. The table selection interface will automatically select or deselect secondary tables as you interact with it. This behavior maintains required relationships between tables, ensuring that the data is valid for import into a Kasm system as-is. ### Autoscale Configs Exports autoscale configurations along with their referenced zones and LDAP configurations. Use this mode for sharing or copying autoscale setups between deployments. * **Import behavior:** Data is merged with existing system data. Name conflicts are resolved through automatic renaming. Zone and LDAP mapping is available during import. * Automatically includes dependent zones and LDAP configurations referenced by the autoscale configs. * See [Autoscale Config Import](./import-configuration.mdx#autoscale-config-import) for details on the import workflow including zone/LDAP mappings and conflict resolution. ### Deployment Configuration A full deployment migration mode that exports all configuration data while excluding ephemeral runtime state. Use this mode when migrating a deployment to new infrastructure or creating a replica for A/B Deployments. * **Import behavior:** Replaces existing non-ephemeral data. Options are available to preserve manager tokens and API key pairs. * **Excludes** runtime state: sessions, ephemeral servers, agents, and connection proxies. * See [Deployment Configuration Import](./import-configuration.mdx#deployment-configuration-import) for details on the import options. ## UUID Tokenization UUID tokenization is available when using the Complete Data Set or Partial Data Set export modes. The Autoscale Configs and Deployment Configuration modes handle UUID management automatically. This feature modifies exported UUIDs to indicate that new ones should be created when the data is imported into Kasm. The original UUIDs are present in the exported data, for ease of troubleshooting. * UUIDs prefixed with `&` will be regenerated upon import. The UUID following the `&` symbol is the original UUID from the export system. * UUIDs prefixed with `*` refer to the same UUID prefixed with `&` in the export. These will be replaced with the respective newly generated UUID on import. Certain tables never have their primary UUIDs included in tokenization, either because they are static components or because tokenization is not appropriate: * connection_proxies * kasms * managers * servers * session_tokens Additionally, the "All Users" group ID tokenization is ignored on import, as the group has a static UUID. Records in the `accounting` table only have their `accounting_id` UUIDs modified. Other UUIDs are left unchanged, as they do not have Foreign Key relationships to other tables and represent historical data about sessions. ### AutoscaleConfig Tokenization By default in the "Complete Data Set" and "Partial Data Set" modes, the Autoscale Configurations are not tokenized when UUID tokenization is enabled. On import, the system gains an exact copy of the state of each Autoscale Configuration as it exists in the export system, including provisioned resources. This means that the import system will begin operating on the Autoscale Configurations; if the export system is still operational, the two systems will compete for control and conflict. **If you plan to use exported AutoscaleConfiguration data as a template rather than system restore, select the "Tokenize Autoscale Configuration UUIDs" option.** This causes the import to generate new AutoscaleConfigurations that are separate from the ones owned by the export system. In this mode, provisioned cloud resources like Servers are not exported, since the importing system will create its own. An example of when to use this mode is when creating side-by-side deployments, such as for a blue/green deployment strategy. If you are specifically looking to export and import autoscale configurations, consider using the dedicated **Autoscale Configs** export mode instead, which provides a streamlined workflow with zone/LDAP mapping and automatic conflict resolution on import. Tokenizing Autoscale Configuration UUIDs means that the import system will not have control over the old configurations and associated resources. Ensure that the old system maintains or tears down the original configurations, otherwise the original cloud resources will be orphaned. ## Export File Format All exports are downloaded as a password-protected ZIP file utilizing AES256 encryption. A utility such as 7zip is needed to extract the data, as many zip utilities built into operating systems like Windows and MacOS do not support AES256 for zip files. A file named `export_data.yaml` resides inside and contains the configurations. Below is a short example snippet of the yaml based configuration export. ```yaml title="Exported Configuration Snippet" alembic_version: 52136dd39702 export_metadata: export_mode: complete images: - allow_network_selection: false available: false categories: - Development cores: 2.0 cpu_allocation_method: Inherit description: The Collaboration Platform for API Development. docker_registry: https://index.docker.io/v1/ docker_token: null docker_user: null enabled: false exec_config: {} filter_policy_force_disabled: false filter_policy_id: null friendly_name: Postman gpu_count: 0 hash: null hidden: false image_id: 2ba504c975654fd18c554905478fc5a1 image_src: img/thumbnails/postman.png image_type: Container link_url: null memory: 2768000000 name: kasmweb/postman:develop notes: null persistent_profile_path: null require_gpu: false restrict_network_names: [] restrict_to_network: false restrict_to_server: false restrict_to_zone: false run_config: {} server_id: null server_pool_id: null session_time_limit: null volume_mappings: {} x_res: 800 y_res: 600 zone_id: null ``` ## Example: Complete Data Set Export 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab. 4. Select **Complete Data Set** as the export mode. 5. Enter the password you would like the export zip file to utilize. 6. (Optional) Enable **Tokenize UUIDs** if you plan to use this export as a template rather than a direct restore. See [UUID Tokenization](#uuid-tokenization) for details. 7. Click **Export**. The configuration will be downloaded as a password-protected zip file. ## Example: Autoscale Configuration Export This example assumes that the Kasm system has one or more preexisting Autoscale Configurations. 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab. 4. Select **Autoscale Configs** as the export mode. 5. Enter the password you would like the export zip file to utilize. 6. Click **Export**. The export will automatically include all autoscale configurations and their dependent zones and LDAP configurations. No manual table selection is needed. ## Example: Deployment Configuration Export 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab. 4. Select **Deployment Configuration** as the export mode. 5. Enter the password you would like the export zip file to utilize. 6. Click **Export**. The export will include all deployment configuration data while automatically excluding runtime state such as active sessions, ephemeral servers, agents, and connection proxies. --- ## Export Schema # Exporting Configuration Schema Administrators are also able to export the system configuration schema ( data structure ). This may be helpful when constructing a custom yaml configuration and is analogous to a database schema dump. Like the import and export files, this will include a matching [Configuration Schema Versioning and Details](schema-versioning.mdx) 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab and Click the **Export Schema** button. 4. The configuration schema will be downloaded as a yaml file. Below is a short example snippet of the yaml based configuration schema export. ```yaml title="Exported Configuration Schema Snippet" alembic_version: 52136dd39702 images: allow_network_selection: required: false type: BOOLEAN available: required: false type: BOOLEAN categories: required: false type: JSON cores: required: false type: FLOAT cpu_allocation_method: required: false type: VARCHAR description: required: false type: VARCHAR docker_registry: required: false type: VARCHAR docker_token: required: false type: VARCHAR docker_user: required: false type: VARCHAR(255) enabled: required: false type: BOOLEAN exec_config: required: false type: JSON filter_policy_force_disabled: required: false type: BOOLEAN filter_policy_id: foreign_key: filter_policies.filter_policy_id required: false type: UUID friendly_name: required: false type: VARCHAR(255) gpu_count: required: false type: INTEGER hash: required: false type: VARCHAR(255) hidden: required: false type: BOOLEAN image_id: required: false type: UUID image_src: required: false type: VARCHAR(255) image_type: required: false type: VARCHAR link_url: required: false type: VARCHAR memory: required: false type: BIGINT name: required: false type: VARCHAR(255) notes: required: false type: VARCHAR persistent_profile_path: required: false type: VARCHAR require_gpu: required: false type: BOOLEAN restrict_network_names: required: false type: JSON restrict_to_network: required: false type: BOOLEAN restrict_to_server: required: false type: BOOLEAN restrict_to_zone: required: false type: BOOLEAN run_config: required: false type: JSON server_id: foreign_key: servers.server_id required: false type: UUID server_pool_id: foreign_key: server_pools.server_pool_id required: false type: UUID session_time_limit: required: false type: INTEGER volume_mappings: required: false type: JSON x_res: required: false type: INTEGER y_res: required: false type: INTEGER zone_id: foreign_key: zones.zone_id required: false type: UUID ``` --- ## Import Configuration # Importing System Configurations Administrators can import system configuration data through a two-step workflow. The import interface expects a password-protected ZIP package that contains a file named `export_data.yaml`, which contains system configuration data in YAML format. This is the same output format provided by the configuration export. See [Exporting System Configurations](export-configuration.mdx) for more details. Only tables from the same application/database version are compatible. Please see [Configuration Schema Versioning and Details](schema-versioning.mdx) for more info. ## Import Workflow ### Step 1: Upload and Decrypt 1. Navigate to the **Import/Export Config** tab under **Diagnostics** -> **System Info**. 2. Click **Import Configuration**. 3. Select the export ZIP file. 4. Enter the encryption password used during export. 5. Click **Next** to proceed to the preview. ### Step 2: Preview and Configure The system decrypts and analyzes the import file, then displays: * The **detected export mode** (Complete Data Set, Partial Data Set, Autoscale Configs, or Deployment Configuration). * A **description** of what will happen when the import is applied. * **Mode-specific configuration options**, detailed in the sections below. Review the preview carefully before clicking **Import** to apply the changes. If the import is unsuccessful, no changes are applied to the system. If the error was permanent, i.e. due to bad data or a server-side error, it will be shown in the dialog. Retryable errors (e.g. request timeout) will trigger a notification, but the import form will allow you to re-attempt the import action. Additional information from the Kasm API may be available in the body of the network request. ## Import Behavior by Export Mode ### Complete Data Set Import Importing a Complete Data Set **replaces ALL existing system configuration data**. This is a destructive operation. All previous configurations will be removed and replaced with those in the provided import data. This may cause the admin to be logged out. A Complete Data Set import reflects the database as it was at export time, including any active sessions, servers, and agents recorded at that moment. If imported onto a different deployment, the UI may show sessions, servers, or agents that do not actually exist on the new system. These stale records may need to be manually cleaned up after the import completes. If preserving runtime state is a concern, consider using the [Deployment Configuration](./export-configuration.mdx#deployment-configuration) export mode instead, which is designed for migration scenarios and handles servers and agents separately. If the export contained [tokenized UUIDs](./export-configuration.mdx#uuid-tokenization), new UUIDs will be generated for all tokenized entries during import. ### Partial Data Set Import Importing a Partial Data Set **merges the imported data additively** with the current system without modifying preexisting data. If Kasm is unable to import the new data without conflicts, the import will be rolled back without any modifications to the system's data. See [Conflict Resolution](#conflict-resolution) for details on how duplicate records are handled. If the export contained [tokenized UUIDs](./export-configuration.mdx#uuid-tokenization), new UUIDs will be generated for all tokenized entries during import. ### Autoscale Config Import Importing an Autoscale Configs export **merges the imported data** with the existing system. The import preview provides additional configuration options: #### Zone Mappings Imported autoscale configurations reference specific zones. During import, the system presents a mapping interface where you can: * **Accept auto-matched zones** -- zones from the import that match existing zones by name are automatically pre-selected. * **Map to a different zone** -- select a different existing zone as the target. * **Create a new zone** -- if there is no name conflict with an existing zone, you can choose to create a new one from the import data. When a name conflict exists, the imported reference must be mapped to an existing zone. #### LDAP Config Mappings Similarly, imported autoscale configurations that reference LDAP configurations present a mapping interface where you can: * **Accept auto-matched LDAP configs** -- LDAP configs from the import that match by name are automatically pre-selected. * **Map to a different LDAP config** -- select a different existing LDAP config. * **Create a new LDAP config** -- if there is no name conflict with an existing LDAP config, you can create a new one from the import data. When a name conflict exists, the imported reference must be mapped to an existing LDAP config or skipped. * **Skip** -- choose not to import the LDAP config reference. #### Enabled State on Import For **Autoscale Configs** and **Deployment Configuration** imports that contain autoscale configurations, the import preview exposes an **Imported Autoscale Configs** setting: * **Import as disabled (default)** -- all imported autoscale configurations are forced to `enabled = false` regardless of their state in the export. Administrators can review and re-enable them individually after the import completes. * **Keep original enabled state** -- each imported autoscale configuration preserves the `enabled` value from the export. The default avoids unexpected provisioning activity when a large number of active configurations are imported onto a new deployment. Use *Keep original enabled state* when performing a backup restore or blue/green cutover where the imported deployment should begin servicing traffic immediately. **Complete** and **Partial** imports do not expose this setting; any autoscale configurations they contain always retain their original `enabled` value from the export. #### Name Conflict Resolution When imported resources have names that conflict with existing resources, the import preview displays a collapsible warning showing: * The **total number of conflicts** detected. * A **detailed breakdown grouped by resource type** (Server Pools, Autoscale Configs, Provider Configs, DNS Provider Configs). * The **original name** and the **new name** that will be assigned on import. Conflicting resources are automatically renamed with a datetime-stamped suffix, for example: `MyConfig (Imported 2026-03-20 14:30Z)`. ### Deployment Configuration Import Importing a Deployment Configuration **replaces existing non-ephemeral data** while preserving runtime state. The import preview provides two additional toggle options: * **Overwrite Manager Token** -- When enabled, replaces the current manager authentication token with the one from the export. When disabled (default), the current manager token is preserved. Disable this to avoid disrupting manager authentication during migration. * **Overwrite API Private and Public Key Pair** -- When enabled, replaces the current API key pair with the one from the export. When disabled, the current keys are preserved. Disable this to avoid disrupting API authentication during migration. Existing users are deleted before import. All users, including the Administrator, will need to log in using their imported passwords or authentication methods. Non-Autoscaled Agents are preserved during Deployment Configuration import. All servers are replaced by the import data. ## Tokenized Exports The import feature will generate new UUIDs for any tokenized UUIDs in the import data. If the tokenization data is incomplete, the import will be rolled back without making any changes to the existing system data. Refer to [the section on UUID tokenization](export-configuration.mdx#uuid-tokenization) for more details. ## Conflict Resolution Conflict resolution behavior depends on the export mode of the imported data. ### Partial Data Set Conflict Resolution For Partial Data Set imports, the system provides simple deduplication and conflict resolution for the following tables: Records affected by the following logic will be removed from the import data; they will not be merged into the existing data. | Resource | Table | Notes | | :----- | :----- | :----- | | System Settings | settings | Records for system settings that are already configured will be dropped from import data. | | Groups | groups | Groups conflicting by name will be dropped from import data. Other import records will be pointed to the existing group. | | Group Settings | group_settings | Records for group settings that are already configured will be dropped from import data. | | Group Permissions | group_permissions | Duplicates of existing Group Permissions will be dropped from import data. | | Users | users | Users conflicting by username will be dropped from import data. Other import records will be pointed to the existing user. | | Group Membership | user_groups | Import will skip assigning an existing user to an existing group of which it is already a member. | | Zones | zones | Zones conflicting by zone_name will be dropped from import data. Other import records will be pointed to the existing zone. | ### Autoscale Config Conflict Resolution For Autoscale Config imports, conflicting resources are automatically renamed rather than dropped. The renaming uses a datetime-stamped suffix: * Format: `ResourceName (Imported YYYY-MM-DD HH:MMZ)` (UTC time, `Z` denotes Zulu/UTC) * If that name is also taken, a counter is appended: `ResourceName (Imported YYYY-MM-DD HH:MMZ) 2` * Applies to: Server Pools, Autoscale Configs, Provider Configs, and DNS Provider Configs. Conflicts and their proposed renames are displayed in the [import preview](#name-conflict-resolution) before the import is applied. ### Complete Data Set and Deployment Configuration Conflict resolution is not applicable for these modes, as existing data is replaced during import. ## Example: Complete System Restore This example assumes that the ZIP file provided for import contains a complete Kasm system configuration export. See [the corresponding export example for more information](export-configuration.mdx#example-complete-data-set-export). This type of import will destroy the existing Kasm system configuration data. 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab and click **Import Configuration**. 4. **Step 1:** Select the complete export ZIP file and enter the password. Click **Next**. 5. **Step 2:** The preview shows **Complete Data Set** mode and warns that all existing data will be replaced. Review the preview. 6. Click **Import**. If successful, all previous configurations will be removed and replaced with those in the provided import data. This may cause the admin to be logged out. ## Example: Import Autoscale Configurations This example assumes that the ZIP file provided for import was exported using the **Autoscale Configs** export mode. See [the corresponding export example for more information](export-configuration.mdx#example-autoscale-configuration-export). 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab and click **Import Configuration**. 4. **Step 1:** Select the autoscale export ZIP file and enter the password. Click **Next**. 5. **Step 2:** The preview shows **Autoscale Configs** mode. Review and configure: * Verify **zone mappings** -- adjust if the auto-matched zones are not correct. * Verify **LDAP config mappings** -- adjust or skip as needed. * Review any **name conflicts** in the collapsible details section. 6. Click **Import**. If successful, new autoscale configurations and related resources will be created. Conflicting names will be auto-renamed as shown in the preview. Other system configuration data remains unmodified. ## Example: Deployment Migration Import This example assumes that the ZIP file provided for import was exported using the **Deployment Configuration** export mode. See [the corresponding export example for more information](./export-configuration.mdx#example-deployment-configuration-export). 1. Log into the Workspace UI as an administrator. 2. From the Admin panel, select **Diagnostics** -> **System Info** from the menu. 3. Navigate to the **Import/Export Config** tab and click **Import Configuration**. 4. **Step 1:** Select the deployment configuration export ZIP file and enter the password. Click **Next**. 5. **Step 2:** The preview shows **Deployment Configuration** mode. Configure: * **Overwrite Manager Token** -- disable if you want to preserve the current manager authentication token. * **Overwrite API Private and Public Key Pair** -- disable if you want to preserve the current API keys. 6. Click **Import**. If successful, the deployment configuration will be updated while preserving runtime state such as active sessions and host servers. --- ## Configuration Import/Export for System Administration # Configuration Import / Export Workspaces allows administrators to export and import the configuration of the system via the user interface. The system provides four export modes to support different use cases: * **[Complete Data Set](./export-configuration.mdx#complete-data-set)** -- Full system backup for disaster recovery or restoration. Replaces all existing data on import. * **[Partial Data Set](./export-configuration.mdx#partial-data-set)** -- Selective table export for targeted operations. Merges additively on import. * **[Autoscale Configs](./export-configuration.mdx#autoscale-configs)** -- Export autoscale configurations with dependent zones and LDAP configs. Supports zone/LDAP mapping and conflict resolution on import. * **[Deployment Configuration](./export-configuration.mdx#deployment-configuration)** -- Full deployment migration excluding runtime state. Replaces non-ephemeral data on import. This may be helpful for configuration management, backup/restore, deployment migration, and facilitating testing and automated deployments. Importing / exporting license information is not supported via this mechanism. Administrators will need to re-apply activation/license keys after executing an import operation. See [Adding A License](../../../reference/license.mdx#adding-a-license) for more details on manually applying keys via the UI or during installation. --- ## Schema Versioning # Configuration Schema Versioning and Details ### Alembic Version The `default_properties.yaml` as well as the schema and configurations exports will include an `alembic_version` property. The value is a unique hash that indicates the schema revision of the database and thus the format and properties that make up and import/export file. This version typically changes with each build of the application. The system will only allow imports and seeding of files that match it's internal `alembic_version`. This means that Administrators are not able to automatically export configurations from an older build of Workspaces and import it in a newer version - only between like versions. ### All Users Group ID The **All Users** group has special significance within the application and must be defined in the schema with group_id `68d557ac-4cac-42cc-a9f3-1c7c853de0f3` ### Default Global Settings The `default_properties.yaml` that ships with each build of workspaces will have a list of [Global Settings](../../../reference/settings.mdx) (`settings:`). Administrators are welcome to adjust the default values, but they should not add or remove settings as the system is expecting these exact settings to be defined. Below is an example of a few global settings. The full configuration will have dozens. It is ok to adjust the values, but none of the entries should be removed, or other properties altered.
**Global Settings**
```yaml settings: - category: logging description: The logging protocol used, allowed values are internal, https, splunk, and elasticsearch name: log_protocol sanitize: false services_restart: manager,api title: Log Protocol // highlight-next-line value: internal value_type: string - category: logging description: The port to use for logging communication. name: log_port sanitize: false services_restart: manager,api title: Log Port // highlight-next-line value: "443" value_type: int ``` ### Default Group Settings The `default_properties.yaml` that ships with each build of workspaces will have a list default [Group Settings](../../security/users-groups-mgmt/groups.mdx). The system defaults are those that have no `group_id assigned`. Administrators should not add/remove or adjust the defaults. However, Administrators can assign additional group settings to existing groups, such as the **All Users** group, to change default behaviors for users. Do not adjust the Default Group Settings - those that don't have `group_id`'s assigned.
**Default Group Settings (No Group ID Assigned)**
```yaml # # emphasize-lines: 3 group_settings: - description: Allow audio streaming for a Kasm. // highlight-next-line group_id: null group_setting_id: "${uuid:group_setting_id:2}" name: allow_kasm_audio value: "False" value_type: bool ```
**Group Setting assigned to a specific group**
```yaml group_settings: - description: Allow audio streaming for a Kasm. // highlight-next-line group_id: 68d557ac-4cac-42cc-a9f3-1c7c853de0f3 group_setting_id: "${uuid:group_setting_id:1001}" name: allow_kasm_audio value: "True" value_type: bool ``` --- ## Slipstream Install # Slip-Stream Install Configurations Administrators may wish to install an instance of Workspaces preloaded with desired configurations. This may be helpful for CI/CD or other programmatically deployed environments such as augmenting terraform projects. This can be accomplished by swapping out the `default_properties.yaml` file found in the standard installation package after it is extracted and before `install.sh` is called. The format of the `default_properties.yaml` file, is the same as one generated from the [Exporting System Configurations](export-configuration.mdx) mechanism, allowing administrators to more easily restore an existing deployment to another system. ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release_[[release]].tar.gz # Replace default_properties.yaml cp kasm_release/conf/database/seed_data/default_properties.yaml sudo bash kasm_release/install.sh ``` This feature is primarly intended for partners and system integrators that have advanced understanding and experience using Kasm Workspaces. Workspaces contains thousands of interconnected configuration items, many of which are internal-facing elements and thus not fully documented. Please see [Configuration Schema Versioning and Details](schema-versioning.mdx) for important implementation concerns. ### Default Properties Pre-Processing When the installer ingests the `default_properites.yaml`, it will first pre-process the file to allow values to be templated with special variables. This may be helpful when constructing references between objects via uuids, or templating values that should be randomized between deployments. It is recommended to inspect the `default_properites.yaml` that is provided with the install package for example usage as it represents the standard configurations for the default install. UUIDs can be templated by using the string `${uuid:}` e.g `${uuid:example1}`. If the same variable is used multiple times in the yaml, it will be replaced with the same UUID.
**Templated Config**
```yaml group_settings: - description: Allows users to see and edit all attributes of the Kasm application. // highlight-next-line group_id: "${uuid:group:1}" // highlight-next-line group_setting_id: "${uuid:group_setting_id:1}" name: administrator value: 'False' value_type: bool - description: Allow audio streaming for a Kasm. // highlight-next-line group_id: "${uuid:group:1}" // highlight-next-line group_setting_id: "${uuid:group_setting_id:2}" name: allow_kasm_audio value: 'False' value_type: bool groups: - description: null // highlight-next-line group_id: "${uuid:group:1}" is_system: false name: Internal Administrators priority: 1000 program_data: null ```
**Resultant Config**
```yaml group_settings: - description: Allows users to see and edit all attributes of the Kasm application. // highlight-next-line group_id: "e2fd5c8e-82c2-4841-8ef0-824e30f16055" // highlight-next-line group_setting_id: "e7173013-fad7-4de8-860b-94ee5a70dcbf" name: administrator value: 'False' value_type: bool - description: Allow audio streaming for a Kasm. // highlight-next-line group_id: "e2fd5c8e-82c2-4841-8ef0-824e30f16055" // highlight-next-line group_setting_id: "b1c4efbe-ddc4-4ebc-839b-483b2e190873" name: allow_kasm_audio value: 'False' value_type: bool groups: - description: null // highlight-next-line group_id: "e2fd5c8e-82c2-4841-8ef0-824e30f16055" is_system: false name: Internal Administrators priority: 1000 program_data: null ``` Datetime objects can be generated for the current time using the `${datetime:utcnow}` variable.
**Templated Config**
```yaml users: // highlight-next-line - created: '${datetime:utcnow}' // highlight-next-line password_set_date: '${datetime:utcnow}' pw_hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 realm: local salt: 6614c4ba-6c49-4f50-8d9a-ce82de5ac852 user_id: 11bf8e0a-e08c-4c1b-81ad-518447d75b49 username: admin@kasm.local ```
**Resultant Config**
```yaml users: // highlight-next-line - created: '2023-02-05 02:41:43.729155' // highlight-next-line password_set_date: '2023-02-05 02:41:43.729155' pw_hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 realm: local salt: 6614c4ba-6c49-4f50-8d9a-ce82de5ac852 user_id: 11bf8e0a-e08c-4c1b-81ad-518447d75b49 username: admin@kasm.local ``` Random string tokens can be be generated using a variable `${random_token:}`. E.g `${random_token:manager_token}`
**Templated Config**
```yaml settings: - category: manager description: An authentication token used in the communication between Kasm Agents and the Manager API server. name: token sanitize: false services_restart: manager title: Token // highlight-next-line value: "${random_token:manager_token}" value_type: password ```
**Resultant Config**
```yaml settings: - category: manager description: An authentication token used in the communication between Kasm Agents and the Manager API server. name: token sanitize: false services_restart: manager title: Token // highlight-next-line value: "2RZGPY1LUPOph4fmU1kU" value_type: password ``` RSA public and private keys can be be generated using variables: `${rsa::private}` and `${rsa::public}`
**Templated Config**
```yaml settings: - category: auth description: Private Key used to sign request between Kasm components. name: api_private_key sanitize: true services_restart: null title: API Private Key // highlight-next-line value: "${rsa:1:private}" value_type: multiline_string - category: auth description: Public key used by Kasm components to validate internal API calls. name: api_public_cert sanitize: false services_restart: null title: API Public Cert // highlight-next-line value: "${rsa:1:public}" value_type: multiline_string ```
**Resultant Config**
```yaml settings: - category: auth description: Private Key used to sign request between Kasm components. name: api_private_key sanitize: true services_restart: null title: API Private Key // highlight-start value: "-----BEGIN PRIVATE KEY----- MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDPS/VMFDiHcmYc ... F0QQggEL0azu+RPZkg2KV2ZqawkFbGeGdhnPbluvmFUZHS0qzs1xbefludeVe9aR 568UxTAiTOowDRY45zwugW52VdBFASdc3w6z/DzPgD2FfI46ZQPzJD4ariJOMlSY ZszdhrNDulOoIsp0Adm/nKtXrT8JJca5 -----END PRIVATE KEY-----" // highlight-end value_type: multiline_string - category: auth description: Public key used by Kasm components to validate internal API calls. name: api_public_cert sanitize: false services_restart: null title: API Public Cert // highlight-start value: "-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoQu+DCpu6IMVRJBlrxn5 /SLIzggFi72fkLTuXTi7gGPCtGMV/5QLJnRjcAAYo9zJoFhob268qcK69FMRD3B nJ//C3zSW5pWvzh5HdRINrjmdZKgCpudEeXYpd/KpIulHzoWLJuiizEM/jlFpJcB ... 89c22kgSOtyQGFJXQLQeFIqyak3fQ2guJ/ZbdJP6CeNJfjLdKFm9RE4bHuuqr2Bt /deSoQfXUXUUZbWf40jqprYTIuaidwBHus8KirY5LAxlDz9RVHvGQHrYq3hRMHcD XLnh226+sKxRSxxdXLwFLyMCAwEAAQ== -----END PUBLIC KEY-----" // highlight-end value_type: multiline_string ``` --- ## Workspaces Platform Administration Guide # Administration The Workspaces platform is a powerful and flexible system. It is highly recommended to watch this quick start administration guide, which configures Workspaces from a fresh install for common use cases and walks through many of the advanced features of the platform. --- ## Kasm Workspaces Autoscale Backup Warning: User Permissions Starting in version 1.17.0, the destination directory for the backup file needs to be readable and writable by the `kasm_db` user, which uses ID 70. --- ## Kasm Workspaces: Autoscale Backups & User Permissions (v1.17.0+) Starting in version 1.17.0, the destination directory for the backup file needs to be readable and writable by the `kasm_db` user, which uses ID 70. --- ## Host Guides # Host Configuration Guides This section explains some host considerations when configuring storage to be used for persistent data. This only applies to [volume map profiles](persistent-profiles.mdx#volume-mount-profiles). #### Using NFS For any [multi server deployment](../../tutorials/install/multi-server-install.mdx) we recommend using NFS for all Persistent data. Without a central file share across all Kasm Agents in the deployment each individual Kasm Agent would have different data stored. The user would get different data depending on which Kasm Agent they were launched to. ##### NFS Server Setup - Install an NFS server on this host. ```Bash sudo apt-get update sudo apt-get install -y nfs-kernel-server ``` ```Bash sudo yum install -y nfs-utils sudo systemctl enable rpcbind sudo systemctl enable nfs-server sudo service rpcbind start sudo service nfs-server start ``` - Create the folder to host the share. ```Bash sudo mkdir /kasmdata sudo chown -R 1000:1000 /kasmdata/ ``` - Add the entry to `/etc/exports`. In this example the IP of the NFS Client is `192.168.1.3`. Note the use of `all_squash`, `anonuid`, and `anongid` settings to ensure that all files are accessed and written as the default Kasm session UID 1000. See [https://linux.die.net/man/5/exports](https://linux.die.net/man/5/exports) for more details. ```Bash /kasmdata 192.168.1.3(rw,sync,all_squash,anonuid=1000,anongid=1000,no_subtree_check) ``` - Expose the new additions defined in the exports. ```Bash sudo exportfs -ar ``` ##### NFS Client Setup - Install an NFS client on this host. ```Bash sudo apt-get update sudo apt-get install -y nfs-common ``` ```Bash sudo yum install -y nfs-utils ``` - Create a directory for the mount. ```Bash sudo mkdir -p /mnt/kasm-nfs ``` - Add an entry to `` `/etc/fstab `` for the NFS mount. In this example the IP of the NFS Server is `192.168.1.2` ```Bash 192.168.1.2:/kasmdata /mnt/kasm-nfs nfs defaults 0 0 ``` - Mount the share. ```Bash sudo mount /mnt/kasm-nfs ``` - Test creating a file. ```Bash sudo touch /mnt/kasm-nfs/example.txt ``` - Inspect the file from the NFS Server to ensure the permissions are UID/GID 1000. ```Bash ls -la /kasmdata/ total 8 drwxr-xr-x 2 1000 1000 4096 Feb 24 08:39 . drwxr-xr-x 20 root root 4096 Feb 23 16:00 .. -rw-r--r-- 1 1000 1000 0 Feb 24 08:39 example.txt ``` - You can now reference the NFS share in volume mappings or persistent profile configurations. In this example we are configuring a shared directory for all users that have access to this Workspace available at the path `/share` to them using a volume mapping. Please see the [Volume Mapping Documentation](volume-mapping.mdx) for more information. ```JSON { "/mnt/kasm-nfs":{ "bind":"/share", "mode":"rw", "uid": 1000, "gid": 1000, "required": true, "skip_check": false } } ``` #### File Permissions and Isolation By default users inside of Kasm Workspaces sessions will run under the Linux UID and GID of 1000. What this means is that when creating persistent data paths it is important to understand that if exposed one user will have the same access to the other users files and vice versa. This becomes particularly important when using volume mappings. If mapping in a non user scoped directory IE `/mnt/kasm/` and continuing to use that path for user scoped directories IE `/mnt/kasm/desktop/{username}` anyone with access to the Workspace with the initial `/mnt/kasm` volume mapping will also have read and write access to all of the other users storage in `/mnt/kasm/desktop/`. Also because of this one user design it means that Administrators can limit access to specific files by modifying their owner and file permissions host level. In this example we will create a read only folder inside of the volume mapping. Lets say you would like to have a universal share folder where users can save/load/delete files in this directory this directory host level is `/mnt/kasm_docs_share` mounted into the launched Workspaces sessions as `/share/`. On the host with access to `/mnt/kasm_docs_share` we create the folder we want to be read only and place files/folder into it. ``` mkdir /mnt/kasm_docs_share/read_only_documents cp -ax /my_data/documents/* /mnt/kasm_docs_share/read_only_documents/ ``` Then we modify the user that owns this directory and the permissions: (in this example we use root but any user outside of 1000:1000 will work) ``` sudo chown root:root /mnt/kasm_docs_share/read_only_documents/ sudo chmod -R 664 /mnt/kasm_docs_share/read_only_documents/ ``` The user will be able to open and copy the files in this directory, but will not be able to make modifications from inside their Workspaces session: ``` default:~$ rm /share/read_only_documents/test.doc rm: remove write-protected regular empty file '/share/read_only_documents/test.doc'? y rm: cannot remove '/share/read_only_documents/test.doc': Permission denied default:~$ cp /share/read_only_documents/test.doc /home/kasm-user/Desktop/ default:~$ ls -l /home/kasm-user/Desktop/test.doc -rw-r--r-- 1 kasm-user kasm-user 0 Jan 26 20:49 /home/kasm-user/Desktop/test.doc ``` This is just a simple example Linux user and file permissions are a bit more complex than that. In this case we are setting the owner to root and then telling the filesystem: * First Number 6- Anyone that is the root user has read and write access. * Second Number 6- Anyone that belongs to the group root has read and write access. * Third Number 4- Anyone else only has read access. Please review this infographic for a better explanation: --- ## Persistent Data: Profiles & Volume Mappings # Persistent Data By default, Kasm Workspaces spins up containerized sessions that are ephemeral in nature. However, some use cases require that certain data or configurations persist between sessions. There are two main ways to achieve this: **Persistent Profiles** and **Volume Mappings**. **Persistent Profiles** automate the process of mounting a host directory into the Workspace as the users home directory. These are analogous to Roaming Profiles found in other platforms. When configured, users may select whether to use their persistent profile when launching a session, disable it (making the session ephemeral) it, reset the profile - (clearing the contents and starting a fresh profile). **Volume Mappings** are a more generic feature that can be used to map host-level directories into the session. They may also be used to share folders across multiple users/workspaces and thus are more appropriate to simulate an organizational share. Volume mapping can be configured at a group level or individual Workspace level. **(Cloud) Storage Mappings** are flexible solution aimed at giving end users the ability to attach their cloud storage accounts directly into the file-systems of container-based sessions. Administrators configure supported **Storage Providers** (e.g Google Drive, Dropbox, OneDrive, Nextcloud, S3). Admins can then configure mappings to those providers at a User, Group or Workspace level. End users can enroll their own accounts for the configured providers via their profile. --- ## General Server Issues # Persistent Profiles Administrators may desire to give each user a personal persistent profile that is restored during each session. This can be achieved in one of three ways: volume mounted profiles, storage mapping based profiles and S3 based profiles. ## Storage Mapping Based Profiles This feature is in [Preview](../../reference/experimental-features/feature-index.mdx#current--past-experimental-features) and not currently recommended for production use. The [Storage Mapping](storage-mappings/index.mdx) provides a way to attach external storage to sessions. Kasm's Storage Mapping supports many different backend storage providers, such as Google Drive, Dropbox, S3, and others. The issue with many of these providers is that they cannot be used for a user's home profile in Linux. To alleviate this issue, Kasm has developed its own storage provider, `Kasm Profile Sync`. The Kasm Profile Sync storage provider supports AWS S3 storage with support for more storage solutions coming. While it has not been tested on all S3 compatible storage solutions, it is known to work on services that are S3 compatible, such as Oracle object storage, GCP, and Wasabi. The **Kasm Profile Sync** storage provider is meant to replace the [S3 Based Profiles](#s3-based-profiles) and provides many advantages over this legacy solution. * SSE-C is used so that each user's profile has a different encryption key managed by Kasm. * Support for unlimited file and profile sizes. The legacy version is limited in both the maximum file size and the total profile size. * Centralized logging of profile sync operations. * S3 credentials are managed per Storage Mapping configuration, instead of globally, allowing for multi-tenancy usage. * Supports for AWS STS credentials, ensuring profile sync uses short-lived limited credentials. * Easier to configure details of profile sync in the admin UI. AWS as of April 2026 blocks SSE-C customer encryption keys by default. Please ensure this security control is disabled when using an s3 bucket for Kasm Profile Sync. See [https://docs.aws.amazon.com/AmazonS3/latest/userguide/default-s3-c-encryption-setting-faq.html](https://docs.aws.amazon.com/AmazonS3/latest/userguide/default-s3-c-encryption-setting-faq.html) for more details. If both Storage Mapping based profiles are configured alongside Volume Mount profiles or the legacy S3 based profiles, the Storage Mapping based profile configuration takes precedence. Any existing data will be migrated to the Storage Mapping profiles, allowing admins to easily migrate to this new solution. While persistent profiles may work on S3 compatible solutions, Kasm cannot provide support for 3rd party products that claim to be S3 compatible. The first step in configuring Storage Mapping based profiles using the **Kasm Profile Sync** provider is to create a Storage Provider configuration. ### Storage Provider Configuration 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Storage** -> **Add**. 3. Provide a name and configure the Volume Config json field. ```json { "backend_storage" : "s3", "log_level" : "info", "filter" : "Downloads/*", "storage_limit" : "20g", "sts" : true } ``` | Field | Description | |-------|-------------| | backend_storage | The type of storage to use on the backend, currently only `s3` is supported. | | log_level | The logging level, expected values of `debug`, `info`, `warning`, and `error`. | | filter | Comma-delimited list of directories or files within the user's home profile to ignore, supports Linux globbing format. **Any whitespace will be interpreted literally; do not insert spaces between entries.**| | storage_limit | Sets a maximum storage size limit. Users will get pop up notifications within the desktop when the profile size has exceeded 90% of the limit. Use the labels `m` or `g` to specify MegaBytes or GigaBytes respectively. A value of `0g` or `0m` disables storage limits. | | sts | Determines if AWS STS will be used for authentication by the profile-sync binary running inside the user's container. This provides additional security by ensuring that temporary limited use tokens are used by endpoints for authentication to S3. This is only supported for AWS S3, other S3 compatible solutions will not work with STS enabled. | After the **Storage Provider** details are configured, the storage provider can be used to create **Storage Mappings** on each desired Workspaces Image. ### Storage Mapping Configuration 1. Log into the Kasm UI as an administrator. 2. Select **Workspaces** -> **Workspaces** 3. Edit the desired Workspace Image 4. Click the **Storage Mapping** tab 5. Click the **Add** button 6. From the **Type** drop down, select the provider you created in the previous section. 7. Enter the S3 Access Key ID, S3 Secret Access Key, and the bucket. ### AWS IAM Role To use an IAM Role assigned to EC2 instances instead of an AWS Access Key and Access Key Secret, use the value `{IAM}` in the **S3 Access Key ID** field and use any value for the **S3 Secret Access Key** field on the Storage Mapping configuration. An IAM role with the polices covered in the below section needs to exist on all Kasm Agents and all Kasm WebApp EC2 instances. Additionally, the [Storage Provider](#storage-provider-configuration) configuration needs to disable `sts`. ### S3 Endpoints You can force Kasm to use a specific endpoint by using this format in the Bucket name field of the Storage Mapping defined on the Workspace. This can be used to ensure all requests go directly to the region the bucket resides in, it can be used to send requests to an VNC S3 endpoint, or it can be used to specify an S3 compatible service. `@` For example: **my-bucket@s3.eu-central-1.amazonaws.com** ### S3 Compatible Solutions There are many object storage solutions out there that claim to be compatible with AWS S3 clients, such as GCP, OCI, and MinIO object storage. No AWS S3 compatible service is 100% compatible and Kasm Technologies cannot feasibly support all providers that claim to be compatible, however, this section documents what we do know that might help our clients configure Kasm to work on these type of services. * You must set `sts` to `false` in the **Storage Provider** configuration. This disables sts tokens for authentication, which is not supported by AWS compatible services. * You must specify an endpoint in the bucket name of the Storage Mapping configuration. AWS S3 now chunks all upload operations and not all "S3 Compatible" services support this. There is a work around for the following providers known not to support chunked uploads. This list may not be all inclusive, if you are having issues with your S3 Compatible service you may try this work around. * OCI To work around the lack of support for chunked uploads for the above list of S3 Compatible services, you must set two environmental variables on the Workspace Image settings. The following example json would go in the **Docker Run Configuration Override** field in the Workspace Image settings. ```json { "environment": { "AWS_REQUEST_CHECKSUM_CALCULATION": "WHEN_REQUIRED", "AWS_RESPONSE_CHECKSUM_VALIDATION": "WHEN_REQUIRED" } } ``` ## Volume Mount Profiles This is achieved by mounting in a host level directory into the container meaning the top level folders used for this setting should exist on the host beforehand. When configured, the user's home directory will be stored at the specified location and mapped in each time the user loads that Workspace. Administrators must use the `{username}` or `{user_id}` variables in the mapping to ensure they are unique per user. `{image_id}` may also be used as a variable. Persistent profiles are configured on a per Workspace basis and should be isolated in their pathing IE if you have a Chrome and Firefox image on your Workspaces deployment and the users are **user@kasm.local** and **admin@kasm.local** the directory structure would look like: It is important that each workspace's profile path is unique. There are some use cases where you would want the profile for different workspaces to be identical. One example would be cloned workspaces. However, even in this scenario it is highly recommended that workspaces have unique profile paths to prevent the files from one workspace conflicting with the files in another. This can happen because most applications will attempt to store their session configuration data at the same file location, however when using shared profile paths this file already exist with a possibly incompatible setting such as a resource lock. The easiest way to ensure unique profile paths is to use a format similar to "`/mnt/kasm_profiles/{username}/{image_id}`" or "`/mnt/kasm_profiles/{user_id}/{image_id}`". ``` /mnt/kasm_profiles/ ├── admin@kasm.local │   ├── chrome │   └── firefox └── user@kasm.local ├── chrome └── firefox ``` The only folder the administrator needs to create is `/mnt/kasm_profiles/` and the rest will be generated on Workspace launch. ## S3 Based Profiles AWS S3 object storage can be used for persistent profiles. The advantages of using S3 for persistent profiles are: - Redundancy - Data management policies in S3 - Globally distributed - Security The user's session container does not have direct authenticated access to S3. When the container starts, it makes an API call to the Kasm API service to request the profile manifest. The Kasm API returns a manifest that contains presigned URLs for each layer of the profile. The S3 presigned URLs are only authorized for each object they are signed for and only for a limited amount of time. This architecture ensures that a single S3 bucket can be securely used for all users in the system. The administrator needs to define the AWS Access Key ID and Access Secret in the [Server Settings](../../reference/settings.mdx#storage). The access key should be defined on a user that only has access to the specific bucket in question, with no other permissions. The user should be able to read and write to the bucket, and create pre-signed URLs. Kasm API services need to be restarted after changing/setting the AWS Access Key ID or Access Key Secret. Finally, the administrator will need to specify the S3 URL path in the Workspace settings, in the format of `s3://bucket-name/folder/{username}/`. Replace bucket-name with the target S3 bucket name. Each Workspace in Kasm should have its own folder, if the folder does not exist, it will be created. Use the `{username}` or `{user_id}` token in the path, to ensure each user has their own directory. Administrators can use different buckets for different Workspaces, as long as the AWS Access Key used in the global settings has the required access to all configured buckets. ### S3 Policy Configurations This feature utilizes pre-signed URLs to facilitate uploading artifacts to S3. The minimum S3 bucket policy required to use this feature is: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "PolicyForAllowKasmS3UserReadWrite", "Effect": "Allow", "Principal": { "AWS": "" }, "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:DeleteObject" ], "Resource": [ "", "/*" ] }, { "Sid": "PolicyForAllowKasmS3UserListLocate", "Effect": "Allow", "Principal": { "AWS": "" }, "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "" } ] } ``` The minimum IAM policy for the S3 credentials used in Kasm are: ```json { "Statement": [ { "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:DeleteObject" ], "Effect": "Allow", "Resource": [ "", "/*" ] }, { "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Effect": "Allow", "Resource": "" } ], "Version": "2012-10-17" } ``` ### S3 Endpoints By default, the endpoint used for S3 access is `s3.amazonaws.com`. Administrators may desire to specify a custom endpoint in order to support the following use cases. - A private VPC Endpoint - AWS Gov Cloud end-points - Region specific end-points - AWS S3 Accelerated Endpoints - S3 Compatible Solutions While persistent profiles may work on S3 compatible solutions, Kasm cannot provide support for 3rd party products that claim to be S3 compatible. Kasm utilizes pre-signed S3 URLs and only supports version 4 signatures. To specify a custom endpoint, in the Workspaces settings, format the Persistent Profile path in the following format: ```text s3://bucket-name@endpoint/folder/{username}/ ``` The following example configures Kasm to use Wasabi (an S3 compliant cloud storage provider) for a persistent profile, where `kasm` is the bucket name, `wasabisys.com` is the endpoint name, and the remaining is the path with `{username}` replaced by the Kasm username. ```text s3://kasm@s3.wasabisys.com/ubuntu2/{username}/ ``` ### Adding a persistent profile to a Workspace To add a persistent profile path to a Workspace from the administrator menu first click on Workspaces -> Workspaces and edit your desired Workspace: ### How to configure a persistent profile in a workspace - Configure the persistent profile path on the [workspace](../../reference/glossary.mdx#workspace). Variables can be used for the Image ID and User ID so that the persistent profile path is uniform across all images: ``` /mnt/kasm_profiles/{image_id}/{user_id} ``` Alternatively, if the paths should be human-readable the image name can be specified in the path and the Username as a variable: ``` /mnt/kasm_profiles/firefox/{username} ``` If Kasm is installed in a multi-server deployment path should reference a shared data storage solution (e.g NFS, HDFS, GFS, SMB, SSHFS) to ensure data continuity. Administrators must ensure this path is accessible from the hosts of all Agent services. Kasm will create the directory if it does not exist. ### Limiting group access to persistent profiles It may be necessary to limit which users can access the persistent profile feature, this can be achieved with a group setting. **See [Group Setting](../security/users-groups-mgmt/groups.mdx#group-settings) for more details.** From the administrator menu first click on Access Management -> Groups and click Edit on your desired group: Under **Settings** find the `allow_persistent_profile` group setting and click edit: This is a Boolean value, set it to true to enable access and false to disable access for this particular group. ### Utilize a persistent profile with creating a Kasm When creating a Kasm, the user will now be presented with a **Persistent Profile** Option. Multiple Settings are available. > - **Enabled** > - The persistent profile path defined on the workspace will be loaded during creation. > - **Disabled** > - The persistent profile will **NOT** be loaded on creation. > - **Reset** > - The existing persistent profile will be deleted and re-created. The is useful if the user desires to clear old profile data and start fresh. ### Size Limits Administrators can place a size limit on S3-based persistent profiles and a size warning for volume mapped profiles. When a user's home profile exceeds the limit, the user will get a warning message within the Workspace desktop session. For S3-based profiles, the user's changes will not be saved between sessions until they reduce the size of their profile. The size limit can be set using the environmental variable **KASM_PROFILE_SIZE_LIMIT**, specified in KB. To specify a persistent profile size limit of 2GB, you would set a value of 2000000. To set the environmental variable, use the [Docker Run Override](../workspaces-sessions/container-workspace/workspaces.mdx#docker-run-config) setting in the Workspace definition. By default, there is no limit. ### Filters S3-based persistent profiles support filters that will ignore files and/or directories. The filter is a comma separated list of file or directory names, relative from the user's home profile path. The default filter is. ```bash .cache,.vnc,Downloads,Uploads ``` This default filter ignores the .cache, .vnc, Downloads, and Uploads directories within the user's home profile. This default filter can be overridden by setting the **KASM_PROFILE_FILTER** environmental variable. To set the environmental variable, use the [Docker Run Override](../workspaces-sessions/container-workspace/workspaces.mdx#docker-run-config) setting in the Workspace definition. Globing is supported, such as `Documents/*.docx`, to mean any file ending in '.docx' or `Documents/**.docx`, meaning any file ending in '.docx' in the Documents directory or any child directory within. ### Video Example This video shows an example of configuring persistent profiles. --- ## Custom # Custom Storage Provider Setup Custom storage providers give administrators the ability to create free-form configurations that create docker volumes and then map them into containers. Configuration is largely instrumented through the **Volume Config** and **Mount Config** options in accordance with any desired docker volume plugin and driver options. Unlike the other providers, Storage Mappings for Custom Storage Providers may only be configured by administrators. No settings are exposed on the Storage Mappings for Custom Storage Providers, so they only service as an association by the admin to a Workspace, Group, or User. - **S3 Example** In this example, we take advantage of the [Variable Substitution](index.mdx#variable-substitution) in order for each user to get their own storage location. Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom-{username} Volume Config (S3 Example) ```json { "driver": "rclone", "driver_opts": { "type": "s3", "path": "bucket-name/folder/{user_id}", "vfs-cache-mode": "off", "dir-cache-time": "10s", "s3-provider": "AWS", "s3-env-auth": "false", "s3-access-key-id": "--redacted--", "s3-secret-access-key": "--redacted--", "s3-region": "us-east-1", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} - **S3 + File Based Encryption Example** In this example, we leverage the rclone storage driver's ability to utilize [Crypt Remote](https://rclone.org/crypt/) as a wrapper around the S3 example from above. This builds on the previous example by implementing file based encryption on each user's files. Files are transparently encrypted/decrypted when utilized in the Kasm session. Files are obfuscated and encrypted when viewed from the S3 console. ![Encrypted File](/img/storage_mapping/custom/encrypted_file.png) ![Obfuscated Filename of Encrypted File](/img/storage_mapping/custom/obfuscated_filename.png) Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom-{username} Volume Config (S3 Example) ```json { "driver": "rclone", "driver_opts": { "type": "crypt", "vfs-cache-mode": "off", "dir-cache-time": "10s", "crypt-filename-encryption": "standard", "crypt-password": "{user_crypt_password}", "crypt-password2": "{user_crypt_salt}", "crypt-remote": ":s3,provider=AWS,env_auth=false,access_key_id=--redacted--,secret_access_key=--redacted--,region=us-east-1:bucket-name/folder/{user_id}", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} - **Azure Blob Example** - The Azure Blob Storage Account Name and Key can be found in the **Security + networking** -> **Access keys** section. More info on the Azure Blob paremeters can be found in the [Rclone Azure blob documentation](https://rclone.org/azureblob/) Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom Volume Config (Azure Blob Example) ```json { "driver": "rclone", "driver_opts": { "type": "azureblob", "path": "container-name", "azureblob-account": "storage-account-name", "azureblob-key": "storage-key", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} ![Add Storage Mapping](/img/storage_mapping/custom/azure_blob.png) - **SMB/CIFS Example** - More info on the SMB parameters can be found in the [Rclone SMB documentation](https://rclone.org/smb/) - The `smb-pass` option needs to be obscured value produced via the [Rclone Obscure](https://rclone.org/commands/rclone_obscure/) utility. Install the latest version of rclone on a separate system and utilize the `rlone obscure` utility to generate the obscured password to use in the configuration. Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom Volume Config (SMB Example) ```json { "driver": "rclone", "driver_opts": { "type": "smb", "path": "optional/share/path", "smb-host": "192.168.1.2", "smb-user": "username", "smb-pass": "--obscured-pass-with-rclone-obscure--", "smb-domain": "WORKGROUP", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} :::note Many of the storage provider examples include default storage driver options used by Rclone. These options work well with Kasm in its default configuration, and administrators can adjust them as needed. The available options often vary by provider plugin, for example Google Drive compared with OneDrive. The Rclone Docker plugin is installed by default as part of the standard Workspace install. For more information about Rclone driver options, see [the Rclone Docker documentation](https://rclone.org/docker/). ::: - **Digital Ocean Spaces Example** Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom Volume Config (S3 Example) ```json { "driver": "rclone", "driver_opts": { "type": "s3", "path": "bucket-name/folder/", "vfs-cache-mode": "off", "dir-cache-time": "10s", "s3-provider": "DigitalOcean", "s3-env-auth": "false", "s3-access-key-id": "--redacted--", "s3-secret-access-key": "--redacted--", "s3-endpoint": "fra1.digitaloceanspaces.com", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} - **Google Cloud Storage Example** Name Custom Provider Storage Provider Type Custom Enabled checked Default Target /custom Volume Config (S3 Example) ```json { "driver": "rclone", "driver_opts": { "type": "s3", "path": "bucket-name/folder/", "vfs-cache-mode": "off", "dir-cache-time": "10s", "s3-provider": "GCS", "s3-env-auth": "false", "s3-access-key-id": "--redacted--", "s3-secret-access-key": "--redacted--", "s3-endpoint": "https://storage.googleapis.com", "uid": "1000", "gid": "1000", "allow_other": "true" } } ``` Mount Config {} ### Create Storage Mapping Storage Mappings for Custom Storage Providers can only be configured by Administrators. 1. From the Workspaces app , select the desired Workspace, User or Group to associate with the Storage Mapping. 2. Select **Storage Mapping** tab and select **Add Storage Mapping**. ![Add Storage Mapping](/img/storage_mapping/custom/add_storage_mapping.png) 3. Select the Custom Storage Provider from the **Type** dropdown and select **Next** ![Configure Storage](/img/storage_mapping/custom/custom_storage_mapping.png) 4. Launch a new container-based session. Verify the Custom storage is mapped inside the session at the `/custom` location. ![Custom Mount](/img/storage_mapping/custom/files.png) --- ## Dropbox # Dropbox Storage Provider Setup The [Dropbox](https://www.dropbox.com/) Storage Provider allows end-users to map in their OneDrive storage into container-based sessions. Access is provided via [Dropbox's OAuth interface](https://www.dropbox.com/apps) and leveraging the [Rclone](https://rclone.org) Docker volume plugin. Reference Docs: - [https://rclone.org/dropbox/](https://rclone.org/dropbox/) ### Creating a Dropbox OAuth App 1. Login to the Dropbox App Console: [https://www.dropbox.com/developers/apps/create](https://www.dropbox.com/developers/apps/create) . 2. Select **Scoped Access**, **Full Dropbox**, give the app a name (e.g `Kasm-Example`), then click **Create app**. ![Create new App](/img/storage_providers/dropbox/create_new_app.png) 3. On the next screen take note of the **App key** and **App Secret** , these will be used as the **Client ID** and **Client Secret** in the Storage Provider Configuration. ![Authentication Details](/img/storage_providers/dropbox/app_key_secret.png) 4. In the **Development users** section, click **Enable additional users** to allow additional accounts to use this app. ![Enable Additional Users](/img/storage_providers/dropbox/enable_additional_users.png) 5. In the OAuth 2 section, enter the following URL for **Redirect URI** , substituting the hostname of the Kasm deployment `https://kasm.example.com/api/cloud_storage_callback` , then click *Add*. ![Redirect Settings](/img/storage_providers/dropbox/app_redirect.png) 6. Select the **Permissions** tab and ensure the following permissions are selected, then click **Submit**. ```text account_info.read files.metadata.read files.metadata.write files.content.write files.content.read sharing.read sharing.write ``` ![DropBox Permissions](/img/storage_providers/dropbox/app_permissions.png) ### Kasm Storage Provider Config 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Storage** -> **Add**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | Name | `Dropbox` | | --- | --- | | Storage Provider Type | `Dropbox` | | Enabled | `checked` | | Client ID | `` | | Client Secret | `` | | Authorization URL | `https://www.dropbox.com/1/oauth2/authorize` | | Authorization URL Options | `{"include_granted_scopes" : "user", "access_type" : "offline", "token_access_type" : "offline"}` | | Token URL | `https://api.dropboxapi.com/1/oauth2/token` | | Redirect URL | `https:///api/cloud_storage_callback` | | Scope | .. code-block:: text files.metadata.read files.metadata.write files.content.read files.content.write sharing.read sharing.write account_info.read | | Default Target | `/dropbox` | | Volume Config | `{ "driver" : "rclone", "driver_opts" : { "type" : "dropbox", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } }` | | Mount Config | `{}` | 4. Click **Save** to save the changes. ### Dropbox storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Dropbox** from the drop-down, then select **Next**. ![Configure the Dropbox storage mapping](/img/storage_mapping/dropbox/configure_storage.webp) 4. The Dropbox login page appears. Log in with the desired account. ![Log in to Dropbox](/img/storage_mapping/dropbox/login.png) 5. Dropbox asks for consent to provide access to the account. Approve the request. ![Approve Kasm access to Dropbox](/img/storage_mapping/dropbox/approve.png) 6. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The Dropbox storage mapping in the profile](/img/storage_mapping/dropbox/storage_mapping.png) 7. Launch a new container-based session. Confirm that Dropbox is mapped inside the session at the `/dropbox` location. ![Dropbox files mapped inside a session](/img/storage_mapping/dropbox/files.png) --- ## GDrive # Google Drive Storage Provider Setup The [Google Drive](https://www.google.com/drive/) Storage Provider allows end-users to map in their Google Drive storage into container-based sessions. Access is provided via Googles Drive's OAuth interface and leveraging the [Rclone](https://rclone.org) Docker volume plugin. Reference Docs: - [https://developers.google.com/identity/protocols/oauth2](https://developers.google.com/identity/protocols/oauth2) - [https://rclone.org/drive/](https://rclone.org/drive/) ### Creating a Google OAuth App 1. Login to the Google Developer Console: [https://console.developers.google.com](https://console.developers.google.com). 2. From the **APIs & Services menu**, Select **OAuth consent screen**. 3. Select **External** then click **Create**. In this example, we walk through creating an integration where any Google user can auth with the Google Drive Storage Provider. This is ideal for a public facing deployment. Choose **Internal** if only users from your Google Workspace corporate account should be allowed to authenticate. Extenal types will need to go through a validation process before being used in production systems. ![OAuth Consent](/img/storage_providers/gdrive/oauth_consent_create.png) 4. Provide values for the **App Name** , **User support email**, and **Developer Contact email**. 5. In the **Authorized Domains** section, enter the Workspaces deployment's top private domain (e.g `example.com`). 6. Click **Save and Continue**. ![OAuth Registration](/img/storage_providers/gdrive/oauth_consent_registration.png) 7. Click **Add or Remove Scopes**. 8. In the **Update Selected Scopes** window check `.../auth/drive` , then click Update. If the option is not available, add `https://www.googleapis.com/auth/drive` to the **Manually add scope** field and click **Add To Table**. ![OAuth Scope](/img/storage_providers/gdrive/oauth_consent_scope.png) 09. Click **Save and Continue**. 10. Until the app is fully verified and published it can only be used to auth specific test accounts. Click **Add Users** to authorize several test google accounts. 11. Click **Save and Continue**. 12. In the **APIs & Services** menu, select **Credentials**. 13. Select **Create Credentials**, then **OAuth client ID**. ![Client ID](/img/storage_providers/gdrive/oauth_client_id.png) 14. Select `Web Application` as the **Application type**, then give the client a name (e.g `Kasm`). 15. Click **Add URI** in the **Authorized redirect URIs** section, and enter `https:///api/cloud_storage_callback`. 16. Click **Create**. ![Create Client](/img/storage_providers/gdrive/create_oauth_client.png) 17. A dialogue will display with a **Client ID** and **Client Secret**. Save these values for the next configuration steps. The JSON download will also include URLs needed for the next configuration steps. ![Client Secret](/img/storage_providers/gdrive/client_secret.png) 18. From the main menu of the Google Cloud Console , search for "Google Drive API". Navigate to the selected page, then click "Enable" if the option is available. No action is needed if the status is currently enabled. ![Enable Drive](/img/storage_providers/gdrive/enable_drive_api.png) ### Kasm Storage Provider Config 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Storage** -> **Add**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | Name | `Google Drive` | | --- | --- | | Storage Provider Type | `Google Drive` | | Enabled | `checked` | | Client ID | `` | | Client Secret | `` | | Authorization URL | `https://accounts.google.com/o/oauth2/auth` | | Authorization URL Options | `{"include_granted_scopes" : "true", "prompt" : "select_account consent", "access_type" : "offline"}` | | Token URL | `https://oauth2.googleapis.com/token` | | Redirect URL | `https:///api/cloud_storage_callback` | | Scope | `https://www.googleapis.com/auth/drive` | | Default Target | `/gdrive` | | Volume Config | `{ "driver" : "rclone", "driver_opts" : { "type" : "drive", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } }` | | Mount Config | `{}` | 4. Click **Save** to save the changes. ### Google Drive storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Google Drive** from the drop-down, then select **Next**. ![Configure the Google Drive storage mapping](/img/storage_mapping/gdrive/configure_storage.png) 4. The Google login page appears. Log in with the desired account. This account must be a test user from the OAuth app creation process. ![Log in to Google](/img/storage_mapping/gdrive/login.png) 5. When the Google OAuth app is not yet approved, a warning appears. Click **Continue**. ![Approve Kasm access to Google Drive](/img/storage_mapping/gdrive/approve.png) 6. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The Google Drive storage mapping in the profile](/img/storage_mapping/gdrive/storage_mapping.png) 7. Launch a new container-based session. Confirm that Google Drive is mapped inside the session at the `/gdrive` location. ![Google Drive files mapped inside a session](/img/storage_mapping/gdrive/files.png) --- ## Storage Mappings Storage Mappings allow administrators to create and attach custom and ephemeral docker volumes in Kasm Workspace Containers. This feature can also be used to allow end users to map popular [ Cloud Storage](../../../tutorials/user-guide/profile.mdx#cloud-storage) services like Google Drive, Dropbox, NextCloud, and Onedrive. In order to use Storage Mappings, administrators must first create **Storage Providers**, which contain the volume and mount configurations, in addition to applicable settings for supported cloud storage providers. The process is as follows: 1. The Administrator configures a **Storage Provider** (e.g Google Drive) 2. The Administrator may now create **Storage Mappings** that leverage the Storage Provider. The mappings may be placed on a User, Group or Workspace object. 3. The Administrator can allow end-users to create their own **Storage Mappings** by configuring the following group settings: - `allow_user_storage_mapping`: When enabled the user is allowed to configure their own **Storage Mappings** via their profile. When disabled, new user configuration will not be allowed, nor will using any previously configured mappings be allowed when new sessions are created. - `max_user_storage_mappings`: The maximum number of Storage Mappings a user is allowed to have registered to their account. - `read_only_user_storage_mappings`: When enabled, any storage mappings configured on the user account will be forced to read-only. 4. If allowed via group settings, end-users can configure Storage Mappings to the registered Providers via the [Cloud Storage](../../../tutorials/user-guide/profile.mdx#cloud-storage) section of the profile widget. 5. When a container-based Workspaces session is created, a docker volume is created on the Agent and mounted inside the session based on the Storage Provider and Storage Mapping configurations. The remote files become available for use within the session. 6. When the session is destroyed, the previously created docker volume is also destroyed. ## Storage Providers | Name | A custom name given to the Storage Provider | |-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Storage Provider Type | Workspaces supports a number of Cloud Storage Provider types including **(Dropbox, Google Drive, NextCloud OneDrive, S3, and Kasm Profile Sync)**. Many of these implementations leverage the [Rclone](https://rclone.org/) docker volume plugin which is automatically installed as part of Workspaces. A **Custom** type may be used to give administrators the ability to create additional interfaces as desired. | | Enabled | If disabled, any Storage Mappings referencing this Storage Provider will not be utilize when creating new sessions. | | Default Target | The folder path where any Storage Mappings created with this provider will be mounted to inside the Kasm session. This should be an absolute path (e.g `/dropbox`) | | Volume Config | A json structure representing the volume to be created during a session. See [Volume Config](rclone.mdx) for more details. | | Mount Config | A json structure representing how the volume is mounted into a session. See [Mount Config](rclone.mdx) for more details. | | Client ID | The Client ID for OAuth based Storage Provider types (e.g Google Drive). | | Client Secret | The Client Secret for OAuth based Storage Provider types (e.g Google Drive). | | Authorization URL | The Authorization URL for OAuth based Storage Provider types (e.g Google Drive). | | Token URL | The Token URL for OAuth based Storage Provider types (e.g Google Drive). | | Redirect URL | The URL an OAuth provider will use to redirect the user back to Workspace. The URL should be in the following format. `https:///api/cloud_storage_callback` | | Scopes | The Scopes to request for OAuth based Storage Providers. Enter one entry per line. | | Webdav URL | (Nextcloud Only). The base Webdav URL for the Nextcloud deployment (e.g `https://:/remote.php/dav/file/` | | Root Drive URL | (OneDrive Only). The OAuth URL used to query the Onedrive user's root drive. (e.g `https://graph.microsoft.com/v1.0/me/drive/root` | In Windows, the Target directory is relative to the user's Desktop within their profile. Therefore, /dropbox would get placed on C:\Users\kasm-user\Desktop\dropbox for the user kasm-user. Storage mappings on VM based sessions are only applied when the server is configured with User SSO enabled. This is because storage mappings are applied per-user at the OS level. When User SSO is active, Kasm users are mapped to corresponding user accounts, allowing the service to correctly scope mappings to each user's file system. To enable this, set the **Connection Credential Type** to **SSO User Accounts** in the [server configuration](../../infra-autoscale/servers.mdx#create-server), which sets `user_sso` to `true` in the Kasm Desktop Service configuration file. This value is automatically synchronized when the service checks in and does not require manual changes. If needed, `user_sso` can be manually overridden in the service configuration file after registration — see the [Linux service configuration](../../workspaces-sessions/server-workspace/linux/linux-service.mdx#configuration) and [Windows service configuration](../../workspaces-sessions/server-workspace/windows/kds-windows-service.mdx#configuration) for details. Without proper user isolation, storage mappings may be applied incorrectly or insecurely across sessions. ### Volume Config The volume config, is a JSON structure that represents how the docker volume is to be created. The available options are defined by the Docker SDK for python [create_volume](https://docker-py.readthedocs.io/en/stable/api.html#docker.api.volume.VolumeApiMixin.create_volume) ```json { "driver" : "rclone", "driver_opts" : { "type" : "s3", "s3-provider" : "AWS", "s3-env-auth" : "false", "s3-region" : "us-east-1", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } } ``` ### Mount Config The mount config, is a JSON structure that represents how the docker volume mounted (aka mapped) to the container session. The available options are defined by the Docker SDK for Python: [Mount](https://docker-py.readthedocs.io/en/stable/api.html#docker.types.Mount) Kasm will automatically assign the only two required parameters `target` and `source` since they will reference the **Default Target** , and the volume created by the **Volume Config**, so in most cases this can be set to an empty dict unless other advanced needs are required. ### Variable Substitution The following variables can be templated into the storage mapping `Default Target` and `Volume Config` properties to support additional use-cases. Note: Variable substitution is not compatible with [Session Staging](../../workspaces-sessions/sessions/session-staging.mdx). - `{username}` - The username of the user provisioning the session. e.g `user@kasm.local` - `{user_id}` - The user_id of the user provisioning the session . e.g `6c0535dc02eb49c4a556cae9816a585d` - `{image_id}` - The image ,aka workspace, id used for the session. eg. `9de4ea298f064e6999c5b9b164e2c04c` - `{user_crypt_password}` - A cryptographic key used when leveraging [Rclone's crypt provider](https://rclone.org/crypt/). Used in place of the `--crypt-password` attribute. - `{user_crypt_salt}`- A cryptographic key used when leveraging [Rclone's crypt provider](https://rclone.org/crypt/). Used in place of the `--crypt-password2` attribute. ### Configuration Examples - [Dropbox Storage Provider Setup](dropbox.mdx) - [Google Drive Storage Provider Setup](gdrive.mdx) - [Nextcloud Storage Provider Setup](nextcloud.mdx) - [OneDrive Storage Provider Setup](onedrive.mdx) - [S3 Storage Provider Setup](s3.mdx) - [Custom Storage Provider Setup](custom.mdx) ### Troubleshooting #### Failures to Provision Sessions If something goes wrong with the storage mapping during the creation of a session, a user will get typically get an "Unexpected Error" message. ![User Dashboard Error](/img/storage_mapping/error_provisioning.png) Administrators should review the application logs for errors either via the application dashboard, or tailing the `kasm_api` and `kasm_agent` containers while reproducing the errors ```bash sudo docker logs -f kasm_agent sudo docker logs -f kasm_api ``` In this case, there was an improper configuration for a driver options in the **Volume Config**. ![Error in Logs](/img/storage_mapping/volume_config_error.png) ### File Browser shortcuts (Bookmarks) Kasm Workspaces images support setting file browser shortcuts in Thunar via the environment variable `CLOUD_MOUNTS` in the format: ``` CLOUD_MOUNTS="|,|" ``` By default, Workspaces will automatically create the `CLOUD_MOUNTS` environment variable according to the storage mappings configured. If desired, the administrator can override this behavior by manually defining the `CLOUD_MOUNTS` environment variable via [docker-run-config](../../workspaces-sessions/container-workspace/workspaces.mdx). This environment variable is a comma and pipe seperated list of mounts and their accompanying type. The type sets an emblem icon on the folder shortcut for easier identification with the supported types: * s3 * nextcloud * onedrive * gdrive * dropbox * kasm (placeholder emblem if Kasm Workspaces logo is preferred) To configure this in Kasm Workspaces navigate to Admin > Workspaces > Edit > "Docker Run Config Override (JSON)", in this example we will be configuring a shortcut for every storage mapping type: ```JSON { "environment": { "CLOUD_MOUNTS" : "/s3|s3,/nextcloud|nextcloud,/onedrive|onedrive,/gdrive|gdrive,/dropbox|dropbox" } } ``` ![Themed filebrowser shortcuts in the Workspace](/img/storage_providers/bookmarks.png) If using the examples provided above this environment variable can be passed as is to most Workspaces images and it will only show paths that are available in the Workspace on startup. If using the Kasm provided browser images (e.g `kasmweb/chrome`, `kasmweb/firefox`) administrators will need to disable the restricted file chooser in order for users to access the cloud mounts by manually defining the `KASM_RESTRICTED_FILE_CHOOSER` environment variable via [Docker Run Config](../../workspaces-sessions/container-workspace/workspaces.mdx). Setting the value to `0` will disable the restrictions, so the user can have access to cloud mounts and the rest of the file system. ```JSON { "environment": { "KASM_RESTRICTED_FILE_CHOOSER" : "0" } } ``` --- ## Nextcloud # Nextcloud Storage Provider Setup The [Nextcloud](https://nextcloud.com/) Storage Provider can be used to allow users to map in their Nextcloud files into their container-based Kasm Session. Access is provided via Nextcloud's WebDAV interface via the [Rclone](https://rclone.org) Docker volume plugin. Reference Docs: - [https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html](https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html) - [https://rclone.org/webdav/](https://rclone.org/webdav/) The storage provider configuration is as follows: | Name | `Nextcloud` | | --- | --- | | Storage Provider Type | `Nextcloud` | | Enabled | `checked` | | Webdav URL | `https://:/remote.php/dav/files/` | | Default Target | `/nextcloud` | | Volume Config | `{ "driver" : "rclone", "driver_opts" : { "type" : "webdav", "webdav-vendor" : "nextcloud", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } }` | | Mount Config | `{}` | :::note Many of the storage provider examples include default storage driver options used by Rclone. These options work well with Kasm in its default configuration, and administrators can adjust them as needed. The available options often vary by provider plugin, for example Google Drive compared with OneDrive. The Rclone Docker plugin is installed by default as part of the standard Workspace install. For more information about Rclone driver options, see [the Rclone Docker documentation](https://rclone.org/docker/). ::: ### Nextcloud storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Nextcloud** from the drop-down. Enter the **Nextcloud Username** and **Nextcloud Password**, then select **Next**. ![Configure the Nextcloud storage mapping](/img/storage_mapping/nextcloud/configure_storage.png) 4. The new storage mapping appears in the Cloud Storage section of the profile. ![The Nextcloud storage mapping in the profile](/img/storage_mapping/nextcloud/storage_mapping.png) 5. Launch a new container-based session. Confirm that the Nextcloud files are mapped inside the session at the `/nextcloud` location. ![Nextcloud files mapped inside a session](/img/storage_mapping/nextcloud/files.png) --- ## Onedrive # OneDrive Storage Provider Setup The [OneDrive](https://www.microsoft.com/en-us/microsoft-365/onedrive/online-cloud-storage) Storage Provider allows end-users to map in their OneDrive storage into container-based sessions. Access is provided via Microsoft's OAuth interface using the [Rclone](https://rclone.org) Docker volume plugin. Reference Docs: - [https://rclone.org/onedrive/](https://rclone.org/onedrive/) - [https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) - [https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols) ### Creating a Microsoft OAuth App 1. Login to the Microsoft Azure Portal: [https://portal.azure.com/](https://portal.azure.com/)/ 2. Select **Azure Active Directory**. ![Azure AD Control Panel](/img/storage_providers/onedrive/azure_ad.png) 3. Select **App Registrations**. ![App Registrations](/img/storage_providers/onedrive/app_registrations.png) 4. Select **New Registration**. 5. Give the app a Name (e.g `Kasm OneDrive Example`). 6. In the **Supported account types** select **Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)**. 7. In the Redirect URI, select Web, then enter the following URL , substituting the hostname of the Kasm deployment `https://kasm.example.com/api/cloud_storage_callback` In this example, we walk through creating an integration where any Microsoft user can auth with the Kasm app. This is ideal for a public facing deployment. Other options are available for single-tenant and multi-tenant configurations. ![Register an App](/img/storage_providers/onedrive/register_app.png) 8. On the next page, the **Application (client) ID** is shown, save this value as the Client ID to be used in the next section. 9. Select **Add a certificate or secret** next to **Client credentials**. ![Client Credentials](/img/storage_providers/onedrive/client_credentials.png) 10. Select the **Client secrets** tab, then slick **New client secret**. 11. Enter a description and expiration then click **Add**. 12. The credentials are shown, save the **Value** as the **Client Secret** to be used in the next section. ![Client Secret](/img/storage_providers/onedrive/client_secret.png) 13. From the **Manage** menu on the left hand side, select **API Permissions**. 14. Select **Add a Permission**. ![API Permissions](/img/storage_providers/onedrive/api_permissions.png) 15. In the new window Select **Microsoft Graph**, then **Delegated permissions**. 16. Add all of the following permissions. ```text Files.Read Files.Read.All Files.ReadWrite Files.ReadWrite.All offline_access Sites.Read.All User.Read ``` ![Add Permissions](/img/storage_providers/onedrive/add_permissions.png) 17. Select the **Overview** section of the Azure app, then Select **Endpoints**. Note the `OAuth 2.0 authorization endpoint (v2)` and `OAuth 2.0 token endpoint (v2)` values for use in the next steps. Note: these will differ depending on the type of App created in the prior section (Internal vs Public vs Multi-Tenant) ![Endpoints](/img/storage_providers/onedrive/endpoints.png) ### Kasm Storage Provider Config 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Storage** -> **Add**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | Name | `OneDrive` | | --- | --- | | Storage Provider Type | `OneDrive` | | Enabled | `checked` | | Client ID | `` | | Client Secret | `` | | Authorization URL | `` | | Authorization URL Options | `{"prompt" : "consent"}` | | Token URL | `` | | Redirect URL | `https:///api/cloud_storage_callback` | | Scope | .. code-block:: text Files.Read Files.ReadWrite Files.Read.All Files.ReadWrite.All Sites.Read.All offline_access openid email profile | | Root Drive URL | `https://graph.microsoft.com/v1.0/me/drive/root` | | Default Target | `/onedrive` | | Volume Config | `{ "driver" : "rclone", "driver_opts" : { "type" : "onedrive", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } }` | | Mount Config | `{}` | 4. Click **Save** to save the changes. ### OneDrive storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **OneDrive** from the drop-down, then select **Next**. ![Configure the OneDrive storage mapping](/img/storage_mapping/onedrive/configure_storage.png) 4. The Microsoft login page appears. Log in with the desired account. ![Log in to Microsoft](/img/storage_mapping/onedrive/login.png) 5. A consent screen appears that requests the permissions needed to access OneDrive. Approve the request. ![Approve Kasm access to OneDrive](/img/storage_mapping/onedrive/approve.png) 6. Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The OneDrive storage mapping in the profile](/img/storage_mapping/onedrive/storage_mapping.png) 7. Launch a new container-based session. Confirm that OneDrive is mapped inside the session at the `/onedrive` location. ![OneDrive files mapped inside a session](/img/storage_mapping/onedrive/files.png) --- ## Rclone :::note Many of the storage provider examples include default storage driver options used by Rclone. These options work well with Kasm in its default configuration, and administrators can adjust them as needed. The available options often vary by provider plugin, for example Google Drive compared with OneDrive. The Rclone Docker plugin is installed by default as part of the standard Workspace install. For more information about Rclone driver options, see [the Rclone Docker documentation](https://rclone.org/docker/). ::: --- ## S3 # S3 Storage Provider Setup The [S3](https://aws.amazon.com/s3/) Storage Provider can be used to allow users to map in their S3 buckets into their container-based Kasm Session. Access is provided via the [Rclone](https://rclone.org) Docker volume plugin. Reference Docs: - [https://rclone.org/s3/](https://rclone.org/s3/) ### Kasm Storage Provider Config 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Storage** -> **Add**. 3. Update the form with the following entries | Name | `S3` | | --- | --- | | Storage Provider Type | `S3` | | Enabled | `checked` | | Default Target | `/s3` | | Volume Config | `{ "driver" : "rclone", "driver_opts" : { "type" : "s3", "s3-provider" : "AWS", "s3-env-auth" : "false", "s3-region" : "us-east-1", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } }` | | Mount Config | `{}` | :::note Many of the storage provider examples include default storage driver options used by Rclone. These options work well with Kasm in its default configuration, and administrators can adjust them as needed. The available options often vary by provider plugin, for example Google Drive compared with OneDrive. The Rclone Docker plugin is installed by default as part of the standard Workspace install. For more information about Rclone driver options, see [the Rclone Docker documentation](https://rclone.org/docker/). ::: 4. Click **Save** to save the changes. ### S3 storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **S3** from the drop-down. Enter the **S3 Access Key ID**, **S3 Secret Access Key**, and **S3 Bucket**, then select **Next**. ![Configure the S3 storage mapping](/img/storage_mapping/s3/configure_storage.png) 4. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The S3 storage mapping in the profile](/img/storage_mapping/s3/storage_mapping.png) 5. Launch a new container-based session. Confirm that the S3 buckets are mapped inside the session at the `/s3` location. ![S3 files mapped inside a session](/img/storage_mapping/s3/files.png) --- ## Volume Mapping ### Configuration Example Kasm Workspaces allows administrators to configure folders to be mapped inside a Kasm each time it is provisioned. This is done by configuring the **Volume Mappings** field on the [Kasm Workspace](../workspaces-sessions/container-workspace/workspaces.mdx). In this guide we will configure a folder on the host `/mnt/kasm_user_share` to be mapped inside the Kasm Desktop workspace to a folder named `/share`. This effectively will act as a file share. All users's who have access to provision the workspace will have access to this folder. #### Create Host Directory On the Kasm Workspaces server, create the directory and change the ownership to user and group **1000**. If Kasm is installed in a multi-server deployment, `/mnt/kasm_user_share` in this example should reference a shared data storage solution (e.g NFS, HDFS, GFS, SMB, SSHFS) to ensure data continuity. Administrators must ensure this path is accessible from the hosts of all Agent services. Please see [Using NFS](./host-guides.mdx#using-nfs) for configuration. **Create Host Directory Example** ```Bash sudo mkdir -p /mnt/kasm_user_share sudo echo "test" | tee /mnt/kasm_user_share/test.txt sudo chown -R 1000:1000 /mnt/kasm_user_share/ ``` #### Workspace Volume Mapping Settings From the administrator dashboard click on Workspaces -> Workspaces and select a Workspace to edit: Scroll down to **Volume Mappings (JSON)** and use the following configuration: ``` { "/mnt/kasm_user_share":{ "bind":"/share", "mode":"rw", "uid": 1000, "gid": 1000, "required": true, "skip_check": false } } ``` Click save and the `/share` directory will be available on any user that launches this Workspace. Although this guide demonstrate mapping a single volume, multiple volume mappings can be defined. > ```JSON > { > "/mnt/kasm_user_share1":{ > "bind":"/share1", > "mode":"rw", > "uid": 1000, > "gid": 1000, > "required": true > }, > "/mnt/kasm_user_share2":{ > "bind":"/share2", > "mode":"rw", > "uid": 1000, > "gid": 1000, > "required": true > } > } > ``` #### Verify Functionality - Launch the Workspace the volume mapping was added to - Verify the user can read and write to the `/share` location. ### User and Image Tokens The volume mapping config supports the use of the following user and image based tokens in the mapping name and bind attribute. This allows the administrator to create unique share locations per user. - `{username}` - The username of the user provisioning the session. e.g `user@kasm.local` - `{user_id}` - The user_id of the user provisioning the session . e.g `6c0535dc02eb49c4a556cae9816a585d` - `{custom_attribute_1}` - The custom attribute 1 value from the user. - `{custom_attribute_2}` - The custom attribute 2 value from the user. - `{custom_attribute_3}` - The custom attribute 3 value from the user. - `{image_id}` - The image ,aka workspace, id used for the session. eg. `9de4ea298f064e6999c5b9b164e2c04c` > ```JSON > { > "/mnt/kasm_user_share/{image_id}/{user_id}":{ > "bind":"/share/{username}", > "mode":"rw", > "uid": 1000, > "gid": 1000, > "required": true, > "skip_check": false > } > } > ``` ### Volume Mapping Configuration options > - **bind** > - The path inside the Kasm where the volume will be mounted. > - **mode** > - `rw` for Read-Write , `ro` for Read-Only. > - **uid** > - The linux user id ownership that should be given to the volume. This permission is applied to the folder on the host. > The uid must be `1000` in order for the Kasm container use to access the files. > - **gid** > - The linux group id ownership that should be given to the volume. This permission is applied to the folder on the > host. The gid must be `1000` in order for the Kasm container use to access the files. > - **required** > - If `true` the volume must be accessible in order to provision the Kasm when requested. If `false` the > system will allow the Kasm to be provision even if connectivity to the volume cannot be established. If not specified > the default is `true`. > - **timeout** > - When a Kasm is provisioned , the system will attempt to establish connectivity to the volume specified. The system > will wait the specified number of seconds before deeming the connectivity has failed. If not specified the default is > `10` seconds > - **skip_check (optional)** > - When a Kasm is provisioned , the system will attempt to establish connectivity to the volume specified and ensure > the ownership of that directory matches the uid:gid specified with a :code:'chown'. On some filesystems such as > those mounted as read only, this check will fail or error. The administrator may choose to set this > value to `true` so the system will skip the check. The default is `false` if not specified. ### Configure Volume Mapping at a Group Level Volume Mappings may also be applied as a [Group Setting](../security/users-groups-mgmt/groups.mdx#group-settings) . This may be useful if a certain set of users should have the mapping. When applied at the group level, all sessions created by members of this group will have the mapping applied. From the administrator menu first click on Access Management -> Groups and click Edit on your desired group: Select the **Settings** tab and click on **Add Settings**, select **volume_mapping** from the dropdown. Enter this example to mount `/mnt/kasm_user_share` from the host to `/share` in all containers launched by this group. ``` { "/mnt/kasm_user_share":{ "bind":"/share", "mode":"rw", "uid": 1000, "gid": 1000, "required": true, "skip_check": false } } ``` And click Submit: Now all sessions created by members of this group will have the mapping applied. ### Video Example This video shows an example of using Volume Mapping to create an organizational share. --- ## AWS AutoScale (Windows) # AWS The following instructions utilize the AWS CLI as a convenience, you can use the AWS Web Console to obtain the required information. The next step in the AutoScale Configuration is the VM Provider Details page. 1. Select **AWS** from the Provider Drop Down. 2. Provide a name for your configuration. 3. Enter the **AWS Access Key ID** and the **AWS Secret Access Key**, follow [this guide](#aws-iam-user) to create a AWS IAM user and credentials. 4. Enter the **AWS Region**. For a list of available regions, use the following AWS CLI command, use the value `RegionName` field ```bash aws account list-regions ``` 5. Enter the **EC2 AMI ID**. You can find the latest AMI ID for an Image by going to the AWS Web Console and starting the workflow to create a new EC2 Instance. When you select an image, its AMI ID will be shown in the web console. Alternatively, you can use the AWS CLI. The following is an example that lists AMIs, filtering by name and sorting so that the latest version is on the top of the list. ```bash aws ec2 describe-images --filter "Name=name,Values=Windows_Server-2022-English-Full-Base*" --query "sort_by(Images, &CreationDate)" | jq -r '.[] | [.Name, .ImageId] | @tsv' Windows_Server-2022-English-Full-Base-2023.01.11 ami-085d15593174f2582 Windows_Server-2022-English-Full-Base-2023.01.19 ami-03cf1a25c0360a382 Windows_Server-2022-English-Full-Base-2023.02.15 ami-0c2b0d3fb02824d92 Windows_Server-2022-English-Full-Base-2023.03.15 ami-0e38fa17744b2f6a5 Windows_Server-2022-English-Full-Base-2023.04.12 ami-0bde1eb2c18cb2abe ``` **Example:** ami-085d15593174f2582 6. Enter the desired **EC2 Instance Type**, check the [AWS Instance Types](https://aws.amazon.com/ec2/instance-types/) page for a full list. Use the `Instance Size` referenced in AWS's documentation. Not all instance types are available in all regions. A Windows server will likely require a non-bursting instance type with at least 4GB of RAM, see the minimum system requirements for the version of Windows you are using. **Example:** c5.xlarge 7. Enter the maximum number of instances. Kasm will not provision more VMs once this maximum number is reached. **Example:** 5 8. Enter a list of **EC2 Security Group IDs** in JSON format. The security groups listed will be applied to the VM. From the AWS Web Console, you can navigate to EC2->Security Groups, use the `Security group ID` column from the table. The following AWS CLI command can be used to display a list of security groups. ```bash aws ec2 describe-security-groups --query "SecurityGroups[*].[GroupName,GroupId,Description]" --output text ``` **Example:** ```[ "sg-fdfd9a504533e9df9"]``` 9. Enter the target **EC2 Subnet ID**. From the AWS Web Console, you can navigate to VPC->Subnets, use the `Subnet ID` column's value for the target subnet. The following AWS CLI command can be used to display a list of subnets. ```bash aws ec2 describe-subnets --query "Subnets[*].[SubnetId,VpcId,CidrBlock,AvailabilityZone]" --output text ``` **Example:** subnet-24582b68 10. Enter an **EBS Volume Size** in Gigabytes, it must the same size or larger than the source AMI. **Example:** 128 11. Enter an **EBS Volume Type**. The following values are supported. - gp2 (recommended) - st1 - standard **Example:** gp2 12. Enter an **EC2 IAM** role to be applied to your VM. Enter a space to bypass this requirement. An IAM Role allows the EC2 instance to access AWS resources. [This example](https://www.wellarchitectedlabs.com/cost/200_labs/200_aws_resource_optimization/2_create_iamrole/) uses an IAM role to allow the EC2 instance to send logs to CloudWatch. **Example:** MyCustomRoleName 13. Enter any additional **EC2 Custom Tags** to add to the instance. **Example:** ```json { "department": "engineering" } ``` 14. Enter an EC2 Startup Script. For Windows it is a PowerShell script that is wrapped in XML. The following example is maintained on this [open-source project](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/blob/develop/latest/windows_vms/aws_local_account.txt). This example creates a local user account with the **Connection Username** and **Connection Password** specified on the previous page. This is only relevant if you are using static credentials and will not work [Active Directory](../../../../workspaces-sessions/server-workspace/windows/authentication.mdx) integration. ```yml $pass = ConvertTo-SecureString -String "{connection_password}" -AsPlainText -Force New-LocalUser -Name {connection_username} -Description 'Programatically generated Kasm user account' -Password $pass -PasswordNeverExpires -AccountNeverExpires | Add-LocalGroupMember -Group administrators | Add-LocalGroupMember -Group "Remote Desktop Users" Start-Service -Name "Audiosrv" ``` This example installs the [Kasm Desktop Service](../../../../workspaces-sessions/server-workspace/windows/kds-windows-service.mdx) and registers it with the deployment. With this service installed, Kasm can [manage local Windows user accounts](../../../../workspaces-sessions/server-workspace/windows/authentication.mdx#single-sign-on-with-dynamic-local-accounts) automatically. ```yml New-EventLog -LogName Application -Source kasm_startup_script Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Information -Message "Downloading Windows Service" # Download and install the Kasm Service Invoke-Webrequest -URI https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.1.2b3f26b.exe -OutFile C:\Users\Public\Downloads\kasm_service_installer.exe Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Information -Message "Installing Windows Service" C:\Users\Public\Downloads\kasm_service_installer.exe /S for ($i = 1; $i -le 20; $i++) {{ Start-Sleep -s 3 $service = Get-Service -Name W32Time -ErrorAction SilentlyContinue if ($service.Length -gt 0 -And (Test-Path -Path "C:\Users\Public\Downloads\kasm_service_installer.exe" -PathType Leaf)) {{ # Register the Kasm Service with the deployment Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Information -Message "Registering the Desktop Service with the Kasm deployment at {upstream_auth_address}" net stop kasm cd "C:\Program Files\Kasm" .\agent.exe --register-host {upstream_auth_address} --register-port 443 --server-id {server_id} --register-token {registration_token} if ($?) {{ net start kasm Start-Service -Name "Audiosrv" Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Information -Message "Successfully installed and registered agent" Exit 0 }} else {{ Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Error -Message "Registration of Agent failed: Check log output of kasm_service in EventViewer" Exit 1 }} }} else {{ Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Information -Message "Service not found, trying again..." }} }} Write-EventLog -LogName "Application" -Source "kasm_startup_script" -EventID 1000 -EntryType Error -Message "Timed out waiting for Kasm Desktop Service to be registered." Exit 1 ``` 15. The **Retrieve Windows VM Password from AWS** option allows Kasm to retrieve the random password generated by AWS for the administrator account. If this checkbox is checked and the **Connection Password** field on the previous page is left empty, Kasm will use the SSH key (covered next) to retrieve and decrypt the password. The password will then be used by users connecting to the server. You do not need to check this box if using the example script in step 14 or if you are using SSO with Active Directory integration. 16. Click the Upload New Key Pair button, paste in an RSA PEM formatted private SSH Key and optionally provide a passphrase for the key. 17. Click Finish It can take a minute or two for the first server to show up in the Servers list for the Pool and a few minutes for the server to become accessible. You can see all servers by going to Compute->Servers in the Kasm Admin Dashboard. You can see only the Servers in the Pool you created for AWS by going to Compute->Pools and selected Edit on the desired Pool. Next [create a Workspace](../../../../workspaces-sessions/server-workspace/auto-scaled-servers.mdx#workspace) to allow access to the Servers in this Pool. ### AWS IAM User ### Kasm uses programmatic access keys to manage resources. These programmatic access keys are associated with an IAM user. Follow this process to create a user with minimal permissions and no access to the AWS Web Console. 1. Create an AWS IAM User for Kasm. - In the AWS Web Console, navigate to IAM->Users. - Click Add User. - Provide a User name. **Example:** kasm-auto-scaling - On the permissions options page, click Attach Policies Directly - Search for AmazonEC2FullAccess, check the box next to it and Click Next - On the final page click Create User 2. Create AWS Access Keys for the Kasm User in AWS. - In the AWS Web Console, navigate to IAM->Users. - Find the user created in step 3 and click the username to edit. - Click the Security Credentials Tab. - Scroll down to Access Keys and click Create Access Keys. - On the next screen select Third Party Service - Check the box indicating you understand the recommendation and click Next. - Optionally add tags on the next step and then click Create access key. - On the final screen you will be shown the Access Key and Secret access key. This will be the only opportunity you will have to get the secret access key. Save both of them in a secure place. --- ## AWS AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on AWS. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to AWS: Ensure you have the appropriate access to your AWS environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Configure your AWS environment ### Setup your AWS Environment - **Create User in IAM**: An API key for Kasm must be created to use for interfacing with AWS. AWS call these Access Keys, and the example will walk through registering one along with the required permissions. * Create a user by going to the IAM service in the AWS portal. * Select Users under Access Management in the IAM menu along the left. In the upper right, select **Create User**. * Give this User a human-readable name such as **Kasm Workspaces**. * Select Attach policies directly and select **AmazonEC2FullAccess**. * Review the information and create the User. - **Create Access Key**: The Access Key is created from the User. * From the list of Users, click on the newly created User. * Click **Create access key** in the right section of the **Summary**. * Select the **Third-party service* use case and create the access key. * Copy the Access Key ID and the Secret Access Key for use in Kasm (the Secret Access Key cannot be retrieved later). - **Set up permissions**: Certain permissions must be set up in AWS by creating inline policies for IAM Roles. * In IAM, select Roles under Access Management, then click **Create Role**. * Select the **AWS Service**, with a Use Case of **EC2**. * Add the permissions **AmazonS3ReadOnlyAccess** and **AmazonSSMManagedInstanceCore**. * Create a human readable Role name and description and create the role. * In IAM, select Users under Access Management, then click on the User created earlier. * In the Permissions Policies section, in the Add Permissions dropdown, select **Create Inline Policy**. * Using the **Visual** Policy Editor, select the **IAM** service. * Under Actions Allowed, expand Write and select **PassRole**. * Under Resources, with Specific selected, click **Add ARNs**. * Leave **This Account** selected and enter the newly created role name in **Resource Role Name with Path**. * Under Request Conditions, click **Add Another Condition**. * Select the Condition **iam:PassedToService**. * Select the Operator **StringEquals**. * Add the value **ec2.amazonaws.com** and click **Add Condition**. * Click **Add More Permissions**. * Select the IAM service. * Under Actions Allowed, expand Read and select **GetInstanceProfile** and **GetRole**. * Under Resources, with Specific selected, for each resource (instance-profile and role) click **Add ARNs**. * Leave **This Account** selected and enter the newly created role name in **Resource Role Name with Path**. * Click **Next**, review, and create the policy. - **Set up a VPC**: A Virtual Private Cloud must be set up through VPC to manage networking. * In VPC, select **Your VPCs** under Virtual Private Clound, then click **Create VPC**. * Select **VPC Only** and give the VPC a human readable name tag. * Enter an IPv4 CIDR and click **Create VPC**. - **Set up a Subnet**: A Subnet must be set up through VPC to manage networking. * In VPC, select **Subnets** under Virtual Private Clound, then click **Create Subnet**. * Select the newly created VPC. * Give the Subnet a human readable name tag. * Select the Availability Zone. * Enter an IPv4 subnet CIDR block and click **Create Subnet**. - **Set up Security Group**: Certain inbound and outbound rules must be set up in AWS by creating a Security Group in EC2. * In EC2, select Security Groups under Network & Security, then click **Create Security Group**. * Give the Security Group a human readable name and description * Select the newly created VPC. * Add Inbound Rules based on needs. Common rules would include destination ports 4902 (for the Kasm Manager to send session and file commands), 443 (for the Kasm Manager to reach agents securetly), and 3389 (if RDP access to agents is needed). * Add Outbound Rule based on needs. ## Configure your AWS details on Kasm * Follow [AutoScale Settings for Agent Pool](../../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or, if you already have an AutoScale Configuration defined, go straight to the All VM Provider Configs page, click Add to and select **Add New** in **VM Provider Configs**. * Configure the following settings based on the instruction that follow: * Select **AWS** from the Provider Drop Down. * Provide a name for your configuration. * Enter your AWS Access Key Id and AWS Secret Access Key from from the AWS Setup above. * Enter the region name, you can use the following AWS CLI command to list available regions, use the RegionName column. ```bash aws ec2 describe-regions --all-regions ``` * Enter the EC2 AMI Id for the Image from AWS (this can be found in the AMI Catalog of the EC2 service in AWS). * Enter the EC2 Instance Type, you can use the following AWS CLI command to list available instance types based on the region selected. ```bash aws ec2 describe-instance-type-offerings \ --location-type "availability-zone" \ --filters "Name=location,Values=us-east-2a" \ --region us-east-2 \ --query "InstanceTypeOfferings[*].[InstanceType]" --output text | sort ``` * Enter the **Max EC2 Nodes**. This puts an upper limit on the number of EC2 Nodes this auto scale configuration can provision. * Enter the **EC2 Security Group IDs** (created in the AWS Setup above) as a JSON array. * Enter the **EC2 Subnet ID** created in the AWS Setup above. * Enter the **EC2 EBS Volume Size** required. * Enter the **EC2 EBS Volume Type** required. | Volume Type Name | |-------------------| | gp3 | | gp2 | | io2 | | io1 | | st1 | | sc1 | | standard | * Enter the **EC2 IAM**, the Role created in the AWS Setup above. * Optionally provide additional tags for the VM, use empty `{}` brackets if no additional tags are needed. * Enter a PowerShell startup script. The following example will create a local user account using the **Connection Username** and **Connection Password** fields specified on the previous screen. This is only relevant if you are using static credentials and will not work [Active Directory](../../../../workspaces-sessions/server-workspace/windows/authentication.mdx) integration. ```powershell $pass = ConvertTo-SecureString -String "{connection_password}" -AsPlainText -Force New-LocalUser -Name {connection_username} -Description 'Programatically generated Kasm user account' -Password $pass -PasswordNeverExpires -AccountNeverExpires | Add-LocalGroupMember -Group administrators | Add-LocalGroupMember -Group "Remote Desktop Users" Start-Service -Name "Audiosrv" ``` * Enter a **Configuration Override** as JSON, use empty `{}` brackets if no configuration is needed. * If it is preferred to use the default Administrator user and password created by AWS, toggle **Retrieve Windows VM Password from AWS** to true. This requires leaving **Connection Password** blank on the AutoScale Details, and populating **Connection Username** with **Administrator**. * Enter a public SSH Private Key, this is required even for Windows systems and can be generated within AWS from EC2 (**Key Pairs** under **Network & Security** in the menu on the left). * Submit the Provider Config ## Test your AWS Autoscaling setup If you have configured non-zero Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in AWS * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## Microsoft Azure AutoScale (Windows) #### Azure The following instructions utilize the Azure CLI. You can open the CLI in the Azure web portal and run these commands directly. See Microsoft's [instructions](https://learn.microsoft.com/en-us/azure/cloud-shell/quickstart?source=recommendations&tabs=azurecli) for basic usage of the Azure Cloud Shell environment. The next step in the AutoScale Configuration is the VM Provider Details page. 1. Select **Azure** from the Provider Drop Down. 2. Provide a name for your configuration. 3. Enter a Subscription ID, Resource Group, and Tenant ID. 4. Enter the Client ID and Client Secret created by following the [Azure App Registration](../../vm-providers.mdx#register-azure-app) instructions. 5. Select the Azure Authority from the drop down. Most users will select **Azure Public Cloud**. 6. Enter the region name, you can use the following Azure CLI command to list available regions, use the Name column. ```bash az account list-locations -o table ``` 7. Enter the **Maximum Instances**. This puts an upper limit on the number of VMs this auto scale configuration can create. 8. Enter a VM Size by name. Use the following Azure CLI command to list all VM sizes available in the desired region. ```bash az vm list-sizes --location "westus" ``` 9. Enter the OS [Disk Type](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-types), using the [Azure Disk Type SKU](https://learn.microsoft.com/en-us/rest/api/storagerp/srp_sku_types). The following is the current list of available type names. Not all disk SKUs are compatible with all VM size types. | Disk Type Name | |-----------------| | Standard_LRS | | Standard_GRS | | Standard_RAGRS | | Standard_ZRS | | Premium_LRS | | Premium_ZRS | | Standard_GZRS | | Standard_RAGZRS | 10. Enter the **OS Disk Size**, in gigabytes. The size need to be at least the size of the target OS Image Reference, defined in the next field. 11. Enter the **OS Image Reference** JSON. Use the following Azure CLI command to list images in the JSON format expected by Kasm. Note that these are default Azure provided images, however, you will most likely need to create a [Custom Image](#custom-image). ```bash # List Windows Server Editions using the offline list (faster) az vm image list --architecture x64 --location westus --offer WindowsServer # Search the full Marketplace for Desktop versions of Windows az vm image list --architecture x64 --location westus --all --publisher MicrosoftWindowsDesktop ``` Here is an example of an OS Image Reference JSON value returned by one of the above queries that can be used. ```json { "architecture": "x64", "offer": "windows-ent-cpc", "publisher": "MicrosoftWindowsDesktop", "sku": "win11-22h2-ent-cpc-os", "urn": "MicrosoftWindowsDesktop:windows-ent-cpc:win11-22h2-ent-cpc-os:22621.963.221213", "version": "22621.963.221213" } ``` 12. Check the **Image is Windows** checkbox. 13. Enter the target **Network Security Group**. In the Azure portal, find your Network Security Group, go to Properties, and find the Resource ID field. 14. Enter the target **Subnet**. In the Azure portal, find your subnet, go to Properties, and find the Resource ID field. 15. Check the **Assign Public IP** box if you desire your VMs to have public IP addresses. It is more secure to not have public IP addresses assigned. Kasm will provide a secure way to provide access to private systems and therefore, it is not strictly necessary to have a public IP. 16. Optionally provide additional tags for the VM, use empty `{}` brackets if no additional tags are needed. 17. Enter a public SSH Key, this is required even for Windows systems. 18. Enter a PowerShell startup script. Azure does not automatically run this script on startup like other cloud providers. You will need to create [Custom Image](#custom-image) in order for the startup script to execute on boot. The following example will create a local user account using the **Connection Username** and **Connection Password** fields specified on the previous screen. This is only relevant if you are using static credentials and will not work [Active Directory](../../../../workspaces-sessions/server-workspace/windows/authentication.mdx) integration. ```powershell $pass = ConvertTo-SecureString -String "{connection_password}" -AsPlainText -Force New-LocalUser -Name {connection_username} -Description 'Programatically generated Kasm user account' -Password $pass -PasswordNeverExpires -AccountNeverExpires | Add-LocalGroupMember -Group administrators | Add-LocalGroupMember -Group "Remote Desktop Users" Start-Service -Name "Audiosrv" ``` 19. Enter a **Config Override** as JSON. This the Image Reference (VERSION_ID from Custom Image Step 13 below) be provided. Additionally, in the example we used Windows 11, which requires SecureBoot to be enabled and the securityType to be set to TrustedLaunch. This is not required for older versions of Windows such as Windows 10 and therefore it is not required to provide override settings for those cases. Finally, some plans in Azure require that the Plan object be included as well. Below are examples for a Windows 10 image, without securityType, and for a Windows 11 image with securityType. Both include the Plan object, but that object may be left out for some plans. ```json { "virtual_machine": { "plan": { "name": SKU, "product": OFFER, "publisher": PUBLISHER }, "properties": { "storageProfile": { "imageReference": { "id": VERSION_ID } } } } } ``` ```json { "virtual_machine": { "plan": { "name": SKU, "product": OFFER, "publisher": PUBLISHER }, "properties": { "securityProfile": { "securityType": "TrustedLaunch", "uefiSettings": { "secureBootEnabled": true, "vTpmEnabled": true } }, "storageProfile": { "imageReference": { "id": VERSION_ID } } } } } ``` ### Custom Image ### Unlike most other cloud providers, Azure does not automatically execute the startup script on boot. You need to create a custom image and implement your own method of executing that script on boot. The following method has been tested by Kasm, but is by no means the only method that can be used. **These procedures are only necessary if you want to utilize Kasm's startup script injection and perform custom actions on boot of the VMs.** 1. Manually create a VM using the appropriate base image, such as Windows 11 Enterprise 2. Install the required software and configure the OS as appropriate for your environment 3. Create a file with the following contents at C:\AzureData\startup.cmd ``` schtasks /Delete /TN "DomainJoin" /F cd C:\AzureData setlocal EnableExtensions EnableDelayedExpansion set tries=0 :CheckForFile IF EXIST CustomData.bin GOTO FoundIt set /a tries+=1 IF !tries! GEQ 40 GOTO Timeout TIMEOUT /T 15 >nul GOTO CheckForFile :FoundIt ren CustomData.bin CustomData.ps1 PowerShell -Command "Set-ExecutionPolicy Unrestricted" PowerShell -file C:\AzureData\CustomData.ps1 GOTO End :Timeout REM Timed out waiting for CustomData.bin (40 x 15s) echo ERROR: Timed out waiting for CustomData.bin after %tries% attempts (about 10 minutes). :End ``` 4. Open a Windows Command Prompt as an Administrator and execute the following command. ``` schtasks /create /tn "DomainJoin" /sc onstart /rl highest /ru system /tr "cmd /c C:\AzureData\startup.cmd > C:\AzureData\startup.log 2>&1" ``` 5. Run sysprep on the VM and shut it down. Run the following in an elevated command prompt. ``` cd %windir%\system32\sysprep sysprep.exe /oobe /generalize /mode:vm /shutdown ``` You may get an error message when running the above command on a Windows 11 system using the default Azure provided image. Look at the log file indicated by the error message. If you see an error message near the bottom of the logs indicating OneDriveSync was installed for the user but not provisioned for all users, remove the software from an elevated PowerShell session with the following command. **Try sysprep again after running this command**. ``` get-appxpackage -allusers -name "microsoft.Onedrivesync" | Remove-appxpackage ``` 6. Open a Cloud Shell in Azure and run the following command to get a list of VMs and find the VM that you just ran sysprep on. ``` az vm list -otable ``` 7. The table provided by the above command will contain the VM name and its resource group name. Plug in your VM name and resource group name into the below command in order to generalize the VM. ``` az vm generalize -g RESOURCE_GROUP_NAME -n VM_NAME ``` 8. Create a Gallery, if one is not already available for the location of the Custom Image VM, which is how images are shared and organized in Azure. Plug in your resource group name and your desired Gallery name. ``` az sig create --resource-group RESOURCE_GROUP_NAME --gallery-name GALLERY_NAME ``` 9. Obtain the full ID of the VM you want to create an image from. Plug in your resource group name and VM name into the below command. ``` az vm get-instance-view -g RESOURCE_GROUP_NAME -n VM_NAME --query id ``` The output should look similar to the following and will be used in step 11. ``` "/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/" ``` 10. From the Azure portal search bar, search for 'Azure compute galleries' and find the Gallery you created on step 8. Click into that gallery. Click the drop down on the Add button and select 'VM Image Definition'. Provide a VM image definition name and select Windows as the OS Type. The Security Type and VM generation may differ based on what base image you started from. For Windows 11, select Trusted Launch for the Security Type, which will lock you into VM generation 2. The Publisher, Offer, and SKU can all be found in the Azure Portal on the VM page, under Source Image Details. After creating the image definition, take note of the name for the subsequent steps. 11. Create a Managed Image using the below command for your desired MANAGED_IMAGE_NAME and appropriate os-type and hyper-v-generation depending on what was selected in Step 10 (using Windows and V2 for the example below). ``` az image create --resource-group RESOURCE_GROUP_NAME --name MANAGED_IMAGE_NAME --source "VM_ID" --os-type Windows --hyper-v-generation V2 --location "eastus" ``` 12. Create an Image version. Plug in your resource group name, gallery name, image definition, desired version number, location, and target regions into the following Azure CLI command. For the managed-image field, use the managed image name you created in step 11. Target regions must include both the region your image is in and the region your resource group is in, if different. ``` az sig image-version create \ --resource-group RESOURCE_GROUP_NAME \ --gallery-name GALLERY_NAME \ --gallery-image-definition IMAGE_DEFINITION_NAME \ --gallery-image-version 1.0.0 \ --location "eastus" --target-regions "eastus" \ --replica-count 2 \ --managed-image MANAGED_IMAGE_NAME ``` Make note of the ID returned from the above command for the next step. 13. In the VM Provider configuration, Step 11 and Step 19, put the ID returned by the previous step into the **OS Image Reference** and **Config Override** fields. The following is an example. ```json { "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//img/IMAGE_DEFINITION_NAME/versions/1.0.0" } ``` --- ## Microsoft Azure AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Microsoft Azure. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to Microsoft Azure: Ensure you have the appropriate access to your Azure environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Configure your Azure environment ### Setup your Microsoft Azure Environment - **Register Azure app**: An API key for Kasm must be created to use for interfacing with Azure. Azure call these apps, and the example will walk through registering one along with the required permissions. * Register an app by going to the Microsoft Entra ID service in the Azure portal. * From the **Add** dropdown select **App Registration**. * Give this app a human-readable name such as **Kasm Workspaces**. * Note the Client ID (Application ID) and Tenant ID (Directory ID) from your App Registration page for use later. - **Create Client Secret**: The Client Secret is created from the App Registration. * Click **Add a certificate or secret** to the right of **Client credentials**. * Click **New client secret* under the *Client secrets** table. * Fill in the Description and Expires fields and click **Add**. * Note the Value (not the Secret ID) for use later. This cannot be copied again afterwards, so save it now. - **Set up permissions**: Certain permissions must be set up in Azure by adding role assignments. * Go to **Resource Groups** and select the **Resource Group** that Kasm will autoscale in. * Select **Access Control (IAM)**. * From the **Add** drop down select **Add role assignment**. * The app created in Azure will need two roles, first select the *Virtual Machine Contributor* role, then on the next page select the app by typing in the name e.g. **Kasm Workspaces**. * Go through this process again to add the *Network Contributor* and the *DNS Zone Contributor* and the *Compute Gallery Image Reader* roles. ## Configure your Microsoft Azure details on Kasm * Follow [AutoScale Settings for Agent Pool](../../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or, if you already have an AutoScale Configuration defined, go straight to the All VM Provider Configs page, click Add to and select **Add New** in **VM Provider Configs**. * Configure the following settings based on the instruction that follow: The following instructions utilize the Azure CLI. You can open the CLI in the Azure web portal and run these commands directly. See Microsoft's [instructions](https://learn.microsoft.com/en-us/azure/cloud-shell/quickstart?source=recommendations&tabs=azurecli) for basic usage of the Azure Cloud Shell environment. * Select **Azure** from the Provider Drop Down. * Provide a name for your configuration. * Enter your Subscription ID, Resource Group, and Tenant ID from the Azure Setup above. * Enter the Client ID and Client Secret created during Azure Setup above. * Select the Azure Authority from the drop down. Most users will select **Azure Public Cloud**. * Enter the region name, you can use the following Azure CLI command to list available regions, use the Name column. ```bash az account list-locations -o table ``` * Enter the **Maximum Instances**. This puts an upper limit on the number of VMs this auto scale configuration can create. * Enter a VM Size by name. Use the following Azure CLI command to list all VM sizes available in the desired region. ```bash az vm list-sizes --location "westus" ``` * Enter the OS [Disk Type](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-types), using the [Azure Disk Type SKU](https://learn.microsoft.com/en-us/rest/api/storagerp/srp_sku_types). The following is the current list of available type names. Not all disk SKUs are compatible with all VM size types. | Disk Type Name | |-----------------| | Standard_LRS | | Standard_GRS | | Standard_RAGRS | | Standard_ZRS | | Premium_LRS | | Premium_ZRS | | Standard_GZRS | | Standard_RAGZRS | * Enter the **OS Disk Size**, in gigabytes. The size need to be at least the size of the target OS Image Reference, defined in the next field. * Enter the **OS Image Reference** JSON. Use the following Azure CLI command to list images in the JSON format expected by Kasm. Note that these are default Azure provided images, however, you will most likely need to create a [Custom Image](#custom-image). ```bash # List Windows Server Editions using the offline list (faster) az vm image list --architecture x64 --location westus --offer WindowsServer # Search the full Marketplace for Desktop versions of Windows az vm image list --architecture x64 --location westus --all --publisher MicrosoftWindowsDesktop ``` Here is an example of an OS Image Reference JSON value returned by one of the above queries that can be used. ```json { "architecture": "x64", "offer": "windows-ent-cpc", "publisher": "MicrosoftWindowsDesktop", "sku": "win11-22h2-ent-cpc-os", "urn": "MicrosoftWindowsDesktop:windows-ent-cpc:win11-22h2-ent-cpc-os:22621.963.221213", "version": "22621.963.221213" } ``` * Check the **Image is Windows** checkbox. * Optionally provide the **Plan Name** for the VM image. This is is only required for images from the marketplace or custom images derived from a marketplace image. * Optionally provide the **Plan Product** for the VM image. This is is only required for images from the marketplace or custom images derived from a marketplace image. * Optionally provide the **Plan Publisher** for the VM image. This is is only required for images from the marketplace or custom images derived from a marketplace image. * Select which features are used (if any) to secure the VM. This is optional, but may be required for certain Windows VMs such as Windows 10 and Windows 11. * Check the **Enable Secure Boot** box to enable Secure Boot for your VM. This is not enabled by default, but may be required for certain Windows VMs such as Windows 11. * Check the **Enable TPM** box to enable TPM for your VM. This is not enabled by default, but may be required for certain Windows VMs such as Windows 11. * Enter the target **Network Security Group**. In the Azure portal, find your Network Security Group, go to Properties, and find the Resource ID field. * Enter the target **Subnet**. In the Azure portal, find your subnet, go to Properties, and find the Resource ID field. * Check the **Assign Public IP** box if you desire your VMs to have public IP addresses. It is more secure to not have public IP addresses assigned. Kasm will provide a secure way to provide access to private systems and therefore, it is not strictly necessary to have a public IP. * Optionally provide additional tags for the VM, use empty `{}` brackets if no additional tags are needed. * Enter a public SSH Key, this is required even for Windows systems. * Enter a PowerShell startup script. Azure does not automatically run this script on startup like other cloud providers. You will need to create a [Custom Image](#custom-image) in order for the startup script to execute on boot. The following example will create a local user account using the **Connection Username** and **Connection Password** fields specified on the previous screen. This is only relevant if you are using static credentials and will not work [Active Directory](../../../../workspaces-sessions/server-workspace/windows/authentication.mdx) integration. ```powershell $pass = ConvertTo-SecureString -String "{connection_password}" -AsPlainText -Force New-LocalUser -Name {connection_username} -Description 'Programatically generated Kasm user account' -Password $pass -PasswordNeverExpires -AccountNeverExpires | Add-LocalGroupMember -Group administrators | Add-LocalGroupMember -Group "Remote Desktop Users" Start-Service -Name "Audiosrv" ``` * Optionally enter a **Config Override** as JSON. * Submit the Provider Config ### Custom Image ### Unlike most other cloud providers, Azure does not automatically execute the startup script on boot. You need to create a custom image and implement your own method of executing that script on boot. The following method has been tested by Kasm, but is by no means the only method that can be used. **These procedures are only necessary if you want to utilize Kasm's startup script injection and perform custom actions on boot of the VMs.** * Manually create a VM using the appropriate base image, such as Windows 11 Enterprise. * Install the required software and configure the OS as appropriate for your environment. * Create a file with the following contents at C:\AzureData\startup.cmd. ``` schtasks /Delete /TN "DomainJoin" /F cd C:\AzureData setlocal EnableExtensions EnableDelayedExpansion set tries=0 :CheckForFile IF EXIST CustomData.bin GOTO FoundIt set /a tries+=1 IF !tries! GEQ 40 GOTO Timeout TIMEOUT /T 15 >nul GOTO CheckForFile :FoundIt ren CustomData.bin CustomData.ps1 PowerShell -Command "Set-ExecutionPolicy Unrestricted" PowerShell -file C:\AzureData\CustomData.ps1 GOTO End :Timeout REM Timed out waiting for CustomData.bin (40 x 15s) :End ``` * Open a Windows Command Prompt as an Administrator and execute the following command. ``` schtasks /create /tn "DomainJoin" /sc onstart /rl highest /ru system /tr "cmd /c C:\AzureData\startup.cmd > C:\AzureData\startup.log 2>&1" ``` * Run sysprep on the VM and shut it down. Run the following in an elevated command prompt. ``` cd %windir%\system32\sysprep sysprep.exe /oobe /generalize /mode:vm /shutdown ``` You may get an error message when running the above command on a Windows 11 system using the default Azure provided image. Look at the log file indicated by the error message. If you see an error message near the bottom of the logs indicating OneDriveSync was installed for the user but not provisioned for all users, remove the software from an elevated PowerShell session with the following command. **Try sysprep again after running this command**. ``` get-appxpackage -allusers -name "microsoft.Onedrivesync" | Remove-appxpackage ``` * Open a Cloud Shell in Azure and run the following command to get a list of VMs and find the VM that you just ran sysprep on. ``` az vm list -otable ``` * The table provided by the above command will contain the VM name and its resource group name. Plug in your VM name and resource group name into the below command in order to generalize the VM. ``` az vm generalize -g RESOURCE_GROUP_NAME -n VM_NAME ``` * Create a Gallery, if one is not already available for the location of the Custom Image VM, which is how images are shared and organized in Azure. Plug in your resource group name and your desired Gallery name. ``` az sig create --resource-group RESOURCE_GROUP_NAME --gallery-name GALLERY_NAME ``` * Obtain the full ID of the VM you want to create an image from. Plug in your resource group name and VM name into the below command. ``` az vm get-instance-view -g RESOURCE_GROUP_NAME -n VM_NAME --query id ``` The output should look similar to the following and will be used in step 11. ``` "/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/" ``` * From the Azure portal search bar, search for 'Azure compute galleries' and find the Gallery you created on step 8. Click into that gallery. Click the drop down on the Add button and select 'VM Image Definition'. Provide a VM image definition name and select Windows as the OS Type. The Security Type and VM generation may differ based on what base image you started from. For Windows 11, select Trusted Launch for the Security Type, which will lock you into VM generation 2. The Publisher, Offer, and SKU can all be found in the Azure Portal on the VM page, under Source Image Details. After creating the image definition, take note of the name for the subsequent steps. * Create a Managed Image using the below command for your desired MANAGED_IMAGE_NAME and appropriate os-type and hyper-v-generation depending on what was selected in Step 10 (using Windows and V2 for the example below). ``` az image create --resource-group RESOURCE_GROUP_NAME --name MANAGED_IMAGE_NAME --source "VM_ID" --os-type Windows --hyper-v-generation V2 --location "eastus" ``` * Create an Image version. Plug in your resource group name, gallery name, image definition, desired version number, location, and target regions into the following Azure CLI command. For the managed-image field, use the managed image name you created in step 11. Target regions must include both the region your image is in and the region your resource group is in, if different. ``` az sig image-version create \ --resource-group RESOURCE_GROUP_NAME \ --gallery-name GALLERY_NAME \ --gallery-image-definition IMAGE_DEFINITION_NAME \ --gallery-image-version 1.0.0 \ --location "eastus" --target-regions "eastus" \ --replica-count 2 \ --managed-image MANAGED_IMAGE_NAME ``` Make note of the ID returned from the above command for the next step. * In the VM Provider configuration, Step 11, put the ID returned by the previous step into the **OS Image Reference** field. The following is an example. ```json { "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//img/IMAGE_DEFINITION_NAME/versions/1.0.0" } ``` ## Test your Microsoft Azure Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace. * Go to Workspaces > Registry. * Make multiple workspaces available. * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds. * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents". * Verify new VM instances in Microsoft Azure. * Check Downscaling. * Terminate sessions to reduce resource usage. * Confirm that Kasm removes agents after the back-off period. --- ## DigitalOcean Autoscaling Configuration # DigitalOcean AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on DigitalOcean. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to Digital Ocean: Ensure you have the appropriate access to your Digital Ocean environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Configure your Digital Ocean environment ### Setup your Digital Ocean Environment * **Create an API Token**: Go to your Digital Ocean dashboard -> "API" -> "Personal Access Tokens" -> "Generate New Token" * Token Name: Give a name (e.g Kasm AutoScale) * Expiration: Set an expiration for your token (e.g 30 days) * Scopes: Choose "Custom Scopes" and give access to the following resources: * actions * certificate * database (remove view credentials) * domain * droplet (remove admin) * firewall * image * load\_balancer * project * regions * sizes * snapshot * ssh\_key * tag * vpc * Generate Token * Save your token securely as you won't be able to see it again. * **Add SSH Key**: You need to assign an SSH key to your newly provisioned droplets. * Go to your Digital Ocean dashboard -> "Settings" -> "Security" -> "Add SSH Key" * Follow the on-screen instructions from Digital Ocean to generate an SSH key pair and paste your Public Key and choose a Key Name. ## Configure Digital Ocean Details on Kasm * Follow [AutoScale Settings for Agent Pool](../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to Digital Ocean * Configure the following settings: * Submit the Provider Config ### "Tag Does Not Exist" Error Upon first testing AutoScaling with Digital Ocean, an error similar to the following may be presented: ``` Future generated an exception: tag zone:abc123 does not exist traceback: .. File "digitalocean/Firewall.py", line 225, in add_tags File "digitalocean/baseapi.py", line 196, in get_data digitalocean.DataReadError: tag zone:abc123 does not exist process: manager_api_server ``` This error occurs when Kasm Workspaces tries to assign a unique tag based on the Zone Id to the Digital Ocean Firewall. If that tag does not already exist in Digital Ocean, the operation will fail and present the error. To workaround the issue, manually create a tag matching the one specified in the error (e.g zone:abc123) via the Digital Ocean console. This can be done via API, or simply creating the tag on a temporary Droplet. ## Test your Digital Ocean Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in Digital Ocean * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## Autoscaling Kasm Workspaces on Google Cloud (GCP) # Google Cloud (GCP) AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Google Cloud (GCP). Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to Google Cloud (GCP): Ensure you have admin access to your Google Cloud (GCP) environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Have access to your Google Cloud (GCP) details; target regions, networks, etc. * Create template images for your autoscale agents, if you require customizations baked into the images ### Setup your GCP environment - **Create service account**: Go to "IAM" -> "Service Accounts" and create a new service account for use with Kasm AutoScaling. Also, make sure to give it the **Compute Admin** role. ![Create Service Account in GCP](/img/autoscaling/providers/gcp/gcp_service_account.png) - **Create Key**: Click on the created service account, and go to "Keys". Click "Add Key" -> Select key type as JSON -> "Create". This will generate a JSON file for you to download that contains all the authentication information required to configure AutoScaling on Kasm. ![Create Key in GCP](/img/autoscaling/providers/gcp/gcp_create_key.png) ## Configure VM Provider Details on Kasm * Submit the Provider Config ## Test Autoscaling * If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately, otherwise... * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents in the Docker Agents section * Verify new VM instances in Google Cloud (GCP) * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## Harvester Autoscaling Configuration # Harvester AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Harvester. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Prerequisites * Access to Harvester: Ensure you have admin access to your Harvester environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Configure your Harvester environment: * Create a namespace for your autoscale deployment * Create a VM network in the new namespace for your agents to use and attach it to a cluster network * Create template images in the new namespace for AutoScale to use ## Setup your Harvester Environment ### Download KubeConfig The KubeConfig YAML file can be downloaded from the Support link on the Harvester dashboard and contains key information you will need to configure autoscaling on Kasm.
### Create Namespace Go to "Namespaces" -> "Create" to create a new namespace in Harvester. Give it a name like `kasm-autoscale` ### Create Network Go to "Virtual Machine Networks" -> "Create" to create a new VM network. - Make sure you select the right namespace - Give the network a name like `kasm-autoscale` - Choose the Type as `Untagged Network` - Choose the `mgmt` Cluster Network
### Create VM template Create the appropriate VM template based on whether you are implementing Server AutoScaling or Docker AutoScaling on Harvester. * For Windows AutoScaling, follow the [Windows Templating Guide](#windows-templating) * For Docker Agent AutoScaling, follow the [Linux Templating Guide](#linux-templating) #### Linux Templating Creating a Linux template in Harvester is pretty straightforward. - Go to "Images" -> "Create" - Choose the correct namespace that you created earlier. - Choose a name for your image (e.g jammy-server-cloudimg-amd64.img). This name needs to be fed to Kasm later. - Select "URL". You can also choose "File" if you want to upload an ISO file instead. You can either install your Linux distro (make sure you choose from the [supported list of operating systems](../../../../explanations/system-requirements.mdx#operating-system)) from scratch with an installation ISO or use a pre-configured ISO like a cloud image. In this demo, we'll use the later. - Enter the URL from where you want Harvester to download the image (e.g https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img)
- Click "Create". This will download the VM to Harvester from the provided URL - Optionally, you can pre-load workspace images on your autoscaled agent VMs so that workspaces launch instantly after provisioning, without waiting for Kasm to pull the necessary Docker images. Read the [Pre-load Workspace Images on Agents guide](../../preload-images-on-agents.mdx) to learn more - You also need to install the QEMU Guest Agent tools on the agent. Read the section titled "Updated Startup Scripts" on [the Pools and Autoscale page](../../pools.mdx) for more information; in the provided script, the lines that run the qemu installation will need to be uncommented #### Windows Templating For an overview of Windows templating and its prerequisites, refer to the [Windows AutoScale Template Creation Guide](../windows-autoscale-templates.mdx). Creating a Windows Template involves additional steps and is not as straightforward as Linux templating. - Go to "Images" -> "Create" - Choose the correct namespace that you created earlier. - Choose a name for your image (e.g windows-server-2022) - Choose "File" and click "Upload File" to upload the Windows ISO file. As an example, you can download Windows Server 2022 from [here](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022). You can also choose "URL" and input the URL from where the ISO file can be downloaded.
- Wait for the ISO file to be uploaded. - Similarly, you also need to upload the VirtIO tools image. Go to "Images" -> "Create" - Select "File" -> "Upload File" to upload the ISO file. You can download the VirtIO files from [here](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.266-1/) - Go to "Virtual Machines" -> "Create" - Select the correct namespace - Give a name for your VM (e.g windows-server-2022-kasm-autoscale) - Set the number of cores and memory.
- Go to the "Volumes" tab and add the following volumes: * **Volume 1** * In the default volume, Set "Image" to the Windows ISO you uploaded earlier * Set "Type" to `cd-rom` * Set "Bus" to `SATA`
* **Volume 2** * Click "Add a Virtual Machine Image" * Set the "Image" to the VirtIO ISO you uploaded earlier * Set "Type" to `cd-rom` * Set "Bus" to `SATA`
* **Volume 3** * Click "Add Volume" * Set "Type" to `disk` * Set "Storage Class" to `harvester-longhorn (Default)` * Set Size to anything more than 40GB. This will be your Windows boot disk. * Set "Bus" to `VirtIO`
- Go to "Networks" - Change the default network like this, * Name: You can let this be `default` * Model: Set this to `virtio` * Network: Set this to the network you created earlier * Type: Set to `bridge`
- Once the VM is provisioned, open it in WebVNC - You will now see the Windows Installation screen. Proceed with the Installation.
- By default, you may not be able to see the list of available disks to install Windows. To fix this, you need to install the VirtIO SCSI controller. Click "Load driver" and install the appropriate driver.
- The available disks must now be listed and you can choose the Windows boot disk you created to install Windows.
- Once Windows is installed, you need to install the other VirtIO drivers like the Network driver. Simply navigate to your VirtIO disk from your File Explorer and install the drivers by running the installer.
- You also need to install the QEMU Guest Agent tools. These can be found in the same VirtIO drive in the `guest-agent` folder.
- [Cloudbase-Init](https://cloudbase.it/cloudbase-init/#download) is also required so Kasm can run the startup script when the Windows VM is provisioned. Simply download the [installer](https://cloudbase.it/cloudbase-init/#download) and run it to install Cloudbase-init.
- You can now install the tools/software you'd like to have on your VM (e.g Microsoft Office) - Finally, you need to enable RDP on your VM. This is required so that Kasm can utilize RDP to create Windows Sessions. Simply search for "Remote Desktop Settings" and enable Remote Desktop
- Shutdown the VM - Edit the VM config, and go to "Volumes". Remove the attached Windows ISO and VirtIO ISO. - Now, go back to "Virtual Machines" and generate a template from the created VM.
- Give your template a name (e.g windows-server-2022-kasm-template) - Make sure you select "With Data" and click "Create"
- This will generate the template from your Windows VM. For more details about Windows Templating, refer to the [Windows AutoScale Template Creation Guide](../windows-autoscale-templates.mdx) ## Configure VM Provider Details on Kasm * Follow [AutoScale Settings for Agent Pool](../infrastructure-components/autoscale-config-docker-agent.mdx) or [AutoScale Settings for Server Pool](../infrastructure-components/autoscale-config-server.mdx) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to Harvester * Configure the following settings * Submit the Provider Config ### Disk Image It is important to correctly specify the disk image name so that Kasm can instruct Harvester to provision a VM based on that image. - If you are not using a custom template and want to use a pre-configured Cloud image directly (typically for Linux VMs), go to "Images" and copy the image name listed under the correct namespace.
- If you are using a custom template (such as the Windows VM template we created earlier), you need to correctly identify the disk image associated with that template. Go to "Advanced" -> "Templates" -> Select the template you want to use, then navigate go to the "Volumes" tab. Here, you can find the image name of the template (no need to include the namespace name). In the screenshot below, the correct disk image to input in Kasm is `templateversion-windows-server-2022-template-new-6l846-image-0`
## Test your Harvester Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in Harvester * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## Nutanix Autoscaling Configuration # Nutanix AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Nutanix. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to Nutanix: * Ensure you have admin access to your Nutanix environment * Ensure you have a directory service or identity provider configured * Ensure you have two users, one to administer the project and create VMs, one to access the Nutanix APIs. * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Have access to your Nutanix server details; target clusters, projects, storage, networks, etc. * Create VMs in the project you have designated for your autoscale VMs ### Setup your Nutanix environment #### Create a new Nutanix Role 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Admin Center** dashboard. 3. Select **IAM** -> **Roles** -> **Create Role** -> **New role**. 4. Enter a value for the **Role Name** field (e.g. kasm-role). 5. Add all the **operations** from the [list of required permissions](#required-permissions) corresponding to the Nutanix API version you plan to use, ensure that any related operations are also added. 6. Click **Save**. #### Create a new Nutanix Project 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Admin Center** dashboard. 3. Select **Projects** -> **Create Project**. 4. Enter a value for the **Project Name** field (e.g. kasm-autoscale). 5. Select **Add Users** -> **Add/Edit Users & Groups**. 6. Click **Add User**. 7. Enter the name of a valid user in the **Name** field. This user will administer the project, create Virtual Machine templates, upload images, etc. 8. From the **Role** drop-down menu, select the default **Project Admin** role. 9. Click **Add User**. 10. Enter the name of a valid user in the **Name** field. This user will be configured in the Kasm Provider to access the Nutanix APIs. 11. From the **Role** drop-down menu, select the new role created above (e.g. kasm-role). 12. Ensure **Allow Collaboration** is enabled. 13. Click **Save Users and Project**. 14. Select **Add Infrastructure** -> **Add Infrastructure**. 15. From the drop-down menu, select the **Infrastructure Endpoint** that will be used to provision Kasm autoscale resources. 16. Click **Configure Resources**. 17. From the drop-down menu, select the **Cluster**. 18. Click **Select VLANs**. 19. Click the checkbox next to the VLAN that will be used to provide network access for Kasm autoscale resources. 20. Click **Confirm and Select Default**. 21. Click **Confirm**. 22. Click **Save**. ## Configure VM Provider Details on Kasm * Follow [AutoScale Settings for Agent Pool](../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to Nutanix * Configure the following settings: * Submit the Provider Config. Support for Nutanix API Version 4 is in Preview. ## Test your Nutanix Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in Nutanix * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period ## How to create an Ubuntu 24LTS VM ### Create Nutanix Ubuntu installation image 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Infrastructure Center** dashboard. 3. Select **Images** -> **Add Image**. 4. From the **Image Source** options list, select the **URL** option. 5. Enter the URL for a valid Ubuntu24 LTS ISO in the **Image URL** field (e.g. [ref](https://releases.ubuntu.com/24.04.2/ubuntu-24.04.2-live-server-amd64.iso)). 6. Click **Add URL**. 7. Enter the name for the ISO in the **Name** field (e.g. kasm-ubuntu-iso). 8. Ensure that **ISO** is selected from the **Type** drop-down menu. 9. Click **Next**. 10. Click **Save**. 11. Wait for the upload to complete. ### Create Nutanix Ubuntu VM 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Infrastructure Center** dashboard. 3. Select **VMs** -> **Create VM**. 4. Enter a value for the **Name** field (e.g. kasm-ubuntu-template). 5. From the **Project** drop-down menu, select the Nutanix Project that was just created (e.g. kasm-autoscale). 6. From the **Cluster** drop-down menu, select the Nutanix Cluster that will be used to provision Kasm autoscale resources. 7. In the **Cores Per CPU** section, enter the number of cores to provision for this VM (e.g. 4). 8. In the **Memory** section, enter the amount of memory to provision for this VM (e.g. 4). 9. Click **Next**. 10. Click **Attach Disk**. 11. Ensure that **Disk** is selected from the **Type** drop-down menu. 12. Ensure that **Allocate from Storage Container** is selected from the **Operation** drop-down menu. 13. From the **Storage Container** drop-down menu, select the Nutanix Storage Container to use when provisioning this VM. 14. In the **Capacity** section, enter the amount of storage to provision for this VM (e.g. 150). 15. Ensure that **SCSI** is selected from the **Bus Type** drop-down menu. 16. Click **Save**. 17. Click **Attach Disk**. 18. Ensure that **CD-ROM** is selected from the **Type** drop-down menu. 19. Ensure that **Clone from Image** is selected from the **Operation** drop-down menu. 20. From the **Image** drop-down, select the Ubuntu installation image you uploaded previously. 21. Ensure that **SATA** is selected from the **Bus Type** drop-down menu. 22. Click **Save**. 23. Click **Attach to Subnet**. 24. From the **subnet** drop-down, select the Nutanix Subnet to use when provisioning this VM. 25. Ensure that **Connected** is selected from the **Network Connection State** drop-down menu. 26. Click **Save**. 27. Click **Next**. 28. Click **Next**. 29. Click **Create VM**. 30. From the list of VMs, right-click the newly created VM, select **Power Operations** and then select **Power On**. 31. Install the OS. 32. From the list of VMs, right-click the newly created VM, select **Update**. 33. Click **Next**. 34. In the list of **Disks**, click the **delete** icon next to the CD-ROM containing the installation ISO image. 35. Click **Save**. 36. SSH into the newly created VM with the credentials created during OS installation. 37. Run the following cleanup commands to prepare this VM as a reusable template: ```bash sudo truncate -s 0 /etc/machine-id sudo truncate -s 0 /var/lib/dbus/machine-id sudo cloud-init clean --logs ``` 38. Shutdown your VM ``` sudo shutdown -P now ``` ## How to create a Windows 2025 Server VM ### Create Nutanix Windows installation image 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Infrastructure Center** dashboard. 3. Select **Images** -> **Add Image**. 4. Click **Add File**. 5. Select a valid Windows 2025 Server ISO from the **File Upload** window. 6. Click **Open**. 7. Enter the name for the ISO in the **Name** field (e.g. kasm-windows-iso). 8. Ensure that **ISO** is selected from the **Type** drop-down menu. 9. Click **Next**. 10. Click **Save**. 11. Wait for the upload to complete. ### Create Nutanix VirtIO driver image 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Infrastructure Center** dashboard. 3. Select **Images** -> **Add Image**. 4. From the **Image Source** options list, select the **URL** option. 5. Enter the URL for a valid VirtIO Driver ISO in the **Image URL** field (e.g. [ref](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable)). 6. Click **Add URL**. 7. Ensure that **ISO** is selected from the **Type** drop-down menu. 8. Click **Next**. 9. Click **Save**. 10. Wait for the upload to complete. ### Create Nutanix Windows VM 1. Log into your Nutanix Prism Central UI as an administrator. 2. Navigate to the **Infrastructure Center** dashboard. 3. Select **VMs** -> **Create VM**. 4. Enter a value for the **Name** field (e.g. kasm-windows-template). 5. From the **Project** drop-down menu, select the Nutanix Project that was just created (e.g. kasm-autoscale). 6. From the **Cluster** drop-down menu, select the Nutanix Cluster that will be used to provision Kasm autoscale resources. 7. In the **Cores Per CPU** section, enter the number of cores to provision for this VM (e.g. 4). 8. In the **Memory** section, enter the amount of memory to provision for this VM (e.g. 4). 9. Click **Next**. 10. Click **Attach Disk**. 11. Ensure that **Disk** is selected from the **Type** drop-down menu. 12. Ensure that **Allocate from Storage Container** is selected from the **Operation** drop-down menu. 13. From the **Storage Container** drop-down menu, select the Nutanix Storage Container to use when provisioning this VM. 14. In the **Capacity** section, enter the amount of storage to provision for this VM (e.g. 150). 15. Ensure that **SCSI** is selected from the **Bus Type** drop-down menu. 16. Click **Save**. 17. Click **Attach Disk**. 18. Ensure that **CD-ROM** is selected from the **Type** drop-down menu. 19. Ensure that **Clone from Image** is selected from the **Operation** drop-down menu. 20. From the **Image** drop-down, select the Windows installation image you uploaded previously. 21. Ensure that **SATA** is selected from the **Bus Type** drop-down menu. 22. Click **Save**. 23. Click **Attach Disk**. 24. Ensure that **CD-ROM** is selected from the **Type** drop-down menu. 25. Ensure that **Clone from Image** is selected from the **Operation** drop-down menu. 26. From the **Image** drop-down, select the VirtIO driver image you uploaded previously. 27. Ensure that **SATA** is selected from the **Bus Type** drop-down menu. 28. Click **Save**. 29. Click **Attach to Subnet**. 30. From the **subnet** drop-down, select the Nutanix Subnet to use when provisioning this VM. 31. Ensure that **Connected** is selected from the **Network Connection State** drop-down menu. 32. Click **Save**. 33. Ensure that **Secure Boot** is enabled. 34. Ensure that **Attach vTPM** is enabled. 35. Click **Next**. 36. Click **Next**. 37. Click **Create VM**. 38. From the list of VMs, right-click the newly created VM, select **Power Operations** and then select **Power On**. 39. From the list of VMs, right-click the newly created VM, select **Launch Console**. 40. Click a button to **Press any key to boot from CD or DVD**. 41. Click **Next**. 42. Click **Next**. 43. Click the checkbox that starts with **I agree**. 44. Click **Next**. 45. Select **Window Server 2025 Standard Evaluation (Desktop Experience)**. 46. Click **Next**. 47. Click **Accept** to agree to the Applicable notices and license terms. 48. Click **Load Driver**. 49. Click **Browse**. 50. Expand the CD Drive containing the VirtIO drivers. 51. Navigate to the **vioscsi/2k25/amd64** folder. 52. Click **Ok**. 53. Select **Red Hat VirtIO SCSI pass-through controller**. 54. Click **Install**. 55. Click **Next**. 56. Click **Install**. 57. Enter a valid password for the built-in Administrator. 58. Confirm the password. 59. Click **Finish**. 60. Click the Ctrl-Alt-Del icon in the console menu to **send Ctrl-Alt-Del**. 61. Enter the Administrator password. 62. Click **Accept**. 63. Launch **File Explorer**. 64. Navigate to the CD Drive containing the VirtIO drivers. 65. Launch the **virtio-win-gt-x64** installer. 66. Click **Next**. 67. Click the checkbox starting with **I accept**. 68. Click **Next**. 69. Click **Next**. 70. Click **Install**. 71. Click **Finish**. 72. Download a valid Windows Cloudinit installer ([ref](https://cloudbase.it/cloudbase-init/)). 73. Launch the installer. 74. Click **Next**. 75. Click the checkbox starting with **I accept**. 76. Click **Next**. 77. Click **Next**. 78. Ensure that **Run Cloudbase-init service as LocalSystem** is enabled. 79. Click **Next**. 80. Click **Install** 81. Allow any Windows User Account Control pop-ups that request changes to the system. 82. Click **Finish**. 83. Select **Local Server** from the **Server Manager**. 84. Click on the **Disabled** link next to **Remote Desktop**. 85. Click **Allow remote connections to this computer**. 86. Click **Ok**. 87. Click **Ok**. 88. Open the Start Menu 89. Enter the value **powershell** into the search field. 90. Click **Run as administrator** from the **Windows PowerShell** application menu. 91. Execute the following command in the PowerShell console: ```powershell Set-ExecutionPolicy Unrestricted ``` 92. Shut down Windows. 93. From the list of VMs, right-click the newly created VM, select **Update**. 94. Click **Next**. 95. In the list of **Disks**, click the **delete** icon next to the **CD-ROM** containing the Windows installation image. 96. In the list of **Disks**, click the **delete** icon next to the **CD-ROM** containing the VirtIO driver image. 97. Click **Save**. ## Required Permissions ### API v3 * AHV VM * Clone Virtual Machine * Delete Virtual Machine * Update Virtual Machine Categories * Update Virtual Machine Power State * View Virtual Machine * Category * Create Or Update Name Category * Create Or Update Value Category * Delete Name Category * Delete Value Category * View Name Category * View Value Category * Cluster * View Cluster * Image * View Image * Marketplace Item * View Marketplace Item * Project * View Project * Subnet * View Subnet * VPC * View VPC ### API v4 * AHV VM * Associate Virtual Machine Categories * Clone Existing Virtual Machine * Delete Existing Virtual Machine * Power On Virtual Machine * View Existing Virtual Machine * View Virtual Machine Disk * Category * Create Category * Delete Category * View Category * Cluster * View Cluster * Image * View Image * Marketplace Item * View Marketplace Item * Project * View Project * Subnet * View Subnet * Storage Container * View Storage Container * Volume Group * Attach Volume Group To AHV VM * Detach Volume Group From AHV VM * VPC * View VPC --- ## Oracle Cloud (OCI) AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Oracle Cloud. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Overview ### Prerequisites * Access to Oracle Cloud (OCI): Ensure you have the appropriate access to your Oracle environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Configure your OCI environment ### Setup your Oracle Cloud Environment - **Create an API Key on OCI**: You need to create an API key so that Kasm can use it to talk to OCI on your behalf. * Generate a key pair with OpenSSL ``` # create a directory for storing your key pair mkdir -p ~/.oci # create private key openssl genrsa -out ~/.oci/oci_api_key.pem 2048 # create public key openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem ``` * Copy your public key * Go to your OCI dashboard -> Click on your Profile -> "User Settings" -> "My Profile" -> "Tokens and Keys" -> "Add API Key" * Select "Paste a public key" and paste your public key here and click "Add" * This will generate the "Public Key Fingerprint". Make a note of it as this value needs to be fed into Kasm later. ## Configure your Oracle Cloud details on Kasm * Follow [AutoScale Settings for Agent Pool](../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to Oracle Cloud * Configure the following settings: * Submit the Provider Config ### OCI Config Override Examples Below are some OCI autoscale configurations that utilize the OCI Config Override. Disables instance metadata service v2 for additional security. ```json { "launch_instance_details": { "instance_options": { "OCI_MODEL_NAME": "InstanceOptions", "are_legacy_imds_endpoints_disabled": true } } } ``` A list of available plugins can be retrieved by navigating to an existing instance's "Oracle Cloud Agent" config page. This example enables the "Vulnerability Scanning" plugin. ```json { "launch_instance_details": { "agent_config": { "OCI_MODEL_NAME": "LaunchInstanceAgentConfigDetails", "is_monitoring_disabled": false, "is_management_disabled": false, "are_all_plugins_disabled": false, "plugins_config": [{ "OCI_MODEL_NAME": "InstanceAgentPluginConfigDetails", "name": "Vulnerability Scanning", "desired_state": "ENABLED" }] } } } ``` ## Test your Oracle Cloud Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in OCI * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## Kasm AutoScale Providers: AWS, Azure, GCP, VMware & More ## Provider Specific Settings Kasm supports AutoScaling on a variety of providers. Each provider has unique configurations that must be set up correctly for optimal performance. Select your provider to learn more: - [AWS](../vm-providers.mdx#aws-settings) - [Azure](../vm-providers.mdx#azure-settings) - [Digital Ocean](digitalocean.mdx) - [GCP](gcp.mdx) - [Harvester](harvester.mdx) - [KubeVirt](../vm-providers.mdx#kubevirt-enabled-providers) - [Nutanix](nutanix.mdx) - [OpenStack](../vm-providers.mdx#openstack-settings) - [Oracle Cloud (OCI)](oci.mdx) - [Proxmox](proxmox.mdx) - [VMWare vSphere](vmware.mdx) --- ## Proxmox Autoscale Configuration # Proxmox AutoScale This guide will walk you through configuring autoscaling for Kasm Workspaces on Proxmox. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Prerequisites * Access to Proxmox: Ensure you have admin access to your Proxmox environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Have access to your Proxmox server details; target clusters, resource pool, storage, networks, etc. * Create template images in the resource pool you have designated for your autoscale agents, must include the qemu guest tools ## Setup your Proxmox environment ### Create Proxmox Pool In your Proxmox dashboard, go to "Permissions" -> "Pools" -> "Create" to create a new `kasm-autoscale` pool. ### Create Proxmox user Go to "Permissions" -> "Users" -> "Add" to create a new user. You don't have to create a new account for autoscaling but we strongly recommend it. ### Create API Token Go to "Permissions" -> "API Tokens" -> "Add" to create a new Proxmox API token to use with Kasm. If you're using an existing Proxmox account, we recommend you leave "Privilege Separation" enabled. If you're using a dedicated Proxmox account, you can disable "Privilege Separation". Make sure you save your generated Token ID and Secret securely as you cannot see them again. ### Create Role To create a Role, go to "Permissions" -> "Roles" -> "Create". You need the following privileges for Kasm autoscaling to function properly. Proxmox v8: * Datastore.AllocateSpace * Pool.Audit * SDN.Use * VM.Allocate * VM.Audit * VM.Clone * VM.Config.CDROM * VM.Config.CPU * VM.Config.Disk * VM.Config.HWType * VM.Config.Memory * VM.Config.Network * VM.Config.Options * VM.Monitor * VM.PowerMgmt Proxmox v9: * Datastore.AllocateSpace * Pool.Audit * SDN.Use * VM.Allocate * VM.Audit * VM.Clone * VM.Config.CDROM * VM.Config.CPU * VM.Config.Disk * VM.Config.HWType * VM.Config.Memory * VM.Config.Network * VM.Config.Options * VM.GuestAgent.Unrestricted * VM.PowerMgmt ### Assign Permissions Finally, assign appropriate permissions to your user by going to "Permissions" -> "Add" -> "User Permission". Select the appropriate user and role, and assign the following permissions * /sdn/zones/\ * /storage/\ * /pool/KasmPool If you are using an existing account and have privilege separation enabled, you need to set these permissions from "Permissions" -> "Add" -> "API Token Permission" ### Create a VM template Create the appropriate VM template based on whether you are implementing Server AutoScaling or Docker AutoScaling on Proxmox. * For Windows AutoScaling, follow the [Windows Templating Guide](../windows-autoscale-templates.mdx) * For Docker Agent AutoScaling, follow the [Linux Templating Guide](#linux-templating) #### Linux Templating - Go to your cluster -> local storage (e.g local (pve)) -> "Upload" - Upload your Linux installation ISO file (you can download Ubuntu Server from [here](https://ubuntu.com/download/server)). If you prefer a different distro, ensure it's a [supported operating system](../../../../explanations/system-requirements.mdx#operating-system). Alternatively, If you have a pre-built or pre-configured linux template (like a cloud image), you can use that instead of installing the OS from scratch. - Click "Create VM" from the top right corner * General Settings * Name: Give your template a name (e.g `ubuntu-server-template`) * Resource Pool: Set it to the resource pool you created earlier * Click "Next" * OS Settings * Select `Use CD/DVD disc image file (iso)` * Storage: Select your local storage to which you uploaded your ISO file * ISO Image: Select the Linux ISO image you uploaded * Guest OS Type: Set to Linux * Click "Next" * System Settings * Machine: Select `q35` * SCSI controller: Select `VirtIO SCSI single` * Enable `Qemu Agent` * Click "Next" * Disk Settings * Bus/Device: Select `VirtIO Block` * Disk Size: Choose the amount of size you want to allocate to your VM (e.g 45GB) * Click "Next" * CPU Settings * Cores: Set to the number of cores you want to allocate to your VM (e.g 4) * Type: Select `host` * Click "Next" * Memory Settings * Memory: Set to the amount of memory you want to allocate to your VM in MiB (e.g 4096) * Click "Next" * Network Settings * Model: Select `VirtIO (paravirtualized)` * Click "Next" * Confirm your settings and click "Finish" - Right-click your created VM and select "Start". Then double-click to open the noVNC window. - Follow the on-screen instructions to install Ubuntu Server - Select "Install OpenSSH server" to be able to SSH into your autoscaled agents. - Once the installation is finished, click "Reboot Now" - Go back to your VM settings on Proxmox -> "Hardware" -> Double-click the `CD/DVD Drive` and select "Do not use any media" to remove the Linux installation media. - You can now SSH into your VM with your credentials instead of using noVNC for ease-of-access - Install and enable `qemu-guest-agent` on your VM ```bash sudo apt update sudo apt install qemu-guest-agent -y sudo systemctl start qemu-guest-agent sudo systemctl enable qemu-guest-agent sudo reboot ``` - Reset your Machine IDs to make your VM suitable for templating ```bash sudo truncate -s 0 /etc/machine-id sudo truncate -s 0 /var/lib/dbus/machine-id ``` - Optionally, you can pre-load workspace images on your autoscaled agent VMs so that workspaces launch instantly after provisioning, without waiting for Kasm to pull the necessary Docker images. Read the [Pre-load Workspace Images on Agents guide](../../preload-images-on-agents.mdx) to learn more - Shutdown your VM - Once the VM is powered off, right-click and select "Convert to template" #### Windows Templating For an overview of Windows templating and its prerequisites, refer to the [Windows AutoScale Template Creation Guide](../windows-autoscale-templates.mdx). - Go to your cluster -> local storage (e.g local (pve)) -> "Upload" - Upload your Windows installation ISO file (you can download Windows Server 2022 from [here](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022)) - Also upload the VirtIO drivers ISO file (you can download VirtIO tools from [here](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.266-1/)) - Click "Create VM" from the top right corner * General Settings * Name: Give your template a name (e.g `windows-server-2022-template`) * Resource Pool: Set it to the resource pool you created earlier * Click "Next" * OS Settings * Select `Use CD/DVD disc image file (iso)` * Storage: Select your local storage to which you uploaded your ISO file * ISO Image: Select the Windows Server ISO image you uploaded * Guest OS Type: Set to `Microsoft Windows` * Select `Add additional drive for VirtIO drivers` * ISO Image: Select the VirtIO ISO image you uploaded * Click "Next" * System Settings * Machine: Select `q35` * SCSI controller: Select `VirtIO SCSI single` * Enable `Qemu Agent` * Disable `Add EFI Disk` * Disable `Add TPM` * Click "Next" * Disk Settings * Bus/Device: Select `SCSI` * Cache: Select `Write back` * Disk Size: Choose the amount of size you want to allocate to your VM (e.g 45GB) * Click "Next" * CPU Settings * Cores: Set to the number of cores you want to allocate to your VM (e.g 4) * Type: Select `host` * Click "Next" * Memory Settings * Memory: Set to the amount of memory you want to allocate to your VM in MiB (e.g 4096) * Click "Next" * Network Settings * Model: Select `VirtIO (paravirtualized)` * Click "Next" * Confirm your settings and click "Finish" - Right-click your created VM and select "Start". Then, double-click to open the noVNC window. - Press any key to boot from the attached Windows Installation media - You will now see the Windows Installation screen. Proceed with the Installation. - By default, you may not be able to see the list of available disks to install Windows. To fix this, you need to install the VirtIO SCSI controller. Click "Load driver" to list all the compatible VirtIO SCSI controllers and install the appropriate driver. - The available disks must now be listed and you can choose the Windows boot disk you created to install Windows. - Once Windows is installed, you need to install the other VirtIO drivers like the Network driver. Simply navigate to your VirtIO disk from your File Explorer and install the drivers by running the installer. - You also need to install the QEMU Guest Agent tools. These can be found in the same VirtIO drive in the `guest-agent` folder. - Reboot your VM - Open a PowerShell window as administrator and set the `ExecutionPolicy` to `Unrestricted` so that Kasm can run the startup script when a VM is provisioned ```powershell Set-ExecutionPolicy Unrestricted ``` - Search for "Remote Desktop Settings" and enable "Remote Desktop" on your VM - Now, you can install any custom software that you'd like to have on your VM (e.g Microsoft Office) - Shutdown your VM - Once the VM is powered off, right-click on it and select "Convert to template" - Go to your created template -> "Hardware" -> Remove the attached Windows ISO and VirtIO ISO disks ## Configure VM Provider Details on Kasm * Follow [Autoscale Config (Docker)](../infrastructure-components/autoscale-config-docker-agent.mdx) or [Autoscale Config (Server)](../infrastructure-components/autoscale-config-server.mdx) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to Proxmox * Configure the following settings: * Submit the Provider Config ## Test your Proxmox Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in Proxmox * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## VMware vSphere Autoscaling Configuration # VMware vSphere AutoScale **Table of Contents** This guide will walk you through configuring autoscaling for Kasm Workspaces on VMware vSphere. Autoscaling in Kasm Workspaces automatically provisions and destroys agents based on user demand, ensuring optimized resource utilization and cost efficiency. ## Prerequisites * Access to VCenter: Ensure you have admin access to your VCenter environment * Kasm Workspaces Installed: A basic setup of Kasm Workspaces must already exist * Understand Key Concepts: * **Zones**: Logical groupings of Kasm services for geographical or organizational segmentation * **Pools**: Logical groupings of Kasm Docker Agents and Server Pools for load balancing * Plan Your Configuration: * Understand your deployment zone requirements * Have access to your Vcenter server details; target clusters, datastores, networks, etc. * Create template images for AutoScale to use ## Set up your vSphere environment ### Create an account We recommend creating a dedicated VCenter user for use with Kasm AutoScale. * Go to "Administration" -> "Single Sign On" -> "Users and Groups" * Choose the correct domain (e.g vsphere.local) * Click "Add" * Choose a username for your Kasm autoscale account (e.g kasm-autoscale) * Choose a password for your account * Click "Add" to create the account ### Create a Kasm AutoScale role * Go to "Administration" -> "Access Control" -> "Roles" * Click "New" * Name your autoscale role (e.g "Kasm Autoscale") * Assign these necessary permissions to your role * **Datastore** * Allocate space * Browse datastore * **Global** * Cancel task * **Network** * Assign network * **Resource** * Assign virtual machine to resource pool * **Virtual machine** * Change Configuration * Advanced configuration **_(required for Cloud-Init startup script method)_** * Change CPU count * Change Memory * Set annotation * Edit Inventory * Create from existing * Create new * Remove * Unregister * Guest operations * Guest operation modifications * Guest operation program execution * Guest operation queries * Interaction * Power off * Power on * Provisioning * Deploy template * Click "Create" to create your new role ### Assign Role to User * Go to "Administration" -> "Access Control" -> "Global Permissions" * Click "Add" * Domain: Choose the right domain (e.g vsphere.local) * User/Group: Choose the Kasm Autoscale user that you just created * Role: Choose the Kasm Autoscale role that you just created * Enable "Propagate to Children" * Click "OK" ### Choose a clone type Create the appropriate VM template based on whether you are implementing Server AutoScaling or Docker AutoScaling on vSphere. * For Windows AutoScaling, follow the [Windows Templating Guide](vmware.mdx#windows-vm-preparation) * For Docker Agent AutoScaling, follow the [Linux Templating Guide](vmware.mdx#linux-vm-preparation) #### Understanding Clone Types Kasm supports three methods for cloning VMs in vSphere: **Full Clone (Template)** - Creates a completely independent copy of the source template - Each clone has its own dedicated storage (full copy of all virtual disks) - Clones are independent of the source template after creation - Best for: Production environments where VM independence is critical **Linked Clone (VM Snapshot)** - Creates VMs using delta disks that reference a parent snapshot - Only changes from the snapshot are stored, significantly reducing storage requirements - Faster provisioning since only delta disks need to be created - Best for: Development/test environments, rapid provisioning scenarios, or when storage is limited - The source must be a **VM with a snapshot**, not a template - The source VM and snapshot must remain available—do not delete them while linked clones exist - Review [VMware's linked clone documentation](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-sdks-tools/8-0/web-services-sdk-programming-guide/virtual-machine-management/linked-virtual-machines.html) for additional limitations (e.g., HA cluster behavior, storage considerations) - The vSphere role requires additional permissions beyond those listed in [Create a Kasm AutoScale role](#create-a-kasm-autoscale-role): - **Virtual machine → Change Configuration**: Advanced configuration, Change Settings - **Virtual machine → Provisioning**: Allow disk access, Allow file access, Clone virtual machine **Instant Clone (Frozen VM)** - Creates VMs by forking a frozen parent VM's memory and CPU state (vmFork) - Sub-second cloning—the clone is already running when created, no OS boot required - vSphere assigns a new MAC address to the clone; Kasm hot-swaps the NIC (full remove + re-add) to force the kernel to read the correct MAC and trigger DHCP - CPU and memory are inherited from the parent VM and cannot be overridden - Startup script is always executed via VMware Guest Operations (cloud-init cannot work since there is no boot sequence) - Best for: Environments requiring the fastest possible provisioning with identical VM configurations - The parent VM must be **powered on and frozen** (admin-managed freeze via `vmware-rpctool "instantclone.freeze"`) - **DHCP is required**—vSphere assigns a new MAC address to the clone, and the guest OS must obtain a new IP via DHCP - **Guest OS credentials** are required for startup script execution via VMware Guest Operations - Cloud-init and guest customization (Sysprep/LinuxPrep) are **not supported**—there is no boot sequence - The vSphere role requires additional permissions beyond those listed in [Create a Kasm AutoScale role](#create-a-kasm-autoscale-role): - **Virtual machine → Change Configuration**: Advanced configuration, Change Settings, Add or remove device - **Virtual machine → Interaction**: Connect devices - **Virtual machine → Provisioning**: Clone virtual machine ### Prepare your VM source Create the appropriate VM template based on whether you are implementing Server AutoScaling or Docker AutoScaling on vSphere. * For Windows AutoScaling, follow the [Windows VM preparation Guide](./vmware.mdx#windows-vm-preparation) * For Docker Agent AutoScaling, follow the [Linux VM preparation Guide](./vmware.mdx#linux-vm-preparation) #### Linux VM preparation * On your vSphere dashboard, go to your datastore and upload an ISO file of your Linux Image (you can create a new dedicated folder for storing ISO files). In this demo, we'll use the [Ubuntu Server 24.04.2 LTS](https://ubuntu.com/download/server) image. If you prefer a different distribution, ensure it's a [supported operating system](../../../../explanations/system-requirements.mdx#operating-system). Alternatively, if you have a pre-configured Linux template like a Cloud Image, feel free to use it instead. * Go back to your Datacenter view, right-click on the datacenter where you want to create a VM and select "New Virtual Machine" * **Select a creation type** * Choose "Create a new virtual machine" and click "Next" * **Select a name and folder** * Virtual machine name: Choose a name for your Virtual Machine (e.g ubuntu-server-kasm-template) * Choose the location where you want to provision this VM. * Click "Next" * **Select a compute resource** * Select the destination compute resource for creating this VM * Click "Next" * **Select storage** * Choose the datastore you want to use for this VM (e.g datastore1) * Click "Next" * **Select compatibility** * Select the appropriate compatibility for your VM (e.g ESXi 8.0 U2 and later) * Click "Next" * **Select a guest OS** * Guest OS Family: Set to "Linux" * Guest OS Version: Set to "Ubuntu Linux (64-bit)" * Click "Next" * **Customize hardware** * CPU: Set to the number of cores you want to allocate to your VM (e.g 4) * Memory: Set to the amount of memory you want to allocate to your VM (e.g 8 GB) * New Hard disk: Set to the amount of disk size you want to allocate to your hard disk. This depends on how many workspace images you plan on hosting on your agents. The more images, the more disk space you'll need. * New CD/DVD Drive: Choose "Datastore ISO File" and then select the Linux ISO file you uploaded. * Enable "Connect At Power On" * Click "Next" * **Read to complete** * Verify all your settings and click "Finish" to create your VM. * Power On your VM * Launch a Web Console to interact with your VM and install Ubuntu on it * Follow the On-Screen instructions to install Ubuntu Server on your VM * PRO TIP: Enable "Install OpenSSH Server" while installing Ubuntu so that you can connect to your VM easily with SSH later. * Once Ubuntu is installed, reboot your VM and while your VM reboots, go back to your VM settings and remove the "CD/DVD drive 1" to remove the installation ISO image from your VM. * You can now SSH into your VM and proceed with the next steps ```bash ssh @ ``` * Install `open-vm-tools` if not already installed ``` sudo apt update sudo apt -y install open-vm-tools ``` * Reboot your VM * Configure the root password for your VM. You will need to input your root credentials to Kasm later so that Kasm can run startup scripts when your autoscaled VMs are provisioned. ```bash sudo passwd root ``` * Optionally, you can pre-load workspace images on your autoscaled agent VMs so that workspaces launch instantly after provisioning, without waiting for Kasm to pull the necessary Docker images. Read the [Pre-load Workspace Images on Agents guide](../../preload-images-on-agents.mdx) to learn more * Power-Off your VM * Once the VM is powered off, right-click on your VM, go to "Template" -> "Convert to Template" **(Full Clone only)** If you plan to use linked clones instead, do **not** convert the VM to a template. Instead, take a snapshot of the powered-off VM as described in [Finish for Linked Clone](#finish-for-linked-clone). #### Windows VM preparation For an overview of Windows templating and its prerequisites, refer to the [Windows AutoScale Template Creation Guide](../windows-autoscale-templates.mdx). * On your vSphere dashboard, go to your datastore and upload an ISO file of your Windows Image (you can create a new dedicated folder for storing ISO files). In this demo, we'll use the [Windows Server 2022](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022) installation ISO. If you have a pre-configured Windows template that you'd like to use, upload it instead. * Go back to your Datacenter, right-click on the datacenter where you want to create a VM and select "New Virtual Machine" * **Select a creation type** * Choose "Create a new virtual machine" and click "Next" * **Select a name and folder** * Virtual machine name: Choose a name for your Virtual Machine (e.g Win-Server-2022-Template) * Choose the location where you want to provision this VM. * Click "Next" * **Select a compute resource** * Select the destination compute resource for creating this VM * Click "Next" * **Select storage** * Choose the datastore you want to use for this VM (e.g datastore1) * Click "Next" * **Select compatibility** * Select the appropriate compatibility for your VM (e.g ESXi 8.0 U2 and later) * Click "Next" * **Select a guest OS** * Guest OS Family: Set to "Windows" * Guest OS Version: Set to "Microsoft Windows Server 2022 (64-bit)" * Click "Next" * **Customize hardware** * CPU: Set to the number of cores you want to allocate to your VM (e.g 2) * Memory: Set to the amount of memory you want to allocate to your VM (e.g 8 GB) * New Hard disk: Set to the amount of disk size you want to allocate to your hard disk. * New CD/DVD Drive: Choose "Datastore ISO File" and then select the Windows ISO file you uploaded. * Enable "Connect At Power On" * Click "Next" * **Read to complete** * Verify all your settings and click "Finish" to create your VM. * Power On your VM * Launch a Remote Console to interact with your VM and install Windows on it * Follow the On-Screen instructions to install Windows Server on your VM * Select "Desktop Experience" so that your users will be able to use the Desktop environment * Choose the drive where you want to install Windows. * Once Windows is installed, reboot your VM and while your VM reboots, go back to your VM settings and detach the "CD/DVD drive 1" to remove the installation ISO image from your VM. * Launch a Remote or Web Console again to access your VM * Choose an Administrator password for your Windows VM * Login to your Windows VM * Install VMWare tools on your Windows VM from vSphere. * Reboot your VM * After rebooting, search for "Remote Desktop Settings" and enable "Remote Desktop" * You can now install any software/tools that you would like on your VM (e.g Microsoft Office) * Shutdown your VM * Once the VM is in powered off state, right-click on it and select "Template" -> "Convert to Template" **(Full Clone only)** If you plan to use linked clones instead, do **not** convert the VM to a template. Instead, take a snapshot of the powered-off VM as described in [Finish for Linked Clone](#finish-for-linked-clone). #### Finish for Linked Clone After completing the OS preparation above, take a snapshot of the powered-off VM to use as the linked clone source: 1. Ensure the VM is powered off 2. Right-click the VM, select "Snapshots" → "Take Snapshot" 3. Name the snapshot (e.g., "kasm-base-v1") and **uncheck** "Include virtual machine's memory" 4. Click "OK" to create the snapshot 5. Note the **VM name** and **snapshot name** for use in the Kasm provider configuration If your Kasm startup script performs package operations on Ubuntu or another Debian-based system, add these exports at the top of the script. They prevent `needrestart` from interrupting service restarts mid-script and suppress interactive `apt` prompts. They are not needed on RHEL-family distributions or Windows. ```bash export NEEDRESTART_MODE=l export NEEDRESTART_SUSPEND=1 export DEBIAN_FRONTEND=noninteractive ``` #### Finish for Instant Clone After completing the OS preparation above, follow these additional steps to prepare the parent VM for instant cloning: 1. Ensure **VMware Tools** is installed and running in the guest OS 2. Power on the VM and verify it is fully booted and functional 3. Ensure the network interface is configured for DHCP—instant clones receive a new MAC address and must obtain a fresh IP. Most distributions (Ubuntu, Debian, etc.) use DHCP by default and require no changes. On **RHEL-family systems** (RHEL 8/9, Oracle Linux, Rocky Linux, AlmaLinux), however, NetworkManager binds profiles to MAC address by default, which prevents DHCP from working after the NIC hot-swap. To fix this, configure the profile to match by interface name instead (use `nmcli con show` to find the profile name): ```bash # RHEL 8 / CentOS 8 (profile typically named "System ens33") nmcli con mod "System ens33" 802-3-ethernet.mac-address "" nmcli con mod "System ens33" connection.autoconnect yes nmcli con mod "System ens33" match.interface-name ens33 # RHEL 9+ / Oracle Linux 9+ (profile typically named "ens33") nmcli con mod ens33 802-3-ethernet.mac-address "" nmcli con mod ens33 connection.autoconnect yes nmcli con mod ens33 match.interface-name ens33 ``` 4. **(Linux only)** Clear the machine ID so each clone receives a unique identity. The machine ID is used by the DHCP client to identify itself to the DHCP server—if all clones share the parent's ID, they may receive the same IP address. Clearing it immediately before freezing ensures each clone generates a fresh ID on wake-up: ```bash echo -n > /etc/machine-id ``` 5. Freeze the VM by running the following command **inside the guest OS**: **Linux:** ```bash vmware-rpctool "instantclone.freeze" ``` **Windows:** ```powershell & "C:\Program Files\VMware\VMware Tools\rpctool.exe" "instantclone.freeze" ``` 6. The VM will appear as powered on in vSphere but its guest OS is frozen. Note the **VM name** for use in the Kasm provider configuration - vSphere 6.7+ required - The frozen parent VM must remain powered on—do not power it off or delete it while instant clones may be created. If the VM is accidentally reset and the frozen state is lost, repeat the freeze step above to restore it. - To update the golden image, reset the frozen VM, boot normally, make your changes, then re-freeze. - The startup script requires OS-specific additions: on Ubuntu and other Debian-based systems, see the tip above about suppressing `needrestart` and `apt` prompts. On all Linux distros, restart Docker to rebuild networking after the NIC hot-swap. See the example instant clone scripts on [GitHub](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) ## Configure VM Provider Details on Kasm * Follow [AutoScale Settings for Agent Pool](../infrastructure-components/autoscale-config-docker-agent.mdx#autoscale-settings-for-agent-pool) or [AutoScale Settings for Server Pool](../infrastructure-components/autoscale-config-server.mdx#autoscale-settings-for-server-pool) to create a new AutoScale config, or select **Create New** in **VM Provider Configs** if you already have one. * Set Provider to "VMWare Vsphere" * Configure the following settings: * Submit the Provider Config When configuring VMware vSphere with Kasm Workspaces, one important item to keep in mind is datastore storage. When clones are created VMware will attempt to satisfy the clone operation if the datastore runs out of space, any VMs that are running on that datastore will be paused until space is available. Kasm Workspaces recommends that critical management VMs such as the vCenter server VM and cluster management VMs are on separate datastores that are not used for Kasm autoscaling. To update a linked clone source: power on the VM, apply updates, power off, take a new snapshot, then update the **Linked Clone Snapshot Name** in Kasm. Existing clones continue running but won't receive updates. Only delete old snapshots after all clones based on them are destroyed. ## Test your VMWare vSphere Autoscaling setup If you have configured non-zero Standby/Minimum Available Session values agents should start provisioning immediately. Otherwise, try launching multiple workspaces to increase resource utilization, prompting Kasm to autoscale new agents. * Provision a Workspace * Go to Workspaces > Registry * Make multiple workspaces available * Go to the Workspaces dashboard and launch sufficient workspace sessions to exceed your resource standby thresholds * Monitor the provisioning of new agents by going to "Infrastructure" -> "Agents" * Verify new VM instances in vSphere * Check Downscaling * Terminate sessions to reduce resource usage * Confirm that Kasm removes agents after the back-off period --- ## AutoScale Scheduling: Optimize Kasm Compute Costs # AutoScale Scheduling Kasm AutoScaling configurations have the capability of being scheduled for active times. This capability allows customers to save compute costs by turning off Kasm AutoScaling when that extra compute is not needed. AutoScale schedules are available as a tab when editing an AutoScale configuration. If no schedule is defined then the AutoScale configuration is considered active unless disabled. Kasm will not scale down a server that has active sessions on it, so the administrator can be assured they will not disrupt any existing Kasm sessions when the schedule becomes inactive. When an AutoScale configuration for **Docker Agents** is inactive any unused staged sessions will be removed and no new sessions (staged or user created) will be assigned to any **Docker Agents** that are part of the inactive AutoScale configuration. Since an AutoScale configuration with an inactive schedule will not provision any compute resources, the administrator may want two AutoScale configurations: one that has minimal standby compute available to minimize compute costs and one that has more substantial resources configured. This will allow users to always get a session even if it takes extra time on off hours. The administrator can even configure 0 for the standby cpu/memory/gpu during the off hours and allow session resource provisioning to be fulfilled fully on demand. Click on **Add Schedule** to create a new schedule for the AutoScaling configuration. On the **Add Schedule** screen there are fields for what days of the week this schedule should be active as well as both a start time, end time, and a timezone. Kasm will convert the time from the Kasm database to match the timezone specified when determining if a schedule is active or not. Multiple schedules can be defined for each AutoScale configuration. ## Example AutoScale Schedules Here are a few examples of how AutoScale schedules can be leveraged. This example is for a business whose core hours are 8 a.m. to 5 p.m., Monday through Friday. Each weekday, this configuration turns on autoscaling at 7 a.m. and turns it off at 6 p.m. This way, all compute is available well before the 8 a.m. start time and costs are reduced overnight and over the weekend, when there is no business need for the compute. The **Add Schedule** screen would look similar to this: A more complicated example would be if an Administrator wanted compute resources to come online at 3 p.m. Wednesday, and stay on until 11 a.m. Friday. For this the administrator would create three separate schedules on the autoscale config which would provide the desired functionality. The first schedule the administrator would select only wednesday, start time 3:00 p.m., and end time 11:59 p.m. The second schedule the administrator would select Thursday, with start time 12:00 a.m. and end time 11:59 p.m. The third schedule the administrator would select Friday, with start time 12:00 a.m. and end time 11:00 a.m. Here is an example of an overnight schedule where the start time is later than the end time. This will result in an overnight schedule. It will become active on the start time on the day(s) of the week selected, and will become inactive at the end time of the following day. In the following example the Autoscale configuration will become active on Tuesday and Thursday at 9:00 p.m. and will deactivate on Wednesday and Friday at 5:00 a.m. By using multiple schedules it is possible to configure multiple active times within a single day. Here morning shift is configured from 8:00 a.m. until 12:00 p.m. on Monday, Wednesday and Friday. The afternoon shift is configured from 2:00 p.m. until 6:00 p.m. on the same days. --- ## AutoScale: Dynamic Resource Management # AutoScale Overview **AutoScaling** is a powerful feature that dynamically provisions and destroys the number of available virtual machines (VMs) within a Pool based on a predefined schedule or real-time user demand. Kasm Workspaces offers **AutoScale** capabilities for both full-stack virtual machines (VMs) and containerized environments. It can dynamically provision and integrate full-stack VMs into a **Server Pool** to support **RDP, KasmVNC, VNC, and SSH** sessions. Additionally, Kasm can AutoScale **Docker Agent VMs** to efficiently manage and deploy container-based workspaces, ensuring optimal resource utilization and scalability. This feature is available in both the Community and Enterprise editions. If you're using an Enterprise edition, please contact a Kasm Technologies representative for details. ### Agents Agents are the compute resources that store workspace images and initiate sessions upon request. Kasm can autoscale agents based on a predefined schedule or real-time user demand. See [Docker Agents](../docker-agent.mdx) for more information. ### Servers Servers are the compute resources that support remote access to environments via protocols such as RDP, KasmVNC, VNC, and SSH. Similar to agents, Kasm can also autoscale servers based on a predefined schedule or real-time user demand. See [Servers](../servers.mdx) for more information. ### Startup Scripts Startup scripts install the Kasm components that a provisioned VM needs, such as the Kasm Agent role and the Kasm Desktop Service. Customize the scripts in the [AutoScale startup scripts GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts). The scripts support Debian-based and RPM-based Linux VMs, including Oracle Linux and RHEL, as well as Windows VMs. Some cloud providers enforce strict limits on startup script (user data) size. For example, AWS EC2 allows only 16 KB of Base64-encoded user data, which is roughly 12-13 KB of actual script content. If you customize the autoscale startup scripts, verify that the result stays within your provider's limit. If your script exceeds the limit, consider hosting it externally (e.g., in an object storage bucket) and having the user data fetch and execute it at boot. ### Zones A strategic organizational grouping of Kasm services that enables advanced resource management, geographic distribution, and logical segmentation. Zones are strongly tied to the Kasm manager role. Once a manager is assigned to a zone, it is responsible for the Kasm resources and operations of the workspaces within that zone. Learn more about [Deployment Zones in Kasm.](../deployment-zones.mdx) ![Create AutoScale config from Pools](/img/zones/deployment_zones_diagram.png) ### Upstream Auth Address This is the endpoint used to authenticate connections to Kasm sessions. It must be correctly set to the address of the resource hosting the Kasm API server. Ensuring proper configuration is essential for newly provisioned VMs to authenticate within the designated Zone. Incorrect settings may result in authentication failures or potential security risks, such as unauthorized access. See [Update Zones](../../networking/reverse-proxy.mdx#update-zones) for more information. - In a **single-server architecture**, this address is set to `proxy` by default which refers to the local proxy. When configuring the Autoscaling feature, the default value must be changed to the actual IP/FQDN of your Kasm server so that the autoscaled agents can report back to your Kasm deployment. - For a **multi-server architecture**, the Web App server's IP/FQDN, or the load balancer's IP/FQDN servicing the Web App servers must be specified for the corresponding Zone. ### Network Communication Requirements **Manager-to-Agent**: Kasm Managers must reach agents on **port 443** (or custom configured port) for provisioning and management. Ensure firewalls/security groups allow this outbound connection. **Agent-to-Manager**: Agents communicate back via the Upstream Auth Address configured in Zone settings on **port 443** (or custom configured port). Ensure your network security groups, firewalls, and routing configurations allow communication **on the required Ports**. Without this connectivity, agents will fail to provision correctly and appear as unreachable in the system. ## Pools Pools can be used to group a set of similar fixed systems together, so they can be treated as a single Workspace for user access. Users will see a single Workspace icon on their dashboard, but their session will get distributed to an available server in the pool. Each server in the pool can be set to support 1 or more concurrent sessions. Kasm automatically distributes the sessions evenly over the servers. You can create two different types of pools in Kasm: * **Docker Agent Pools:** These pools contain Linux-based VMs running a Docker engine. They're designed for hosting Linux-based workspaces. Each VM within a Docker Agent pool can run multiple workspace containers. * **Server Pools:** These pools contain Windows-based VMs. They're designed for hosting Windows-based workspaces. Each VM in a Server pool typically provides a single Windows desktop experience, often accessed via RDP. AutoScaling is available in the Community and Enterprise editions only. If applicable, the administrator will have 3 links underneath the table for **All AutoScale Configs**, **All VM Provider Configs** and **All DNS Provider Configs**. These allow the administrator to see all of the configs available and make changes, but the recommended approach is to use the **Edit** option on a specific pool. ![Server Pools](/img/compute/pools.webp) ## Create Pool - Click the **Infrastructure** item in the navigation menu. - Select the **Pools** option in the dropdown menu. - Select **Add** from the top right of the **Pools** table. - Provide a name for the server pool. - Choose the pool type. It can be either Docker Agent or Server. ![Create Pool](/img/autoscaling/pool_create.png) ## AutoScale Configuration Kasm has the ability to automatically provision and destroy [Servers](../../../reference/glossary.mdx#server) and Docker [Agents](../../../reference/glossary.mdx#agent) based on user demand. The AutoScale configuration differs slightly between Servers and Agents. There are two ways to create an Autoscale config: * **Method 1**: Go to "Infrastructure" -> "Pools" -> Edit your Pool -> "AutoScale Configurations" tab -> "Add". The AutoScale type and Pool will be auto-populated based on your selected Pool. ![Create AutoScale config from Pools](/img/autoscaling/autoscale_config_create_from_pool.png) * **Method 2**: Go to "Infrastructure" -> "Pools" -> "All AutoScale Configs" -> "Add". Then choose the correct Autoscale Type and Pool. ![Create AutoScale config](/img/compute/autoscale_list.webp) AutoScale configurations differ between Docker Agent Pools and Server Pools. * Docker Agents: Designed for **Linux VMs** with the Docker Engine installed. These VMs dynamically provision and manage container-based workspaces to optimize resource utilization. * Servers: Designed for compute resources (**Windows and Linux**) that support RDP, KasmVNC, VNC, and SSH connections, allowing remote access to full desktop environments or specific applications. Select the appropriate configuration guide based on your deployment needs: * [Autoscale Configuration (Docker Pool)](infrastructure-components/autoscale-config-docker-agent.mdx) * [Autoscale Configuration (Server Pool)](infrastructure-components/autoscale-config-server.mdx) ## AutoScale Scheduling AutoScale Scheduling in Kasm Workspaces allows administrators to define specific active periods for AutoScaling, optimizing resource usage and reducing costs. By setting schedules, AutoScaling can automatically provision or scale down compute resources based on predefined times. * **Benefits**: Saves compute costs by deactivating AutoScaling when resources are not needed. * **How It Works**: Administrators can configure schedules per AutoScale configuration, defining active days, start/end times, and time zones. * **Flexibility**: Supports different scheduling strategies, including business-hour scaling, overnight schedules, and multi-day configurations. * **Key Considerations**: Servers with active sessions will not be scaled down, ensuring uninterrupted user access. To learn more about configuring AutoScale Scheduling, refer to the **[AutoScale Scheduling Documentation](autoscale-scheduling.mdx)**. ## Provider Specific Settings Kasm supports AutoScaling on a variety of providers. Each provider has unique configurations that must be set up correctly for optimal performance. Select your provider to learn more: - AWS - Azure - Digital Ocean - GCP - Harvester - KubeVirt - Nutanix - OpenStack - Oracle Cloud (OCI) - Proxmox - VMWare vSphere --- ## AutoScale Config: Docker Agent Pools # AutoScale Configuration (Docker Agent Pool) This section covers the AutoScale configuration for Pools of type "Docker Agent". ![Create Autoscale Agent](/img/compute/create_autoscale_agent.webp) ## AutoScale Settings for Agent Pool Many of the settings below apply to the agents that are created during autoscaling. When changing these settings on an autoscale config they are not automatically applied to existing agents and they must be manually updated on existing agents that were created from that autoscale config. * Configure the following settings in your Kasm deployment. | Name | Description | | :------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | Whether to enable this config or not. If disabled, autoscaled agents from this config **cannot be manually deleted**. Re-enable the config to remove them. | | **Name** | Name for the AutoScale config . | | **AutoScale Type** | The type of AutoScale confog this is, either a Docker Agent or a Server. | | **Pool** | Which pool this AutoScale config is attached to. | | **Aggressive Scaling** | When enabled, the system may take more expedient measures to provision raw compute resources for on-demand session requests. See [Aggressive Scaling](autoscale-config-server#aggressive-scaling) for more details. | | | **Deployment Zone** | Which zone this AutoScale config applies to. | | **Downscale Backoff (Seconds)** | This setting prevents prevents the system from downscaling (deleting Agents) for this amount of time (in seconds) when needed. This is useful for preventing the system from thrashing up and down if the available resource hover around an interval that would typically trigger autoscaling. | | **Standby Cores** | The number of standby cores that the system should try to keep "always available" at any given time in addition to any that is needed to satisfy the Staging Config requirements. If the number of available cores falls below this number, more Agents are created. If the number of available cores rises above this number, Agents are deleted as long as it wont result in the number of available cores falling below this number. A value of 0 indicates no additional standby compute is created. The AutoScaler will only provision enough compute according to the Staging Config requirements. | | **Standby GPUs** | The number of standby GPUs that the system should try to keep "always available" at any given time in addition to any that is needed to satisfy the Staging Config requirements. If the number of available GPUs falls below this number, more Agents are created. If the number of available GPUs rises above this number, Agents are deleted as long as it wont result in the number of available GPUs falling below this number. A value of 0 indicates no additional standby compute is created. The AutoScaler will only provision enough compute according to the Staging Config requirements. | | **Standby Memory** | The amount of memory that the system should try to keep "always available" at any given time in addition to any that is needed to satisfy the Staging Config requirements. If the amount of available memory falls below this number, more Agents are created. If the amount of available memory rises above this number, Agents are deleted as long as it wont result in available amount falling below this number. Values entered in the UI are stored as bytes (`standby_memory_bytes`) and the unit selector supports Bytes/MiB/GiB. When using the Admin API, supply the number of bytes. A value of 0 indicates no additional standby compute is created. The AutoScaler will only provision enough compute according to the Staging Config requirements. | | **Agent Cores Override** | When an Agent is created, the compute resource (e.g AWS EC2 / Digital Ocean Droplet) will have a set amount of CPU and Ram as defined by the cloud provider's instance type. This setting should typically be set to match the instance type but can be set to a preferred value. | | **Agent GPUs Override** | When an Agent is created, the compute resource (e.g AWS EC2 / Digital Ocean Droplet) will have a set number of GPUs as defined by the cloud provider's instance type. This setting should typically be set to match the instance type but can be set to a higher number to allow oversubscribing. | | **Agent Memory Override** | When an Agent is created, the compute resource (e.g AWS EC2 / Digital Ocean Droplet) will have a set amount of CPU and RAM as defined by the cloud provider's instance type. This setting should typically be set to match the instance type but can be set to a preferred value. The UI stores the value as bytes (`agent_memory_override_bytes`) and exposes a unit selector (Bytes/MiB/GiB) for convenience. API clients must send the number of bytes. | | **Rotate Agent in (Days)** | The number of days until Agents are Drained and replaced with new Agents. This sets the "Drain Time" of the agent when it is created. A value of "0" disables this function. **Note:** Existing agents will not be updated when this field is changed. To apply new rotation settings to existing agents, each existing agent must be manually updated. | | **Pre Warm Rotated Agent Replacements for (Minutes)** | The number of minutes before the Agent's "Drain Time" that Kasm will begin provisioning a replacement Agent. This allows time for a replacement Agent to be installed before the old agent is rotated out. A value of "0" disables this function. | | **Register DNS** | If enabled, the Agent's IP will be registered in DNS. | | **Base Domain Name** | Define a base name for the automatic DNS registration for the Agent. The system will create a full name using ``.\. If the Base Domain Name is "agents.kasm.example.com", the full DNS name generated will be ``.agents.kasm.example.com (e.g 123abcd.agents.kasm.example.com). This Base Domain Name, must already be a registered DNS zone within the cloud provider's DNS system. | * Click "Next" and you will now be prompted to enter your [provider-specific details](../autoscale-providers/oci.mdx). ## Pre-load Workspace Images on Agents Pre-loading workspace images on your provisioned agents helps eliminate delays caused by image downloads after the VMs are brought online. Follow the [Pre-load Workspace Images on Agents guide](../../preload-images-on-agents.mdx) to learn how to fetch workspace images using the Kasm API and bake them into your VM templates for faster and more efficient autoscaling. ## Provider Specific Settings Kasm supports AutoScaling on a variety of providers. Each provider has unique configurations that must be set up correctly for optimal performance. Select your provider to learn more: - AWS - Azure - Digital Ocean - GCP - Harvester - KubeVirt - Nutanix - OpenStack - Oracle Cloud (OCI) - Proxmox - VMWare vSphere --- ## AutoScale Configuration: Server Pools # AutoScale Configuration (Server Pool) This section covers the AutoScale configuration step of the Wizard for Pools of type "Server". ## AutoScale Settings for Server Pool Many of the settings below apply to the servers that are created during autoscaling. When changing these settings on an autoscale config they are not automatically applied to existing servers and must be manually updated on existing servers that were created from that autoscale config. * Configure the following settings in your Kasm deployment. | Name | Description | | :------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Enabled** | Whether to enable this config or not. If disabled, autoscaled agents from this config **cannot be manually deleted**. Re-enable the config to remove them. | | **Name** | Name for the AutoScale config. | | **AutoScale Type** | The type of AutoScale config this is, either a Docker Agent or a Server. | | **Pool** | Which pool this AutoScale config is attached to. | | **Aggressive Scaling** | When enabled, the system may take more expedient measures to provision raw compute resources for on-demand session requests. See [Aggressive Scaling](#aggressive-scaling) for more details. | | **Deployment Zone** | Which zone this AutoScale config applies to. | | **Downscale Backoff (Seconds)** | This setting prevents prevents the system from downscaling (deleting Servers) for this amount of time (in seconds) when needed. This is useful for preventing the system from thrashing up and down if the available resource hover around an interval that would typically trigger autoscaling. | | **Require Checkin** | When enabled, the system will wait to receive a callback from the newly created server to set its status to Running. The callback may come from the Kasm Windows Service or by calling the `set_server_status` API. See [require_checkin](#require-checkin) for more details. | | **Kasm Desktop Service Installed** | When enabled, the sytem will assume the Kasm Desktop Service is installed, enabling workflows that require the agent. | | **Connection Type** | Whether to use KasmVNC or RDP, VNC, or SSH. | | **Connection Port** | Which port to connect on. | | **Connection Credential Type** | Which type of credentials are used for this server. Options are Static Credentials, Dynamic User Accounts, SSO User Accounts, and Authenticate with Smartcard. See [sso_windows_ldap](../windows-autoscale-templates.mdx), [ssh_authentication_options](#authentication-options-when-connecting-to-an-ssh-server) | | **SSO Domain** | The domain to use for SSO User Accounts **Connection Credential Type**. A blank entry will pass the username to Windows exactly as it is in Kasm. A value of localhost will instruct Kasm to drop any domain part from the Kasm username i.e. john_smith@example.com becomes john_smith when passed to Windows. | | **Connection Username** | Which username to connect to the server with. Only visible with Static Credentials **Connection Credential Type**. | | **Connection Password** | Which password to connect to the server with. Only visible with Static Credentials **Connection Credential Type**. | | **Use User SSH Key** | Whether to use the SSH keys assigned to a Kasm user. (Only applicable to SSH connection type) | | **Connection Private Key** | The private key to authenticate against the SSH server with. (Only applicable to SSH connection type) | | **Connection Private Key Passphrase** | The passphrase encrypting the specified private key. (Only applicable to SSH connection type) | | **Connection Info (JSON)** | Any extra connection info. | | **Create Active Directory Computer Record** | Whether to create an active directory record or not. See [ad_computer_record](#create-active-directory-computer-record) | | **Reusable** | Whether the connection reusable. | | **Minimum Available Sessions** | The minimum available sessions that should be free. Auto scale more resources if under this threshold. | | **Max Simultaneous Sessions Per Server** | Max sessions per server allowed. See [max_simultaneous_sessions_per_server](autoscale-config-server.mdx#max-simultaneous-sessions-per-server) | | **Max Simultaneous Users** | For RDP/SSH servers, the number of concurrently connected users per server. | | **Expire Servers in (Days)** | The number of days until autoscaled servers are placed into "Draining" mode and replaced with new servers. This sets each server's "Drain Time" when it is created. A value of "0" disables this function. **Note:** Existing autoscaled servers are not updated when this field is changed. To apply new rotation settings to existing servers, update each server manually. | | **Pre Warm Rotated Server Replacements for (Minutes)** | The number of minutes before the Server's "Drain Time" that Kasm will begin provisioning a replacement Server. This allows time for a replacement Server to be provisioned before the old Server is rotated out. A value of "0" disables this function. | * Click "Next" and you will now be prompted to enter your [provider-specific details](../autoscale-providers/oci.mdx). ### Max Simultaneous Sessions Per Server For RDP and SSH servers, the `Max Simultaneous Session Per Server` and `Max Simultaneous Users` work together. SSH and RDP support multiple sessions per user per server. For RDP this is typically found in RemoteApp use cases. For SSH and RemoteApp servers you may want 1 server to handle just 2 concurrent users but up to 10 concurrent sessions each. These settings are used for two purposes, auto-scaling and deciding where to assign new sessions to. For auto scaling, Kasm periodically checks to see that it has resource availability to create `Minimum Available Sessions` on the existing servers in the pool. It checks how many sessions and how many new users each server can handle, it uses the lower of those two values to determine how many new sessions each existing server can likely handle. If the total from all servers is less than the `Minimum Available Sessions`, new servers are created until it reaches the desired capacity. Kasm will not allow a single user to provision multiple RDP desktops per server. Only RemoteApps are allowed to be assigned to the same server for a single user. Kasm will allow one desktop and multiple RemoteApps on the same server for a user. ### Require Checkin The **Require Checkin** flag can be used to ensure the system waits until a newly created server is fully ready before allowing a users session to connect. Administrators may use the autoscale startup script to ensure the desired configurations and services are properly initialized (e.g RDP is enabled and running). If using Windows sessions, administrators may use the [Kasm Desktop Service](../../../workspaces-sessions/server-workspace/windows/kds-windows-service.mdx). All systems may use the `set_server_status` API. ```md POST /api/set_server_status?token={checkin_jwt} ``` **Example request**: ```json { "status": "running", "status_message": "Initialization Complete", "status_progress": "100" } ``` ```bash curl -k -X POST -H "Content-Type: application/json" -d '{{"status": "running", "status_message": "Initialization Complete", "status_progress": "100"}}' https://{upstream_auth_address}/api/set_server_status?token={checkin_jwt} ``` Additional examples are available in the [workspaces-autoscale-startup-scripts](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/) repo. ### Create Active Directory Computer Record As covered in the above table, the AutoScaling configuration for a Server Pool allows the administrator to automatically join new VMs to an active directory domain. If the checkbox for **Create Active Directory Computer Record** is checked two additional fields will be shown, **LDAP Config** and **Active Directory Computer OU DN**. Kasm Workspaces creates the AD Computer record, but it **does not join the computer to the domain**, this needs to be done on the system itself. When Kasm creates the AD record, a temporary randomly generated password is created which can be used on the target VM to join it to Active Directory. Kasm can inject this password in a PowerShell script on the VM. That PowerShell script needs to be executed when the VM starts up, in order to complete the process of adding the VM to Active Directory. Below is an example PowerShell script, the special tags `{ad_join_credential}` and `{domain}` will be replaced by Kasm with the randomly generated password and domain name respectively. This script is placed in the [VM Provider](../vm-providers.mdx) configuration in the Startup Script field. ```powershell $joinCred = New-Object pscredential -ArgumentList ([pscustomobject]@{{ UserName = $null; Password = (ConvertTo-SecureString -String '{ad_join_credential}' -AsPlainText -Force)[0] }}) Add-Computer -Domain "{domain}" -Options UnsecuredJoin,PasswordPass -Credential $joinCred -Force -Restart ``` Some cloud providers will automatically execute this startup script when the VM boots, making it easy to get auto AD joining working end-to-end. Other cloud providers, such as Azure, do not automatically execute this script. See the details of each [VM Config Provider](../vm-providers.mdx). **LDAP Config** The LDAP Config drop down allows the administrator to select which [LDAP configuration](../../../security/users-groups-mgmt/ldap.mdx) to use to add the computer record to Active Directory. The LDAP Configuration does not have to be enabled, this allows the administrator to use one LDAP configuration for Authentication and another for AD Computer record creation. If using LDAP for end-user authentication to Kasm Workspaces, the administrator can also configure single-sign on to the Windows systems. **Active Directory Computer OU DN** This is the DN of the Active Directory Computer OU that the administrator would like the computer records placed in. The LDAP config must be using an SSL secured LDAPS connection or the LDAP server will not permit Kasm to create the AD Computer record. ### Single Sign-On to Windows Systems via LDAP When users login to Kasm via [LDAP Authentication](../../../security/users-groups-mgmt/ldap.mdx), they are able to create sessions to Windows systems that are joined to the same Active Directory domain and are configured for SSO credential pass-through. In the above table covering the Auto Scale configuration fields for Server Pools is the **Connection Credential Type** field. Select the value *SSO User Accounts* in the Auto Scale configuration for the Server Pool. This requires that all users accessing servers in this Server Pool are authenticated to Kasm using LDAP authentication. See our Windows Deployment Guide video for a walk through of this topic and more. ### Authentication Options When Connecting to an SSH Server Kasm Workspaces has the ability to connect to arbitrary SSH servers. It can use SSH key or password authentication. There are a few combinations of options on the Autoscale Config edit screen that can be selected. The Autoscale Config can be configured to use: - Username/password authentication - Username and select the `Use User SSH Key` to send the username and private key stored with the Kasm user. - Username and a pasted in private key, optionally you can include a passphrase if the key has one. Select the value *SSO User Accounts* in the **Connection Credential Type** field and check the **Use User SSH Key** checkbox and Kasm Workspaces will send the user's Kasm Workspaces username along with the user's Kasm Workspaces SSH key allowing easy multiple user support on SSH servers. There are some restrictions on the ssh keys supported that are enforced by the connection proxy library used for the ssh server connections: The SSH key can be in either OpenSSH format (beginning with `-----BEGIN OPENSSH PRIVATE KEY-----`) or RSA PKCS1 format (beginning with `-----BEGIN RSA PRIVATE KEY-----` or `-----BEGIN PRIVATE KEY-----`) with a key size of 2048. When using RSA keys with some newer Linux distributions such as Ubuntu 22.04 LTS, you may need to edit the `/etc/ssh/sshd_config` file on the target server and add these two lines to the config: ```bash HostKeyAlgorithms +ssh-rsa PubkeyAcceptedKeyTypes +ssh-rsa ``` ### Aggressive Scaling Starting in Workspaces 1.14.0, administrators can choose to leverage fully on-demand compute resources for container and server/server pool based sessions. When users requests a session, and no compute is available, the system will queue the request, provision the resources according to the autoscale configs, then fulfill the request. This will prevent the user from receiving a No Resources error. Instead, the user will be presented with a status indicator while the request is fulfilled, which may take several minutes. This can be used alongside the existing standby and staging mechanism to give the administrator more options to balance compute costs with session delivery times. Enabling **Aggressive Scaling** in the Autoscale Config, instructs the system to make more opportunistic choices when requesting resources, with the goal of reducing the users wait time. This mode may result in compute resources being utilized in less cost-efficient ways, since users may end up on separate machines instead of pooled together depending on the circumstance. This mode may also result in the system scaling slightly beyond the max instances defined on the associated VM Provider due to the potential concurrent nature of resource provisioning. ## Provider Specific Settings Kasm supports AutoScaling on a variety of providers. Each provider has unique configurations that must be set up correctly for optimal performance. Select your provider to learn more: - AWS - Azure - Digital Ocean - GCP - Harvester - KubeVirt - Nutanix - OpenStack - Oracle Cloud (OCI) - Proxmox - VMWare vSphere ## Windows Templating To AutoScale Windows resources in Kasm Workspaces, you must first create Windows templates that will serve as the base images for provisioning new instances. These templates should include necessary configurations such as licensing considerations, required drivers, guest agents, sysprep, domain join settings, and any additional software required for your deployment. Properly prepared templates ensure seamless AutoScaling and optimal resource utilization. For more details about Windows templates, refer to the [Windows AutoScale Template Creation Guide](../windows-autoscale-templates.mdx) --- ## Kasm Workspaces: Compute VM Provider Configuration & Auto Scaling # VM Providers ## VM provider configs :::note AutoScaling is available in the Community and Enterprise editions only. For more information on licensing, visit [Licensing](../reference/license.mdx). ::: | **Name** | **Description** | | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **VM Provider Configs** | Select an existing config or create a new config. When you change the details of an existing config, those details change for everything that uses the same VM provider config. | | **Provider** | Select a provider from AWS, Azure, Digital Ocean, Google Cloud, or Oracle Cloud. When you select an existing provider, Kasm selects this automatically. | ## AWS settings A number of settings are required to use this functionality. The AWS settings appear in the Pool configuration when the feature is licensed. ![AWS Settings](/img/compute/vm_aws.webp) | **Name** | **Description** | | --- | --- | | **Name** | A name to use to identify the config. | | **AWS Access Key ID** | The AWS Access Key used for the AWS API. | | **AWS Secret Access Key** | The AWS Secret Access Key used for the AWS API. | | **AWS: Region** | The AWS Region the EC2 Nodes should be provisioned in. e.g (us-east-1) | | **AWS: EC2 AMI ID** | The AMI ID to use for the provisioned EC2 nodes. This should be an OS that is supported by the Kasm installer. | | **AWS: EC2 Instance Type** | The EC2 Instance Type (e.g t3.micro). Note the Cores and Memory override settings don't necessarily have to match the instance configurations. This is to allow for over provisioning. | | **AWS: Max EC2 Nodes** | The maximum number of EC2 nodes to provision regardless of the need for available free slots | | **AWS: EC2 Security Group IDs** | A Json list containg security group IDs to assign the EC2 nodes. e.g `["sg-065ae66f2d", "sg-02522kdkas"]` | | **AWS: EC2 Subnet ID** | The subnet ID to place the EC2 nodes in. | | **AWS: EC2 EBS Volume Size** | Select the root EBS volume size for the EC2 nodes. The admin console accepts Bytes/GiB and stores the value as bytes (`aws_ec2_ebs_volume_size_bytes`). API integrations must submit the number of bytes using whole GiB (2^30) increments. | | **AWS: EC2 EBS Volume Type** | The EBS Volume Type (e.g gp2) | | **AWS: EC2 IAM** | The IAM to assign the EC2 Nodes. Administrators may want to assign CloudWatch IAM access. | | **AWS: EC2 Custom Tags** | A Json dictionary for custom tags to assigned on auto-scaled Agent EC2 Nodes. e.g `{"foo":"bar", "bin":"baz"}` | | **AWS: EC2 Startup Script** | When the EC2 Nodes are provision this script is executed. The script is responsible for installing and configuring the Kasm Agent. | | **Retrieve Windows VM Password from AWS** | When provisioning an AWS Windows VM Kasm can retrieve the password generated by AWS and store it in the Server configuration record created during the AutoScale provision. This will only happen if the **Connection Password** field from the attached AutoScale config is blank. When populated Kasm will use the defined value instead of what is returned from AWS. The Administrator may want to leave this field blank and disable retrieving the password from AWS if they wish the Kasm user to be presented with a login screen to manually enter credentials upon connecting to the Windows Workspace. NOTE: This setting only affects Windows (RDP connection type) AWS instances. | | **SSH Keys** | The SSH Key pair to assign the EC2 node | | **AWS Config Override (JSON)** | Custom configuration may be added to the provision request for advanced use cases. Instance configuration is overridden in the 'instance_config' configuration block e.g. `{"instance_config":{"EbsOptimized": true}}` [See EC2 Documentation for available options.](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/run_instances.html) | ## Azure settings A number of settings are required to use this functionality. The Azure settings appear in the Pool configuration when the feature is licensed. ## Register Azure app Kasm requires an API key to interface with Azure. Azure calls these keys apps. The example walks through registering one along with the required permissions. 1. Register an app by going to the Microsoft Entra ID service in the Azure portal. 2. From the **Add** dropdown select **App Registration** 3. Give this app a human-readable name such as **Kasm Workspaces** 4. Go to **Resource Groups** and select the **Resource Group** that Kasm uses for AutoScaling. 5. Select **Access Control (IAM)** 6. From the **Add** drop down select **Add role assignment** 7. The app created in Azure needs four roles. First, select the *Virtual Machine Contributor* role. On the next page, select the app by typing in the name, for example **Kasm Workspaces**. 8. Repeat this process to add the *Network Contributor*, *DNS Zone Contributor*, and *Compute Gallery Image Reader* roles. ## Azure VM settings A number of settings are required to use this functionality. The Azure settings appear in the Pool configuration when the feature is licensed. ![Azure VM](/img/compute/vm_azure.webp) | **Name** | **Description** | | --- | --- | | **Name** | A name to use to identify the config. | | **Subscription ID** | The Subscription ID for the Azure Account. This can be found in the Azure portal by searching for Subscriptions in the search bar in Azure home then selecting the subscription to use. (e.g `00000000-0000-0000-0000-000000000000`) | | **Resource Group** | The Resource Group the DNS Zone and/or Virtual Machines belong to (e.g `dev`) | | **Tenant ID** | The Tenant ID for the Azure Account. This can be found in the Azure portal by going to Microsoft Entra ID using the search bar in Azure home. (e.g `00000000-0000-0000-0000-000000000000`) | | **Client ID** | The Client ID credential used to auth to the Azure Account. Client ID can be obtained by registering an application within Microsoft Entra ID. (e.g `00000000-0000-0000-0000-000000000000`) | | **Client Secret** | The Client Secret credential created with the registered application in Microsoft Entra ID. (e.g `abc123`) | | **Azure Authority** | Which Azure authority to use, there are four, Azure Public Cloud, Azure Government, Azure China and Azure Germany. | | **Region** | The Azure region where the Agents will be provisioned. (e.g `eastus`) | | **Max Instances** | The maximum number of Azure VMs to provision regardless of the need for additional resources. | | **VM Size** | The size configuration of the Azure VM to provision (e.g `Standard_D2s_v3`) | | **OS Disk Type** | The disk type to use for the Azure VM. (e.g `Premium_LRS`) | | **OS Disk Size** | Select the boot volume size to assign the compute instance. The admin console accepts Bytes/GiB and stores the value as bytes (`azure_os_disk_size_bytes`). API integrations must submit the number of bytes in whole GiB (2^30) increments. | | **OS Image Reference (JSON)** | The OS Image Reference configuration for the Azure VMs (e.g `{"publisher":"canonical","offer":"0001-com-ubuntu-server-jammy","sku":"22_04-lts-gen2","version":"latest"}` or `{"id":"/subscriptions/000.../resourceGroups/dev/providers/Microsoft.Compute/galleries/development-gallery/img/ubuntu-22.04-custom"}`) | | **Image is Windows** | Is this a windows VM being created | | **Plan Name** | Plan Name for the VM image. This is optional, and is only required for images from the marketplace or custom images derived from a marketplace image. | | **Plan Product** | Plan Product for the VM image. This is optional, and is only required for images from the marketplace or custom images derived from a marketplace image. | | **Plan Publisher** | Plan Publisher for the VM image. This is optional, and is only required for images from the marketplace or custom images derived from a marketplace image. | | **Security Type** | Which features used (if any) to security the VM. This is optional, but may be required for certain Windows VMs such as Windows 10 and Windows 11. | | **Secure Boot Enabled** | Whether or not Secure Boot is enabled for the VM. This is not enabled by default, but may be required for certain Windows VMs such as Windows 11. | | **TPM Enabled** | Whether or not TPM is enabled for the VM. This is not enabled by default, but may be required for certain Windows VMs such as Windows 11. | | **Network Security Group** | The network security group to attach to the VM (e.g `/subscriptions/000.../resourcegroups/dev/providers/Microsoft.Network/networkSecurityGroups/example-nsg`) | | **Subnet** | The subnet to attach the VM to (e.g `/subscriptions/000.../resourceGroups/dev/providers/Microsoft.Network/virtualNetworks/development-vnet/subnets/default`) | | **Assign Public IP** | If checked, the VM will be assigned a public IP. If no public ip IP is assigned the VM must ne attached to a standard load balancer of the subnet must have a NAT Gateway or user-defined route (UDR). If a public IP is used, the subnet must not also include a NAT Gateway. [Reference](https://docs.microsoft.com/en-us/azure/virtual-network/ip-services/default-outbound-access) | | **Tags (JSON)** | A JSON dictionary of custom tags to assign to the VMs (e.g `{"foo":"bar", "bin": "baz"}` ) | | **OS Username** | The login username to assign to the new VM (e.g `testuser`) | | **OS Password** | The login password to assign to the new VM. Note: Password authentication is disabled for SSH by default | | **SSH Public Key** | The SSH public key to install on the VM for the defined user: (e.g `ssh-rsa AAAAAAA....`) | | **Agent Startup Script** | When instances are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent. | | **Config Override (JSON)** | Custom configuration may be added to the provision request for advanced use cases. The emitted json structure is visible by clicking **JSON View** when inspecting the VM in the Azure console. The keys in this configuration can be used to update top level keys within the emitted json config (e.g `{"location":"eastus"}`). Nested items can be updated by using dot notation in the key (e.g `{"hardware_profile.vm_size":"Standard_D4s_v3"}`) Exiting array elements can be updated by specifying the index in the dot notation (e.g `{"os_profile.linux_configuration.ssh.public_keys.0.path":"/home/ubuntu/.ssh/authorized_keys"}`) | ## Digital Ocean settings :::note A detailed guide on Digital Ocean AutoScale configuration is available here. ::: :::warning Review [Tag Does Not Exist Error](#tag-does-not-exist-error) for known issues and workarounds. ::: ![Digital Ocean VM Provider](/img/compute/vm_do.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Token** | The token to use to connect to this VM | | **Max Droplets** | The maximum number of Digital Ocean droplets to provision , regardless of whether more are needed to fulfill user demand. | | **Region** | The Digital Ocean Region where droplets should be provisioned. (e.g nyc3) | | **Image** | The Image to use when creating droplets. (e.g docker-24-04). See [Digital Ocean documentation](https://docs.digitalocean.com/products/droplets/details/img/) for more details. | | **Droplet Size** | The droplet size configuration (e.g c-2). See [https://slugs.do-api.dev](https://slugs.do-api.dev/) for more details | | **Tags** | A tag(s) to assign the droplet when it is created. This should be a comma separated list of tags. | | **SSH Key Name** | The SSH Key to assign to the newly created droplets. The SSH Key must already exist in the Digital Ocean Account. | | **Firewall Name** | The name of the Firewall to apply to the newly created droplets. This Firewall must already exist in the Digital Ocean Account. Go to your Digital Ocean dashboard -> "Networking" -> "Firewalls" to view existing firewalls or create a new firewall | | **Startup Script** | When droplets are provisioned this script is executed. The script is responsible for installing and configuring the Kasm Agent. Example scripts can be found on our [GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) | ### Tag does not exist error When you first test AutoScaling with Digital Ocean, an error similar to the following may appear: ```yml // highlight-next-line Future generated an exception: tag zone:abc123 does not exist traceback: .. File "digitalocean/Firewall.py", line 225, in add_tags File "digitalocean/baseapi.py", line 196, in get_data digitalocean.DataReadError: tag zone:abc123 does not exist process: manager_api_server ``` This error occurs when Kasm Workspaces tries to assign a unique tag based on the Zone ID to the Digital Ocean Firewall. When that tag does not already exist in Digital Ocean, the operation fails and presents the error. To work around the issue, manually create a tag matching the one specified in the error, for example `zone:abc123`, through the Digital Ocean console. Create the tag through the API or by adding it to a temporary Droplet. ## Google Cloud (GCP) settings :::note A detailed guide on GCP AutoScale configuration is available here. ::: ![GCP VM Provider](/img/compute/vm_google.webp) | Name | Description | | --- | --- | | **Name** | An identifying name for this provider configuration e.g. Google Cloud (GCP) Docker Agent AutoScale Provider | | **GCP Credentials** | The JSON formatted credentials for the service account used to authenticate with GCP: [Ref](https://cloud.google.com/iam/docs/creating-managing-service-account-keys#iam-service-account-keys-create-console) | | **Max Instances** | The maximum number of GCP compute instances to provision regardless of the need for additional resources. | | **Project ID** | The Google Cloud Project ID (e.g pensive-voice-547511) | | **Region** | The region to provision the new compute instances. (e.g us-east4) | | **Zone** | The zone the new compute instance will be provisioned in (e.g us-east4-b) | | **Machine Type** | The Machine type for the GCP compute instances. (e.g e2-standard-2) | | **Machine Image** | The Machine Image to use for the new compute instance. (e.g projects/ubuntu-os-cloud/global/img/ubuntu-2204-lts) | | **Boot Volume Size** | Select the boot volume size to assign the compute instance. The admin console accepts Bytes/GB and stores the value as bytes (`gcp_boot_volume_bytes`). API integrations must submit the number of bytes in whole GB (10^9) increments. | | **Disk Type** | The disk type for the new instance. (e.g pd-ssd, pd-standard, etc.) | | **Customer Managed Encryption** **Key (CMEK)** | The optional path to the Customer Managaged Encryption Key (CMEK) (e.g projects/pensive-voice-547511/locations/global/keyRings/my-keyring/cryptoKeys/my-key | | **Network** | The path of the Network to attach the new instance. (e.g projects/pensive-voice-547511/global/networks/default) | | **Sub Network** | The path of the Sub Network to attach the new instance.(e.g projects/pensive-voice-547511/regions/us-east4/subnetworks/default) | | **Public IP** | If checked, a public IP will be assigned to the new instances | | **Network Tags (JSON)** | A JSON list of the Network Tags to assign the new instance. (e.g `["https-server", "foo", "bar"]`) | | **Custom Labels (JSON)** | A JSON dictionary of Custom Labels to assign the new instance (e.g `{"foo": "bar", "bin":"baz"}`) | | **Metadata (JSON)** | A JSON list of metadata objects to add to the instance. (e.g `[{"key": "ssh-keys", "value":"user1:ssh-rsa user1"}]`) [Reference](https://cloud.google.com/compute/docs/connect/add-ssh-keys#add_ssh_keys_to_instance_metadata) | | **Service Account (JSON)** | A JSON dictionary representing for a service account to attach to the instance. (e.g `{"email": "service-account@example.com", "scopes":["https://www.googleapis.com/auth/cloud-platform"]}`) [Reference](https://cloud.google.com/iam/docs/creating-managing-service-account-keys#iam-service-account-keys-create-gcloud) | | **Guest Accelerators (JSON)** | A JSON list representing the guest accelerators (e. GPUs) to attach to the instance. (e.g `[{"acceleratorType":"projects//zones//acceleratorTypes/nvidia-tesla-t4","acceleratorCount":1}]`) [Reference](https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert) | | **GCP Config Override (JSON)** | A JSON dictionary that can be used to customize attributes of the VM request. The only attributes that cannot be overridden are `name` and `labels` (e.g `{"shieldedInstanceConfig":{"enableIntegrityMonitoring":true,"enableSecureBoot":true,"enableVtpm":true}}` [Reference](https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert) | | **VM Installed OS Type** | The family of the OS installed on the VM (e.g. linux or windows). | | **Startup Script Type** | The type of startup script to execute, this determines the key used when creating the GCP startup script metadata. [Windows Startup Scripts](https://cloud.google.com/compute/docs/instances/startup-scripts/windows) [Linux Startup Scripts](https://cloud.google.com/compute/docs/instances/startup-scripts/linux) | | **Startup Script** | When instances are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent. Bash is supported on Linux instances and Powershell for Windows instance. Example scripts can be found on our [Github repo](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) | ### Note on updating existing Google Cloud Providers (GCP) Review the settings for all existing Google Cloud Providers (GCP). Two new fields were added: `VM Installed OS Type`, which defaults to `Linux`, and `Startup Script Type`, which defaults to `Bash Script`. A provider configured with a Windows VM does not launch the startup script successfully without changing these values. ## Harvester settings :::note A detailed guide on Harvester AutoScale configuration is available here. ::: | **Setting** | **Description** | | --- | --- | | Name | An identifying name for this provider configuration e.g. Harvester Docker Agent AutoScale Provider | | Max Instances* | The maximum number of autoscale instances to be provisioned, regardless of other settings | | Host | The address of the Harvester instance, from the KubeConfig file (e.g. https://harvester.example.com/k8s/clusters/local) | | SSL Certificate | The Harvester certificate as a base64 encoded string, from the KubeConfig file | | API Token | The API token for authentication to Harvester, from the KubeConfig file | | VM Namespace | The name of the Harvester namespace where the VMs will be provisioned (e.g. kasm-autoscale) | | VM SSH Public Key | A public key to add to the autoscale agents, this is then provided as `{ssh_key}` for use in the startup script | | Cores | The number of CPU cores to configure for the autoscale agents | | Memory | The amount of memory to assign to the autoscale agents. The admin console accepts Bytes/MiB/GiB and stores the value as bytes (`memory_bytes`). API integrations must submit the number of bytes. | | Disk Image | The name of the Harvester image to use for autoscale agents. See Harvester Disk Image for more details. | | Disk Size | The size of the disk to use for autoscale agents. The admin console accepts Bytes/MB/MiB/GB/GiB and stores the value as bytes (`disk_size_bytes`). API integrations must submit the number of bytes. | | Network Type | The network type for the autoscale agents (pod or multus) | | Interface Type | The interface type for the autoscale agents (masquerade or bridge) | | Network Name | The name of the network to connect to the autoscale agents to, if the network is not in the default namespace this must be specified as namespace/name (e.g. kasm-autoscale/kasm-network) (multus network type only) | | Startup Script | cloud-init, Bash, or Powershell script to run after agent creation, typically to install the Kasm Agent and/or any other runtime dependencies you may have. Example scripts can be found on our [GitHub repository.](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) Make sure to use the correct script based on the target OS (bash/cloud-init for Linux and Powershell for Windows). | | Configuration Override | A optional config override that contains a complete YAML manifest file used when provisioning the autoscale agents | | Enable TPM | Enable TPM for the autoscale agents | | Enable EFI Boot | Enable the EFI bootloader for the autoscale agents | | Enable Secure Boot | Enable Secure Boot for the autoscale agents (required EFI Boot to be enabled) | ## Oracle Cloud (OCI) settings :::note A detailed guide on OCI AutoScale configuration is available here. ::: ![OCI VM Provider](/img/compute/vm_oracle.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **User OCID** | The OCID of the user to authenticate with the OCI API. (e.g ocid1.user.oc1..xyz). You can find this by going to your OCI dashboard -> Click on your Profile -> You can find your user OCID here. | | **Public Key Fingerprint** | The public key fingerprint of the authenticated API user created in OCI. (e.g xx:yy:zz:11:22:33) | | **Private Key** | The private key (PEM format) of the authenticated API user created in OCI. | | **Region** | The OCI Region name. (e.g us-ashburn-1). See [Regions](https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm) for the list | | **Tenancy OCID** | The Tenancy OCID for the OCI account. (e.g ocid1.tenancy.oc1..xyz) | | **Compartment OCID** | The Compartment OCID where the auto-scaled agents will be placed. (e.g ocid1.compartment.oc1..xyx) | | **Network Security Group OCIDs** **(JSON)** | A JSON list of Security Group OCIDs that will be assigned to the auto-scaled agents. (e.g `["ocid1.networksecuritygroup.oc1.iad.xxx","ocid1.networksecuritygroup.oc1.iad.yyy"]`). To create or find existing Network Security Groups, go to your OCI dashboard -> "Network Security Groups". See [Network Security Groups](https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/networksecuritygroups.htm) for more details | | **Max Instances** | The maximum number of OCI compute instances to provision regardless of the need for available free slots. | | **Availability Domains (JSON)** | A JSON list of availability domains where the OCI compute instances may be placed. (e.g `["BEol:US-ASHBURN-AD-1", "BEol:US-ASHBURN-AD-2"]`). See [Availability Domains](https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm) for more details | | **Image OCID** | The OCID of the Image to use when creating the compute instances. (e.g ocid1.image.oc1.iad.xyz) See [OCI Image Families](https://docs.oracle.com/en-us/iaas/img/) for the list | | **Shape** | The name of the shape used for the created compute instances. (e.g VM.Standard.E4.Flex) See [OCI Compute Shapes](https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm) for the list | | **Flex CPUs** | The number of OCPUs to assign the compute instance. This is only applicable when a Flex shape is used. | | **Burstable Base CPU** **Utilization** | The baseline percentage of a CPU Core that can be use continuously on a burstable instance (Select 100% to use a non-burstable instance). [Reference](https://docs.oracle.com/en-us/iaas/Content/Compute/References/burstable-instances.htm). | | **Flex Memory** | The amount of memory to assign the compute instance. This is only applicable when a Flex shape is used. The admin console accepts Bytes/MiB/GiB and stores the value as bytes (`oci_flex_memory_bytes`). API integrations must submit the number of bytes in whole GiB (2^30) increments. | | **Boot Volume Size** | The size of the boot volume to assign the compute instance. The admin console accepts Bytes/GB and stores the value as bytes (`oci_boot_volume_bytes`). API integrations must submit the number of bytes in whole GB (10^9) increments. | | **Boot Volume VPUs Per GB** | The Volume Performance Units (VPUs) to assign to the boot volume. Values between 10 and 120 in mulitples of 10 are acceptable. 10 is the default and represents the `Balanced` profile. The higher the VPUs, the higher the volume performance and cost. [Reference](https://docs.oracle.com/en-us/iaas/Content/Block/Concepts/blockvolumeperformance.htm#Block_Volume_Performance). | | **Custom Tags (JSON)** | A Json dictionary of custom freeform tags to assigned the auto-scaled instances. e.g `{"foo":"bar", "bin":"baz"}` | | **Subnet OCID** | The OCID of the Subnet where the auto-scaled instances will be placed. (e.g ocid1.subnet.oc1.iad.xyz) To create or find existing subnets, go to your OCI dashboard -> "Networking" -> "Virtual Cloud Networks" -> "Subnets" | | **SSH Public Key** | The SSH public key to insert into the compute instances if you want to SSH into your instances. (e.g ssh-rsa XYABC) | | **Startup Script** | When instances are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent. Example scripts can be found on our [GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) | | **OCI Config Override** | A JSON dictionary that can be used to customize attributes of the VM request. An OCI Model can be specified with the "OCI_MODEL_NAME" key. Reference: [OCI Python Docs](https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Instance/LaunchInstance) and [Kasm Examples](#oci-config-override-examples). | Find the OCI Image ID for the desired operating system version and region by navigating the [OCI Image page](https://docs.oracle.com/en-us/iaas/img/). ### OCI config override examples The following OCI AutoScale configurations use the OCI Config Override. Disables instance metadata service v2 for additional security. ```json { "launch_instance_details": { "instance_options": { "OCI_MODEL_NAME": "InstanceOptions", "are_legacy_imds_endpoints_disabled": true } } } ``` A list of available plugins can be retrieved by navigating to an existing instance's "Oracle Cloud Agent" config page. This example enables the "Vulnerability Scanning" plugin. ```json { "launch_instance_details": { "agent_config": { "OCI_MODEL_NAME": "LaunchInstanceAgentConfigDetails", "is_monitoring_disabled": false, "is_management_disabled": false, "are_all_plugins_disabled": false, "plugins_config": [{ "OCI_MODEL_NAME": "InstanceAgentPluginConfigDetails", "name": "Vulnerability Scanning", "desired_state": "ENABLED" }] } } } ``` ## Nutanix settings :::note A detailed guide on Nutanix AutoScale configuration is available here. ::: | **Setting** | **Description** | | --- | --- | | Name | An identifying name for this provider configuration e.g. Nutanix Docker Agent AutoScale Provider | | Max Instances | The maximum number of autoscale instances to be provisioned, regardless of other settings | | Host | The IP or FQDN of the Nutanix Prism Central server (e.g. 192.168.100.40 or nutanix.example.com) | | Port | The listening port to the Nutanix Prism Central server. This is usually 9440 | | Username | The name of the user that Kasm will use to access the Nutanix Prism Central server | | Password | The Password of the user that Kasm will use to authenticate against the Nutanix Prism Central server | | Verify SSL | Whether to validate SSL certificates. Set to False to enable self-signed certificates. Defaults to True | | API Version | The API version used to communicate with Prism Central. v3 is recommended, v4 compatibility is currently in Preview | | VM Candidate Name | The name of the VM used to clone new autoscaled VMs | | VM Cores | The number of CPU cores to provision on the new autoscaled VMs | | VM Memory | The amount of memory to provision on the new autoscaled VMs. The admin console accepts Bytes/MiB/GiB and stores the value as bytes (`memory_bytes`). API integrations must submit the number of bytes. | | Startup Script | When VMs are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent for Docker Agent roles, or the Kasm Desktop Service for Windows VMs if desired. Bash scripts and cloud-config yaml formats are supported on a Linux host and Powershell scripts on Windows hosts Example scripts are available on our [GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) | ## Proxmox settings :::note A detailed guide on Proxmox AutoScale configuration is available here. ::: | **Setting** | **Description** | | --- | --- | | Name | An identifying name for this provider configuration e.g. Proxmox Docker Agent AutoScale Provider | | Max Instances | The maximum number of autoscale instances to be provisioned, regardless of other settings | | Host | The hostname or IP and port of your Proxmox instance (e.g. 192.168.100.40:8006) | | Username | The name of the autoscale user in Proxmox, including the auth realm (e.g. KasmUser@pve) | | Token Name | The name of the API token associated with the user (e.g. kasm_token and not KasmUser@pve!kasm_token) | | Token Value | The secret value of the API token associated with the user | | Verify SSL | Whether or not to verify the SSL certs in the Proxmox environment. Disable if you are using self-signed certs | | VMID Range Lower | The start of the VMID range for Kasm to use for autoscale agents. Must not overlap with any other Proxmox autoscale providers configured in Kasm | | VMID Range Upper | The end of the VMID range for Kasm to use for autoscale agents. Must not overlap with any other Proxmox autoscale providers configured in Kasm | | Full Clone | If enabled performs a full clone rather than a linked clone. A linked clone is faster to provision but will have reduced performance compared to a full clone | | Template Name | The name of the VM template to use when cloning new autoscale agents | | Cluster Node Name | The name of the Proxmox node containing the VM template | | Resource Pool Name | Specify the resource pool to use for cloning the new autoscale agents | | Storage Pool Name | Optionally specify a storage pool to use for cloning the new autoscale agents. This requires Full Clone to be enabled | | Target Node Name | Optionally specify a cluster node to provision new autoscale agents on (defaults to the Cluster Node Name) | | VM Cores | The number of CPU cores to configure for the autoscale agents | | VM Memory | The amount of memory for the autoscale agents. The admin console accepts Bytes/MiB/GiB and stores the value as bytes (`memory_bytes`). API integrations must submit the number of bytes. | | Installed OS Type | Linux or Windows | | Startup Script Path | The absolute path to where the startup script will be uploaded and run from, typically `/tmp` for Linux or `C:\windows\temp` for Windows. The path must exist on the template. | | Startup Script | Bash (Linux) or Powershell (Windows) startup script to run after agent creation, typically to install the Kasm Agent and/or any other runtime dependencies. Example scripts are available on our [GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) | ## VMware vSphere settings :::note A detailed guide on vSphere AutoScale configuration is available here. ::: ![vSphere VM Provider](/img/compute/vm_vsphere_from_1_19_0.webp) | Setting | Description | | --- | --- | | **Name** | An identifying name for this provider configuration. | | **vSphere vCenter Address** | The IP or FQDN of the VMware vSphere vCenter server to use. | | **vSphere vCenter Port** | The management port of your Vcenter instance (typically 443) | | **vSphere vCenter Username** | The username to use when authenticating with the vSphere vCenter server (e.g kasm-autoscale) | | **vSphere vCenter Password** | The password to use when authenticating with the vSphere vCenter server. | | **Clone Type** | Select the cloning method: **Full Clone (Template)** creates independent VMs from a template with dedicated storage, **Linked Clone (VM Snapshot)** creates VMs using delta disks from a snapshot for faster provisioning and reduced storage, and **Instant Clone (Frozen VM)** creates VMs by forking a frozen parent VM's memory/CPU state for sub-second cloning. | | **VM Template Name** | (Full Clone only) The name of the template VM to use when cloning new autoscaled VMs. | | **Linked Clone VM Name** | (Linked Clone only) The name of the source VM (not template) to use for linked clones. This VM must have a snapshot available. | | **Linked Clone Snapshot Name** | (Linked Clone only) The name of the snapshot on the source VM to clone from. | | **Frozen VM Name** | (Instant Clone only) The name of the frozen parent VM to use for instant clones. This VM must be powered on and frozen. | | **Max Instances** | The maximum number of vSphere VM instances to provision regardless of the need for available free slots. | | **Datacenter Name** | The datacenter to use for cloning the new vSphere VM instances. | | **VM Folder** | The VM folder to use for cloning the new vSphere VM instances. This field is optional, if left blank the VM folder of the template is used. | | **Use Datastore Cluster** | (Full Clone only) When enabled, the **Datastore Name** field is treated as a Datastore Cluster name and vSphere will recommend the optimal datastore for each clone. If the recommendation fails, the clone falls back to the source VM's datastore. Not available for linked clones. | | **Datastore Name** | The datastore (or datastore cluster, when **Use Datastore Cluster** is enabled) to use for cloning new vSphere VM instances. This field is optional; if left blank, the datastore of the source VM is used. | | **Cluster Name** | The cluster to use for cloning the new vSphere VM instances. This field is optional, if left blank the cluster of the template is used. | | **Resource Pool** | The resource pool to use for cloning the new vSphere VM instances. This field is optional, if left blank the resource pool of the template is used. | | **Number of Guest CPUs** | (Full Clone and Linked Clone only) The number of CPUs to configure on new vSphere VM instances. This option is not dependent on the number of CPUs configured on the template. Instant clones inherit the CPU configuration of the frozen parent VM. | | **Amount of Guest Memory** | (Full Clone and Linked Clone only) The amount of memory to configure on new vSphere VM instances. This option is not dependent on the amount of memory configured on the template. Instant clones inherit the memory configuration of the frozen parent VM. The admin console accepts Bytes/MiB and stores the value as bytes (`vsphere_memory_bytes`). API integrations must submit the number of bytes in whole MiB (2^20) increments. | | **What family of OS is installed** **in the VM** | Whether the template OS is Linux or Windows. This is needed to ensure proper execution of the startup script. | | **Startup Script Execution Method** | (Full Clone and Linked Clone only) Choose how the startup script is executed: **Cloud-Init (Recommended)** - Injects the script via cloud-init/cloudbase-init for first-boot execution. Requires cloud-init (Linux) or cloudbase-init (Windows) to be installed in the template (**_Additional permissions required_**). **VMware Guest Operations (Legacy)** - Executes the script directly via VMware Tools Guest Operations API after the VM boots. Requires VMware Tools and valid OS credentials. Instant clones always use VMware Guest Operations (no boot sequence). | | **Guest VM Username** | (Required for VMware Guest Operations method and Instant Clone) The username to use for running the startup script on the new vSphere VM instance. This account should have sufficient privileges to execute all commands in the startup script. | | **Guest VM Password** | (Required for VMware Guest Operations method and Instant Clone) The password for the **Guest VM Username** account. | | **Startup Script** | When instances are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent. Scripts are run as bash scripts on a Linux host and Powershell scripts on a Windows host. Example scripts are available on our [GitHub repository](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) Additional troubleshooting steps can be found in the VMware vSphere section of the AutoScale documentation. | | **VM SSH Public Key** | A public key to add to the autoscale agents, this is then provided as `{ssh_key}` for use in the startup script. | ### Permissions for vCenter service account These are the minimum permissions that your service account requires in vCenter for a default configuration. The account might require additional privileges depending on the features and configurations you have in place. Kasm advises creating a dedicated service account for Kasm Workspaces AutoScaling with these permissions to enhance security and minimize potential risks. * Datastore * Allocate space * Browse datastore * Global * Cancel task * Network * Assign network * Resource * Assign virtual machine to resource pool * Virtual machine * Change Configuration * Change CPU count * Change Memory * Set annotation * Edit Inventory * Create from existing * Create new * Remove * Unregister * Guest operations * Guest operation modifications * Guest operation program execution * Guest operation queries * Interaction * Power off * Power on * Provisioning * Deploy template ### Network connectivity The agent startup scripts use VMware guest script execution through VMware Tools. This functionality requires direct HTTPS connectivity between the Kasm Workspaces Manager and the ESXi hosts running the agent VMs. ### Notes on vSphere datastore storage When you configure VMware vSphere with Kasm Workspaces, keep datastore storage in mind. When clones are created, VMware attempts to satisfy the clone operation. When the datastore runs out of space, any VMs running on that datastore are paused until space is available. Kasm Workspaces recommends placing critical management VMs, such as the vCenter server VM and cluster management VMs, on separate datastores that are not used for Kasm AutoScaling. ## OpenStack settings A number of settings are required to use this functionality. The OpenStack settings appear in the Pool configuration when the feature is licensed. Find the appropriate OpenStack configuration options on the "API Access" page of the OpenStack UI by downloading the "OpenStack RC File". ![OpenStack VM](/img/compute/vm_openstack.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Max Instances** | The maximum number of OpenStack compute instances to provision regardless of the need for additional resources. | | **OpenStack Identity Endpoint** | The endpoint address of the OpenStack Keystone endpoint (e.g. `https://openstack.domain:5000`) | | **OpenStack Nova Endpoint** | The endpoint address of the OpenStack Nova (Compute) endpoint (e.g. `https://openstack.domain:8774/v2/`) | | **OpenStack Nova Version** | The version to use with the OpenStack Nova (Compute) endpoint (e.g. `2.90`) | | **OpenStack Glance Endpoint** | The endpoint address of the OpenStack Glance (Image) endpoint (e.g. `https://openstack.domain:9292`) | | **OpenStack Glance Version** | The version to use with the OpenStack Glance (Image) endpoint (e.g. `2`) | | **OpenStack Cinder Endpoint** | The endpoint address of the OpenStack Cinder (Volume) endpoint. **Note: The address contains the OpenStack Project ID** (e.g. `https://openstack.domain:8776/v3/383a0dad105e460ab5a863ea0a45932b`) | | **OpenStack Cinder Version** | The version to use with the OpenStack Cinder (Volume) endpoint. (e.g. `3`) | | **Project Name** | The name of the OpenStack Project where VMs will be provisioned. | | **Authentication Method** | The authentication method used to authenticate against the OpenStack Identity (Keystone) service. Supported options are **Application Credential** or **User**. See the **Known Issue** below regarding Application Credential authentication. | | **Application Credential ID** | The Credential ID of the OpenStack Application Credential. | | **Application Credential Secret** | The OpenStack Application Credential secret. | | **Project Domain Name** | The domain that the OpenStack Project belongs to. This value is typically obtained from the OpenStack RC file (`OS_PROJECT_DOMAIN_NAME`). If `OS_PROJECT_DOMAIN_NAME` is not present, use `OS_PROJECT_DOMAIN_ID` if supported by your OpenStack deployment. For many deployments, such as OpenMetal, the value is `Default`. | | **User Domain Name** | The domain that the OpenStack User belongs to. This value is typically obtained from the OpenStack RC file (`OS_USER_DOMAIN_NAME`) (e.g. `Default`). | | **Username** | The OpenStack username used to authenticate. This value is available in the OpenStack RC file as `OS_USERNAME` and is typically the same username used to sign in to the OpenStack Horizon dashboard. | | **Password** | The password for the OpenStack user account used to authenticate. This is the same password used to sign in to the OpenStack Horizon dashboard. The password is not stored in the OpenStack RC file and must be entered separately. | | **Metadata** | A Json Dictionary containing the metadata tags applied to the OpenStack VMs (e.g. `{"my_tag": "my_value"}`) | | **Image ID** | The ID of the Image used to provision OpenStack VMs. | | **Flavor** | The name of the desired Flavor for the OpenStack VM (e.g. `gen.medium`) | | **Create Volume** | Enable to create a new Block storage (Cinder) volume for the OpenStack VM. (When disabled, ephemeral Compute (Nova) storage is used.) | | **Volume Size** | Select the size of the VM volume when "Create Volume" is enabled. The admin console accepts Bytes/GiB and stores the value as bytes (`openstack_volume_size_bytes`). API integrations must submit the number of bytes using whole GiB (2^30) increments. | | **Volume Type** | The type of volume to use for the new OpenStack VM Volume (e.g. `__DEFAULT__`) | | **Startup Script** | When OpenStack VMs are provision this script is executed. The script is responsible for installing and configuring the Kasm Agent. | | **Security Groups** | A list containing the security groups applied to the OpenStack VM (e.g. `["sg1", "sg2"]`) | | **Network ID** | The ID of the network that the OpenStack VMs will be connected to. | | **Key Name** | The name of the SSH Key used to connect to the instance. | | **Availability Zone** | The Name of the Availability Zone that the OpenStack VM will be placed into. | | **Config Override** | A JSON dictionary that can be used to customize attributes of the VM request | :::warning Known Issue The OpenStack provider supports both **Application Credential** and **User** authentication methods. However, **Application Credential** authentication may not work with newer OpenStack deployments and can result in a **401 Unauthorized** response from the OpenStack Identity (Keystone) service. ![401 Unauthorized Error](/img/compute/openstack_401_error.png) Until this issue is resolved, use **User** authentication when configuring the OpenStack provider. ::: :::tip OpenStack RC File Many of the OpenStack provider configuration values can be obtained from the OpenStack RC file provided by your OpenStack deployment. To download the OpenStack RC file: 1. Sign in to the OpenStack Horizon dashboard. 2. Navigate to **Project** → **API Access**. 3. Click **Download OpenStack RC File**. The RC file contains values that can be used to populate several OpenStack provider fields. Example values from an OpenStack RC file: ```bash export OS_AUTH_URL=https://openstack.domain:5000 export OS_PROJECT_NAME="admin" export OS_USER_DOMAIN_NAME="Default" export OS_PROJECT_DOMAIN_ID="default" export OS_USERNAME="admin" ``` | Kasm Field | OpenStack RC Variable / Source | |------------|--------------------------------| | OpenStack Identity Endpoint | `OS_AUTH_URL` | | Project Name | `OS_PROJECT_NAME` | | Project Domain Name | `OS_PROJECT_DOMAIN_NAME` or `OS_PROJECT_DOMAIN_ID` | | User Domain Name | `OS_USER_DOMAIN_NAME` | | Username | `OS_USERNAME` | | OpenStack Nova Endpoint | Obtained from the Compute (Nova) service endpoint. | | OpenStack Glance Endpoint | Obtained from the Image (Glance) service endpoint. | | OpenStack Cinder Endpoint | Obtained from the Block Storage (Cinder) service endpoint. The endpoint includes the Project ID. | The OpenStack RC file does **not** contain the user's password. You will be prompted to enter it when sourcing the RC file. ::: ## User Credentials ![Credential](/img/compute/openstack_user_credential.png) Application Credentials remain available in the product. However, due to the known issue described above, we recommend using **User** authentication. If **Application Credential** authentication results in a **401 Unauthorized** error, switch to **User** authentication. ### OpenStack notes The OpenStack provider requires OpenStack endpoints to present trusted, signed TLS certificates. Configure this through an API gateway that presents a valid certificate or by configuring valid certificates on each individual service (reference: [OpenStack Docs](https://docs.openstack.org/charm-guide/latest/admin/security/tls.html)). The OpenStack provider requires that OpenStack endpoints present trusted, signed TLS certificates. This can be done through an API gateway that presents a valid certificate or through configuring valid certificates on each individual service [Openstack Docs](https://docs.openstack.org/charm-guide/latest/admin/security/tls.html). ```yaml - service: volumev3 method: POST path: /v3/*/volumes - service: volumev3 method: DELETE path: /v3/*/volumes/* - service: volumev3 method: GET path: /v3/*/volumes - service: volumev3 method: GET path: /v3/*/volumes/* - service: volumev3 method: GET path: /v3/*/volumes/detail - service: compute method: GET path: /v2.1/servers/detail - service: compute method: GET path: /v2.1/servers - service: compute method: GET path: /v2.1/flavors - service: compute method: GET path: /v2.1/flavors/* - service: compute method: GET path: /v2.1/servers/*/os-volume_attachments - service: compute method: GET path: /v2.1/servers/* - service: compute method: GET path: /v2.1/servers/*/os-interface - service: compute method: POST path: /v2.1/servers - service: compute method: DELETE path: /v2.1/servers/* - service: image method: GET path: /v2/img/* - service: image method: GET path: /v2/schemas/image ``` ## KubeVirt enabled providers ### Overview Kasm supports AutoScaling in Kubernetes environments running KubeVirt. Supported environments include generic k8s installations as well as GKE and Harvester deployments. ### Updated startup scripts Kasm has released updated startup scripts to include KubeVirt support. The most important change is the inclusion of the qemu-agent. ``` https://github.com/kasmtech/workspaces-autoscale-startup-scripts/blob/develop/latest/docker_agents/ubuntu.sh ``` The qemu-agent installation snippet is commented out by default in the startup script. To use it with KubeVirt, first uncomment it. ### Config overrides Kasm generates VMs using a Kubernetes YAML manifest described by this API specification: ``` https://kubevirt.io/api-reference/main/definitions.html#_v1_virtualmachine ``` When Kasm providers do not expose a required feature, you can override the provider configuration. To do this, store the entire manifest in the provider `config_override`. Kasm parses the manifest and attempts to update certain fields. The `metadata` is updated so that the `name` field contains a unique name, the `namespace` matches the namespace in the provider config, and the `labels` contain various labels required for AutoScale functionality. All other values are preserved. The `runStrategy` is set to `Always` and the `hostname` is set to match the unique name. To support startup scripts, a `disk` with the following settings is appended to the `disks`: ``` - name: config-drive-disk cdrom: bus: sata readonly: true ``` This points to a `volume` that is appended to the `volumes` with the following settings: ``` - name: config-drive-disk cloudInitConfigDrive: secretRef: name: f'{name}-secret' ``` The manifest spawns multiple VMs, so unique names for certain resources such as PVCs are necessary. To support this, the provider replaces any instance of `$KASM_NAME` with a unique name. To use this for multiple different types of resources, append to the name as in this suggested PVC example: ``` volumes: - name: disk-0 persistentVolumeClaim: claimName: $KASM_NAME-pvc ``` Because the manifest spawns multiple VMs, use a disk cloning method such as the `dataVolume` feature of the Containerized Data Importer interface created by KubeVirt. ### Caveats The k8s namespace for Kasm resources is configured on the provider and must not be updated while the provider is in use. Updating it can result in unpredictable behavior and orphaned resources. To change the k8s namespace, create a new AutoScale and provider with the new namespace. Update the old AutoScale configuration, setting the standby cores, GPUs, and memory to 0. This allows new resources to transition to the new provider. Orphaned k8s objects can exist for various reasons, such as power loss of the Kasm server during VM creation. Currently, you must clean up these objects manually. The k8s objects that Kasm creates are virtualmachines, secrets, and PVCs. The Kasm KubeVirt provider does not work out of the box with the following Kubernetes deployments: - KIND. The default KIND deployment uses local-path-provisioning for storage, which does not support CDI cloning. ### KubeVirt settings A number of settings are required to use this functionality. The KubeVirt settings appear in the Pool configuration when the feature is licensed. Find the appropriate Kubernetes configuration options by downloading the KubeConfig file provided by your Kubernetes installation. ![KubeVirt VM](/img/compute/vm_kubevirt.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Max Instances** | The maximum number of KubeVirt compute instances to provision regardless of the need for additional resources. | | **Kubernetes Host** | The address of the kubernetes cluster (e.g. `https://kubevirt.domain:5000`). | | **Kubernetes SSL Certificate** | The kubernetes cluster certificate as a base64 encoded string of a PEM file. | | **Kubernetes API Token** | The bearer token for authentication to the kubernetes cluster. | | **VM Namespace** | The name of the Kubernetes namespace where the VMs will be provisioned (e.g. kasm-autoscale). | | **VM SSH Public Key** | The Public SSL Certificate used to access the VM. | | **VM Cores** | The nubmer of CPU cores to configure for the VM. | | **VM Memory** | The amount of memory to configure for the VM. The admin console accepts Bytes/MiB/GiB and stores the value as bytes (`memory_bytes`). API integrations must submit the number of bytes. | | **VM Disk Size** | The size of the disk to configure for the VM. The admin console accepts Bytes/MB/MiB/GB/GiB and stores the value as bytes (`disk_size_bytes`). API integrations must submit the number of bytes. | | **VM Disk Source** | The name of the source PVC containing a cloud ready disk image used to clone a new disk volume | | **VM Interface Type** | The interface type for the VM (e.g. masquerade or bridge). | | **VM Network Name** | The name of the network interface. If using a multus network, it should match the name of that network. If the network is not in the default namespace, it should be specified as namespace/name (e.g. kasm-autoscale/kasm-network). | | **VM Network Type** | The network type for the VM (e.g. pod or multus). | | **VM Startup Script** | When VMs are provisioned, this script is executed and is responsible for installing and configuring the Kasm Agent. Scripts are ran as bash scripts on a Linux host and Powershell scripts on a Windows host. Additional troublshooting steps can be found in the VMWare vSphere section of the Autoscale documentation. | | **Configuration Override** | A config override that contains a complete YAML manifest file used when provisioning the VM. | | **Enable TPM** | Enable TPM for VM. | | **Enable EFI Boot** | Enable the EFI boot loader for the VM. | | **Enable Secure Boot** | Enable secure boot for the VM (requires EFI boot to be enabled). | ### KubeVirt GKE setup example This example assumes you have a GKE account, a Linux development environment, and an existing Kasm deployment (ref). The example will assume the following variables: - cluster name `kasm` - zone `us-central1` - region `us-central1-c` - machine-type `c3-standard-8` - namespace `kasm` - storage class name `kasm-storage` - pvc name `kasm-ubuntu-jammy` - pvc size `25GiB` - pvc image `jammy-server-cloudimg-amd64.img` These should be replaced with values more appropriate to your installation. #### Ensure GKE is configured - Install the gcloud console ([ref](https://cloud.google.com/sdk/docs/install)): ```Bash curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-linux-x86_64.tar.gz tar -xf google-cloud-cli-linux-x86_64.tar.gz ./google-cloud-sdk/install.sh -q --path-update true --command-completion true . ~/.profile ``` - Initialize the gcloud console ([ref](https://cloud.google.com/sdk/docs/initializing)): ```Bash gcloud init --no-launch-browser gcloud config set compute/region us-central1 gcloud config set compute/zone us-central1-c ``` - Enable the GKE engine API ([ref](https://cloud.google.com/kubernetes-engine/docs/how-to/nested-virtualization#before_you_begin)): ```Bash gcloud services enable container.googleapis.com ``` - Create a cluster with nested virtualization support ([ref](https://cloud.google.com/kubernetes-engine/docs/how-to/nested-virtualization#enable-nested-virt)): ```Bash gcloud container clusters create kasm \ --enable-nested-virtualization \ --node-labels=nested-virtualization=enabled \ --machine-type=c3-standard-8 ``` - Install the kubectl gcloud component ([ref](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_kubectl)): ```Bash gcloud components install kubectl ``` - Configure GKE kubectl authentication ([ref](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin)): ```Bash gcloud components install gke-gcloud-auth-plugin gcloud container clusters get-credentials kasm \ --region=us-central1-c ``` - Create the Kasm namespace: ```Bash kubectl create namespace kasm ``` #### Install KubeVirt Note: The current v1.3 release of KubeVirt introduced a bug preventing GKE support. You must install the v1.2.2 release. - Install KubeVirt ([ref](https://kubevirt.io/user-guide/cluster_admin/installation/)): ```yml #export RELEASE=$(curl https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt) export RELEASE=v1.2.2 kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-cr.yaml ``` - Wait for it to be ready. This may time out multiple (2-3) times before returning successfully: ```Bash kubectl -n kubevirt wait kv kubevirt --for condition=Available ``` #### Install the Containerized Data Importer extension In order to support efficient cloning KubeVirt requires the Containerized Data Importer extension ([ref](https://github.com/kubevirt/containerized-data-importer)). - Install the CDI extension: ```Bash export VERSION=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml ``` - Create a new storage class that uses the GKE CSI driver and has the `Immediate` volume binding mode: ```Bash kubectl apply -f - < tmp.deploy.ca.crt touch $HOME/local.cfg export KUBECONFIG=$HOME/local.cfg kubectl config set-cluster local --server=https://$KUBE_API_EP --certificate-authority=tmp.deploy.ca.crt --embed-certs=true kubectl config set-credentials $KUBE_SA_NAME --token=$KUBE_API_TOKEN kubectl config set-context local --cluster local --user $KUBE_SA_NAME kubectl config use-context local ``` - Validate your kubeconfig works ```Bash kubectl version ``` This should display both the client and server versions. If it does not, retrieve the current config used by kubectl to ensure it uses the correct config: ```Bash kubectl config view ``` Ensure that it is using the local settings you generated and not an existing GKE configuration. #### Upload a PVC Use the `virtctl` tool to upload a VM image. Both the `raw` and `qcow2` formats are supported. The image should be cloud-ready, with cloud-init configured. - Download and install the `virtctl` tool: ```Bash VERSION=$(kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.observedKubeVirtVersion}") ARCH=$(uname -s | tr A-Z a-z)-$(uname -m | sed 's/x86_64/amd64/') || windows-amd64.exe echo ${ARCH} curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-${ARCH} chmod +x virtctl sudo install virtctl /usr/local/bin ``` - Expose the CDI Upload Proxy by executing the following command in another terminal: ```Bash kubectl -n cdi port-forward service/cdi-uploadproxy 8443:443 ``` - Use the `virtctl` tool to upload the VM image: ```Bash virtctl image-upload pvc kasm-ubuntu-jammy --uploadproxy-url=https://localhost:8443 --size=25Gi --image-path=./jammy-server-cloudimg-amd64.img --insecure -n kasm ``` #### Ensure Kasm is configured - Configure Kasm - Add a license - Set the default zone upstream address to the address of the Kasm host - Add a Pool - `Name` KubeVirt Pool - `Type` Docker Agent - Add an Auto-Scale config - `Name` KubeVirt AutoScale - `AutoScale Type` Docker Agent - `Pool` KubeVirt Pool - `Deployment Zone` default - `Standby Cores` 4 - `Standby GPUs` 1 - `Standby Memory` 4 GiB (select GiB in the unit selector) - `Downscale Backoff` 600 - `Agent Cores Override` 4 - `Agent GPUs Override` 1 - `Agent Memory Override` 4 GiB (select GiB in the unit selector) - Create a new VM Provider - `Provider` KubeVirt - `Name` KubeVirt Provider - `Max Instances` 10 - `Host` paste server URI from kubeconfig - `SSL Certificate` paste certiciate-authority-data from kubeconfig - `API Token` paste token from kubeconfig - `VM Namespace` kasm - `VM Public SSH Key` paste user public ssh key - `Cores` 4 - `Memory` 4 GiB (select GiB in the unit selector) - `Disk Source` kasm-ubuntu-jammy - `Disk Size` 30 GiB (select GiB in the unit selector) - `Interface Type` bridge - `Network Name` default - `Network Type` pod - `Startup Script` paste ubuntu docker agent startup script --- ## Windows Autoscale Templates # Windows AutoScale Template Creation ## Overview Kasm Workspaces can AutoScale Windows VMs in supported Cloud Providers/Hypervisors. Servers AutoScaled by Kasm should be seen as individual servers connected to via RDP. Kasm Workspaces provides session handling and ensures users a distributed to the pool of servers. Kasm auto-scaling is not supported as a way to scale RDS deployments. Autoscaling of Windows servers requires one or more Windows template images to deploy from. ### Prerequisites #### Licensing > Any stated or implied licensing restrictions with respect to Microsoft products and services are to the best of our knowledge and may not represent the current state and may not be an accurate summarization of what are complicated licensing restrictions. Ensure to consult with Microsoft to fully understand your rights as a licensee of their products and services. First, it’s important to note that Microsoft has specific licensing requirements for accessing their software applications through remote desktop services (RDS) and virtual desktop infrastructure (VDI) solutions. These licensing requirements can be complex and may vary depending on the specific scenario and product being used. In general, if you are using Kasm Workspaces as an RDP connection to an RDP application or RDS Session host, you will need to ensure that you have the appropriate Microsoft licenses for the software being accessed. This may include licenses for Windows Server, Remote Desktop Services (RDS) Client Access Licenses (CALs), and/or Microsoft Office. Kasm Workspaces provides the ability to connect to RDP applications and RDS Session hosts using the internal Connection Proxy service, which allows for secure remote access to Windows-based applications and desktops from any device or browser. If the Windows VMs are in the cloud, you have the option to use pay-as-you-go (PAYG) licensing or bring-your-own-licensing (BYOL). When using PAYG licensing, the Windows licensing costs are built into your cloud costs. Some cloud providers charge the Microsoft licensing fee separately, so it may not be included directly in the estimated instance pricing. See your cloud provider for details on Microsoft licensing. If you decide to use the BYOL approach, you will be responsible for either manually licensing your servers or automating the licensing process of Windows servers. Kasm does not provide support or assistance with licensing Microsoft products. The following Microsoft licensing restrictions should be evaluated when selecting an architecture and/or cloud provider. * Microsoft explicitly disallows running versions of Office later than 2019 on a VM in any cloud provider other than Microsoft Azure. * Microsoft explicitly does not support Windows 10/11 multi-session images running in any cloud provider other than Microsoft Azure. The result is that running Windows 10/11 in any cloud provider, other than Azure, will require 1 VM per user, which will have profound licensing cost implications. * Running of Windows 10/11 in a cloud provider other than Azure is heavily restricted by Microsoft. While you will not find Windows 10/11 images in any cloud provider’s image marketplace, you can still create custom images on your own and handle licensing of the operating system yourself. Kasm does not provide support for licensing of Microsoft products. ### Image Creation #### Additional Drivers Depending on your target VM environment you may need to install additional drivers, such as the [VirtIO](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso) SCSI drivers, as part of the Windows template install process. These drivers should be mounted as an additional drive at install time so that they are available to the Windows installer. #### Guest Agents Ensure that you install the required guest tools for your target VM environment, such as VMware Tools or the QEMU Guest Agent, as well as any necessary additional boot-time services such Cloudbase-Init. #### Sysprep [Sysprep](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--generalize--a-windows-installation) is a Microsoft tool to generalise Windows installs for image deployments. While Kasm does not require Windows templates to be generalised, there are some scenarios where it is required. If you are deploying to Azure then running sysprep is required. If you are joining your Windows AutoScale VMs to Active Directory then running sysprep is recommended. Generalised images may require additional first run tasks to be performed by your AutoScale startup scripts to configure them for your use. #### Multi-User Environments If you intend to support multi-user environments on your Windows AutoScale VMs then you should ensure that the default user profile on the template has been configured to meet your requirements. You will also need to install the Kasm Desktop Service as part of your AutoScale startup script. #### Audio Services The Windows Audio (`Audiosrv`) service is not started by default on Windows Server and so if audio support is required this should be handled by your startup script or, if not using sysprep, by setting the service to Automatic startup on your template. #### Additional Software To improve the speed at which your Windows AutoScale VMs can be provisioned it is recommended where possible to install any required software onto the template, rather than installing at runtime. In scenarios where license keys or product activation is required, you may be able to install the unlicensed software onto the template and configure licensing at runtime. We recommend regularly rebuilding your templates to keep your software up to date and secure. #### Domain Join AutoScaled servers can be configured to automatically join Active Directory. This is a two step process which involves Kasm first creating a Computer Object in Active Directory, within a specified AD container. When the Computer Object is created, a random single use password is created, which can only be used to join the computer to the domain. The final step of joining the computer to the domain must be done from the Windows server itself. This is facilitated through the startup script of the VM Provider configuration. The Powershell startup script can then join the computer to the domain using the single use random password that was created by Kasm. * Create an LDAP Configuration that will be used for user authentication to Kasm. * Create an LDAP Configuration that will be used to create computer objects in AD. The service account used by this LDAP configuration must have permissions to create and remove computers from the domain. You can use the same LDAP configuration that is used to authenticate users or you can create a different LDAP configuration used specifically for joining and removing systems. If you use a separate LDAP configuration, leave it disabled so that it cannot be used for authentication purposes. * In the AutoScale Configuration, select `SSO User Accounts` for the Connection Credential Type. * In the AutoScale Configuration, check the Create Active Directory Computer Record box. * In the LDAP Config select the LDAP configuration created in step 2. * In the Active Directory Computer OU DN, enter the AD OU Distinguished Name. Example: `OU=Computers,DC=example,DC=local` * Enable Recursively Cleanup Active Directory Computer Record if you anticipate the Computer objects having child objects. This can prevent `notAllowedOnNonLeaf` errors when cleaning Azure VMs. * Click Next to save the AutoScale configuration. * The next page is the VM Provider configuration. Scroll down to the startup script and provide one which includes a domain join command, such as: ```powershell $joinCred = New-Object pscredential -ArgumentList ([pscustomobject]@{{ UserName = $null; Password = (ConvertTo-SecureString -String '{ad_join_credential}' -AsPlainText -Force)[0] }}) Add-Computer -Domain "{domain}" -Options UnsecuredJoin,PasswordPass -Credential $joinCred -Force -Restart ``` > If your script uses curly brackets, aside from Kasm variables, you must escape them by doubling them up. #### Startup Scripts Each VM Provider has special caveats around how their startup scripts are handled, see the VM Provider page for your target environment for more details. While each VM Provider may behave a bit differently or expect a slightly different format, they all support PowerShell scripts and that script will have access to Kasm managed variables. We provide some examples in our [AutoScale start scripts Github repo](https://github.com/kasmtech/workspaces-autoscale-startup-scripts). The following table lists variables that are accessible from the startup PowerShell script. > For VMware, due to the way VMware Tools operates, Kasm requires a direct network connection to the ESX host running a Windows VM in order to execute the startup script. All other AutoScale activities occur via connection to vCenter. ##### Startup Script Variables | Variable Name | Description | | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | connection_username | If the AutoScale configuration is set to use a static username for Kasm user sessions, the username will be contained in this variable. | | connection_password | If the AutoScale configuration is set to use a static password for Kasm user sessions, this variable will contain the password. | | ad_join_credential | If the AutoScale configuration is set to join the VM to an Active Directory domain, Kasm creates the AD record and sets a random password that can only be used for joining the VM to the domain. This can then be used in a Powershell startup script to complete the process of joining the system to the domain. | | domain | If the AutoScale configuration is set to join the VM to an Active Directory domain, this variable will contain the name of the domain. | #### Kasm Desktop Service The Kasm Desktop Service is a Windows service that provides additional capabilities to users that are connected to the desktop through Kasm Workspaces: * Upload files to the remote desktop * Download files from the remote desktop * See a preview screenshot of the desktop in the Kasm Workspaces dashboard * Run PowerShell scripts on session start, session end, or service start * Kasm managed local Windows users and credentials * File Mapping * Supports multiple concurrent users on the same Windows system users and credentials * File Mapping * Supports multiple concurrent users on the same Windows system rs and credentials * File Mapping * Supports multiple concurrent users on the same Windows system rs and credentials * File Mapping * Supports multiple concurrent users on the same Windows system rs and credentials * File Mapping * Supports multiple concurrent users on the same Windows system ers and credentials * File Mapping * Supports multiple concurrent users on the same Windows system We recommend that you always install the Kasm Desktop Service as part of your AutoScale startup script. The example scripts in our [AutoScale start scripts Github repo](https://github.com/kasmtech/workspaces-autoscale-startup-scripts) demonstrate the unattended install process. The Kasm Desktop Service uses HTTPS/SSL to communicate with the rest of the Kasm Workspace services. The service installer will open the Windows firewall for TCP port 4902, ensure that firewalls and/or cloud security groups allow inbound TCP port 4902 coming from Kasm API server and Connection Proxy servers. The Kasm Desktop Service will talk outbound to the API Server on the port your deployment utilizes, TCP port 443 by default. Ensure security groups and our firewall rules allow this communication. TCP port 443 by default. Ensure security groups and our firewall rules allow this communication. --- ## Database Admin: Backup, Restore & Passwords # Database ## PostgreSQL Database Kasm uses Postgres as the backend database. This section covers backup and restoration of the Kasm database. ### Backups The following script will backup the Postgres data and all conf files to a single file. ```yml # this will place the back at /tmp/backup.tar sudo docker exec kasm_db pg_dump -U kasmapp -F t kasm > /tmp/backup.tar ``` This can be scripted out in a cron job, for example daily, with the date in the filename of the tar file for historical backups. Change the /tmp to a directory that is using an NFS mount so the files are stored off the server. ### Restore The following script will restore the database from backup. This example assumes the server is just the database role, however, this process will work just as well on a system where all roles are installed. ```bash # download the same version of kasm that is on the primary database server and unpack it cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz # install just the database component sudo bash kasm_release/install.sh -b # copy the backup.tar into the kasm_db container sudo docker cp backup.tar kasm_db:/tmp/backup.tar # restore the database sudo docker exec kasm_db pg_restore -d kasm /tmp/backup.tar -c -U kasmapp ``` If you restore to a different server you will need to change the database IP or hostname that is referenced by all API and Manager systems. You can avoid this using several methods. Use a hostname and change the IP address in your DNS record. This may take up to an hour to propogate depending on the TTL setting of the DNS record. Use a 5 minute TTL if possible. The other method is to use a virtual IP address if you have a router or firewall inbetween your database servers and the manager/api components. Finally, you can use NGINX with layer 4 load balancing. You can back one backend server as back in the upstream definition in nginx. ### Change Database Password Administrators may wish to change the password Kasm API service uses to connect to the database. The following will change the password for the kasmapp user in the PostgreSQL database and the password that the Kasm API is configured to use when attempting to connect to the PostgreSQL database. Changing the Postgres password involves restarting Kasm services and will result in an interruption in service. Login to the server with the Database role and run the following to change the database password. Replace 'new_password' with your desired password, ensuring it does not contain any `$`, `'` or `"` characters. ```Bash sudo docker exec -it kasm_db psql -U kasmapp -d kasm -c "ALTER ROLE kasmapp WITH PASSWORD 'new_password';" ``` Login to the server with the Web App role and stop the Kasm Services. ```Bash sudo systemctl stop kasm ``` Edit the API app config, replacing the value on the line starting with 'password: ' with your new desired password. ```Bash sudo vi /opt/kasm/current/conf/app/api/api.app.config.yaml ``` Start Kasm Services on Web App server. ```Bash sudo systemctl start kasm ``` --- ## Kasm Deployment Zones: Configuration and Management # Deployment Zones Deployment Zones are created to enable logical grouping of Kasm services. In large or distributed deployments, it may be desirable to route users to Kasm services that are closer geographically to improve the user experience. In other use cases, Deployment Zones might be defined for special network segments representing different tenants or security enclaves. Administrators can then leverage standard routing, DNS, load balancing, or other networking techniques to direct user traffic to a desired Zone. ![Deployment Zones Diagram](/img/zones/deployment_zones_diagram.png) ### Capabilities Utilizing multiple deployment zones allows administrators to: - Prefer end-user sessions are provisioned in the Deployment Zone the user is connected to. - When a user connects to the Kasm UI, the server will attempt to provision the Kasm on Agents in the same Zone, only falling back to other Agent's in other Zone's if all Agents in the current zone are full or unavailable. - Restrict certain [Workspaces](../../reference/glossary.mdx#workspace) to only provision on Agent's within a given Deployment Zone. See [Add/Edit Kasm Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) - This option is most useful if the Deployment Zones represent special network enclaves that only certain Workspaces and perhaps certain Users should be allowed to access. ### Configuring Deployment Zones #### Defining Zone Configurations Existing Deployment Zones can be updated in the UI by an administrator. Deployment Zones can only be created at Web App installation time. See [the instructions](../../tutorials/install/multi-server-install.mdx#install-web-app-role) for more information. ![Zones List](/img/zones/deployment_zones_list.webp) ![Update Zone](/img/zones/deployment_zones_config.webp)
Zone Configuration Options
| **Field** | **Description** | **Default Value** | |----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------| | **Zone Name** | The name given to the Zone. | | | **Allow Origin Domain** | Connections to Kasm sessions are restricted to authorized Origins. This value is the authorized origin domain. | `"$request_host$"` | | **Upstream Auth Address** | Connections to Kasm sessions are authenticated against a Kasm API server. This value is the address of the server. | `"proxy"` | | **Load Balance Strategy** | Determines how the system prioritizes Agents when a user requests a new Kasm session: • **Least Load**: Prioritizes Agents with the least consumed CPU/Memory. • **Most Load**: Prioritizes Agents with the most consumed CPU/Memory. • **Least Kasms**: Prioritizes Agents with the fewest active sessions. • **Most Kasms**: Prioritizes Agents with the most active sessions. *For Server Pools of type "Server", load is based on session count vs. configured supportable sessions.* *For SSH, RDP, and RemoteApp sessions, a server the user already has an active session on is preferred over this strategy, provided that server has not reached its configured session capacity.* | **Least Load** | | **Search Alternate Zones** | Allows the system to search for resources in alternate Zones if the same-Zone Agents cannot satisfy the session request. Same-Zone Agents are always preferred. | **Enabled** | | **Prioritize Static Agents** | Prefers using fixed Agents before utilizing auto-scaled [Docker Agents](docker-agent.mdx). | **Enabled** | | **Labels** | Labels assigned to all servers and agents in this zone. These labels can be used to control where [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) sessions are launched. You can specify these labels in a Workspace's "Include Labels" or "Exclude Labels" settings to ensure sessions run only on certain servers or agents. | **None** | | **Proxy Connections** | When **enabled**, the user connects to the Kasm session via a proxy server. When **disabled**, connections go directly to the Kasm Agent hosting the session. | **Enabled** | | **Proxy Hostname** | Hostname of the proxy server used when Proxy Connections are enabled. | `"$request_host$"` | | **Proxy Path** | The base path appended to the Kasm connection URL when using Proxy Connections. | `"/desktop"` | | **Proxy Port** | The port used for the proxy server. If set to `0`, Kasm Workspaces will try to detect the correct port from `window.location.port`. | `"0"` | | **Proxy RDP Local Client Connections** | When **enabled**, RDP connections from native RDP clients are proxied through Kasm Web App servers to the RDP Gateway, allowing use of a single domain. When **disabled**, clients connect directly to the Guac role, which requires public IP and DNS. This setting applies only if **Enable RDP HTTPS Gateway** is also enabled. | **Enabled** | | **RDP HTTPS Proxy Hostname** | Hostname/IP of the load balancer or proxy in front of the HTTPS-based RDP Gateway. | `"$request_host$"` | | **RDP HTTPS Proxy Port** | Port number of the load balancer or proxy for the HTTPS-based RDP Gateway. | `"443"` | | **Restrict RDP Client IP Address** | Enforces that the client's IP for the RDP connection matches the IP of the API call that initiated the session. Not compatible with changing IPs (e.g., via load balancers, proxies, or tunnels like Cloudflare). | **Disabled** | | **Enable RDP HTTPS Gateway** | When **enabled**, uses HTTPS RDP Gateway protocol. When **disabled**, standard RDP over port 3389 is used. | **Disabled** | | **Enable RDP HTTPS Gateway DLP** | Sends HTTPS RDP connections through Data Loss Prevention (DLP). This may affect performance/scalability. Disabling DLP disables some Kasm data protection features and breaks single sign-on. Applies only if **Enable RDP HTTPS Gateway** is enabled. | **Disabled** | **\$request_host\$** referenced as the default for several settings above can be used to automatically reference the domain/host used in the URL to access the Kasm deployment. For example if users accesses Kasm via `https://east.kasm.server` , **\$request_host\$** will be `east.kasm.server`. #### Assigning Zone Configurations [agents](../../reference/glossary.mdx#agent) are assigned the Zone of whichever manager they are currently checked in to. Once defined, the Kasm services need to be configured to be members of the given Zone. The Deployment Zone setting for API Servers (kasm_api, kasm_manager) is set their configuration file. The default zone is **default** ```bash grep zone_name /opt/kasm/current/conf/app/api/api.app.config.yaml zone_name: east ``` - Ensure all Kasm services are stopped ```Bash sudo systemctl stop kasm ``` - Edit the **zone_name** property in api.app.config.yaml ```Bash vi /opt/kasm/current/conf/app/api/api.app.config.yaml ``` - Restart the Kasm Services ```Bash sudo systemctl start kasm ``` --- ## Direct to Agent Configuration in Kasm Workspaces # Direct To Agent ## Overview By default, connections to Kasm session are proxied through the Web App role to the Agent role. This works well in most situations, and reduces complexity. In some situations it may be desired have users make connections directly through the agent instead of being proxied through the Web App. ![Connection Workflows](/img/direct_to_agent/workflows.png) In order to utilize the Direct to Agent workflow, the following requirements must be met. - Kasm Workspaces is installed in a multi-server configuration. - All Web App and Agent servers must be resolvable via DNS by clients and all Kasm role servers and must be registered within the same domain eg. `app-1.kasm.example.com` `agent-1.kasm.example.com`. - Clients and Kasm role servers must be able to connect to the Agent and Web App addresses (as resolved by DNS) via HTTPS. - All Web App and Agent servers must have valid certificates trusted by the clients. See [Certificates](../networking/replace-certificates.mdx) for configuration details. These instructions assumes starting from a working multi-server install. ## Agent Update In this section we will configure the Agent's to utilize their DNS name when registering to the Workspaces system. - Stop the services on the Agent ```Bash sudo systemctl stop kasm ``` - Update the `public_hostname` value in `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` the the public DNS name of the Agent eg `agent-1.kasm.example.com` ```Bash vi /opt/kasm/current/conf/app/agent/agent.app.config.yaml ``` - Start the services on the Agent ```Bash sudo systemctl start kasm ``` - Log into the Workspaces UI as administrator. Select **Infrastructure** -> **Docker Agents**. Verify the Agent is checking in as the proper DNS name. - Repeat these steps for all Agents. ## Application Settings - Log into the Workspaces UI as an administrator - Select **Infrastructure** -> **Zones** then select **Edit** next to the applicable Zone. - Uncheck **Proxy Connections**. Click Save. ![Zone Configuration](/img/direct_to_agent/proxy_connections.webp) - From the Admin panel select **Settings** -> **Global** - Set **Kasm Authorization Domain** to the parent domain of the Web App and Agent servers. eg `kasm.example.com`. ![Auth Domain](/img/direct_to_agent/auth_domain.webp) - Restart the services on all Web App servers ```Bash sudo systemctl restart kasm ``` ## Testing - Log out of the Workspaces UI. - In a new Incognito browser window log into the Workspaces UI. - Open the browser developer tools and navigate to the Network tab. Enter `vnc.html` into the filter. - Launch a new session. The Url in developer tools should have the Agent's address as the domain ![Developer Tools](/img/direct_to_agent/developer_tools.png) --- ## Kasm Workspaces: DNS Provider Configs # # DNS Provider Configs This feature requires a special license. Please contact your Kasm Technologies representative for details. ![Create New DNS](/img/compute/dns_create_new.webp) | **Name** | **Description** | | --- | --- | | **DNS Provider Configs** | Select an existing config or create a new config. If you select an existing config and change any of the details, those details will be changed for anything using the same DNS Provider config. | | **Provider** | Select a provider from AWS, Azure, Digital Ocean, Google Cloud or Oracle Cloud. If you select an existing provider this will be selected automatically. | ## AWS DNS Provider Settings ![AWS DNS Provider](/img/compute/dns_aws.webp) | **Name** | **Description** | | --- | --- | | **Name** | A name to use to identify the config. | | **Access Key ID** | The AWS Access Key used for the AWS API. | | **Access Key Secret** | The AWS Secret Access Key used for the AWS API. | ## Azure DNS Provider Settings ![Azure DNS Provider](/img/compute/dns_azure.webp) | **Name** | **Description** | | --- | --- | | **Name** | A name to use to identify the config. | | **Subscription ID** | The Subscription ID for the Azure Account. This can be found in the Azure portal by searching for Subscriptions in the search bar in Azure home then selecting the subscription you want to use. (e.g `00000000-0000-0000-0000-000000000000`) | | **Resource Group** | The Resource Group the DNS Zone and/or Virtual Machines belong to (e.g `dev`) | | **Tenant ID** | The Tenant ID for the Azure Account. This can be found in the Azure portal by going to Microsoft Entra ID using the search bar in Azure home. (e.g `00000000-0000-0000-0000-000000000000`) | | **Client ID** | The Client ID credential used to auth to the Azure Account. Client ID can be obtained by registering an application within Microsoft Entra ID. (e.g `00000000-0000-0000-0000-000000000000`) | | **Client Secret** | The Client Secret credential created with the registered application in Microsoft Entra ID. (e.g `abc123`) | | **Azure Authority** | Which Azure authority to use, there are four, Azure Public Cloud, Azure Government, Azure China and Azure Germany. | | **Region** | The Azure region where the Agents will be provisioned. (e.g `eastus`) | ## Digital Ocean DNS Provider Settings ![Digital Ocean DNS Provider](/img/compute/dns_do.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Token** | The token to use to connect to this VM | ## Google Cloud (GCP) DNS Provider Settings ![Google Cloud DNS Provider](/img/compute/dns_google.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Project** | The Google Cloud Project ID (e.g pensive-voice-547511) | | **Credentials** | The JSON formatted credentials for the service account used to authenticate with GCP: [Ref](https://cloud.google.com/iam/docs/creating-managing-service-account-keys#iam-service-account-keys-create-console) | ## Oracle Cloud (OCI) DNS Provider Settings ![OCI DNS Provider](/img/compute/dns_oracle.webp) | Name | Description | | --- | --- | | **Name** | A name to use to identify the config. | | **Fingerprint** | The public key fingerprint of the authenticated API user. (e.g xx:yy:zz:11:22:33) | | **Tenancy OCID** | The Tenancy OCID for the OCI account. (e.g ocid1.tenancy.oc1..xyz) | | **Region** | The OCI Region name. (e.g us-ashburn-1) | | **Compartment OCID** | The Compartment OCID where the auto-scaled agents will be placed. (ocid1.compartment.oc1..xyx) | | **User OCID** | The OCID of the user to authenticate with the OCI API. (e.g ocid1.user.oc1..xyz) | | **Private Key** | The private key (PEM format) of the authenticated API user. | --- ## Docker Agents: Management & Configuration # Docker Agents An Agent is any compute resource where a user's containerized [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx) can be provisioned. The compute resource needs the [Kasm Agent role](../../explanations/system-architecture.mdx) installed. ## View Agents View a list of Agents by selecting **Infrastructure** -> **Docker Agents** from the Kasm UI. ![Agents List](/img/agents/view_agents.webp) ### Agent Actions Clicking the arrow for the session will present a list of potential actions: - **Edit** - Edit and view details for the selected Agent. - **Delete Sessions** - Mark all sessions on the Agent as "deleting". The Sessions will be deleted in a few moments. Sessions resumed from a stopped state will have the previous files intact, but previously running programs will need to be restarted. - **Delete** - Delete the Agent from the Kasm Deployment. - **Drain** - Mark the Agent as "Draining". An Agent in Draining mode will not allow new sessions to be created. Once all existing sessions on the Agent are closed, the agent will be Deleted. (This Option is only Applicable to Agents created from an Autoscale Pool) ### Agent Details More details about an individual Agent can be seen by clicking the **Edit** (pencil) icon under the **Details** and **Usage** tabs. ![Agents Details](/img/agents/agent_details.webp) The bar chart shows two different stats for RAM and CPU respectively. It shows how much RAM/CPU is currently being utilized and it shows how much is currently allocated. If you have an agent that has 6 CPUs, is overriden to 12 CPUs, and has two desktops allocated, 1 at 2 CPUs and 1 at 3 CPUs, it will show 5 of 12 CPUs are allocated. It will also show what the current CPU utilization was during the last checkin. ## Agent Chart Historical CPU, Memory, and disk utilization can be tracked for an Agent by viewing the **Dashboard** in the Kasm UI. ![Agents Utilization Chart](/img/agents/agent_chart.webp) ## Agent Settings Agent settings may be configured from the Kasm UI by selecting **Infrastructure** -> **Agents** -> **Edit** (Pencil Icon) ![Update Agent](/img/multi_install/update_agent.webp) | **Field** | **Description** | | --- | --- | | Enabled | When checked, the Agent will service requests to create sessions. When disabled, the Agent will not be considered for requests to create more sessions. This is useful to "drain" sessions from an agent prior to maintenance. | | Automatically Prune Images | Instruct the Agent to automatically delete (prune) unneeded images. Only Kasm Workspaces images are pruned. **Off** - Pruning is disabled. **Normal** - Prune untagged (dangling) images. **Aggressive** Prune untagged images and any image that is no longer defined in the application. | | Cores Override | Instruct the system to treat the Agent as if it has this number of CPU Cores. This is useful to tactically oversubscribe the Agent. 0 indicates no-override. The system will use the actual CPU Cores of the system. | | NVIDIA CUDA GPUs Override | Instruct the system to treat the Agent as if it has this number of NVIDIA CUDA GPUs. This is useful to tactically oversubscribe the Agent. 0 indicates no-override. The system will use the actual number of GPUs for the system. | | Memory Override | Instruct the system to treat the Agent as if it has this amount of Memory (in bytes). This is useful to tactically oversubscribe the Agent. 0 indicates no-override. The system will use the actual memory of the system. | | Drain Time | The time when this Agent switches to "Draining" mode. In Draining mode, the Agent will not accept any new sessions and once all active sessions have ended, the Agent will be automatically deleted. | | Labels | Labels assigned to this Agent. These labels can be used to control where [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) sessions are launched. You can specify these labels in a Workspace's "Include Labels" or "Exclude Labels" settings to ensure sessions run only on certain agents. | ### CPU / Memory / GPU Override An Agent reports how much RAM, CPU cores, and GPU resources are available on the system. If an Agent has 6 CPU cores and 6 GB of RAM and all Images are set to 1 CPU and 1 GB of RAM, only 6 sessions can be provisioned on the Agent at one time. You can, however, override CPU, RAM, and GPU resources to allow for oversubscribing. Here you are able to override the CPU, GPU, and RAM. A value of 0 means no override. If an agent server has 6 CPUs, you can, for example, configure an override of 12 CPUs. This would allow you to provision 12 instances of a user desktop, if each image was set to 1 CPU. The agent would still need 12 GB of RAM to provision 12 users if each image was set to 1GB of RAM. You can also override RAM in the same manner as CPUs. It is important to ensure your servers have a SWAP partition adequate in size to overcome over utilization of RAM. Not having a swap file can result in user desktops being destroyed when RAM is over subscribed. Overriding the GPU count allows the agent to assign more user sessions to a one or more GPUs. The system must have at least one physical GPU to override. For both CPU and GPU override, the setting allows administrators to oversubscribe resources. However, it does not allow administrators to provide more resources to a single session than a system has. For example, if a system has 1 GPU and the GPU override was set to 10, that would allow 10 sessions requiring 1 GPU each to be created. The system, however, will not allow an image set to 10 GPUs to be assigned to an agent that has only 1 physical GPU, even of an override of 10 GPUs is used. ## GPU Support In the Update Agent form, there is a **GPU Hardware** section, this allows you to see the GPUs detected on the system and what features that GPU supports. From here you can enable and disable features on each GPU. In the example screenshot below, the NVIDIA GPU supports video encoding acceleration, but the administrator has disabled it. Disabling a feature will ensure that GPU is not assigned to containers for the selected feature. ![Update Agent](/img/multi_install/agent_gpu_hardware.webp) The following video demonstrates detecting, monitoring, and configuring GPU hardware from the Docker Agent interface. Workspaces supports passing through NVIDIA based GPUs to streaming containers. Workspaces utilizes the NVIDIA container toolkit. For a full list of supported GPUs and operating systems see [https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/platform-support.html](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/platform-support.html). The [NVIDIA drivers and container toolkit](../../tutorials/install/gpu.mdx) must be installed on all Workspaces Agent servers with GPUs intended to pass through to containers. GPUs can be used within a streaming container for a number of purposes, to include graphics, gaming, running applications that use CUDA, and developing with GPU accelerated frameworks such as Pytorch or Tensorflow. Using Workspaces allows organizations to easily manage and provide access to GPU backed resources. Follow the [GPU How-To](../../tutorials/install/gpu.mdx) for a detailed walk through of a deployment. Workspaces allows administrators to see how many GPUs an agent has. The number displayed only includes NVIDIA CUDA GPUs as seen by the NVIDIA container runtime. Other GPUs can be seen in the Agent details view. ![Agent GPU Resources](/img/gpus/agents_view.webp) Administrators can view all GPU details of an agent in the Update GPU form, Usage tab. NVIDIA CUDA hardware is displayed in the middle section with usage statistics. All GPUs are shown in the button GPU section along with what features that GPU supports. In this example screenshot, the NVIDIA GPU supports NVENC, however, it has been disabled by the administrator. Features can be enabled/disabled in the Details tab of the same view. ![Agent GPU Details](/img/gpus/agent_details.webp) Workspaces images allow defining GPU requirements. Set the number of GPUs this container should be assigned and/or what graphics and video acceleration methods are required. A requested session using this image will only be provisioned on an agent that has the number of selected CUDA GPUs or a GPU with the requested features. Only NVIDIA GPUs are explicitly passed through and have a count defined. Other GPUs are automatically passed through based on what features are needed, for example VAAPI video acceleration. ![File Mappings Table](/img/images/image_gpu_settings.webp) ### GPU Accelerated Graphics Kasm Workspaces Images may support DRI3, EGL, and/or VULKAN for GPU acceleration. The Workspace Image settings allow you to specify which to use. DRI3 is natively supported by KasmVNC and is the preferred method, however, DRI3 is not supported by NVIDIA. Intel and AMD GPUs generally support DRI3. NVIDIA GPUs generally support EGL and VULKAN, with the exception of enterprise grade GPUs that may not have DRM devices exposed. EGL is supported with the use of VirtualGL while Vulkan is supported through the use of Zink. Virtual GL is generally pre-installed on Kasm maintained Workspace image that are based on Ubuntu. Zink is generally included in the MESA package that is installed on all Kasm maintained Workspaces images. Testing with your specific application and desktop environment is needed to know which graphics acceleration method is the right choice for you. You must be using an image that is based on a Kasm Workspaces image version 1.19.0 or higher. See our [Workspace Images](../workspaces-sessions/container-workspace/workspaces.mdx#workspace-image-gpu-support) documentation for details on which core images support which GPU features. The security of multi-tenant container GPU acceleration is not well established. This feature should be used with caution and with full understanding of the potential security implications. These features are being provided for by the GPU manufacturer and are merely being orchestrated by Kasm Workspaces. Kasm Technologies Inc provides no warranty of the security of such features provided by GPU vendors. Kasm Technologies recommends that GPUs not be shared between different security contexts and/or boundaries. NVIDIA provides the MIG feature on enterprise grade GPUs for creating smaller instances from a single GPU, which Kasm supports. ### GPU Video Acceleration Kasm detects support for VAAPI and NVENC hardware based video encoding/decoding acceleration. You can enable these features on Workspaces Image settings and the appropriate DRM devices will be passed through to any resulting containers. KasmVNC currently supports VAAPI for h.264 and h.265 encoding and will automatically use the hardware when detected. ### NVIDIA MIG Support NVIDIA Multi-Instance GPU (MIG) is a feature available on select NVIDIA data center GPUs (such as the A100 and H100) that allows a single physical GPU to be partitioned into multiple isolated GPU instances. Each MIG instance functions as an independent GPU slice with dedicated compute, memory, and bandwidth resources. MIG enables more efficient and secure GPU utilization by allowing multiple Workspaces or user sessions to securely share the same GPU hardware without contention or interference. Kasm automatically disables the physical GPU from being used by Kasm sessions when MIG instances are detected, as seen in this screenshot. MIG instances will be listed under the physical GPU, indented slightly as shown here. ![NVIDIA MIG GPUs](/img/gpus/agent_gpus_mig.webp) #### Enabling MIG on supported NVIDIA GPUs 1. Use `nvidia-smi` command to list GPUs and get the GPU index for the target GPU. Each GPU has a unique index, usually starting at 0. For this demonstration below, we will use `0`. 2. Check if your GPU supports the MIG feature, change your `-i 0` to reference your GPU index if not 0. ```Bash # This GPU supports MIG but it is current disabled. nvidia-smi -i 0 --query-gpu=pci.bus_id,mig.mode.current --format=csv pci.bus_id, mig.mode.current 00000000:00:04.0, Disabled # This GPU does not support the MIG feature nvidia-smi -i 0 --query-gpu=pci.bus_id,mig.mode.current --format=csv pci.bus_id, mig.mode.current 00000000:21:00.0, [N/A] ``` 2. Enable MIG ```Bash sudo nvidia-smi -i 0 -mig 1 Warning: MIG mode is in pending enable state for GPU 00000000:00:04.0:Not Supported Reboot the system or try nvidia-smi --gpu-reset to make MIG mode effective on GPU 00000000:00:04.0 All done. ``` 3. Reboot the system. 4. List available MIG . ```Bash nvidia-smi mig -lgip +-------------------------------------------------------------------------------+ | GPU instance profiles: | | GPU Name ID Instances Memory P2P SM DEC ENC | | Free/Total GiB CE JPEG OFA | |===============================================================================| | 0 MIG 1g.5gb 19 7/7 4.75 No 14 0 0 | | 1 0 0 | +-------------------------------------------------------------------------------+ | 0 MIG 1g.5gb+me 20 1/1 4.75 No 14 1 0 | | 1 1 1 | +-------------------------------------------------------------------------------+ | 0 MIG 1g.10gb 15 4/4 9.75 No 14 1 0 | | 1 0 0 | +-------------------------------------------------------------------------------+ | 0 MIG 2g.10gb 14 3/3 9.75 No 28 1 0 | | 2 0 0 | +-------------------------------------------------------------------------------+ | 0 MIG 3g.20gb 9 2/2 19.62 No 42 2 0 | | 3 0 0 | +-------------------------------------------------------------------------------+ | 0 MIG 4g.20gb 5 1/1 19.62 No 56 2 0 | | 4 0 0 | +-------------------------------------------------------------------------------+ | 0 MIG 7g.40gb 0 1/1 39.38 No 98 5 0 | | 7 1 1 | +-------------------------------------------------------------------------------+ ``` 5. Create MIG instances. In this example, I chose the 1g.10gb profile to create 4 instances, each with 10GB of VRAM. ```Bash sudo nvidia-smi mig -cgi 1g.10gb,1g.10gb,1g.10gb,1g.10gb -C Successfully created GPU instance ID 4 on GPU 0 using profile MIG 1g.10gb (ID 15) Successfully created compute instance ID 0 on GPU 0 GPU instance ID 4 using profile MIG 1g.10gb (ID 0) Successfully created GPU instance ID 3 on GPU 0 using profile MIG 1g.10gb (ID 15) Successfully created compute instance ID 0 on GPU 0 GPU instance ID 3 using profile MIG 1g.10gb (ID 0) Successfully created GPU instance ID 5 on GPU 0 using profile MIG 1g.10gb (ID 15) Successfully created compute instance ID 0 on GPU 0 GPU instance ID 5 using profile MIG 1g.10gb (ID 0) Successfully created GPU instance ID 6 on GPU 0 using profile MIG 1g.10gb (ID 15) Successfully created compute instance ID 0 on GPU 0 GPU instance ID 6 using profile MIG 1g.10gb (ID 0) ``` 6. Verify that `nvidia-smi` shows the newly created instances. ```Bash nvidia-smi Tue Mar 31 13:13:13 2026 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 590.48.01 Driver Version: 590.48.01 CUDA Version: 13.1 | +-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA A100-SXM4-40GB Off | 00000000:00:04.0 Off | On | | N/A 33C P0 44W / 400W | 119MiB / 40960MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | MIG devices: | +------------------+----------------------------------+-----------+-----------------------+ | GPU GI CI MIG | Shared Memory-Usage | Vol| Shared | | ID ID Dev | Shared BAR1-Usage | SM Unc| CE ENC DEC OFA JPG | | | | ECC| | |==================+==================================+===========+=======================| | 0 3 0 0 | 30MiB / 9984MiB | 14 0 | 1 0 1 0 0 | | | 0MiB / 6105MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 4 0 1 | 30MiB / 9984MiB | 14 0 | 1 0 1 0 0 | | | 0MiB / 6105MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 5 0 2 | 30MiB / 9984MiB | 14 0 | 1 0 1 0 0 | | | 0MiB / 6105MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 6 0 3 | 30MiB / 9984MiB | 14 0 | 1 0 1 0 0 | | | 0MiB / 6105MiB | | | +------------------+----------------------------------+-----------+-----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | No running processes found | +-----------------------------------------------------------------------------------------+ ``` The following video demonstrates enabling MIG mode, creating instances with `nvidia-smi`, and assigning them to Kasm Workspaces. ## Changing Manager Token An administrator may wish to change the token that Agents use to check into the manager. The steps outlined below will change the token on each of the agents and on the manager. Changing the Manager token involves restarting Kasm services and will result in an interruption in service. First, enter the Kasm Admin UI -> Settings -> Global and change the value of "Token" in the manager settings to your new desired token. ![Manager Token Settings](/img/agents/manager_token.webp) **Login to each server with the agent role and complete the following steps:** Stop the Agent Services ```Bash sudo systemctl stop kasm ``` Replace the value of 'token' in the agent config with the new manager token. ```Bash sudo vi /opt/kasm/current/conf/app/agent/agent.app.config.yaml ``` Start the Agent Services ```Bash sudo systemctl start kasm ``` After one minute the Agents should all be checked back into the Manager as shown in the "Infrastructure" -> "Agents" page in the Kasm Admin UI. --- ## Kasm Workspaces: Manager Service - Overview and Enable/Disable # Managers ## Overview The **Manager Service** (`kasm_manager`) is the coordination layer between the Kasm API and the Agent fleet. Every Agent periodically checks in with a Manager to report available resources and receive instructions. Managers in turn track session state, monitor Agent health, and elect a **Primary Manager** per zone to handle time-sensitive tasks such as promoting Agents and reconciling session counts. In a multi-server deployment, multiple Managers can run within the same [Deployment Zone](./deployment-zones.mdx). At any given time, exactly one Manager per zone holds the Primary Manager role. If the current Primary Manager becomes unavailable, another Manager in the zone automatically assumes the role. ## View Managers Navigate to **Infrastructure** -> **Managers** in the Kasm admin UI to see a list of all registered Managers and their current state. Each Manager entry shows: | Column | Description | |---|---| | **Instance ID** | Unique identifier for the Manager container instance. | | **Enabled** | Whether the Manager is currently active and accepting Agent connections. | | **First Reported Time** | Timestamp when the Manager first registered with the deployment. | | **Last Reported Time** | Time elapsed since the Manager last sent a heartbeat. | | **Zone** | The Deployment Zone this Manager belongs to. | | **Status** | Current operational status (`running`, `unknown`). | | **Primary Manager** | Indicates which Manager holds the primary role in its zone. | ## Enable / Disable a Manager Managers can be **disabled without stopping or restarting the container**. This is useful for taking a Manager out of rotation for maintenance, debugging, or rolling updates while keeping the Agent fleet operational. At least one Manager per zone must remain enabled at all times. The UI will display an error and prevent the action if disabling a Manager would leave a zone with no enabled Managers. ### How it works When a Manager's `enabled` flag is set to `false` in the database: 1. **Sentinel file created** : The Manager process writes a sentinel file at `/tmp/kasm_manager_draining` inside the container (mapped to `/opt/kasm/current/tmp/manager/` on the host). 2. **Nginx stops serving the Manager** : The `kasm_proxy` nginx container checks for the sentinel file on every incoming request. When present, nginx returns `503 Service Unavailable` with a `Retry-After: 30` header on `/health` and stops proxying `/manager_api/` requests — both behaviors triggered independently by the same sentinel check. 4. **Work suspended** : The Manager's internal guardian loop skips all work when `enabled=false`, preventing a disabled Manager from promoting itself to Primary or modifying shared resources. 5. **Container stays healthy** : Docker's container health reporting is patched to distinguish between "disabled" and "unhealthy", so a disabled Manager continues to report `healthy` to Docker and will **not** trigger an automatic restart. When the Manager is re-enabled: - The sentinel file is removed. - Nginx resumes proxying requests normally and returns `200 OK`. - The guardian loop resumes, and the Manager can eventually re-acquire the Primary role if appropriate. ### Primary Manager failover If you disable the current Primary Manager, another enabled Manager in the same zone automatically promotes itself to Primary. All Agents in the zone re-register with the new Primary Manager. This promotion happens within a few minutes as part of the regular guardian loop cycle. After re-enabling a Manager, allow up to a minute for it to return to `running` status. The guardian loop processes state on a fixed interval, so the transition is not instantaneous. ## Verifying Manager State The following commands can be run on the host where the Manager container is running to confirm expected behavior after a state change. **Check the healthcheck endpoint response:** The Manager exposes two health endpoints serving different purposes: | Endpoint | Used by | Disabled response | |---|---|---| | `/__healthcheck` | Docker internal healthcheck | `503` — remapped to `healthy` by the healthcheck script to prevent container restart | | `/health` | `kasm_proxy` nginx | `503` — nginx stops proxying requests to the Manager | To inspect the Manager process directly (bypassing nginx): ```bash docker exec -it kasm_manager curl -i http://localhost:8181/__healthcheck ``` - `200 OK` — Manager is enabled and healthy. - `503` with `{"ok": false, "status": "disabled", "enabled": false}` body — Manager is intentionally disabled. Docker's healthcheck script maps this to `healthy` so the container is **not** restarted. - `500` — Manager process is unhealthy (missed heartbeat or timeout). **Confirm Docker still considers the container healthy:** ```bash docker inspect --format='{{.State.Health.Status}}' kasm_manager ``` This should report `healthy` even when the Manager is disabled. A `unhealthy` result would indicate the container is at risk of being restarted. **Verify Agent routing after disabling (Diagnosis logs):** After disabling a Manager, check the **Diagnostics** section in the admin UI for `503` responses in the Manager request logs. Agents should stop routing to the disabled Manager within one check-in interval. --- ## Compute Pool Administration & Auto Scaling # Pools Pools can be used to group a set of similar fixed systems together, so they can be treated as a single Workspace for user access. Users will see a single Workspace icon on their dashboard, but their session will get distributed to an available server in the pool. Each server in the pool can be set to support 1 or more concurrent sessions. Kasm automatically distributes the sessions evenly over the servers. Pools can also be used to auto scale servers using a supported [VM provider](autoscale/vm-providers.mdx). Auto scaling can be used to automatically provision [Servers](servers.mdx) or [Docker Agents](docker-agent.mdx). AutoScaling is available in the Community and Enterprise editions only. If applicable, the administrator will have 3 links underneath the table for **All AutoScale Configs**, **All VM Provider Configs** and **All DNS Provider Configs**. These allow the administrator to see all of the configs available and make changes, but the recommended approach is to use the **Edit** option on a specific pool. ## Create Pool - Click the **Infrastructure** item in the navigation menu. - Select the **Pools** option in the dropdown menu. - Select **Add** from the top right of the **Pools** table.
**Pool Configuration Options**
| **Field** | **Description** | | --- | --- | | **Name** | The name given to the Pool. | | **Type** | The type of Server Pool. Can either be [Docker Agent](docker-agent.mdx) or [Server](servers.mdx). | | **Server Assignment** | (Only Server pools) Whether the pool will allow [User-Server assignment](../workspaces-sessions/server-workspace/user-server-assignment.mdx). | | **Labels** | Labels assigned to all servers and agents in this Server Pool. These labels can be used to control where [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) sessions are launched. You can specify these labels in a Workspace's "Include Labels" or "Exclude Labels" settings to ensure sessions run only on certain servers or agents. | ## Servers List **This list is only shown for Pools of type Server** This list is almost identical to the [Servers](servers.mdx) list with the exception that only servers that are assigned to this pool are shown. Use the assign button to assign existing servers to this pool. ## Docker Agents List **This list is only shown for Pools of type Docker Agent** This list is almost identical to the [Agents](docker-agent.mdx) list with the exception that only servers that are assigned to this pool. Use the assign button to assign existing agents to this pool. ## AutoScale The AutoScale system groups resources using Pools. Refer to [the AutoScale documentation](autoscale/index.mdx) for more information. --- ## Preload Images on Agents for Autoscaling # Pre-load Workspace Images on Agents To optimize autoscaling of Docker agents, you can pre-load workspace images on your agents so that you don't have to wait for Kasm to pull your workspace images after the agent is provisioned. You can configure this during the creation of your Linux VM template, irrespective of the VM provider. If you're using rolling images, keep in mind that the versions pulled during pre-loading reflect the latest available at that moment. Once your agents come online and register with Kasm, they will automatically check for updates. If a newer version of a rolling image is available, Kasm will update it accordingly. ## Create a Kasm API key - Go to your Kasm Admin Dashboard -> "Settings" -> "Developers" - Click "Add API Key" - Give your API key a name - Enable `Read Only` - Set an Expiration date for your API key (Optional) - This will generate your `API KEY` and `API KEY SECRET`. Save them securely as you cannot see these values again - Next, give your API key the `Images View` permission and click "Submit" ## Fetch and pull your Workspace Images Run the following bash script that does the following: - Install Docker CE (based on instructions from [https://docs.docker.com/engine/install/ubuntu](https://docs.docker.com/engine/install/ubuntu)) - Export Kasm Variables (`KASM_HOST`, `API_KEY`, `API_KEY_SECRET`) - Fetch the Workspaces Images list from your Kasm deployment - Pull the Workspace Images with `docker pull` This script assumes you are running Ubuntu OS on your agents as listed [here](https://docs.docker.com/engine/install/ubuntu/#os-requirements). If you are using a different Linux distro, make sure to change the docker installation logic accordingly. Make sure to replace following variables with the actual values from your Kasm deployment: - `KASM_HOST`: The IP/FQDN of your Kasm deployment. If you're using a multi-server setup, this is the IP/FQDN of your Kasm Web App role. - `API_KEY`: The API Key you generated earlier. - `API_KEY_SECRET`: The API Key Secret you generated earlier. ```yml # Install Docker on Ubuntu (ref: https://docs.docker.com/engine/install/ubuntu/) sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install -y docker-ce # Kasm API variables export API_KEY= export API_KEY_SECRET= export KASM_HOST= # Fetch and pull all images curl -sk -X POST "https://${KASM_HOST}/api/admin/get_images" \ -H "Content-Type: application/json" \ -d "{\"api_key\":\"${API_KEY}\",\"api_key_secret\":\"${API_KEY_SECRET}\"}" \ | jq -r '.images[] | select(.name != null) | .name' \ | while read -r image_name; do echo "Pulling image: $image_name" sudo docker pull "$image_name" done ``` After pulling all the required workspace images, you can shut down the VM and create a template from it. When Kasm triggers autoscaling and provisions new agent VMs from this template, the workspace images will already be pre-loaded. This eliminates the delay caused by image downloads during provisioning, resulting in faster workspace launches. --- ## Kasm Rolling Image Management: Managing Rolling Images # Rolling Image Management Rolling Image Management lets you control how and when Kasm images receive updates by choosing rolling or static tags. Rolling tags pull the latest builds on startup to keep security fixes and patches current, while static tags lock to a specific release for change control. Kasm provides a rolling utility to manage rolling images that Kasm uses to run. The default behavior of the Kasm installer is to use rolling images. To install Kasm using static images, pass in the `-f or --use-static-images` arguments during the installation process. ```Bash sudo bash kasm_release/install.sh -f ``` The Kasm installer also accepts a specific dated rolling image tag to use during the initial install. To specify a dated rolling image, pass in the `-F or --use-tag` arguments and the dated rolling image tag desired during the installation process. If the `-F or --use-tag` arguments are used without specifying a dated rolling tag, the installer defaults to the dated rolling tag matching its own build date. ```Bash sudo bash kasm_release/install.sh -F 1.19.0-rolling-2026-05-01 ``` Example of rolling images, static images, and dated rolling images: - Rolling Image: 1.19.0-rolling (updated frequently) - Static Image: 1.19.0 (Will not be updated) - Dated Rolling Image: 1.19.0-rolling-2026-05-01 (Will not be updated) ## Find Available Rolling Tags To list the available dated rolling tags, query the Docker Hub API for one component. All core services share the same dated tags, so querying `api` is enough. This uses `grep` and `sed`, so no extra tooling is required: ```Bash curl -s "https://hub.docker.com/v2/repositories/kasmweb/api/tags?page_size=100" | grep -o '"name":"[^"]*"' | sed 's/"name":"//;s/"//' | grep '^1\.19\.0-rolling' | sort ``` To see which build your deployment currently runs, so you can compare it against the list, use [**Check Current Image**](#check-current-image): ```Bash sudo /opt/kasm/bin/utils/rolling_util -d ``` ## Update to a Newer Rolling Build To update to a newer rolling build, first determine whether your deployment is running the default `-rolling` tag or dated `-rolling-` tags. Check the image tags the running Kasm services use: ```Bash sudo docker ps --format '{{.Image}}' | grep kasmweb ``` **To the latest build, when running rolling images (the default `-rolling` tag):** rolling tags pull the latest build on startup, so restarting Kasm updates the core services to the most recent rolling build. ```Bash sudo systemctl restart kasm ``` **To a specific dated build (including the newest dated build):** [list the available tags](#find-available-rolling-tags) and choose the one you want. The [**Rollback**](#rollback) capability (`-r `) updates every service to that tag and records the current build as a rollback point; restart Kasm to apply the change. ```Bash sudo /opt/kasm/bin/utils/rolling_util -r 1.19.0-rolling-2026-07-14 sudo systemctl restart kasm ``` To move a deployment that is pinned to a dated tag back to the auto-updating `-rolling` tag, use [**Switch to latest**](#switch-to-latest). On a multi-server deployment, perform these steps on each server. ## Update an Offline Deployment Air-gapped hosts cannot reach Docker Hub, so newer rolling images cannot be pulled directly. There are two ways to update an offline deployment, depending on your environment. ### Use the offline upgrade bundles Follow the standard **Offline Upgrade** procedure in the [single-server upgrade guide](../upgrade/single-server-upgrade.mdx) or the [multi-server upgrade guide](../upgrade/multi-server-upgrade.mdx). ### Manually transfer a specific dated build To move a specific dated build to an air-gapped deployment, list the available builds on an internet-connected machine, download the images for the build you want, transfer them, and load them on your Kasm servers. **On an internet-connected machine:** 1. List the available dated rolling tags. All core services share the same dates, so querying one repository (`api`) is enough. ```Bash curl -s "https://hub.docker.com/v2/repositories/kasmweb/api/tags?page_size=100" | grep -o '"name":"[^"]*"' | sed 's/"name":"//;s/"//' | grep '^1\.19\.0-rolling' | sort ``` 2. Choose a tag from the list, set it as `TAG`, and download all Kasm images for that build. Match the architecture of your Kasm servers with `--platform`, because `docker pull` otherwise fetches the variant for the machine you run it on. ```Bash TAG=1.19.0-rolling-2026-07-14 # the build you chose above PLATFORM=linux/amd64 # use linux/arm64 for arm servers; must match your Kasm servers tagged="" for name in api agent manager proxy postgres kasm-guac rdp-gateway rdp-https-gateway; do docker pull --platform "$PLATFORM" "kasmweb/${name}:${TAG}" tagged="${tagged} kasmweb/${name}:${TAG}" done docker save $tagged -o "kasm-${TAG}.tar" ``` **Transfer** the resulting `kasm-.tar` archive to each Kasm server. **On each air-gapped Kasm server**, load the images, pin every service to the tag, and restart. On a multi-server deployment, repeat this on every server. ```Bash TAG=1.19.0-rolling-2026-07-14 docker load -i "kasm-${TAG}.tar" sudo /opt/kasm/bin/utils/rolling_util -r "$TAG" sudo systemctl restart kasm ``` On restart, Kasm attempts to refresh rolling images but tolerates the failure when the server is offline, and starts from the images you loaded. Match the image architecture to your Kasm servers: an `amd64` image will not run on an `arm64` host, and vice versa. ## Rolling Utility The Rolling Utility will help manage the rolling images used by Kasm. The utility contains the following capabilities: - [Rollback](#rollback) - [Check Current Image](#check-current-image) - [Switch to Latest](#switch-to-latest) - [Update Tracked Rolling Image](#update-rolling-tag) - [Clean Up Rolling Ledger](#clean-up-ledger) For multi-server installation, run the rolling utility on each server. This utility will only apply to the core Kasm services. - API - Agent - Manager - Proxy - RDP Gateways - Postgres ### Rollback This capability will roll back the image that Kasm uses to run. Since the rolling image is updated frequently, in the event that the latest rolling image is causing a problem with Kasm, you can roll back to an earlier build. Rollback has two forms, both described below: `-r` with no tag rolls back to the previous build by its digest, and `-r ` sets every service to a dated tag you specify. In either case the deployment stays on the rolled-back image until you use the [**switch to latest**](#switch-to-latest) feature. ```Bash sudo /opt/kasm/bin/utils/rolling_util -r ``` When run without a tag, the utility does not use a tag at all. It reads the previous image's digest (SHA256) from the rolling ledger and pins each service to that digest (for example, `kasmweb/api@sha256:...`). The ledger records the current and previous digest for every image and is refreshed automatically on each restart, so the previous digest is the build the host ran immediately before the current one. If the ledger has no previous digest for an image (for example, right after a fresh install), that image is left unchanged. Because the ledger tracks digests, it records a new rollback point only when the running image's digest changes — that is, when a genuinely different build is pulled. Changing only the tag does not create a rollback point if both tags resolve to the same image. For example, if you pin to a dated tag and later return to `-rolling` while both point to the same build, a subsequent `-r` without a tag will not reverse that switch; it rolls back to the last build that was actually different, or does nothing. To move to a specific build in that situation, pass the tag explicitly. You can also pass a specific tag to pin every service to that dated build, whether newer or older than the current one. See [Find Available Rolling Tags](#find-available-rolling-tags) to choose a tag. ```Bash sudo /opt/kasm/bin/utils/rolling_util -r 1.19.0-rolling-2026-05-01 ``` If specifying a tag, please only use tags that contain the current version of Kasm. Do not use an older version (e.g. specifying 1.18.0 tags when Kasm 1.19.0 is installed) After using this capability, please restart Kasm. ```Bash sudo systemctl restart kasm ``` If you switch to the latest rolling tag (i.e. with `-l`) from a dated rolling tag (i.e. installed with `-F`) and then attempt to rollback to the previous dated tag using `-r` without a specified value, verify the resulting tags in your docker compose file to ensure that the images have switched to using a SHA. It is possible that the latest rolling tag and your dated rolling tag were pointing to the same image SHA, which would cause the rolling util to leave the rolling tag on the images. If this is the case, you will need to rollback again and provide the dated rolling tag from before. E.g. `-r 1.19.0-rolling-2026-05-01` ### Check Current Image This capability will output the creation date of the image currently being used by Kasm, as well as the creation date of the previously used image. This information is helpful when troubleshooting potential problems. If contacting the Kasm team for assistance, please include this information. ```Bash sudo /opt/kasm/bin/utils/rolling_util -d ``` ### Switch to latest During a rollback, Kasm pins the rollback version, effectively making Kasm behave as if using static images. This capability will switch Kasm back to using the latest rolling image. ```Bash sudo /opt/kasm/bin/utils/rolling_util -l ``` After using this capability, please restart Kasm. ```Bash sudo systemctl restart kasm ``` ### Update Rolling Tag This capability will update the Rolling Ledger to track the current and previous running image. The Rolling Ledger will be updated automatically after every restart. Normally, you will not need to use this capability manually. ```Bash sudo /opt/kasm/bin/utils/rolling_util -u ``` ### Clean Up Ledger This capability removes tracking entries from the rolling ledger for images that are no longer present on the host. It cleans up only the ledger's bookkeeping; it does not delete any Docker images or tags, so it does not reclaim disk space from old dated rolling images. Since image information can be useful in troubleshooting, please do not use this capability without being directed by the Kasm Team. A rollback with `-r` (no tag) restores the previous image by its digest, so old Kasm images on the host are your rollback targets. Avoid manually deleting old Kasm images (for example, with `docker image prune`) unless you are sure you will not need to roll back to them. ```Bash sudo /opt/kasm/bin/utils/rolling_util -c ``` --- ## Kasm Workspaces: Managing Compute Servers (VNC, RDP, SSH) # Servers Kasm Workspaces provides session management and rendering of sessions for fixed systems or auto scaled systems that support either KasmVNC, RDP, SSH, or VNC. [Workspaces](../workspaces-sessions/container-workspace/workspaces.mdx) can be created and assigned to [Groups](../security/users-groups-mgmt/groups.mdx), providing users access to the servers from their dashboard. ## Create Server To create a new server, navigate to Infrastructure->Servers->Servers and click Add. Fill in the required information about the server. In order for the server to be accessible to users, a [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx) must be created and then add the Workspace to a [Group](../security/users-groups-mgmt/groups.mdx). ## Server Configuration The following fields appear when creating and/or updating a Server. | Property | Description | | :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Enabled | Show and allow connections to this server. | | Friendly Name | The server name displayed to users. | | Deployment Zone | Which deployment zone to set for the server. | | Pool | Which pool does the server belong to. | | Assigned User | (Optional) Select a User to assign to this Server. Only available for members of `Server` type Pools with [user-server assignment](../workspaces-sessions/server-workspace/user-server-assignment.mdx) enabled. | | Drain Time | (Update view only) The time when this server switches to "Draining" mode, in which the server will not accept any new sessions. Once all active sessions have ended, the server will be automatically deleted. This field is editable for autoscaled servers so that administrators can rotate a specific server earlier than the autoscale "Expire Servers in (Days)" setting. | | Labels | Labels assigned to this Server. These labels can be used to control where [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) sessions are launched. You can specify these labels in a Workspace's "Include Labels" or "Exclude Labels" settings to ensure sessions run only on certain servers. | | Kasm Desktop Service | Whether this is a Windows host with Kasm Desktop Service installed | | Connection Type | Whether to use KasmVNC, RDP, SSH, or VNC. | | IP/Hostname | The IP or Hostname used to connect to the server. | | Connection Port | Which port to connect to the server on. | | Connection Credential Type | Which type of credentials are used for this server. Options are Static Credentials, Dynamic User Accounts, SSO User Accounts, Authenticate with Smartcard, and Prompt User | | SSO Domain | This field applies when **Connection Credential Type** is set to `SSO User Accounts`. Use this field to modify the username. For example, in Kasm the username may be john.smith@acme.com, but Windows may expect john.smith@acme.local. A value of `localhost` strips the domain name from the username, i.e. `john.smith`. A value ending in `\` prepends this field to the username, i.e. `acme.local\john.smith`. All other values are appended to the username with @, i.e. `john.smith@acme.local`. | | Connection Username | The username to use to connect to the server. Only visible with Static Credentials **Connection Credential Type**. | | Connection Password | The password to use to connect to the server. Only visible with Static Credentials **Connection Credential Type**. | | Use User SSH Key | (Optional) This only applies to the SSH Connection type. When selected Kasm uses the User's SSH Keys to authenticate against the server. | | Connection Private Key | (Optional) This only applies to the SSH Connection type. This is the private key to be used to authenticate to the server. | | Connection Private Key Passphrase | (Optional) This only applies to the SSH Connection type. This is the passphrase of the Private Key specified above. | | Connection Info | (Optional) Additional connection info that needs to be passed to the server. For more information see the Connections section of the [global settings](../../reference/settings.mdx) | | Max Simultaneous Sessions | The maximum amount of sessions that can connect to the server at a time. For RDP servers with RemoteApps, admins may want to set this value higher than then `Max Simultaneous Users` setting to allow for multiple RemoteApps per user. | | Max Simultaneous Users | For RDP and SSH servers, the number of concurrently connected users per server. | ### Single Sign-On to Windows Systems via LDAP When users login to Kasm via [LDAP Authentication](../security/users-groups-mgmt/ldap.mdx), they are able to create sessions to Windows systems that are joined to the same Active Directory domain and are configured for SSO credential pass-through. In the above table covering the configuration fields for Servers is the **Connection Credential Type** field. Select the value *SSO User Accounts* in the **Connection Credential Type** field. This requires that all users accessing this server are authenticated to Kasm using LDAP authentication. See our Windows Deployment Guide video for a walk through of this topic and more. ## Authentication Options When Connecting to an SSH Server Kasm Workspaces has the ability to connect to arbitrary SSH servers. It can use SSH key or password authentication. There are a few combinations of options on the Server edit screen that can be selected. The server can be configured to use: - Username/password authentication - Username and select the `Use User SSH Key` to send the username and private key stored with the Kasm user. - Username and a pasted in private key, optionally including a passphrase if the key requires one. Select the value *SSO User Accounts* in the **Connection Credential Type** field and check the **Use User SSH Key** checkbox and Kasm Workspaces will send the user's Kasm Workspaces username along with the user's Kasm Workspaces SSH key allowing easy multiple user support on SSH servers. There are some restrictions on the ssh keys supported that are enforced by the connection proxy library used for the ssh server connections: The SSH key can be in either OpenSSH format (beginning with `-----BEGIN OPENSSH PRIVATE KEY-----`) or RSA PKCS1 format (beginning with `-----BEGIN RSA PRIVATE KEY-----` or `-----BEGIN PRIVATE KEY-----`) with a key size of 2048. When using RSA keys with some newer Linux distributions such as Ubuntu 22.04 LTS, you may need to edit the `/etc/ssh/sshd_config` file on the target server and add these two lines to the config: ```bash HostKeyAlgorithms +ssh-rsa PubkeyAcceptedKeyTypes +ssh-rsa ``` ## SSH session continuity Kasm Workspaces uses Guacamole to provide SSH connectivity for SSH server definitions. Guacamole does not provide the ability to resume SSH sessions. This means that when disconnecting from an SSH Workspace such as when clicking **Workspaces** from the control panel it will not be possible to resume the same session when clicking **Resume** and a fresh SSH session will be created. This also applies to disconnections caused by network interruptions. To avoid this a user can utilize a utility such as screen/tmux to have a persistent terminal session on the server. ### Tmux Connection Settings Example This is an example of how it would be possible to configure the Kasm connection settings for a Server to use tmux to have a preserved environment on an SSH server. ```json { "guac": { "type": "ssh", "settings": { "font-size": "11", "color-scheme": "gray-black", "font-name": "monospace", "scrollback": "1000", "command": "tmux a || tmux" } } } ``` ### Screen Connection Settings Example This is an example of how it would be possible to configure the Kasm connection settings for a Server to use screen to have a preserved environment on an SSH server. ```json { "guac": { "type": "ssh", "settings": { "command": "screen -R my_session" } } } ``` ## Creating Templates For Use With The VMware vSphere Provider When using the VMware vSphere provider the administrator must create templates on the cluster for the provider to clone from. ### Linux Templates When creating Linux VM templates ensure that: - VMware tools are installed, either the official version or open-vm-tools. - If SSH access is desired, ensure that a public SSH certificate is installed on the machine, and use the matching private key when creating the [Autoscale Configuration](autoscale/infrastructure-components/autoscale-config-server#autoscale-settings-for-server-pool). - If creating this template for use in a Docker Agent pool, take note of the primary ethernet interface name as that will be needed for the [autoscale startup scripts](https://github.com/kasmtech/workspaces-autoscale-startup-scripts). #### Troubleshooting Linux Startup Script Execution The startup script will be copied to a temporary directory on the Linux host, this is usually /tmp. inside the temporary directory VMware will create a folder named vmware-root_ followed by a set of random numbers e.g. vmware-root_437-1849036237. Then VMware will create the script file inside this directory also randomly named e.g. vmware119.sh. VMware does not provide a logging facility for executing these scripts but the script writer could log important events by creating an adjacent file and writing to it. If the script fails during testing of the Autoscale/vm-provider configuration the administrator can bring up VMware console access to the cloned machine, find the script in the temporary directory and manually execute the script to observe it's output. ### Windows Templates When creating a Windows VM template ensure that: - VMware tools is installed. - Remote desktop has been enabled on the VM. - The startup script entered into the [VM Config Provider](autoscale/vm-providers.mdx) will be run as a Powershell script, so ensure that unrestricted remote scripting is enabled. - If desired ensure that the [Kasm Desktop Service](../workspaces-sessions/server-workspace/windows/kds-windows-service.mdx) is installed, this will make uploads and downloads available from the [Kasm Control Panel](../../tutorials/user-guide/control-panel.mdx). #### Troubleshooting Windows Startup Script Execution The startup script will be copied to a temporary directory on the Windows host, this is usually the directory pointed to by %TEMP%. This environment variable must be resolved when logged in as the user the script will be executed as to give an accurate location. Inside the temporary directory VMware will create a folder named vmware-root_ followed by a set of random numbers e.g. vmware-root_437-1849036237. Then VMware will create the script file inside this directory also randomly named e.g. vmware119.sh. VMware does not provide a logging facility for executing these scripts but the script writer could log important events by creating an adjacent file and writing to it. If the script fails during testing of the Autoscale/vm-provider configuration the administrator can bring up VMware console access to the cloned machine, find the script in the temporary directory and manually execute the script to observe it's output. ## Bulk Import Servers can be created in bulk through the "Import Servers" button on the Server administration page. The Developer API also exposes the [`/api/public/batch_create_server`](../../reference/developer-api.mdx#batch-create-servers) endpoint for programmatic use. ### CSV Formatting ### Server CSV Schema The CSV file for Server bulk imports recognizes the following columns. Optional columns may be omitted if they are not needed for any record. The descriptions from the "Create Server" properties table above apply to these fields, except where noted. A Server's combination of Zone, IP / Hostname, and Port is unique during import. A CSV record that duplicates an existing Server will cause the import to fail. | Column Header | Required | Default | User Property | Notes | | --- | --- | --- | --- | --- | | name | Yes | | Friendly Name | | | zone_name | yes | | Deployment Zone | | | connection_type | yes | | Connection Type | Values: `"KasmVNC"`, `"RDP"`, `"VNC"`, and `"SSH"` | | connection_credential_type | yes | | Connection Credential Type | Values: `"STATIC"`, `"SSO_CREATE_USER"`, `"SSO_USERNAME"`, `"SMARTCARD"`, `"PROMPT_USER"` | | ip_hostname | yes | | IP/Hostname | | | port | yes | | Connection Port | | | pool_id | No | `null` | Pool | This is the `pool_id` (UUID) of the Server Pool. | | assigned_username | No | `null` | Assigned User | See notes above about pool requirements. | | windows_service_installed | No | `"false"` | Kasm Desktop Service | | | connection_username | Conditionally | `null` | Connection Username | See notes below | | connection_password | Conditionally | `null` | Connection Password | See notes below | | sso_username_domain | No | `null` | SSO Domain | | | private_key | No | `null` | Connection Private Key | | | passphrase | No | `null` | Connection Private Key Passphrase | | | use_user_private_key | No | `"false"` | Use User SSH Key | Paste the contents of the SSH keyfile (inside quotes) in this field, including linebreaks. | | connection_info | No | `null` | Connection Info | | | max_simultaneous_sessions | No | `1` | Max Simultaneous Sessions | | | max_simultaneous_users | No | `1` | Max Simultaneous Users | | | labels | No | `null` | Labels | Labels assigned to this Server. These labels can be used to control where [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx#add--edit-workspaces) sessions are launched | **Valid Credential Type Combinations** * `"KasmVNC"` connections require `"STATIC"` credentials and values for `connection_username` and `connection_password` * `"RDP"` connections support all types. The `"SSO_CREATE_USER"` credential setting requires `windows_service_installed` to be `true` * `"VNC"` connections only support `"STATIC"` credentials * `"SSH"` connections support `"STATIC"` and `"SSO_USERNAME"` credential types Below is an example of a valid Server CSV file containing all columns. It would generate five servers: 1. A KasmVNC server 2. A RDP server in a Server Pool that creates users in the SSO Domain on demand 3. A VNC server 4. A SSH Server that is assigned to an initial User and uses the connecting User's SSH certificate for authentication. 5. A SSH Server that uses an encrypted SSH private key for all connections ```csv name,zone_name,connection_type,connection_credential_type,ip_hostname,port,pool_id,assigned_username,windows_service_installed,connection_username,connection_password,sso_username_domain,passphrase,private_key,use_user_private_key,connection_info,max_simultaneous_sessions,max_simultaneous_users,labels KasmVNC Server,default,KasmVNC,STATIC,internal.host.local,6901,,,,test_user,SuperPassword1!,,,,,,, RDP Server 1,default,RDP,SSO_CREATE_USER,192.168.10.24,3389,00001111-2222-3333-4444-5555-666677778888,,true,,,localssodomain,,,,,1,1,"production,windows" VNC Server,default,VNC,STATIC,192.168.20.5,5900,,,,vnc_user,vnc_pass,,,,,,, Personal SSH Server,default,SSH,STATIC,bob.host.local,22,,bob@local,false,,,,,,true,,24,1,"development,personal" Shared SSH Server,default,SSH,STATIC,192.168.20.15,22,,,,,,,super_securePASSPHRASE!2,"-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,F399B33DA2403C6087C082C64C9ABD25 Nr/Qzem29v5dkE/bKsOOg8tJvzsSBncoiUysfZ2gpTLrILDRPMYb9fh36HrAJVSO ... vUmKldKBvmfBFOoAUc1MqUNO8gxuEGEU37FGdiZG7EZmSSjphR3Q//zFbGyC4myl -----END RSA PRIVATE KEY-----",,,,"shared,production" ``` --- ## Using systemd for Kasm Service Management Kasm Workspaces provides systemd service integration, allowing admins to manage Kasm services using standard systemd commands ensuring proper initialization order of all plugins and components. ## Service Names Kasm automatically installs the following systemd services: | Service Name | Description | |--------------|-------------| | `kasm.service` | Main Kasm service that controls all components | | `kasm-network-plugin.service` | Kasm Network Plugin service that manages the docker network plugin providing egress capabilities | ## Service Management To list all installed Kasm related services: ```bash sudo systemctl list-unit-files | grep kasm ``` To check the status of Kasm services: ```bash sudo systemctl status kasm sudo systemctl status kasm-network-plugin ``` To start/stop/restart all Kasm services: ```bash # start sudo systemctl start kasm # stop sudo systemctl stop kasm # restart sudo systemctl restart kasm ``` ### Enable/Disable Automatic Startup Kasm services are enabled by default during installation to automatically start at system boot. To manage automatic startup of all Kasm services at boot: ```bash # enable sudo systemctl enable kasm # disable sudo systemctl disable kasm ``` ## Troubleshooting Startup Issues If you encounter issues with Kasm services starting up, check the following: 1. Verify the service status: ```bash sudo systemctl status kasm ``` 2. Check for error messages in the startup logs: ```bash sudo journalctl -u kasm -n 100 ``` 3. Ensure Docker is running, as Kasm requires it to start properly: ```bash sudo systemctl status docker ``` 4. Check if all required services are enabled for automatic startup: ```bash sudo systemctl list-unit-files | grep kasm ``` --- ## Configure TLS Certificates for Kasm on Kubernetes Kasm requires TLS for secure communication between its components. For your Kasm Kubernetes deployment to function correctly, you must create and add a certificate secret to the **Kasm namespace**. This guide covers the three most common methods for creating and managing your TLS secret. --- ## Options for Creating Your Certificate Secret 1. [Use cert-manager (Recommended)](#using-cert-manager-recommended) 2. [Manually create a self-signed certificate](#manually-creating-a-self-signed-certificate) 3. [Upload a certificate from a Certificate Authority (CA)](#upload-a-certificate-from-a-different-certificate-authority-ca) :::note Before you begin: - Ensure you know which Kubernetes namespace your Kasm deployment uses (`{NAMESPACE}` is used in this document). - Decide if you'll use cert-manager or manage your own certificate files. ::: --- ## Using cert-manager (Recommended) If your cluster has [cert-manager](https://cert-manager.io/docs/) installed, you can let cert-manager automatically create and manage your TLS secret. The Helm chart is already configured for this scenario. You will need to know the name and kind of your issuer, then pick a secret name. 1. Open your `values.yaml` file and locate the `certificate` block: ```yaml certificate: secretName: {SECRET-NAME} certManager: enabled: true addWildCard: true issuerName: {ISSUER-NAME} issuerKind: "" issuerGroup: "" annotations: {} labels: {} ``` 2. Copy and paste the block to your `my-values.yaml` 3. Apply any modifications you would like to make. 4. Deploy or update your Helm release as usual. The following table describes the fields available for configuring the certificate: | Field | Description | |---|---| | `secretName` | The name of the Kubernetes secret where the certificate is stored. cert-manager will create and manage this secret automatically. | | `certManager.enabled` | Set to `true` to enable cert-manager integration. | | `certManager.addWildCard` | When `true`, adds a wildcard SAN (``*.{publicAddr}``) to the generated certificate. | | `certManager.issuerName` | The name of the cert-manager `Issuer` or `ClusterIssuer` to use for certificate issuance. | | `certManager.issuerKind` | The kind of the cert-manager issuer. Leave empty to default to `Issuer`. Set to `ClusterIssuer` if using a cluster-wide issuer. | | `certManager.issuerGroup` | The API group of the issuer. Leave empty to default to `cert-manager.io`. | | `certManager.annotations` | Additional annotations to add to the Certificate resource. | | `certManager.labels` | Additional labels to add to the Certificate resource. | See the [cert-manager documentation](https://cert-manager.io/docs/) for details on configuring [Issuers and ClusterIssuers](https://cert-manager.io/docs/concepts/issuer/). :::note If you have already deployed Kasm using the Helm chart, remember to update your values file according to the instructions in the [installation guide](../../tutorials/install/kubernetes). ::: --- ## Manually Creating a Self-Signed Certificate If you do not use cert-manager, you can generate a self-signed certificate and create a Kubernetes secret manually. There are two options: 1. Use the example script below (copy-paste and run): ```bash openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout tls.key -out tls.crt \ -subj "/CN=kasm.example.com/O=Kasm Self-Signed" ``` 2. Follow the guide in the official [Kubernetes documentation](https://kubernetes.io/docs/tasks/administer-cluster/certificates/) **Filename requirements for this chart:** * Certificate file: `tls.crt` * Key file: `tls.key` * CA certificate (optional, for custom CAs): `ca.crt` --- ## Upload a Certificate from a Different Certificate Authority (CA) If you already have a certificate from your organization's CA or a public CA: 1. Obtain/export your certificate (`tls.crt`), key (`tls.key`), and optional CA certificate (`ca.crt`). 2. Continue to the [Adding the generated TLS secret to Kubernetes](#adding-the-generated-tls-secret-to-kubernetes) section below. --- ## Adding the Generated TLS Secret to Kubernetes Run the following commands, substituting your values: ```bash # Set your secret and namespace names SECRET_NAME="kasm-cert-secret" NAMESPACE="kasm-ns" # Create a TLS secret (cert + key only): kubectl create secret tls $SECRET_NAME \ --cert=tls.crt \ --key=tls.key \ --namespace $NAMESPACE # If you need to include a CA certificate as well: kubectl create secret generic $SECRET_NAME \ --from-file=tls.crt=/path/to/tls.crt \ --from-file=tls.key=/path/to/tls.key \ --from-file=ca.crt=/path/to/ca.crt \ --namespace $NAMESPACE ``` :::note The Helm chart expects the `certificate.secretName` in your `my-values.yaml` to match the secret you just created. You can also set this at install/upgrade time by adding the following in your `my-values.yaml`: ```yaml certificate: secretName: {SECRET-NAME} ``` ::: :::note If you have already deployed Kasm using the Helm chart, remember to update your values file according to the instructions in the [installation guide](../../tutorials/install/kubernetes). ::: --- ## Cloud-Managed TLS If you are deploying on a managed Kubernetes platform (e.g., GKE, EKS, AKS), you may prefer to terminate TLS at a cloud-managed load balancer or gateway rather than at the Kubernetes Ingress. For example, on GCP you can use a [Gateway](https://cloud.google.com/kubernetes-engine/docs/concepts/gateway-api) with [Google-managed certificates](https://cloud.google.com/certificate-manager/docs/overview) to handle external TLS, while still using cert-manager or self-signed certificates for internal cluster traffic. This hybrid approach can simplify certificate lifecycle management and firewall configuration, as the external IP is managed by the cloud provider. --- ## Additional References * [kubectl create secret tls](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_create/kubectl_create_secret_tls/) * [kubectl create secret generic](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_create/kubectl_create_secret_generic/) * [cert-manager documentation](https://cert-manager.io/docs/) * [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/) --- ## Migrate Kasm Workspaces from VM to Kubernetes # Migrate from VM to Kubernetes This guide walks you through migrating your existing VM-based Kasm deployment to Kubernetes. :::note Ensure your VM deployment is on Kasm **1.19.0** before migrating. If you are on an older version, upgrade your VM deployment first. ::: :::warning **Scope:** This guide covers the migration of the **Kasm control plane**, including primary zone dedicated and connection proxies. Agents and additional zone dedicated and connection proxies are not part of the Helm chart and must be migrated or reinstalled separately after the control plane is up. ::: Choose the section that matches your current database setup: - [Included DB](#migrating-with-included-db) — your VM uses Kasm's built-in PostgreSQL container (`database.standalone=false`) - [Standalone DB](#migrating-with-standalone-db) — your VM connects to an external PostgreSQL database (`database.standalone=true`) --- ## Migrating with Included DB Use this path if your VM deployment uses Kasm's built-in PostgreSQL container. :::warning This migration requires downtime. Your existing Kasm deployment will be unavailable during the process. Plan accordingly and schedule a maintenance window. ::: ### At a Glance 1. [Back up the database on the VM](#1-back-up-the-database-on-the-vm) 2. [Preserve your Kasm secrets](#2-preserve-your-kasm-secrets) 3. [Transfer the backup to Kubernetes](#3-transfer-the-backup-to-kubernetes) 4. [Install the Kasm Helm chart](#4-install-the-kasm-helm-chart) 5. [Confirm the DB is running](#5-confirm-the-db-is-running) 6. [Restore the database](#6-restore-the-database) 7. [Verify and log in](#7-verify-and-log-in) --- ### 1. Back Up the Database on the VM Follow the official Kasm documentation to take a database backup on your VM: - [Container DB Backup](../infra-autoscale/database) Rename the backup file to `kasm_dump.tar` once complete. --- ### 2. Preserve Your Kasm Secrets To retain the same credentials after migration, create the Kasm secrets in your target namespace before installing the chart. Copy the file `examples/kasm-secrets.yaml` from our [chart source](https://github.com/kasmtech/kasm-helm/blob/release/1.1190.0/examples/kasm-secrets.yaml) and populate it with the credential values from your VM deployment: :::warning The secret name must be `{RELEASE_NAME}-secrets`, where `{RELEASE_NAME}` is the name you will use in your `helm install` command. Update the `name` field in `kasm-secrets.yaml` accordingly before applying. ::: :::warning All secret values must be base64 encoded. Encode a value with: `echo -n {secret-value} | base64` ::: ```bash kubectl create namespace {NAMESPACE} kubectl apply -f kasm-secrets.yaml -n {NAMESPACE} ``` Verify the values are correct: ```bash kubectl -n {NAMESPACE} get secrets/{RELEASE_NAME}-secrets \ --template='{{ range $key, $value := .data }}{{ printf "%s: %s\n" $key ($value | base64decode) }}{{ end }}' ``` --- ### 3. Transfer the Backup to Kubernetes Download [db-upload.yaml](https://raw.githubusercontent.com/kasmtech/kasm-helm/refs/heads/release/1.1190.0/examples/db-upload.yaml) and update the following fields before applying: | Field | Value | |---|---| | `image` | Replace with your current VM Kasm version, e.g. `kasmweb/api:1.19.0` | | `storageClassName` | Commented out by default to use the namespace default. Uncomment and set a value to use a specific storage class | | `claimName` | PVC name for the backup. Keep default (`kasm-db-dump-pvc`) unless you need a custom name — if changed, update `claimName` in `db-restore.yaml` to match | Deploy the upload pod to create a PVC and receive the backup file: ```bash kubectl apply -f db-upload.yaml -n {NAMESPACE} ``` Copy your backup file into the pod: ```bash kubectl cp /path/to/kasm_dump.tar {NAMESPACE}/{UPLOAD_POD_NAME}:/data/kasm-db-dump/kasm_dump.tar ``` Replace `{UPLOAD_POD_NAME}` with the actual pod name. Retrieve it with: ```bash kubectl get pods -n {NAMESPACE} ``` Monitor the upload pod logs to confirm the transfer is complete: ```bash kubectl logs -f {UPLOAD_POD_NAME} -n {NAMESPACE} ``` Expected output: ``` Waiting for DB file upload... File uploading. ⏳ Upload in progress... (size: 150240768 bytes) ✅ File upload complete. Final size: 206191616 bytes ``` Verify the `Final size` matches the size of your local backup file exactly before proceeding. --- ### 4. Install the Kasm Helm Chart **Install your TLS certificate** into the namespace before installing the chart. Refer to [Configure TLS Certificates for Kasm on Kubernetes](./configure_tls) for the available methods. Note the secret name you create — you will need it in `my-values.yaml` below. Create your `my-values.yaml`. Refer to the [chart documentation](https://github.com/kasmtech/kasm-helm/tree/release/1.1190.0/charts/kasm-helm) for all available configuration options, including ingress settings. At minimum, include: ```yaml publicAddr: kasm.contoso.com certificate: secretName: {CERTIFICATE_SECRET_NAME} # The TLS secret name you created above dbManagement: initialize: false ``` :::warning Set `dbManagement.initialize: false`. Enabling it will pre-populate the schema and conflict with the restore in Step 6. ::: Install the chart: :::warning The `{RELEASE_NAME}` used here must match the secret name you applied in the previous step. For example, if your secret is named `kasm-secrets`, your release name must be `kasm`. ::: #### OCI Registry (Recommended) ```bash helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` #### Classic Helm Repository ```bash helm repo add kasm https://helm.kasm.com helm repo update helm install {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` --- ### 5. Confirm the DB is Running Watch the pods until the DB is ready: ```bash kubectl get pods -n {NAMESPACE} --watch ``` Example output: ```text kasm-api-default-7985f66df6-pnhng 0/1 Init:0/1 0 53s kasm-db-1-19-0-0 1/1 Running 0 52s kasm-guac-6d44dd8844-zmpzv 0/1 Init:0/1 0 53s kasm-manager-default-585f45f8df-h8n6z 0/1 Init:0/2 0 53s kasm-proxy-default-9c98f99f8-k69wt 0/1 Init:0/4 0 52s kasm-rdp-gateway-f9996c885-n74h5 0/1 Init:0/1 0 52s kasm-rdp-https-gateway-6f5d456b59-67hxj 0/1 Init:0/1 0 52s ``` Once the `{RELEASE_NAME}-db-*` pod shows `Running`, press `Ctrl+C` to stop watching and proceed to the next step. --- ### 6. Restore the Database Download [db-restore.yaml](https://raw.githubusercontent.com/kasmtech/kasm-helm/refs/heads/release/1.1190.0/examples/db-restore.yaml) and update the following fields: | Field | Value | |---|---| | `image` | Replace with your current VM Kasm version, e.g. `kasmweb/api:1.19.0` | | `POSTGRES_HOST` | DB service name. Run `kubectl -n {NAMESPACE} get service` to find it | | `POSTGRES_DB` | Defaults to `kasm`. Only change if you set `database.kasmDbName` in `my-values.yaml` | | `POSTGRES_USER` | Defaults to `kasmapp`. Only change if you set `database.kasmDbUser` in `my-values.yaml` | | `secretKeyRef.name` | Must be `{RELEASE_NAME}-secrets`, where `{RELEASE_NAME}` is your Helm release name | | `secretKeyRef.key` | Defaults to `db-password` — auto-generated by the Helm chart. Keep default | | `claimName` | Defaults to `kasm-db-dump-pvc`. Keep default unless you changed it in `db-upload.yaml` | Apply the restore job: ```bash kubectl apply -n {NAMESPACE} -f db-restore.yaml kubectl logs -f job/kasm-db-restore -n {NAMESPACE} ``` Expected output when the restore completes: ``` Restoring database from /data/kasm-db-dump/kasm_dump.tar Restore complete ``` --- ### 7. Verify and Log In After the restore completes, the pods will gradually come into a running state. Watch until all pods are running: ```bash kubectl get pods -n {NAMESPACE} --watch ``` Once all pods are running, press `Ctrl+C` to stop watching. If you enabled ingress in your `my-values.yaml`, update your DNS record for `publicAddr` to point to the ingress address. Retrieve it with: ```bash kubectl get ingress -n {NAMESPACE} ``` Use the value in the `ADDRESS` column. Once DNS has propagated, access your Kasm environment using the `publicAddr` you set. For credentials, run: ```bash helm get notes {RELEASE_NAME} -n {NAMESPACE} ``` --- ## Migrating with Standalone DB Use this path if your VM deployment connects to an external PostgreSQL database. Since your database is not managed by Kasm, it will continue running independently. :::warning This migration requires downtime. Your existing Kasm deployment will be unavailable during the process. Plan accordingly and schedule a maintenance window. ::: ### At a Glance 1. [Back up the database](#1-back-up-the-database) 2. [Preserve your Kasm secrets](#2-preserve-your-kasm-secrets-1) 3. [Install the Kasm Helm chart](#3-install-the-kasm-helm-chart) 4. [Verify and log in](#4-verify-and-log-in) --- ### 1. Back Up the Database Follow the official Kasm documentation to take a backup of your standalone PostgreSQL database: - [Standalone DB Backup](../../tutorials/install/remote-database#backing-up-the-postgresql-server) Store the backup in a safe location before proceeding. Once the backup is complete, stop all Kasm services on the VM to prevent any further writes to the database: ```bash sudo /opt/kasm/current/bin/stop ``` --- ### 2. Preserve Your Kasm Secrets To retain the same credentials after migration, create the Kasm secrets in your target namespace before installing the chart. Edit and apply [kasm-secrets.yaml](https://raw.githubusercontent.com/kasmtech/kasm-helm/refs/heads/release/1.1190.0/examples/kasm-secrets.yaml) with the credential values from your VM deployment: :::warning The secret name must be `{RELEASE_NAME}-secrets`, where `{RELEASE_NAME}` is the name you will use in your `helm install` command. Update the `name` field in `kasm-secrets.yaml` accordingly before applying. ::: :::warning All secret values must be base64 encoded. Encode a value with: `echo -n {secret-value} | base64` ::: ```bash kubectl create namespace {NAMESPACE} kubectl apply -f kasm-secrets.yaml -n {NAMESPACE} ``` Verify the values are correct: ```bash kubectl -n {NAMESPACE} get secrets/{RELEASE_NAME}-secrets \ --template='{{ range $key, $value := .data }}{{ printf "%s: %s\n" $key ($value | base64decode) }}{{ end }}' ``` --- ### 3. Install the Kasm Helm Chart **Install your TLS certificate** into the namespace before installing the chart. Refer to [Configure TLS Certificates for Kasm on Kubernetes](./configure_tls) for the available methods. Note the secret name you create — you will need it in `my-values.yaml` below. Create your `my-values.yaml`. Refer to the [chart documentation](https://github.com/kasmtech/kasm-helm/tree/release/1.1190.0/charts/kasm-helm) for all available configuration options, including ingress settings. At minimum, include: ```yaml publicAddr: kasm.contoso.com certificate: secretName: {CERTIFICATE_SECRET_NAME} # The TLS secret name you created above database: standalone: true hostname: "{DB_HOSTNAME}" # <-- REPLACE with your standalone DB hostname port: 5432 # Change if your PostgreSQL instance uses a non-default port kasmDbName: kasm # Default VM installation uses "kasm". Change if you used a different database name kasmDbUser: kasmapp # Default VM installation uses "kasmapp". Change if you used a different database user dbManagement: initialize: false ``` Install the chart: :::warning The `{RELEASE_NAME}` used here must match the secret name you applied in the previous step. For example, if your secret is named `kasm-secrets`, your release name must be `kasm`. ::: #### OCI Registry (Recommended) ```bash helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` #### Classic Helm Repository ```bash helm repo add kasm https://helm.kasm.com helm repo update helm install {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` --- ### 4. Verify and Log In The pods will gradually come into a running state. Watch until all pods are running: ```bash kubectl get pods -n {NAMESPACE} --watch ``` Once all pods are running, press `Ctrl+C` to stop watching. If you enabled ingress in your `my-values.yaml`, update your DNS record for `publicAddr` to point to the ingress address. Retrieve it with: ```bash kubectl get ingress -n {NAMESPACE} ``` Use the value in the `ADDRESS` column. Once DNS has propagated, access your Kasm environment using the `publicAddr` you set. For credentials, run: ```bash helm get notes {RELEASE_NAME} -n {NAMESPACE} ``` --- ## Troubleshooting See [Kubernetes Troubleshooting](../troubleshooting/kubernetes) for assistance. --- ## Configure Multi-Zone Proxies with Kubernetes # Multi-Zone Proxies with Kubernetes By default, all session traffic is routed through the Kubernetes cluster where the Kasm Helm chart is deployed. When you define additional zones, those zones only receive the App role from the Helm chart — proxy and agent components must be provisioned externally. Multi-zone deployments are commonly used to serve users across geographic regions, but zones can also be used to segment groups of users or isolate different workload types across separate pools of compute resources — for example, separating contractor traffic from internal users, or giving a specific team dedicated agent capacity. This guide walks through deploying the external proxy components for an additional zone. The Connection Proxy is required if the zone supports RDP or VNC sessions. The Dedicated Proxy is optional for Docker sessions — it routes traffic locally within the zone rather than through the App role, which reduces latency when the zone is geographically distant from the primary zone. :::tip[Not sure which components you need?] See [Kubernetes Deployment Options](../../explanations/kubernetes-deployment-options) for a breakdown of which roles the Helm chart covers and which you need to provision externally based on your session types. ::: This guide covers two configurations: - **Docker sessions only** — no additional VMs required. Optionally deploy a Dedicated Proxy to reduce latency. - **Docker and RDP/VNC sessions** — requires one VM per additional zone (a Connection Proxy). Optionally add a Dedicated Proxy to reduce Docker session latency. --- ## Before You Begin ### VM Requirements | Session Type | Required VMs | Optional VMs | |---|---|---| | Docker only | None | Dedicated Proxy (reduces latency) | | Docker + RDP/VNC | Connection Proxy | Dedicated Proxy (reduces Docker session latency) | ### DNS Hostnames Each proxy VM needs its own DNS hostname, separate from the zone's `proxyAddress`, sharing the same parent domain. For example, given: ```yaml proxyAddress: zone-b.kasm.contoso.com ``` | VM | Example Hostname | Configured in Kasm UI as | |---|---|---| | Dedicated Proxy | `proxy.zone-b.kasm.contoso.com` | **Proxy Hostname** | | Connection Proxy *(RDP/VNC)* | `rdp.zone-b.kasm.contoso.com` | **RDP HTTPS Proxy Hostname** | ### Network Requirements - **Dedicated Proxy**: must have network connectivity to all Kasm Agents in the zone and bidirectional connectivity to the zone `proxyAddress`. - **Connection Proxy**: must have network connectivity to all RDP and VNC targets in the zone that users will access, and bidirectional connectivity to the zone `proxyAddress`. :::note For best performance, Kasm Agents and their zone's Dedicated Proxy should be deployed on infrastructure that is close to each other and to the users they serve. This keeps session traffic within the zone rather than routing it back through the primary zone. ::: --- ## Step 1: Configure Multi-Zone Kasm Helm In your `my-values.yaml`, configure the `kasmZones` section to define multiple zones: ```yaml publicAddr: kasm.contoso.com kasmZones: - name: primary proxyAddress: kasm.contoso.com - name: zone-b proxyAddress: zone-b.kasm.contoso.com ``` Then install or upgrade your Kasm Helm chart with these values. See [Install Kasm on Kubernetes](../../tutorials/install/kubernetes) or [Upgrade Kasm on Kubernetes](../upgrade/kubernetes/upgrade_new_chart) for instructions. :::note 1. The first zone in the list is treated as the primary zone and receives the full set of proxy roles from the Helm chart. External proxies are only needed for additional zones. 2. Traffic to the configured `publicAddr` in the ingress rule is routed to the primary zone. ::: --- ## Step 2: Install the Dedicated Proxy *(optional)* :::note Skip this step if latency through the primary zone is acceptable. Without a Dedicated Proxy, Docker session traffic routes through the App role's built-in proxy rather than a zone-local relay. ::: Follow the [proxy installation steps](../../tutorials/install/multi-server-install) (`--role proxy`) in the Multi-Server Installation guide, setting `--api-hostname` to the zone's `proxyAddress` from `my-values.yaml` (e.g., `zone-b.kasm.contoso.com`). This tells the dedicated proxy where to forward upstream authentication requests. --- ## Step 3: Install the Connection Proxy *(RDP and VNC sessions)* :::note Skip this step if you are only proxying Docker sessions. ::: Follow the [connection proxy installation steps](../../tutorials/install/multi-server-install) (`--role guac`) in the Multi-Server Installation guide, using the following flag values specific to this zone: - `--api-hostname`: The zone's `proxyAddress` from `my-values.yaml`, e.g., `zone-b.kasm.contoso.com`. - `--public-hostname`: The DNS hostname of this connection proxy VM (see [Before You Begin](#before-you-begin)). - `--registration-token`: Retrieve your token with: ```bash kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets -o jsonpath="{.data.service-token}" | base64 -d; echo ``` - `--server-zone`: The zone `name` from `my-values.yaml`, e.g., `zone-b`. --- ## Step 4: Configure the Kasm Zone Log in to your Kasm UI. You can retrieve the `admin@kasm.local` password with: ```bash kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \ -o jsonpath="{.data.admin-password}" | base64 -d; echo ``` In the Kasm Admin UI, go to **Infrastructure** → **Deployment Zones** → **Edit** your additional zone: 1. **Upstream Auth Address**: Set to the zone's `proxyAddress` from `my-values.yaml`, e.g., `zone-b.kasm.contoso.com`. 2. **Proxy Hostname**: Set to your dedicated proxy hostname, e.g., `proxy.zone-b.kasm.contoso.com`. 3. **RDP HTTPS Proxy Hostname** *(RDP and VNC sessions)*: Set to your connection proxy hostname, e.g., `rdp.zone-b.kasm.contoso.com`. --- ## Configure Direct RDP Connections on Kubernetes (Port 3389) # Direct RDP Connections on Kubernetes (Port 3389) When a user launches an RDP workspace in Kasm, the session can be delivered in three ways depending on workspace and zone configuration: | Connection mode | How it works | Extra Kubernetes config needed | |---|---|---| | **Web native client** | Rendered in the browser via Guacamole; no RDP gateways involved | None | | **Thick client via RDP HTTPS Gateway** | Native RDP client connects over HTTPS (port 443) via the RDP HTTPS Gateway | None — works through standard ingress | | **Thick client via RDP Gateway (direct)** | Native RDP client connects directly on port 3389 via the RDP Gateway | Required — this guide | ```mermaid --- title: RDP Connection Paths config: layout: elk --- flowchart TB subgraph clients ["Client"] Browser(["Browser"]) RDPClient([Native RDP Client]) end Ingress["Ingress\n(port 443)"] NP["NodePort / LoadBalancer\n(port 3389)"] Guacamole[Guacamole] HTTPS_GW[RDP HTTPS Gateway] RDP_GW[RDP Gateway] Session([Workspace Session]) Browser -->|"HTTPS"| Ingress Ingress --> Guacamole Guacamole -->|"Path 1 — web native"| Session RDPClient -->|"HTTPS port 443"| Ingress Ingress --> HTTPS_GW HTTPS_GW -->|"Path 2 — RDP HTTPS Gateway"| RDP_GW RDP_GW --> Session RDPClient -->|"TCP port 3389\n(this guide)"| NP NP -->|"Path 3 — direct RDP Gateway"| RDP_GW ``` The web native and RDP HTTPS Gateway modes both work out of the box with a standard Kasm Kubernetes deployment. The thick client default is to route through the RDP HTTPS Gateway. To switch to the direct RDP Gateway path, an admin must disable **Enable RDP HTTPS Gateway** in the zone settings — after which Kasm generates `.rdp` files that connect directly on port 3389. :::note The RDP HTTPS Gateway also routes connections internally through the RDP Gateway when **Enable RDP HTTPS Gateway DLP** is enabled (the default). This is transparent and does not require any of the configuration in this guide. ::: This guide covers the additional Kubernetes configuration needed to expose the **RDP Gateway** on **port 3389** for direct thick client connections. Standard Kubernetes Ingress does not support arbitrary TCP ports, so you must expose the RDP Gateway using a NodePort or LoadBalancer service type. --- ## How it Works When a user launches an RDP session using the direct RDP Gateway path, Kasm generates an `.rdp` file containing the gateway address. This address is built from the `SERVER_HOSTNAME` environment variable on the RDP Gateway container, which defaults to the internal Kubernetes service name (not reachable from outside the cluster). The Kasm Helm chart provides the `directRdpService` values to handle this configuration. When enabled, the chart: 1. Creates an external-facing service (NodePort or LoadBalancer) to route port 3389 traffic to the RDP Gateway pods 2. Automatically sets `SERVER_HOSTNAME` to the `rdpAccessURL` you provide, so generated `.rdp` files contain the correct external address --- ## Step 1: Configure `directRdpService` in Your Values File Add the `directRdpService` block to your `my-values.yaml`. Choose **LoadBalancer** (cloud environments with a load balancer provisioner) or **NodePort** (available on any cluster). ### Option A: LoadBalancer A LoadBalancer service provisions an external IP or hostname from your cloud provider. Clients connect directly to port 3389 on that address. ```yaml directRdpService: enabled: true rdpAccessURL: rdp.example.com type: LoadBalancer ``` Cloud providers may require annotations to configure the load balancer (e.g., internal vs external, NLB vs ALB). Add them under `directRdpService.annotations`: ```yaml directRdpService: enabled: true rdpAccessURL: rdp.example.com type: LoadBalancer annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb ``` ### Option B: NodePort A NodePort service exposes a port on every worker node in the cluster. External clients connect to any node IP on the assigned node port. ```yaml directRdpService: enabled: true rdpAccessURL: rdp-node.example.com type: NodePort ``` :::note If your nodes are behind a load balancer or NAT, set `rdpAccessURL` to the address clients actually reach — not the internal node IP. ::: --- ## Step 2: Apply the Configuration Apply your updated values file: #### OCI Registry (Recommended) ```bash helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml \ --set dbManagement.initialize=false \ --set dbManagement.upgrade.enable=false ``` #### Classic Helm Repository ```bash helm repo add kasm https://helm.kasm.com helm repo update helm upgrade {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml \ --set dbManagement.initialize=false \ --set dbManagement.upgrade.enable=false ``` --- ## Step 3: Configure DNS (LoadBalancer only) :::tip[This step is optional] Skip this step if you used **NodePort**, or if your cluster runs [ExternalDNS](https://kubernetes-sigs.github.io/external-dns/) or a similar controller that automatically creates DNS records from service annotations. ::: If you chose LoadBalancer, retrieve the external address assigned by your cloud provider: ```bash kubectl get service -n {NAMESPACE} -l app.kubernetes.io/name={RELEASE_NAME}-rdp-gateway ``` Create a DNS record pointing your `rdpAccessURL` hostname to the value in the `EXTERNAL-IP` column. Wait a few minutes for provisioning if the value shows ``. --- ## Verify 1. Confirm the RDP Gateway service shows the expected type and external address: ```bash kubectl get service -n {NAMESPACE} -l app.kubernetes.io/name={RELEASE_NAME}-rdp-gateway ``` 2. Confirm `SERVER_HOSTNAME` is set to your `rdpAccessURL`: ```bash kubectl get deployment {RELEASE_NAME}-rdp-gateway -n {NAMESPACE} \ -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="SERVER_HOSTNAME")].value}' ``` 3. In the Kasm Admin UI, go to **Infrastructure** → **Deployment Zones** → **Edit** your zone and confirm **Enable RDP HTTPS Gateway** is disabled. 4. Launch an RDP workspace through the Kasm web interface. Kasm will generate an `.rdp` file — open it in your RDP client and verify the connection succeeds on port 3389. --- ## Troubleshooting See [Kubernetes Troubleshooting](../troubleshooting/kubernetes) for general pod and service diagnostics. --- ## Kasm Workspaces: Bridged Network Source NAT Configuration # Bridged Network Source NAT ## Overview Administrators may desire to provision Kasm sessions that egress out of a specific IP assigned to the host. This might be useful if the network utilizes special policy routes based on source IPs to direct traffic. In this example we will demonstrate how to: - Create a custom docker network using the bridge driver. - Configure the docker network to egress out of defined interface IP. - Configure a Kasm Workspace to always be provisioned on the desired docker network, using the **Restrict to Docker Network** [Workspace Setting](../workspaces-sessions/container-workspace/workspaces.mdx) In this model, the Kasm sessions will be given a NATed address inside the docker network pool (e.g 172.19.0.0/16) but when the traffic leaves the docker host it will utilize a specific IP that belongs to one of the hosts interfaces. ![Desired Configuration](/img/bridged_network_source_nat/diagram.png) ## Environment **Network Interfaces** | **Interface** | **IP(s)** | | ------------- | -------------------------------- | | enp0s3 | 192.168.4.53/24 192.168.4.153/24 | | enp0s8 | 192.168.56.103/24 | ```Bash ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:be:61:fa brd ff:ff:ff:ff:ff:ff inet 192.168.4.53/22 brd 192.168.7.255 scope global noprefixroute dynamic enp0s3 valid_lft 12112sec preferred_lft 12112sec inet 192.168.4.153/24 scope global enp0s3 valid_lft forever preferred_lft forever inet6 fe80::e7be:8f90:49c:ec27/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: enp0s8: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:b4:47:93 brd ff:ff:ff:ff:ff:ff inet 192.168.56.103/24 brd 192.168.56.255 scope global noprefixroute dynamic enp0s8 valid_lft 506sec preferred_lft 506sec inet6 fe80::dbad:e1ea:d353:c4a/64 scope link noprefixroute valid_lft forever preferred_lft forever ``` ## Docker Network Configuration The docker network names used in this example are intentionally prefixed with `z_` . Due to a quirk `docker` will choose the default route for the container based on the name of the docker network ordered alphabetically. We name these custom networks accordingly so that they won't cause interruptions with the Kasm service containers or user workflow. 1. Create a bridged docker network named `z_custom_a` > ```Bash > sudo docker network create \ > --driver bridge \ > --attachable \ > --opt "com.docker.network.bridge.name"="z_custom_a" \ > --opt "com.docker.network.bridge.enable_ip_masquerade"="false" \ > z_custom_a > ``` 1. After the network is created, get the auto-generated subnet > ```Bash > sudo docker inspect z_custom_a | grep Subnet > "Subnet": "172.19.0.0/16", > ``` 1. Update `iptables` to source nat traffic from the custom docker network to the defined IP > ```Bash > sudo iptables -t nat -A POSTROUTING -s 172.19.0.0/16 ! -o z_custom_a -j SNAT --to-source 192.168.4.153 > ``` 1. Create a bridged docker network named `z_custom_b`. > ```Bash > sudo docker network create \ > --driver bridge \ > --attachable \ > --opt "com.docker.network.bridge.name"="z_custom_b" \ > --opt "com.docker.network.bridge.enable_ip_masquerade"="false" \ > z_custom_b > ``` 1. After the network is created, get the auto-generated subnet > ```Bash > sudo docker inspect z_custom_b | grep Subnet > "Subnet": "172.20.0.0/16", > ``` 1. Update `iptables` to source nat traffic from the custom docker network to the defined IP > ```Bash > sudo iptables -t nat -A POSTROUTING -s 172.20.0.0/16 ! -o z_custom_b -j SNAT --to-source 192.168.56.103 > ``` 1. The generated briged interfaces can also be observed using `ip a` > ```Bash > ip a > ... > 32: z_custom_a: mtu 1500 qdisc noqueue state DOWN group default > link/ether 02:42:5e:07:7a:e6 brd ff:ff:ff:ff:ff:ff > inet 172.19.0.1/16 brd 172.19.255.255 scope global z_custom_a > valid_lft forever preferred_lft forever > 33: z_custom_b: mtu 1500 qdisc noqueue state DOWN group default > link/ether 02:42:f4:a5:a7:ca brd ff:ff:ff:ff:ff:ff > inet 172.20.0.1/16 brd 172.20.255.255 scope global z_custom_b > valid_lft forever preferred_lft forever > ``` ## Kasm Workspace Configuration 1. Log into the Kasm UI as an administrator. 2. Select **Workspaces** -> **Workspaces**. 3. Select **Edit** next to the desired Workspace from the arrow menu. 4. Check **Restrict Image to Docker Network** and select the desired network ![Restrict Image to Docker Network](/img/bridged_network_source_nat/restrict_to_network.webp) Create a new session using the Workspace and verify the configurations. In this example we make a request to a web server that returns our IP ![Verification](/img/bridged_network_source_nat/verification.png) --- ## BYOVPN: Running VPNs Inside Kasm Workspaces Containers # Bring Your Own VPN Containers (BYOVPN) This guide will cover how to use the Kasm Workspaces images that come pre-built to simplify using VPNs within the containers. The images support allowing the end-user or admin to specify the configuration details for the following VPN Services. * [OpenVPN](https://openvpn.net/) * [Wireguard](https://www.wireguard.com/) * [Tailscale](https://tailscale.com/) The following images are available to install via the [Kasm Workspaces Registry](https://registry.kasmweb.com/) | | **Docker Image** | **Dockerhub Path** | **AMD64** | **ARM64** | **GPU** | | :------------ | :-------------------------------------------- | :--------------------------------------------- | :-------- | :-------- | :-------- | | | kasmweb/ubuntu-jammy-desktop-vpn:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-desktop-vpn) | **X** | **X** | **X** | ## End-User provided VPN Configuration By default, the BYOVPN images utilize a custom [Workspace Launch Forms](../workspaces-sessions/container-workspace/workspace-launch-form.mdx) to present options for the end-user to configuring their VPN details, such as a Tailscale authentication key. When the user selects the VPN Workspace from the dashboard, the form will be rendered to capture the VPN details. When the workspace is launched, the user will be presented with notifications regarding the state of the VPN Connection. With a number of consumer VPN services offering OpenVPN and/or WireGuard based connection options, this provides substantial flexibility for user's to leverage their own VPN accounts within Kasm. If this is the desired use-case, no futher action is needed other than to install the Workspace and publish it to users.
OpenVPN Example
Wireguard Example
## Admin-Provided VPN Configurations The BYOVPN Images can also be used to pre-configure the VPN Connection requiring no end-user intervention. In order to use the admin-provided configurations, remove the **Launch Config** configurations from the Workspace entry. This will remove the custom launch form when launching the Workspace, and allow the container to use the admin-provided options. VPN configurations or credentials supplied by the admin may be visible to the end-user when running the container. If this is not acceptable, consider using a [VPN Sidecar](./vpn-sidecar.mdx). ### Tailscale Configuration Tailscale is not a full VPN isolation solution out of the box, it allows you to connect to the shared machines also connected to the account. All other Internet traffic will still go out over the local network by default. In order to use Tailscale an auth key will need to be generated from the Tailscale admin dashboard, please reference [Getting the Tailscale auth key](vpn-sidecar.mdx) to generate one. By default, Tailscale does not require manual device approval for machines that seek to automatically join the network, even when joining with pre-generated keys. However, if this setting is enabled, the Tailscale connection will not succeed for new Kasm sessions until the Tailscale admin approves them. See [Device Approval](https://tailscale.com/kb/1099/device-approval) for more information. With an auth key the **Docker Run Config Override** for the Workspace will need to be modified to upldate the `TAILSCALE_KEY` IE: ```json { "environment": { // highlight-next-line "TAILSCALE_KEY": "tskey-auth-XXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "SHOW_VPN_STATUS": "1", "SHOW_IP_STATUS": "1" }, "sysctls": { "net.ipv4.conf.all.src_valid_mark": 1 }, "dns": [ "8.8.8.8", "8.8.4.4" ] } ``` ### Wireguard Configurations * After installing the Workspace from the Kasm Workspace Registry, navigate to the Administrator Dashboard -> Workspaces -> Workspaces -> click the arrow next to the Workspace -> Click Edit (pencil icon) -> File Mapping tab -> Add File Mapping. * Select Text for Type * Customize the Name (here we use `VPN Config`) * Customize the Description (here we use `VPN Configuration File`) * Set the destination path as `/dockerstartup/wireguard.conf` * Paste the contents of your Wireguard configuration file in the Text area * Click Save #### Wireguard DNS Wireguard uses configuration information from it's own conf file to setup DNS in the Workspace so the default Google DNS servers can be left in the **Docker Run Config Override** or removed it will not matter once connected on init. ### OpenVPN Configurations * After installing the Workspace from the Kasm Workspace Registry, navigate to the Administrator Dashboard -> Workspaces -> Workspaces -> click the arrow next to the Workspace -> Click Edit (pencil icon) -> File Mapping tab -> Add File Mapping. * Select Text for Type * Customize the Name (here we use `VPN Config`) * Customize the Description (here we use `VPN Configuration File`) * Set the destination path as `/dockerstartup/openvpn.conf` * Paste the contents of your OpenVPN configuration file in the Text area * Click Save #### OpenVPN DNS The default settings are pointed to Google's public DNS servers. It is important to keep in mind that private DNS servers that only the client can access will not function over an OpenVPN tunnel. It is necessary to use either public DNS servers or DNS servers that can be accessed on the server side of the tunnel. #### OpenVPN authentication OpenVPN might also require a username and password as well as the config file being mapped into the Workspace. This depends entirely on the Server side configuration. This is automatically detected by the VPN enabled Workspace and will prompt the user to enter their username and password when the container is launched. After entering the authentication information the user will be notified when the VPN is connected or if there was an error. #### OpenVPN Automating user/pass Authentication If the OpenVPN server requires user/pass authentication, and the workflow desired is automatically log in, an additional file will need to be mapped into the container referencing this login information. * Navigate to the Administrator Dashboard -> Workspaces -> Workspaces -> click the arrow next to the Workspace -> Click Edit (pencil icon) -> File Mapping tab -> Add File Mapping * Select Text for Type * Customize the Name (here we use `Auth`) * Customize the Description (here we use `OpenVPN Authentication file`) * Set the destination path as `/dockerstartup/openvpn-auth` * In the text area enter the username on the first line and the password as the second line. * Click Save It is also necessary to reference this file in the main OpenVPN configuration by modifying the line `auth-user-pass` to: ``` auth-user-pass /dockerstartup/openvpn-auth ``` ## VPN and Public IP Status Notifications By default, the VPN containers will display VPN Status, and Public IP Status messages when the VPN connection is established. This can be helpful to end users to verify connectivity. These notifications can be removed by adjusting the `SHOW_VPN_STATUS` and `SHOW_IP_STATUS` environment variables to `0` using the Docker Run Config. ```json { "environment": { "TAILSCALE_KEY": "", // highlight-next-line "SHOW_VPN_STATUS": "0", // highlight-next-line "SHOW_IP_STATUS": "0" }, "sysctls": { "net.ipv4.conf.all.src_valid_mark": 1 }, "dns": [ "8.8.8.8", "8.8.4.4" ] } ``` ## Troubleshooting On any connection errors the user will be notified via a pop up and logs of the logic flow are stored inside the Workspace under the path `/dockerstartup/vpn_start.log`. This file can be read by the user in a terminal using: ``` cat /dockerstartup/vpn_start.log ``` Or any other GUI text editor in the Workspace. --- ## Cisco Umbrella / OpenDNS Integration # Cisco Umbrella / OpenDNS Administrators have several options for integrative Kasm with Cisco Umbrella / OpenDNS. - Users can be redirected to Kasm session when accessing restricted sites. - Kasm sessions can be configured to use custom DNS servers, thus using DNS filtering systems such as Cisco Umbrella / OpenDNS. In some situations this may be preferred to Kasm Workspace's built in [Web Filtering](../security/web-filtering.mdx). ## Redirect Blocked Requests to Kasm Administrators can configure Cisco Umbrella to redirect the user's request to Kasm when a policy is violated. For example, it certain categories of sites are denied by Cisco Umbrella policy, the Administrator may wish to provide access to the site only through Kasm isolation. This is instrumented via the use of a **Custom Block Page** that is coded to either automatically redirect the user to Kasm or provide a link for the user to click. The following figure shows an example of a user's request being denied by Cisco Umbrella policy to auctions sites. The custom block page is shown, and the user has the option to open the link inside a Kasm session. The Kasm session is opened in a new window and automatically launches to the requested site. ### Deploy a Custom Block Page A custom block page is used to redirect the user's original request to Kasm or provide them a link to do so. Administrator's must customize and place the block page in a website that is accessible to all users. 1. Download the example block page: [Custom Block Page Example](https://kasm-static-content.s3.amazonaws.com/cisco_umbrella_custom_block_page.html) (Right Click and Save) The example block page is intentionally devoid of styling to more simply illustrate the workflow. Administrators can customize the page with styling and branding as desired. 2. Edit the file and replace `kasm.server` in the `kasm_url` variable with a domain for your Kasm Deployment.
Partial Block Page Contents
```jsx ... // highlight-next-line var kasm_url = "https://kasm.server/#/go?kasm_url="; var urlParams = new URLSearchParams(window.location.search); var kasm_message_elem = document.getElementById("kasm"); var kasm_link_elem = document.getElementById("kasm_link"); var url_elem = document.getElementById('url'); ... ``` 3. Deploy the file to a web server that is accessible by the users. e.g `https://my.server/block.html` ### Update Cisco Umbrella 01. Log into the [Cisco Umbrella Portal](https://login.umbrella.com/) 02. Select **Policies** -> **Policy Components** -> **Block Page Appearance** 03. Click **Add** 04. Update the **Block Page Appearance Name** (e.g **Kasm Block Page**) 05. Choose a **Blocked requests should be treated:** method. 06. Select **Redirect users to this URL** and enter the address of the deployed custom block page: e.g `https://my.server/block.html` 07. Select **Save** 08. Select **Policies** -> **Management** -> **All Policies** 09. Expand the desired policy (e.g **Default Policy**) and select **Edit** under **Custom Block Page Applied** 10. Select **Use a Custom Appearance** and select the policy created in the previous steps (e.g **Kasm Block Page**) 11. Select **Set & Return** then select **Save** It may take several minutes for changes to the policy to take effect. 12. When applicable users violate the policy they should see the configured block page with the option to open the link in Kasm. Cisco provides [Test URLs](https://support.umbrella.com/hc/en-us/articles/115000411528-What-are-the-Umbrella-Test-Destinations-) to help verify behavior. ## Kasm Sessions as Cisco Umbrella / OpenDNS Clients ### DNS Configuration Administrators can configure Kasm sessions to use custom DNS server such as those provide by Cisco Umbrella / OpenDNS. Use the following steps to locate the Cisco Umbrella DNS servers for the account, then see [Custom DNS Servers](./custom-dns-servers.mdx) for configuration details details. 1. Log into the [Cisco Umbrella Portal](https://login.umbrella.com/) 2. Select **Deployments** -> **Core Identities** -> **Networks** 3. Select **+** next to desired networks's IP address 4. The DNS Servers are displayed. Utilize the **IPv4** DNS Servers when configuring an image with [Custom DNS Servers](./custom-dns-servers.mdx) 6) Once configured, navigate to one of the [Test URLs](https://support.umbrella.com/hc/en-us/articles/115000411528-What-are-the-Umbrella-Test-Destinations-) from within the Kasm session to verify the configuration. ### Root Certificate Installation In order to for Cisco Umbrella / OpenDNS to utilize more advanced filtering , inspect SSL traffic and display block pages without the user getting a warning, the custom root certificate must be installed within the Kasm Image. Use the following steps to retrieve the CA cert provided by Cisco. Once retrieved, create a custom Image using the certificate by following the [Custom CA Certificates](./custom-root-certificate.mdx) instructions. **Helpful References** * [https://docs.umbrella.com/umbrella-user-guideinstall-the-cisco-umbrella-root-certificate](https://docs.umbrella.com/umbrella-user-guide/docs/install-the-cisco-umbrella-root-certificate) 1. Log into the [Cisco Umbrella Portal](https://login.umbrella.com/) 2. Select **Deployments** -> **Configuration** -> **Root Certificate** 3. Select *Download Certificate* 4. Create a custom Image using the certificate by following the [Custom CA Certificates](./custom-root-certificate.mdx) instructions. --- ## Kasm Workspaces: Gathering Client Debugging Information # Client Debugging Information Administrators may need users to gather detailed connection information to triage a problem. The following steps may be used to harvest Console logs and HAR (HTTP Archive Format) network information from the client. Data gathered by the following steps will contain sensitive information. Never post this data to public forums. It should be securely transmitted to the Kasm administrator. It is recommended that users change their passwords after submitting the debugging information. ## Developer Tools Console Log and HAR Data The following steps can be used to gather the Console logs and HAR networking data. The example is for Firefox, but is similarly applicable for Chrome/Chromium-based browsers. ### Pre-Test - Log into Kasm Workspaces. - Press **F12** to open the web browser **Developer Tools.** - Select the **Network** tab in the developer tools, and ensure **Persist Logs** is checked. ![Enabling Network Persist Logs Setting](/img/client_debugging/ff_network_persist_logs.png) - Select the **Console** tab and ensure **Persist Logs** is checked. ![Enabling Console Persist Logs Setting](/img/client_debugging/ff_console_persist_logs.png) - *Conduct the desired test.* ### Post-Test - Select the **Network** tab from developer tools. Select the settings gear icon and select **Save all as HAR**. ![Exporting to HAR file](/img/client_debugging/ff_save_as_har.png) - Select the **Console** tab from the developer tools. Right click one of the messages and select, **Export Visible Messages To → File**. ![Exporting to Console logs](/img/client_debugging/ff_export_console_logs.png) - *Send the files to the Kasm administrator.* --- ## Securing Kasm with Cloudflare Tunnels # Cloudflare Tunnels A Cloudflare Tunnel provides secure web connectivity to your Kasm Workspaces instance without requiring a publicly routable IP address or valid external SSL certificate by routing through the Cloudflare service. In this video, we will show you how to configure Kasm Workspaces with Cloudflare Tunnels using your own DNS hostname. ## Video Tutorial If you prefer to follow along with a video tutorial, you can watch this YouTube video that covers the same steps outlined in this guide. ## Prerequisites Before starting, please ensure that you have completed the following steps: 1. Deployed a Kasm instance. 2. Registered a DNS domain. 3. Set up a Cloudflare account. 4. Connected cloudflare nameservers to your domain provider. ## Connecting Your Domain to Cloudflare The first step is to connect your domain to Cloudflare. To do this, you need to change the name servers for your domain to Cloudflare's name servers. Here are the steps to follow: 1. Navigate to the DNS tab on the left-hand side of your Cloudflare dashboard. ![Location of Cloudflare DNS Section](/img/cloudflare_tunnels/dns.webp) 2. Scroll to the bottom and copy the two Cloudflare name servers. 3. Log in to your domain provider and replace the existing name servers with the Cloudflare name servers. The process of changing your domain's name servers may take up to 48 hours to propagate. ### Setting up the Tunnel To set up the tunnel after connecting your domain to Cloudflare, follow these steps: 1. Navigate to the Access tab on the left-hand side of your Cloudflare dashboard and click on the "Launch Zero Trust" button. This will take you to the zero-trust dashboard, where you can access tunnels by clicking the drop-down arrow next to Access and selecting Tunnels. ![Location of Cloudflare Tunnels Zero Trust](/img/cloudflare_tunnels/access.webp) 2. To install a new tunnel, click on "Create a Tunnel," give it a name, and click "Save Tunnel." 3. Select the Docker tab and copy the provided code. 4. Paste this code into a text editor of your choice, such as VS Code. Add "-d" after the "run" section to ensure it runs in the background. 4. Copy and paste the updated code into your host machine, and you'll see that it's now connected. ![Example of Code With -d](/img/cloudflare_tunnels/code.webp) For more information about installing and configuring Cloudflare Tunnel, you can refer to [the official documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps). ### Connecting to a Public Host Domain Once the tunnel is connected and running, you can connect it to a public host domain. To connect your tunnel to a public host domain, follow these steps: 1. Navigate to your existing tunnel by clicking on the drop-down arrow next to "Access" and selecting "Tunnels." ![Location of Cloudflare Tunnels Tunnels](/img/cloudflare_tunnels/tunnels.webp) 2. Find the name of your tunnel and click on it. 3. Click on the "Configure" button, and then click on "Public Hostname." ![Location of Cloudflare Tunnels Add Hostname](/img/cloudflare_tunnels/add_hostname.webp) 4. To create a new tunnel route, enter a subdomain, such as "test," and select your domain from the dropdown menu. 5. Leave the path section blank and select "HTTPS" as the service type. 6. In the URL section, enter the IP address of your Kasm instance. 7. Click on the "Additional Application Settings" tab. 8. Enable "No TLS Verify" and "HTTP2 Connection." 9. Save the hostname. ### Testing the Connection To test the connection, you can either enter the URL into your search bar or click on the created route and then the external link. Your Kasm Workspaces instance is now accessible via your domain using Cloudflare Tunnels. If you are using the [RDP local client workspace option](../workspaces-sessions/container-workspace/workspaces.mdx), make sure the [**Restrict RDP Client IP Address**](../infra-autoscale/deployment-zones.mdx) setting is disabled in Infrastructure / Zones. If it isn't may not be able to connect, as the IP stored with the request will differ due to the connection being over the tunnel. If this is the case it will be reported in the Error Logs with a message such as "Invalid Request. Wrong client IP." ## Conclusion By following the steps outlined in this guide, you can easily configure your Kasm Workspaces with Cloudflare Tunnels and your own SSL certificates for your domain. This allows you to provide secure and convenient access to your Kasm Workspaces instance through your own domain name, with the added benefits of Cloudflare's CDN and DDoS protection. --- ## Configure Custom DNS Servers in Kasm Workspaces # Custom DNS Servers Administrators can use the **Docker Run Config** [Workspace Setting](../workspaces-sessions/container-workspace/workspaces.mdx) or [Group Setting](../security/users-groups-mgmt/groups.mdx) to specify custom DNS servers that are used by the Kasm sessions. ```json { "dns": [ "208.67.220.220", "208.67.222.222" ] } ``` The following instructions demonstrate how to configure custom DNS servers using the **Docker Run Config** [Workspace Setting](../workspaces-sessions/container-workspace/workspaces.mdx) 1. Log into the Kasm UI as an administrator. 2. Select **Workspaces** -> **Workspaces** 3. Select **Edit** (Pencil) next to the desired Workspace from the arrow menu. 4. Specify the DNS Server in **Docker Run Config** ![Custom DNS in Docker Run Config](/img/custom_dns/docker_run_config.webp) 5. Select Save New sessions created with this Workspace will utilize the specified DNS servers for resolution. --- ## Install Custom Root Certificates in Images # Custom Root Certificates Administrators may wish to install custom root certificates inside a Kasm Image so that users can access organization resources that have certificates singed by an internal CA, or to utilize transparent proxies to inspect traffic and enforce policies. In order to install a custom root cert inside an Image, the Administrator must build a Custom Image. Administrators should first review [Building Custom Images](../workspaces-sessions/container-workspace/customization/building-images.mdx) documentation to familiarize themselves with the process. ## Building the Custom Image The following steps may be used to install a custom root certificate. The steps make use of our [open source Git repository](https://github.com/kasmtech/workspaces-images) that contains the example Dockerfiles and scripts. Firefox is used in the example but the same steps will apply for the other provided images. For simplicity, the steps assume the Image is being built on a Single Server Kasm deployment. If using a multi-server/distributed deployment these steps can be performed from a seperate machine and the Image pushed to a registry. See [Building Custom Images](../workspaces-sessions/container-workspace/customization/building-images.mdx) for more details. - SSH to the Kasm Workspaces server and clone the example Git repository that has examples of for creating custom images. > ```yml > git clone https://github.com/kasmtech/workspaces-images > cd workspaces-images > ``` - Place your certificate in the following directory, overwriting the placeholder file that is currently there `./src/ubuntu/install/certificates/ca.crt` ( ensure it is named ca.crt) - Edit `dockerfile-kasm-firefox` and uncomment the following lines – ( Remove the “#” characters ). This will : > ```yml > ... > # Install Custom Certificate Authority > # COPY ./src/ubuntu/install/certificates $INST_SCRIPTS/certificates/ > # RUN bash $INST_SCRIPTS/certificates/install_ca_cert.sh && rm -rf $INST_SCRIPTS/certificates/ > ... > ``` > > ```yml > ... > # Install Custom Certificate Authority > COPY ./src/ubuntu/install/certificates $INST_SCRIPTS/certificates/ > RUN bash $INST_SCRIPTS/certificates/install_ca_cert.sh && rm -rf $INST_SCRIPTS/certificates/ > ... > ``` - Build the image. > ```yml > sudo docker build -t firefox:custom -f dockerfile-kasm-firefox . > ``` - Login to the Kasm UI as an administrator, and create a new Workspaces that references the new Docker image. See [Building Custom Images.](../workspaces-sessions/container-workspace/customization/building-images.mdx) for details. --- ## Gateway-based Egress: Custom # Custom Custom is a gateway-based egress provider type for advanced and provider-specific integration patterns. Use this when OpenVPN/Wireguard built-in types do not match your environment. ## Typical inputs - Provider type: `Custom` - Gateway config: provider-specific fields required by your custom implementation. - Credential model: optional, based on your custom provider requirements. ## Best-fit use cases - Proprietary or internally developed VPN/tunneling systems. - Integration patterns that require custom connection bootstrap logic. --- ## Gateway-based Egress Overview Gateway-based providers route workspace traffic through selectable egress gateways. Supported providers in this model: - [Custom](./custom.mdx) - [OpenVPN](./openvpn.mdx) - [PureVPN (Managed)](./purevpn.mdx) - [Wireguard](./wireguard.mdx) The following is an example of the new Egress Selection menu presented when a User launches a Workspace: ## Gateway Selection Behavior Egress Providers and Egress Credentials can be applied to users, groups, and workspaces. When users launch a workspace, they are presented with available gateways. Gateways are shown only when: - The gateway is enabled. - A credential exists for the same provider mapped to the selected workspace, user, or one of the user's groups. A credential can be paired with a gateway even if they are mapped to different resources. For instance the User "user@kasm.local" can use a Gateway attached to "All Users" group with a credential attached to "user@kasm.local". The first matching, enabled credential in a list credentials sorted by their egress_credential_id will be automatically selected to be used when a user specifies an Egress Gateway when launching a Workspace. Manually specifying an Egress Credential on Workspace launch is not currently supported. If a Credential has **Limit Active Connections** enabled and the number of concurrent connections using that credential has reached the limit it will not be available to be used on a new Egress credential until a Kasm Session using the credential have ended. ## Configuration Workflow In this example we will be configuring an OpenVPN provider, but Wireguard is also supported. ### Create Provider and Gateways - Log into the Kasm Web UI as an administrator - Click **Infrastructure -> Egress** - Click **Add** | Name | Description | | :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | Enable or disable this configuration | | **Name** | The Unique Name for the Egress Provider | | **Egress Provider Type** | The type of Egress Provider Configuration | | **Enable New Managed Gateways** | (Managed Egress Provider Only) When enabled any new Egress Gateways sent by the Egress Plugin Service will be automatically enabled. | - Fill out the form and click **Save** - A list of all Egress Providers is shown. - Click the arrow menu on the OpenVPN Provider and Select **Edit** - Select the **Egress Gateway** tab and click **Add** | Name | Description | | :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | Enable or Disable this configuration. | | **Name** | The Unique Name for the Egress Gateway | | **Country** | The Country for the Egress Gateway | | **City** | The City for the Egress Gateway | | **Config** | The Egress Gateway Config (OpenVPN, Wireguard or Custom) | For Wireguard Configurations the `PrivateKey` value in Config is set by the Egress Credential. ### Assigning Provider and Credentials Provider Assignments and Credential creation can be done on Users, Groups and Workspaces. In this example we will be performing an Assignment on the User *user@kasm.local*. - Log in to the Kasm Web UI as Administrator - Click **Access Management** -> **Users** - Click the arrow menu on *user@kasm.local* and select **Edit**. - Click on the **Egress** tab and select **Add** | Name | Description | | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | Enable or Disable this configuration. | | **Egress Provider** | The name of the Egress Provider to Map. | | **Allow All Gateways** | When Enabled, all Egress Gateways in the selected Provider will be mapped. Disabling requires that the Admin specify which gateways to map in the **Selected Gateways** field. | | **Selected Gateways** | When **Allow All Gateways** is enabled this setting sets the gateways that apply to this mapping. | - Fill out the form and click **Save** - Click on the **Egress Credential** tab. | Name | Description | | :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | Enable or Disable this configuration. | | **Egress Provider** | The name of the Egress Provider for this Credential. | | **Name** | The name of this Egress Credential. | | **Username** | The Username for the Egress Credential (OpenVPN Provider) | | **Password** | The Password for the Egress Credential (OpenVPN Provider) | | **Private Key** | The Wireguard Private Key for the Egress Credential (Wireguard Provider) | | **Custom Credential** | The Custom Credential for the Egress Credential (Custom Provider) | | **Allow All Gateways** | When Enabled, the Credential will apply to all Egress Gateways in the selected Provider. Disabling requires that the Admin specify which gateways to map in the **Selected Gateways** setting. | | **Selected Gateways** | When **Allow All Gateways** is enabled, this sets the gateways that this Credential can be used with. | | **Limit Active Connections** | When Enabled, the number of concurrent connections that this Egress Credential can be used in is limited to the setting in **Active Connection Limit**. | | **Active Connection Limit** | When **Limit Active Connections** is enabled, this value sets the maximum number concurrent connections the credential can be used in. | Now that the Egress Provider and Credential are assigned to this user, they may select the Egress Gateway when launching a Container Workspace. --- ## Gateway-based Egress: OpenVPN # OpenVPN OpenVPN is a gateway-based egress provider type in Kasm. Use this provider when you want launch-time gateway selection and credential-based VPN tunneling. ## Typical Inputs - Provider type: `OpenVPN` - Gateway config: OpenVPN configuration and endpoint details. - Credential model: username and password credentials assigned through Kasm mappings. ## Best-Fit Use Cases - Existing OpenVPN infrastructure with known operational patterns. - Teams that require user-selectable gateways by region or policy. - Environments that already distribute OpenVPN client configs. ## Setup Pattern 1. Create an egress provider with type **OpenVPN**. 2. Add one or more egress gateways. 3. Map provider to users/groups/workspaces. 4. Create egress credentials with username/password. 5. Launch workspace and select a gateway. --- ## Gateway-based Egress: PureVPN (Managed) # PureVPN (Managed) Kasm has partnered with PureVPN to provide a quick and easy way to gain secure access to **80+ locations across 65 countries**. This "Managed" Egress Provider is a licensed feature, requiring a Kasm license to use. All gateways are owned and operated by PureVPN, with Kasm servers managing auto-population of gateways and credential configuration. To purchase the PureVPN Managed Egress license, contact a Kasm sales rep or purchase via our [web checkout](https://kasm.com/server-checkout). You can find more details about licensing in our [Licensing Guide](../../../../reference/license.mdx). Once you have the appropriate license applied to your Kasm deployment, give it a few minutes so that Kasm can verify and apply the new feature to your deployment. ## Integration You can then go to **"Infrastructure" -> "Egress"** to see that the PureVPN Egress provider has now been added. You can click "Edit" to view/configure more details about the PureVPN provider. The "Enable New Managed Gateways" option decides whether you want to automatically add and configure new gateways that might be added by PureVPN in the future. ## Managed Egress Providers Kasm allows for Licenses to be purchased that grant a number of connections to a Managed Egress Provider. When a license that grants the use of an Managed Egress Provider is applied to the Kasm Workspaces deployment, Kasm Workspaces automatically reaches out to the Kasm Egress Plugin Service to obtain a list of Egress Accounts and Egress Providers and adds them to the Kasm Deployment. For example the following screenshot is of the Egress Providers section on a deployment that has a License applied that grants 5 connections to the PureVPN Managed Egress Provider. Using these Managed Egress Providers is as simple as [mapping them to a User, Group, or Workspace](../../../../tutorials/user-guide/pwa.mdx). Managed Egress providers do not require the creation of Egress Credentials, they only require mapping the Egress Provider to a User Group or Workspace. ### Egress Plugin System Info When a license is added that grants connections for a Managed Egress Provider, it creates a "Egress Plugins" Tab in `Diagnostics->System Info`, which contains summarized information about all the Egress Plugins for all the Licenses on the Kasm Workspaces Deployment. Listed below are the fields in the Egress Plugins table: | **Name** | **Description** | | :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Egress Plugin ID** | The ID of the Egress Plugin. | | **Accounts** | The number of Managed Egress Accounts currently provisioned on this Kasm Workspaces Deployment for this Plugin. | | **Allowed Connections** | The total number of allowed connections permitted by all the licenses on the Kasm Workspaces Deployment for this Plugin | | **Remaining Connections** | The number of remaining available connections for this plugin. This is based on the number of accounts provisioned on the system and the the number of Workspaces sessions currently using an Egress Connection. | ### Egress Plugin License Info Information about the Managed Egress Providers granted by an individual license can be viewed by logging into the Kasm Workspaces Admin UI and navigating to `Diagnostics->System Info->Licenses` and then selecting the "View" button on an individual license and then scrolling to the "Egress Plugins" section. The first entry is a table containing a list of the Egress Plugins granted by the license: | **Name** | **Description** | | :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Egress Plugin ID** | The ID of the Egress Plugin. | | **Accounts** | The number of Managed Egress Accounts currently provisioned on this Kasm Workspaces Deployment for this Plugin on this License. | | **Allowed Connections** | The total number of allowed connections permitted by this license on the Kasm Workspaces Deployment for this Plugin. | | **Remaining Connections** | The number of remaining available connections for this Plugin on this License. This is based on the number of accounts provisioned on this system and the number of Workspaces sessions currently using an Egress connection. | Next are a number of fields that show Egress Plugin information for the License: | **Name** | **Description** | | :--------------------------- | :------------------------------------------------------------------------------------------------- | | **Is License Valid** | The License validity according to the Egress Plugin Service. | | **Is Entitlement Valid** | The License Entitlement validity according to the Egress Plugin Service. | | **Next Egress Plugin Check In** | The next time Kasm Workspaces will attempt to query the Egress Plugin Service to update Managed Egress Accounts and Managed Egress Providers for this License. | | **Last Egress Plugin Check In** | The last time this License was checked in to the Egress Plugin Service. | ### Managed Egress Provider Info When a license is added that grants access to Managed Egress providers, additional information about the Egress Providers can be found by logging into Kasm Administrator UI, navigating to `Infrastructure->Egress` and selecting **Edit** on a Managed Egress Provider and then navigating to **Details** and then scrolling down to the **Egress Plugins** section. The section contains the following: | **Name** | **Description** | | :------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | | **Is Managed** | Wether the Egress Provider is managed by an Egress Plugin. | | **Egress Plugin ID** | The ID of the Egress Plugin that Manages this Egress Provider. | | **Egress Plugin Account Count** | The number of Managed Egress Accounts currently provisioned on this Kasm Workspaces Deployment for this Managed Egress Provider. | | **Egress Plugin Active Connections** | The number Kasm Connections currently using this Manage Egress Provider | | **Egress Plugin Remaining Connections** | The number of remaining available connections for this Managed Egress. This is based on the number of accounts provisioned on this system and the number of active connections. | --- ## Gateway-based Egress: Wireguard # Wireguard Wireguard is a gateway-based egress provider type in Kasm. Use this provider when you want low-overhead gateway-based tunneling with Wireguard configs and private-key credential handling. ## Typical Inputs - Provider type: `Wireguard` - Gateway config: Wireguard peer/network configuration. - Credential model: user-specific private key material stored in Kasm egress credentials. ## Best-Fit Use Cases - Environments that already standardize on Wireguard for secure transport. - Deployments that require user-scoped key management. ## Setup Pattern 1. Create an egress provider with type **Wireguard**. 2. Add one or more Wireguard gateways. 3. Map provider to users/groups/workspaces. 4. Create egress credentials with Wireguard private key. 5. Launch workspace and select a gateway. --- ## Egress Configuration: Gateways, VPN & Zero Trust # Egress Kasm Workspaces lets administrators define **Egress Providers** to control how session traffic reaches external or private destinations. Kasm supports two egress models: - **Gateway-based egress**: users choose a gateway at launch and the workspace's outbound traffic tunnels through that route. - **Zero-trust egress**: access is identity and policy based. Use egress to meet security, network segmentation, and geography requirements. **Egress Providers** can be mapped to a [Workspace](../../workspaces-sessions/container-workspace/workspaces.mdx), [User](../../security/users-groups-mgmt/users.mdx) or [Group](../../security/users-groups-mgmt/groups.mdx) For gateway-based providers, this mapping controls which gateways can be selected at launch. Credentials can also be assigned on workspace/group/user objects. For example, username/password for OpenVPN, or private key for Wireguard. For operational logs, troubleshooting commands, and forensics considerations, see [Operations and Troubleshooting](./operations_and_troubleshooting.mdx). When using [Banners](../../workspaces-sessions/banners.mdx), Kasm can expose egress environment variables (provider, gateway, location). ## Choose An Egress Model ### [Gateway-based](./gateway_based/index.mdx) Gateway-based providers use provider-specific gateway configs and optional user credentials. Administrators may use the Egress feature to grant access to secure environments via a VPN or have Kasm traffic be routed through a location geographically separated from the Kasm Deployment. - [Custom](./gateway_based/custom.mdx): Flexible provider model for non-standard or internal integrations. - [OpenVPN](./gateway_based/openvpn.mdx): Classic VPN workflow using username/password credentials. - [PureVPN (Managed)](./gateway_based/purevpn.mdx): Managed gateway catalog synchronized through Kasm licensing. - [Wireguard](./gateway_based/wireguard.mdx): Lightweight VPN workflow using user private key credentials. ### [Zero-trust](./zero_trust/index.mdx) Zero-trust egress is a security model that treats every connection as untrusted until verified by identity and policy. Instead of giving broad network path access through a selected gateway, administrators define who can access which services under what conditions. - [OpenZiti](./zero_trust/openziti/index.mdx): Identity-driven, policy-based egress without launch-time gateway selection. ## Video tutorial ## Operational Guidance Shared runtime, diagnostics, and maintenance guidance is in: - [Operations and Troubleshooting](./operations_and_troubleshooting.mdx) --- ## Egress Operations and Troubleshooting This page covers runtime implementation details and operational checks that apply to egress deployments. ## Runtime Implementation Kasm egress relies on a Docker network plugin to manage session networking, including interface setup, routing rules, and provider-specific tunnel handling. Primary logs: - `/var/log/kasm-sidecar/network_sidecar.log`: network setup, tunnel behavior, policy/routing actions. - `/var/log/kasm-sidecar/plugin.log`: Docker engine interactions made by the sidecar plugin. Plugin runtime files are written under: - `/var/run/kasm-sidecar/$container_namespace` A quick way to retrieve a container namespace: ```bash docker inspect -f '{{.NetworkSettings.SandboxKey}}' $container_name | grep -o -E "[a-h0-9]+$" ``` ## Environment Variables When egress is enabled for a session, Kasm can expose these variables in the container: ```bash KASM_EGRESS_GATEWAY_NAME KASM_EGRESS_GATEWAY_CITY KASM_EGRESS_GATEWAY_COUNTRY KASM_EGRESS_PROVIDER_NAME ``` Example: ```bash KASM_EGRESS_PROVIDER_NAME=PureVPN KASM_EGRESS_GATEWAY_NAME=AU-MELBOURNE-31 KASM_EGRESS_GATEWAY_COUNTRY=AU KASM_EGRESS_GATEWAY_CITY=Melbourne ``` To disable exposure, set `EXPOSE_EGRESS_ENVIRONMENT_VARS=0` in [Docker Run Config](../../workspaces-sessions/container-workspace/workspaces.mdx#docker-run-config): ```json { "environment": { "EXPOSE_EGRESS_ENVIRONMENT_VARS": "0" } } ``` ## Troubleshooting Flow If a session cannot connect to an egress provider, users are shown an error in the launch flow. Use this checklist: 1. Verify plugin health with `docker plugin ls`. 2. Review `/var/log/kasm-sidecar/network_sidecar.log` for setup and connection errors. 3. Validate provider config files under `/var/run/kasm-sidecar/$container_namespace/$vpn` (for example, `.../wg/wg.conf`). 4. Confirm `kasm_proxy` is attached to the sidecar network bridge via `docker exec -it kasm_proxy ip a`. The interface name should follow the pattern `k-p-p-*.` 5. Validate session routes with `docker exec -it kasm_proxy ip route` and verify traffic leaves on the plugin interface. ```bash default via 172.20.0.1 dev k-p-1389f8 172.20.0.0/16 dev k-p-1389f8 proto kernel scope link src 172.20.0.3 ``` 6. Confirm hostname resolution for `KASM_API_HOST` by inspecting container `env` and `/etc/hosts`. ```bash > docker exec -it $CONTAINER_NAME env | grep KASM_API_HOST KASM_API_HOST=proxy > docker exec -it $CONTAINER_NAME cat /etc/hosts fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.20.0.2 proxy 172.20.0.3 505c32d766d9 ``` 7. Inspect namespace `iptables` rules with `nsenter --net=$container_namespace iptables -L -v -n`. Example route output: ```bash Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 897 131K ACCEPT 0 -- k-p-1389f8 * 172.20.0.2 0.0.0.0/0 # <-- kasm_proxy IP address 20581 4534K ACCEPT 0 -- lo * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT 0 -- tun0 * 0.0.0.0/0 0.0.0.0/0 25 7620 ACCEPT 0 -- wg * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT 0 -- * * 172.20.0.0/16 0.0.0.0/0 # <-- kasm_sidecar_network IP range 28 9644 ACCEPT 0 -- * * XXX.XXX.XX.XX 0.0.0.0/0 # <-- VPN server IP Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 78 16678 ACCEPT 6 -- * k-p-1389f8 0.0.0.0/0 172.20.0.2 tcp dpt:443 # <-- kasm_proxy IP address 20581 4534K ACCEPT 0 -- * lo 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT 0 -- * tun0 0.0.0.0/0 0.0.0.0/0 27 2340 ACCEPT 0 -- * wg 0.0.0.0/0 0.0.0.0/0 1125 4567K ACCEPT 0 -- * * 0.0.0.0/0 172.20.0.0/16 # <-- kasm_sidecar_network IP range 29 4464 ACCEPT 0 -- * * 0.0.0.0/0 XXX.XXX.XX.XX # <-- VPN server IP ``` ## Restarting The Network Plugin In case of issues not caused by a VPN misconfiguration (as described by steps 4-8), the following script can be used to restart the plugin: Ensure no active workspaces using egress are running on the target agent before restarting the plugin. ```yml # disconnect kasm_proxy from the plugin network plugin_name=$(docker network inspect kasm_sidecar_network --format '{{.Driver}}') docker network disconnect kasm_sidecar_network kasm_proxy # restart the plugin docker network rm kasm_sidecar_network docker plugin disable $plugin_name docker plugin enable $plugin_name # reconnect kasm_proxy to the plugin network docker network create -d $plugin_name kasm_sidecar_network docker network connect kasm_sidecar_network kasm_proxy ``` Some VPN Providers such as Private Internet Access may use configurations that are not supported by the latest package versions used by the Kasm Network Plugin. This may result in connections failing or timing out. [See this OpenSSL GitHub issue for more details.](https://github.com/openssl/openssl/discussions/24301) ## Upgrading The Network Plugin Occasionally Docker or dependency changes require plugin upgrades. Ensure no active workspaces using egress are running on the target agent before performing this upgrade. ```yml # disconnect kasm_proxy from the plugin network plugin_name=$(docker network inspect kasm_sidecar_network --format '{{.Driver}}') plugin_reference=$(docker plugin inspect $plugin_name --format '{{.PluginReference}}') docker network disconnect kasm_sidecar_network kasm_proxy # upgrade the plugin docker network rm kasm_sidecar_network docker plugin disable $plugin_name docker plugin rm $plugin_name docker plugin install --alias $plugin_name --grant-all-permissions $plugin_reference # reconnect kasm_proxy to the plugin network docker network create -d $plugin_name kasm_sidecar_network docker network connect kasm_sidecar_network kasm_proxy ``` ## Forensics and Geolocation Egress gateways can support forensic and location-sensitive workflows, but they are not a complete attribution solution by themselves. Key considerations: - VPN egress IP alone may not satisfy a full forensic profile. Browser locale, timezone, and profile-level settings can still expose mismatches. - Geolocation databases vary by provider and service. Different websites may report different locations for the same exit IP. - Shared commercial VPN IPs can trigger additional anti-abuse checks (for example, CAPTCHAs). For dedicated IP and managed attribution requirements, contact Kasm sales for an enterprise architecture review. --- ## Zero-trust Egress Overview Zero-trust providers in Kasm use identity and policy controls rather than launch-time gateway selection. ## What zero trust means In a zero-trust model, access is not granted simply because traffic is on a trusted network path. Each connection is evaluated against identity and policy, and only explicitly authorized services are reachable. For Kasm egress, this means administrators still map providers to users, groups, and workspaces in Kasm, while the zero-trust provider enforces service-level access policy. ## Benefits - Enforces least-privilege service access instead of broad network-level access. - Limits blast radius if credentials or a session are compromised. - Removes launch-time gateway and per-user VPN credential selection complexity. - Improves policy consistency and audit posture through centralized access rules. Currently supported providers: - [OpenZiti](./openziti/index.mdx) ## Model characteristics - Provider mappings are still managed in Kasm (users/groups/workspaces). - Access is determined by provider-side policy and identity. - No per-user gateway picker at launch. - No per-user VPN credential model in Kasm for this type. --- ## Zero-trust Egress: OpenZiti # OpenZiti OpenZiti is the first zero-trust egress provider supported in Kasm. Unlike gateway-based providers, OpenZiti grants access by identity and policy at the service layer, not by tunnel selection at workspace launch. ## How OpenZiti differs from gateway-based egress Gateway-based providers (OpenVPN, Wireguard, PureVPN) tunnel a session's whole network path through a chosen gateway, and the user picks which gateway at workspace launch. OpenZiti is structured differently: - **Service-level access, not network-path access.** Each session reaches specific named services, not the network behind a gateway. - **No launch-time gateway picker.** Which services a session can reach is decided by OpenZiti policy, evaluated against the session's identity. - **No per-user VPN credentials in Kasm.** Kasm automates the OpenZiti identity lifecycle (create, enroll, remove) for entitled users and workspaces. - **Per-connection authorization.** Every access decision is policy-evaluated against the requesting identity, which makes audit straightforward. ## Terminology The vocabulary you need before reading the rest of this page or the quickstart. - **Controller** — OpenZiti control plane for identities, services, and policies. - **Edge router** — data-plane component that carries authorized traffic in the OpenZiti fabric. - **Identity** — certificate-backed user, workload, or device identity used for authentication and authorization. - **Service** — a logical target (host:port) protected by OpenZiti policies. Reached by name from a session, not by IP. - **Dial** — permission for an identity to connect to a service. - **Bind** — permission for an identity to host (provide) a service. ## How it fits together An OpenZiti deployment has at minimum a controller and one edge router. Workloads hosting private services run alongside (or as) router tunnelers and Bind those services to the controller. Clients with dial-permitted identities reach those services by name; the router routes their traffic through the encrypted fabric. Kasm hooks in by holding an admin identity for one OpenZiti provider and using it to manage per-user and per-workspace identities under that controller. At session launch, the sidecar drops the right identity into the session namespace and starts a Ziti tunnel inside it. Whether that session can actually reach any given service is decided by OpenZiti policy — Kasm never overrides that. For the deeper architecture (multi-tenant networks, public/private router split, policy role design), see the [kziti architecture](./kziti.mdx) page. ## Constraints worth knowing about - Provider mapping is still done in Kasm (users, groups, workspaces). Kasm decides *who gets a managed identity*; OpenZiti decides *what each identity can reach*. - There is no per-user Egress Credential model for OpenZiti providers, and no launch-time gateway selector. - A Kasm mapping without matching OpenZiti policies gives the user an enrolled identity but no service access. - Identity reconciliation is asynchronous — mapping changes take effect after the next reconcile cycle, not instantly. ## Setup outline 1. Create an egress provider with type **OpenZiti**. 2. Configure the OpenZiti admin identity JSON on the provider. 3. Map the provider to users, groups, or workspaces. 4. Configure OpenZiti policies that allow Kasm-managed identities to access target services. 5. Launch a workspace and validate service reachability. For an evaluation lab on a single VM, see the [quickstart](./quickstart.mdx). For the Kasm-side internals, see the [integration deep dive](./kasm_integration_deep_dive.mdx). ## What Kasm does behind the scenes For each enabled OpenZiti provider, Kasm reconciles identities against entitled users and workspaces: 1. Discover entitled users and workspaces from provider mappings. 2. Create and enroll missing OpenZiti identities. 3. Store the identity JSON for launch-time use. 4. Remove identities that are no longer entitled. At workspace launch the sidecar: 1. Retrieves the managed identity JSON for the session. 2. Writes the identity files under `/var/run/kasm-sidecar/$container_namespace/ziti`. 3. Starts `ziti tunnel run --identity-dir ` in the session namespace. 4. Configures DNS so Ziti name resolution works inside the session, with upstream fallback for non-Ziti destinations. The [integration deep dive](./kasm_integration_deep_dive.mdx) covers the full identity lifecycle, naming conventions, and troubleshooting flow. --- ## OpenZiti Kasm Integration Deep Dive # Kasm Integration Deep Dive This page explains what Kasm is doing behind the scenes when OpenZiti egress is enabled. ## Integration overview Kasm OpenZiti support is based on a provider model: - An egress provider of type `OpenZiti` is configured in Kasm. - An OpenZiti admin identity is stored on that provider. - Kasm periodically reconciles entitled users/workspaces and manages OpenZiti identities. - At session launch, the sidecar injects identity files and starts `ziti tunnel run`. ## Identity lifecycle For each enabled OpenZiti provider: 1. Kasm identifies entitled users/workspaces from provider mappings. 2. Kasm creates missing OpenZiti identities and enrolls them. 3. Identity JSON is stored for launch-time use. 4. Identities no longer entitled are removed. Identity names are generated with Kasm metadata patterns such as: - `kasm-user---` - `kasm-workspace---` ## Session launch behavior At workspace start: 1. Sidecar receives script data for OpenZiti setup. 2. Sidecar writes user/workspace identity JSON under: `/var/run/kasm-sidecar/$container_namespace/ziti` 3. Sidecar starts: `ziti tunnel run --identity-dir ` 4. DNS behavior is updated so Ziti name resolution functions inside the session namespace. If tunnel startup fails, session startup reports an egress-related error and logs details for admin diagnostics. ## Configuration summary OpenZiti configuration in Kasm is done through: - **Infrastructure -> Egress -> Add** with provider type **OpenZiti**. - **OpenZiti Configuration** tab on that provider for admin identity JSON. - Mappings to users/groups/workspaces that should receive OpenZiti access. OpenZiti does not use per-user Egress Credentials or gateway selection in the same way as OpenVPN/Wireguard providers. ## Policy expectations Kasm mapping grants entitlement to participate in OpenZiti identity lifecycle, but effective service access still depends on OpenZiti policy. Typical requirements: - Service policy allowing managed identities to dial target services. - Edge-router policy allowing managed identities to use required routers. ## Troubleshooting and validation - Confirm provider type is `OpenZiti` and config is present. - Confirm identities are created in OpenZiti after mappings and reconciliation. - Confirm policy roles include expected Kasm-managed identity names. - Check logs: - `/var/log/kasm-sidecar/network_sidecar.log` - `/var/run/kasm-sidecar/$container_namespace/ziti.log` ## Related docs - [How OpenZiti differs from gateway-based egress](./index.mdx#how-openziti-differs-from-gateway-based-egress) - [OpenZiti Quickstart](./quickstart.mdx) - [Egress Overview](../../index.mdx) --- ## Add an HA Controller with kziti # Add an HA controller For production, run multiple controllers with Raft consensus. Three-node clusters are the common production minimum, with 2-of-3 quorum surviving a single host loss. After your single-controller deployment is healthy, follow the steps below for each additional controller you want to add. Additional requirements for adding an HA controller: - The new controller host needs `docker` and `docker compose` (same as the bootstrap host) **plus `7zip`** (`p7zip-full` on Debian/Ubuntu, `p7zip` on RHEL/Fedora) to extract the encrypted join package. - The new host does **not** need the `kziti` binary. The join package is self-contained and includes the installer. - You will be transferring two things to the new host: the encrypted join package, and the extraction password. These should travel through different channels. - The new controller needs its own DNS A record (e.g. `ziti2.example.com`) and its router needs one too (e.g. `ziti2-router.example.com`), with ports `1280/tcp`, `6262/tcp`, and `3022/tcp` open inbound. ## On the existing controller Generate a join package for the new controller: ```bash kziti deploy ha create-join-package \ --output /tmp/join.zip \ --node-name ziti-c-2 \ --controller-host ziti2.example.com \ --router-host ziti2-router.example.com \ --admin-password '' ``` Notes on the flags: - `--node-name` is the cluster member name. It must be unique within the cluster. - `--controller-host` and `--router-host` are the FQDNs of the **new** controller and its router — not the existing one. - Add `--controller-ip ` if the new controller's hostname does not resolve from inside the existing controller container. This injects an `extra_hosts` entry into a docker-compose override on the existing host so it can reach the new node by name during the join. `kziti` produces an **AES-encrypted zip** at the path you supplied with `--output`, and prints a randomly generated extraction password. Transfer the zip to the new host: ```bash scp /tmp/join.zip user@ziti2.example.com:/tmp/ ``` Send the extraction password through a **separate** secure channel — a password manager, an encrypted message, or similar. Do not put the password in the same email or the same chat as the zip. ## On the new controller host Install `7zip` if it is not already present: ```bash # Debian / Ubuntu apt-get install -y p7zip-full # RHEL / Fedora dnf install -y p7zip ``` Extract the encrypted package and run the bundled installer: ```bash 7z x -p /tmp/join.zip -o/tmp/kziti-join bash /tmp/kziti-join/install.sh ``` If the bootstrap controller's hostname does not resolve from this new host, add `--existing-controller-ip ` to the `install.sh` invocation so the new node can reach the bootstrap controller during join. The new controller starts as a non-voter, syncs Raft state from the existing cluster, and self-promotes to a voting member once it is caught up. ## Verify cluster health On any controller host, list cluster members: ```bash docker compose -f /opt/kziti/docker-compose.yml exec ziti-controller \ ziti agent cluster list ``` The new node should appear with `voter: true` once promotion completes (typically within a minute of join). --- ## kziti CLI Reference This page is auto-generated from the kziti CLI source. Run `kziti --help` for the same content interactively. To regenerate this page, run `python scripts/gen-cli-docs.py` in the kziti repo and copy the output to `docs/how-to/networking/egress/zero_trust/openziti/kziti-operations/cli-reference.mdx` in the docs project. ## Global options - `--version`, `-V` — Show version and exit. - `--verbose`, `-v` — Enable verbose/debug logging. - `--profile` — Use a specific profile for this command invocation. - `--output-format`, `-o` — Output format for list/show commands: table|json ## `kziti access` Manage identity access to networks, services, and service sets. **Usage:** ```bash kziti access COMMAND [ARGS]... ``` ### `kziti access grant` Grant an identity access to a network, service set, or individual service. This command adds the appropriate role attribute to the identity, allowing it to access the specified resource through existing Dial service policies. **Examples:** ```bash # Grant access to entire network kziti access grant user-123 net-corp-a # Grant access to service set kziti access grant user-123 svcset-devops # Grant access to individual service kziti access grant user-123 svc-corp-a-gitlab ``` **Usage:** ```bash kziti access grant [OPTIONS] IDENTITY_ID_OR_NAME RESOURCE_ID ``` **Arguments:** - `IDENTITY_ID_OR_NAME` *(required)* — Identity ID or name to grant access to - `RESOURCE_ID` *(required)* — Network ID (e.g., 'net-corp-a'), Service Set ID (e.g., 'svcset-devops'), or Service ID ### `kziti access list` List all access grants for an identity. Shows all networks, service sets, and services that the identity has access to based on its role attributes, displayed in a detailed table format. **Example:** ```bash kziti access list user-123 ``` **Usage:** ```bash kziti access list [OPTIONS] IDENTITY_ID_OR_NAME ``` **Arguments:** - `IDENTITY_ID_OR_NAME` *(required)* — Identity ID or name to list access for ### `kziti access remove` Remove an identity's access to a network, service set, or individual service. This command removes the appropriate role attribute from the identity, revoking its access to the specified resource. **Examples:** ```bash # Remove access to entire network kziti access remove user-123 net-corp-a # Remove access to service set kziti access remove user-123 svcset-devops # Remove access to individual service kziti access remove user-123 svc-corp-a-gitlab ``` **Usage:** ```bash kziti access remove [OPTIONS] IDENTITY_ID_OR_NAME RESOURCE_ID ``` **Arguments:** - `IDENTITY_ID_OR_NAME` *(required)* — Identity ID or name to revoke access from - `RESOURCE_ID` *(required)* — Network ID (e.g., 'net-corp-a'), Service Set ID (e.g., 'svcset-devops'), or Service ID **Options:** - `--yes`, `-y` — Skip confirmation prompt. ### `kziti access who` List all identities that have access to a network, service set, or service. **Examples:** ```bash kziti access who net-corp-a kziti access who svcset-devops kziti access who svc-corp-a-gitlab ``` **Usage:** ```bash kziti access who [OPTIONS] RESOURCE_ID ``` **Arguments:** - `RESOURCE_ID` *(required)* — Network ID (e.g., 'net-corp-a'), Service Set ID (e.g., 'svcset-devops'), or Service ID ## `kziti config` Manage kziti configuration. **Usage:** ```bash kziti config COMMAND [ARGS]... ``` ### `kziti config init` Interactive configuration setup wizard. **Usage:** ```bash kziti config init ``` ### `kziti config path` Show config file path. **Usage:** ```bash kziti config path ``` ### `kziti config profiles` Manage named configuration profiles. **Usage:** ```bash kziti config profiles COMMAND [ARGS]... ``` #### `kziti config profiles create` Create a new profile, optionally by cloning an existing profile. **Usage:** ```bash kziti config profiles create [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — New profile name **Options:** - `--from` — Copy configuration from an existing profile #### `kziti config profiles delete` Delete a profile. **Usage:** ```bash kziti config profiles delete [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Profile name to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt #### `kziti config profiles list` List configured profile names. **Usage:** ```bash kziti config profiles list ``` #### `kziti config profiles show` Show details for one profile. **Usage:** ```bash kziti config profiles show [OPTIONS] [NAME] ``` **Arguments:** - `NAME` — Profile name (defaults to selected profile) #### `kziti config profiles use` Set the active profile. **Usage:** ```bash kziti config profiles use [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Profile name to set active ### `kziti config set-ziti` Configure the Ziti connection for a profile. With --host / --user / --password, creates and enrolls a new admin identity (same as 'kziti config init'). Use --identity to point to an existing identity JSON file instead. **Examples:** ```bash kziti config set-ziti --host https://ziti.example.com:1280 --user admin --password secret kziti config set-ziti --identity /path/to/admin-kziti.json ``` **Usage:** ```bash kziti config set-ziti [OPTIONS] ``` **Options:** - `--host` — Ziti controller URL (e.g. https://ziti.example.com:1280) - `--user`, `-u` — Admin username - `--password`, `-p` — Admin password — creates and enrolls a new admin identity - `--identity-name` — Name for the new enrolled identity (default: `admin-kziti`) - `--identity`, `-i` — Path to an existing identity JSON file (skip enrollment) - `--profile` — Profile to update (defaults to selected profile) ### `kziti config show` Show current configuration. **Usage:** ```bash kziti config show ``` ## `kziti deploy` Deploy and manage the OpenZiti stack. **Usage:** ```bash kziti deploy COMMAND [ARGS]... ``` ### `kziti deploy ha` HA cluster operations. **Usage:** ```bash kziti deploy ha COMMAND [ARGS]... ``` #### `kziti deploy ha add-member` Tell the bootstrap controller to add a new member to the RAFT cluster. **Usage:** ```bash kziti deploy ha add-member [OPTIONS] ``` **Options:** - `--target` *(required)* — Target node, e.g. tls:ctrl2.example.com:1280 - `--install-dir` — Installation directory. (default: `/opt/kziti`) #### `kziti deploy ha create-join-package` Build an encrypted, self-contained HA join package for a new node. **Usage:** ```bash kziti deploy ha create-join-package [OPTIONS] ``` **Options:** - `--output`, `-o` *(required)* — Output zip path. - `--node-name` *(required)* — Unique cluster node name (e.g. 'ctrl2'). - `--controller-host` *(required)* — Joining controller FQDN. - `--controller-ip` — IP this bootstrap node should use to reach the joining controller's hostname. Required if --controller-host doesn't resolve from inside the bootstrap container (no shared DNS). Injected as a docker-compose.override.yml extra_hosts entry on THIS node. - `--controller-port` — Port the joining controller will bind and advertise. Defaults to the bootstrap's controller port. Set a different port (e.g. 1281) when both controllers run on the same machine. - `--router`, `--no-router` — Include an edge router (default: yes). - `--router-host` — Joining router FQDN (required if --router). - `--router-port` — Port the joining router will bind. Defaults to 3022. Set a different port (e.g. 3028) for same-machine deployments. (default: `3022`) - `--admin-user` — Admin username. (default: `admin`) - `--admin-password` *(required)* — Bootstrap controller admin password (to mint the router JWT). - `--install-dir` — Installation directory. (default: `/opt/kziti`) #### `kziti deploy ha recover` Recover a cluster that's lost quorum because a joining node went down without being removed from membership first. Spins up a short-lived ephemeral peer that impersonates the dead node to restore quorum, runs remove-member, then cleans up. Preserves all edge state (users, services, routers, policies). **Usage:** ```bash kziti deploy ha recover [OPTIONS] ``` **Options:** - `--node` *(required)* — Node ID of the dead member to remove (e.g. ctrl2) - `--install-dir` — Installation directory. (default: `/opt/kziti`) #### `kziti deploy ha remove-member` Remove a member from the RAFT cluster. Run on a remaining cluster node. **Usage:** ```bash kziti deploy ha remove-member [OPTIONS] ``` **Options:** - `--node` *(required)* — Node ID to remove, e.g. ctrl2 - `--install-dir` — Installation directory. (default: `/opt/kziti`) - `--yes`, `-y` — Skip confirmation prompt. ### `kziti deploy install` Install the OpenZiti stack. **Usage:** ```bash kziti deploy install [OPTIONS] ``` **Options:** - `--profile` — Deployment profile. (default: `standard`) - `--controller-host` — Controller FQDN. - `--controller-port` — Controller port. (default: `1280`) - `--router-host` — Router FQDN. - `--router-port` — Router port. (default: `3022`) - `--admin-password` — Admin password. - `--admin-user` — Admin username. (default: `admin`) - `--trust-domain` — SPIFFE trust domain. - `--node-name` — Cluster node name. - `--enrollment-token` — Router enrollment JWT. - `--join-package` — Path to HA join package zip. - `--install-dir` — Installation directory. (default: `/opt/kziti`) - `--project` — Compose project name (defaults to install-dir basename). Lets multiple stacks coexist on one host. - `--ziti-tag` — OpenZiti image tag. Defaults to the pinned v2 prerelease. Note: openziti/ziti-controller:latest currently points at 1.6.12, not v2 -- avoid unless you're testing v1 regression. (default: `2.0.0`) - `--enable-sni-proxy`, `--no-enable-sni-proxy` — Enable SNI routing proxy on port 443. - `--registry-prefix` — Private registry prefix. (default: ``) - `--registry-username` — Registry username. - `--registry-password` — Registry password. - `--yes`, `-y` — Skip confirmation prompt. - `--dry-run`, `--no-dry-run` — Show plan without installing. ### `kziti deploy render` Render deployment files without installing. **Usage:** ```bash kziti deploy render [OPTIONS] ``` **Options:** - `--profile` — Deployment profile. (default: `standard`) - `--controller-host` — Controller FQDN. - `--controller-port` — Controller port. (default: `1280`) - `--router-host` — Router FQDN. - `--router-port` — Router port. (default: `3022`) - `--admin-password` — Admin password. - `--admin-user` — Admin username. (default: `admin`) - `--trust-domain` — SPIFFE trust domain. - `--node-name` — Cluster node name. - `--enrollment-token` — Router enrollment JWT. - `--join-package` — Path to HA join package zip. - `--install-dir` — Installation directory. (default: `/opt/kziti`) - `--project` — Compose project name (defaults to install-dir basename). Lets multiple stacks coexist on one host. - `--ziti-tag` — OpenZiti image tag. Defaults to the pinned v2 prerelease. Note: openziti/ziti-controller:latest currently points at 1.6.12, not v2 -- avoid unless you're testing v1 regression. (default: `2.0.0`) - `--enable-sni-proxy`, `--no-enable-sni-proxy` — Enable SNI routing proxy on port 443. - `--registry-prefix` — Private registry prefix. (default: ``) - `--registry-username` — Registry username. - `--registry-password` — Registry password. - `--output-dir` — Write files to directory instead of stdout. ### `kziti deploy uninstall` Remove the OpenZiti stack. **Usage:** ```bash kziti deploy uninstall [OPTIONS] ``` **Options:** - `--install-dir` — Installation directory. (default: `/opt/kziti`) - `--remove-data`, `--no-remove-data` — Also remove volumes and data. - `--yes`, `-y` — Skip confirmation prompt. ## `kziti identity` Manage Ziti identities. **Usage:** ```bash kziti identity COMMAND [ARGS]... ``` ### `kziti identity create` Create a new identity and write an OTT enrollment token to a .jwt file. By default the enrollment token is saved to \.jwt in the current directory. Use --auto-enroll to immediately enroll the identity and save the resulting identity JSON file instead. Identities created via this command are tagged kasm_type=manual, which marks them as operator-managed and allows them to be deleted with 'identity delete'. **Usage:** ```bash kziti identity create [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Identity name **Options:** - `--email` — Email address to store as a tag - `--auto-enroll` — Automatically enroll the identity and save JSON file - `--output-dir` — Directory to write the enrollment token JWT (or identity JSON with --auto-enroll). Defaults to current directory. - `--admin` — Grant admin privileges to the identity ### `kziti identity delete` Delete a Ziti identity. Only identities created via 'kziti identity create' (tagged kasm_type=manual) can be deleted. Router identities, Kasm-managed user/workspace identities, and the default admin identity are all blocked. Deleting an identity revokes all of its access grants and invalidates any active sessions. **Usage:** ```bash kziti identity delete [OPTIONS] IDENTITY_ID_OR_NAME ``` **Arguments:** - `IDENTITY_ID_OR_NAME` *(required)* — Identity ID or name to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt. ### `kziti identity list` List all Ziti identities. **Usage:** ```bash kziti identity list [OPTIONS] ``` **Options:** - `--limit`, `-l` — Max items to return (default: `100`) - `--type` — Filter by identity type: user|workspace ### `kziti identity search` Search identities by filter expression. **Usage:** ```bash kziti identity search [OPTIONS] QUERY ``` **Arguments:** - `QUERY` *(required)* — Search query (e.g. "name contains 'user'") ### `kziti identity show` Show details for a specific identity. **Usage:** ```bash kziti identity show [OPTIONS] IDENTITY_ID ``` **Arguments:** - `IDENTITY_ID` *(required)* — Identity ID ## `kziti network` Manage ZTNA networks. **Usage:** ```bash kziti network COMMAND [ARGS]... ``` ### `kziti network create` Create a new ZTNA network. **Usage:** ```bash kziti network create [OPTIONS] NETWORK_ID NAME ``` **Arguments:** - `NETWORK_ID` *(required)* — Network ID (e.g., 'net-corp-a' or 'corp-a') - `NAME` *(required)* — Network display name (e.g., 'Corp A') ### `kziti network delete` Delete a ZTNA network. **Usage:** ```bash kziti network delete [OPTIONS] NETWORK_ID ``` **Arguments:** - `NETWORK_ID` *(required)* — Network ID to delete (e.g., 'net-corp-a') **Options:** - `--yes`, `-y` — Skip confirmation prompt ### `kziti network list` List all ZTNA networks. **Usage:** ```bash kziti network list ``` ### `kziti network rename` Rename an existing ZTNA network. **Usage:** ```bash kziti network rename [OPTIONS] NETWORK_ID NEW_NAME ``` **Arguments:** - `NETWORK_ID` *(required)* — Network ID to rename (e.g., 'net-corp-a') - `NEW_NAME` *(required)* — New network display name ## `kziti router` Manage edge routers. **Usage:** ```bash kziti router COMMAND [ARGS]... ``` ### `kziti router dmz` Manage DMZ routers. **Usage:** ```bash kziti router dmz COMMAND [ARGS]... ``` #### `kziti router dmz delete` Delete a DMZ router. **Usage:** ```bash kziti router dmz delete [OPTIONS] ROUTER_ID ``` **Arguments:** - `ROUTER_ID` *(required)* — Router ID to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt #### `kziti router dmz list` List all DMZ routers. **Usage:** ```bash kziti router dmz list [OPTIONS] ``` **Options:** - `--limit`, `-l` — Max items to return (default: `100`) #### `kziti router dmz provision` Provision a new DMZ router. **Usage:** ```bash kziti router dmz provision [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Router name **Options:** - `--tunneler`, `--no-tunneler` — Enable tunneler mode (default: enabled) - `--cost` — Router cost for path selection - `--output-dir`, `-d` — Directory to write JWT file (default: current directory) (default: `.`) ### `kziti router list` List all Ziti edge routers. **Usage:** ```bash kziti router list [OPTIONS] ``` **Options:** - `--limit`, `-l` — Max items to return (default: `100`) ### `kziti router private` Manage private routers. **Usage:** ```bash kziti router private COMMAND [ARGS]... ``` #### `kziti router private delete` Delete a private router. **Usage:** ```bash kziti router private delete [OPTIONS] ROUTER_NAME_OR_ID ``` **Arguments:** - `ROUTER_NAME_OR_ID` *(required)* — Router name or ID to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt #### `kziti router private list` List all private routers. **Usage:** ```bash kziti router private list [OPTIONS] ``` **Options:** - `--network`, `-n` — Filter by network ID - `--limit`, `-l` — Max items to return (default: `100`) #### `kziti router private provision` Provision a new private router for a network. **Usage:** ```bash kziti router private provision [OPTIONS] NETWORK_ID NAME ``` **Arguments:** - `NETWORK_ID` *(required)* — Network ID (e.g., 'net-corp-a' or 'corp-a') - `NAME` *(required)* — Router name **Options:** - `--tunneler`, `--no-tunneler` — Enable tunneler mode (default: enabled) - `--cost` — Router cost for path selection - `--output-dir`, `-d` — Directory to write JWT file (default: current directory) (default: `.`) ### `kziti router show` Show details for a specific edge router. **Usage:** ```bash kziti router show [OPTIONS] ROUTER_ID ``` **Arguments:** - `ROUTER_ID` *(required)* — Edge router ID ## `kziti service` Manage Ziti services. **Usage:** ```bash kziti service COMMAND [ARGS]... ``` ### `kziti service create` Create a new service. **Examples:** ```bash kziti service create corp-a gitlab gitlab.corp-a.internal 443 --alias gitlab.corp-a.zt kziti service create corp-a ssh-bastion 10.10.5.25 22 --alias ssh.corp-a.zt kziti service create corp-a web-app webapp.local 80,443 --alias web.corp-a.zt --service-set devops kziti service create corp-a wiki wiki.corp-a.internal 443 --alias wiki.corp-a.zt --service-set devops --service-set infra ``` **Usage:** ```bash kziti service create [OPTIONS] NETWORK_ID NAME DESTINATION PORTS ``` **Arguments:** - `NETWORK_ID` *(required)* — Network ID (e.g., 'net-corp-a' or 'corp-a') - `NAME` *(required)* — Service name - `DESTINATION` *(required)* — Destination DNS name or IP address - `PORTS` *(required)* — Port specification (e.g., '443', '80,443', '8000-8100') **Options:** - `--alias` *(required)* — Alias DNS name used as the intercept address (must differ from destination). - `--service-set`, `-g` — Service set name (repeatable: --service-set devops --service-set infra) ### `kziti service delete` Delete a service and its associated configs. **Usage:** ```bash kziti service delete [OPTIONS] SERVICE_ID ``` **Arguments:** - `SERVICE_ID` *(required)* — Service ID or svc-\ to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt ### `kziti service list` List all services or services for a specific network. **Usage:** ```bash kziti service list [OPTIONS] ``` **Options:** - `--network`, `-n` — Filter by network ID - `--limit`, `-l` — Max items to return (default: `100`) ### `kziti service search` Search services by filter expression. **Examples:** ```bash kziti service search 'name contains "gitlab"' kziti service search 'name = "corp-a-web"' ``` **Usage:** ```bash kziti service search [OPTIONS] QUERY ``` **Arguments:** - `QUERY` *(required)* — Filter expression (e.g. 'name contains "gitlab"') ### `kziti service show` Show details for a specific service. **Usage:** ```bash kziti service show [OPTIONS] SERVICE_ID ``` **Arguments:** - `SERVICE_ID` *(required)* — Service ID ### `kziti service update` Rename a service. Note: Updating destination, ports, or alias is not yet supported. **Usage:** ```bash kziti service update [OPTIONS] SERVICE_ID ``` **Arguments:** - `SERVICE_ID` *(required)* — Service ID to update **Options:** - `--name` — New service name ## `kziti service-set` Manage service sets (global, cross-network groupings of services). **Usage:** ```bash kziti service-set COMMAND [ARGS]... ``` ### `kziti service-set add` Add an existing service to a service set. **Example:** ```bash kziti service-set add devops svc-corp-a-wiki kziti service-set add devops ``` **Usage:** ```bash kziti service-set add [OPTIONS] NAME SERVICE_REF ``` **Arguments:** - `NAME` *(required)* — Service set name (e.g. 'devops') - `SERVICE_REF` *(required)* — Service UUID or svc-\ ### `kziti service-set create` Create a global service set. Service sets are cross-network groupings — services from any network can belong to the same set. An identity granted access to a set gets Dial access to all services in it, regardless of which network hosts them. **Example:** ```bash kziti service-set create devops "DevOps Services" kziti service create corp-a gitlab gitlab.internal 443 --alias gitlab.corp-a.zt --service-set devops kziti service create corp-b wiki wiki.internal 443 --alias wiki.corp-b.zt --service-set devops kziti access grant user-123 svcset-devops ``` **Usage:** ```bash kziti service-set create [OPTIONS] NAME [DISPLAY_NAME] ``` **Arguments:** - `NAME` *(required)* — Service set name (e.g. 'devops') - `DISPLAY_NAME` — Optional human-readable label ### `kziti service-set delete` Delete a global service set. **Usage:** ```bash kziti service-set delete [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Service set name to delete **Options:** - `--yes`, `-y` — Skip confirmation prompt ### `kziti service-set list` List all global service sets. **Usage:** ```bash kziti service-set list ``` ### `kziti service-set remove` Remove an existing service from a service set. **Example:** ```bash kziti service-set remove devops svc-corp-a-wiki kziti service-set remove devops ``` **Usage:** ```bash kziti service-set remove [OPTIONS] NAME SERVICE_REF ``` **Arguments:** - `NAME` *(required)* — Service set name (e.g. 'devops') - `SERVICE_REF` *(required)* — Service UUID or svc-\ ### `kziti service-set show` Show details and member services for a service set. **Usage:** ```bash kziti service-set show [OPTIONS] NAME ``` **Arguments:** - `NAME` *(required)* — Service set name ## `kziti status` Show connection status for the OpenZiti controller. **Usage:** ```bash kziti status ``` ## `kziti ziti` OpenZiti management commands. **Usage:** ```bash kziti ziti COMMAND [ARGS]... ``` ### `kziti ziti audit` Audit the live Ziti configuration for policy misconfigurations. Checks for issues that cause routing loops, privilege escalation, or broken connectivity — including the ouroboros circuit-cycle bug, overly broad Bind policies, router identities with Dial access, and host/intercept address overlap. Exits 0 when the configuration is clean, 1 when any ERROR is found. **Usage:** ```bash kziti ziti audit ``` --- ## Configure kziti Before running any operational command, `kziti` needs to know how to reach your OpenZiti controller. This page explains the configuration model and covers the commands for setting it up. ## What a profile is A **profile** is a named set of credentials that `kziti` uses to authenticate against one OpenZiti controller. Every profile contains: - A path to an enrolled **identity JSON file** (the standard way), or - A raw **management API URL + cert/key pair** (for environments where a pre-existing PKI manages the controller credential). All operational commands (`network`, `service`, `access`, `router`, …) read from the active profile. Switching profiles switches the target controller entirely — there is no mixing of credentials within a single command. One profile exists by default and is named `default`. Most operators running a single controller never need more than one. ## First-time setup The interactive wizard creates a new admin identity, enrolls it against the controller, and stores the resulting JSON file automatically: ```bash kziti config init ``` It prompts for the controller URL, admin credentials, and an identity name, then writes a config file at `~/.config/kziti/config.toml`. For scripted or CI environments, use `config set-ziti` directly: ```bash kziti config set-ziti \ --host https://ziti.example.com:1280 \ --user admin \ --password '' ``` This runs the same enrollment flow non-interactively and updates the active profile. To point a profile at an existing identity file instead: ```bash kziti config set-ziti --identity /path/to/existing-identity.json ``` Verify the connection: ```bash kziti status ``` ## Multiple profiles Use separate profiles when you have more than one controller — staging and production, multiple customer deployments, or a primary and DR controller. ### Create a profile for a second controller ```bash # Create a blank profile kziti config profiles create staging # Enroll a new identity against the staging controller into that profile kziti config set-ziti \ --profile staging \ --host https://ziti-staging.example.com:1280 \ --user admin \ --password '' ``` ### Switch the active profile All commands run against whichever profile is currently active: ```bash kziti config profiles use staging kziti network list # now talks to the staging controller kziti config profiles use default kziti network list # back to production ``` ### Use a profile for a single command The global `--profile` flag overrides the active profile for one invocation without changing the persisted setting: ```bash kziti --profile staging service list kziti --profile staging access grant alice@example.com net-demo ``` This is useful in scripts where the caller controls which environment a command targets. ### Clone a profile To create a staging profile that starts from the same settings as production: ```bash kziti config profiles create staging --from default # Then update just the Ziti credentials kziti config set-ziti --profile staging --host https://ziti-staging.example.com:1280 ... ``` ## View current configuration ```bash kziti config show ``` Shows all profiles, which is active, and the connection settings for each (secrets redacted). For a single profile: ```bash kziti config profiles show staging ``` ## Profile commands reference | Command | What it does | |---------|-------------| | `kziti config init` | Interactive wizard — prompts for controller URL, credentials, and identity name | | `kziti config set-ziti --host … --user … --password …` | Non-interactive enrollment — creates and enrolls a new admin identity | | `kziti config set-ziti --identity /path/to/file.json` | Point a profile at an existing identity JSON file | | `kziti config show` | Show all profiles and their settings | | `kziti config path` | Print the config file path | | `kziti config profiles list` | List profile names and indicate which is active | | `kziti config profiles create ` | Create a new empty profile | | `kziti config profiles create --from ` | Clone an existing profile | | `kziti config profiles use ` | Set the persistent active profile | | `kziti config profiles show ` | Show settings for one profile | | `kziti config profiles delete ` | Delete a profile (cannot delete the last one) | ## Config file location The config file lives at `~/.config/kziti/config.toml` by default, respecting `XDG_CONFIG_HOME` when set. When running under `sudo`, `kziti` resolves the path against the invoking user's home so that deploy commands (which require root) and operational commands (which do not) see the same config. Enrolled identity JSON files are stored under `~/.config/kziti/identities//`. --- ## Grant Access with kziti # Grant access with kziti For the underlying model see [kziti architecture](../kziti.mdx). ## Find the identity If you know the identity name (a Kasm user email, a workspace name, or an external user identifier), you can use that directly. To browse: ```bash kziti identity list ``` To search by substring or attribute: ```bash kziti identity search 'name contains "alice"' ``` Kasm-managed identities have predictable names like `kasm-user---` and `kasm-workspace---`. ## Three scopes of access `kziti access grant` accepts three kinds of resource ID, in order of decreasing breadth: - **A network ID** (e.g. `net-corp-a`) — the identity gains access to every service in the network. - **A service set ID** (e.g. `svcset-devops`) — access to every service in the named set. - **A service ID** (e.g. `svc-corp-a-gitlab`) — access to a single service only. Pick the narrowest scope that satisfies the requirement. Service-set grants are the common middle ground for groups of users who need access to a coherent set of services. ## Grant access ### To an entire network ```bash kziti access grant alice@example.com net-corp-a ``` ### To a service set ```bash kziti access grant alice@example.com svcset-devops ``` ### To a single service ```bash kziti access grant alice@example.com svc-corp-a-gitlab ``` Adds the resource ID as a role attribute on the identity. Effective immediately for new sessions; existing tunnels may need to reconnect. ## List grants for an identity ```bash kziti access list alice@example.com ``` The output shows each access role attribute the identity holds (`net-*`, `svcset-*`, or `svc-*`), with a human-readable description of what it covers. ## Who has access to a resource The inverse of `access list` — given a resource, show every identity that can reach it: ```bash # All identities with access to the corp-a network kziti access who net-corp-a # All identities with access to a service set kziti access who svcset-devops # All identities with access to a single service kziti access who svc-corp-a-gitlab ``` Accepts the same resource IDs as `grant` and `remove`. For each matching identity the output shows the name, type (Kasm user, workspace, or external), and whether it currently has an active session. Use `-o json` (the global `--output-format` flag) for machine-readable output. ## Revoke access Use the same scope you used to grant: ```bash kziti access remove alice@example.com svcset-devops ``` `remove` strips the role attribute immediately for new dial attempts; existing tunnels are not torn down. To terminate live sessions for a compromised identity, revoke the workspace mapping in Kasm to remove the identity entirely. --- ## Operations with kziti These how-to guides cover the day-to-day administration of a `kziti`-managed OpenZiti deployment. They assume you already have a working [kziti](../kziti.mdx) deployment and have configured Kasm Workspaces to use OpenZiti as an [egress provider](../index.mdx). If you have not yet read the [kziti architecture](../kziti.mdx) page, the mental model there will make these pages easier to follow. ## What's in this section - [Configure kziti](./configure-profiles.mdx) — set up `kziti` to talk to your controller, and manage named profiles for multiple environments. - [Manage networks](./manage-networks.mdx) — create, list, and delete the private networks that group services together, and provision the private routers that host those services. - [Publish services](./publish-services.mdx) — define services that Kasm sessions and external clients can dial through OpenZiti, and group them into service sets. - [Grant access](./grant-access.mdx) — give a Kasm user, workspace, or external identity access to a network, service set, or individual service. - [Recover from quorum loss](./recover-quorum.mdx) — restore an HA cluster after a controller has gone down without being cleanly removed. - [Remove an HA controller](./remove-ha-controller.mdx) — cleanly remove a controller from the Raft cluster. - [Tear down a deployment](./teardown.mdx) — uninstall `kziti` from a host, with or without removing persistent data. - [kziti CLI Reference](./cli-reference.mdx) — auto-generated reference for every command, subcommand, argument, and flag. ## When to reach for raw OpenZiti instead `kziti` covers the operational shape described in the [kziti architecture](../kziti.mdx). For inspections that fall outside the kziti command surface (raw policy bodies, controller diagnostics, ZAC visualisation, and so on), the OpenZiti CLI and project tooling remain available — `kziti` does not hide them from you. See the architecture page for the boundary between kziti's scope and raw OpenZiti's domain. --- ## Manage Networks with kziti # Manage networks with kziti A **network** in `kziti` is a logical grouping of services — typically one customer, team, or environment. Each network gets one or more **private routers** that host its services and connect outbound to the public routers in the existing kziti deployment. This guide covers creating networks, provisioning their private routers, and removing them. ## List existing networks ```bash kziti network list ``` ## Create a new network Creating a network is a control-plane record only — infrastructure comes from the private router (next section). ```bash kziti network create net-corp-a "Corp A" ``` The first argument is the **network ID** — the `net-` prefix is the convention used in role attributes and access grants (e.g. the network `net-corp-a` is granted via `kziti access grant alice@example.com net-corp-a`). The short form without the prefix (`corp-a`) also works and is normalised automatically. Keep the name short and lowercase. The second argument is a human-readable display name. ## Provision a private router for the network ### Step 1. Create the router record on the controller On the controller host: ```bash kziti router private provision net-corp-a corp-a-router-1 --output-dir /tmp ``` This creates an OpenZiti router identity tagged for the network and writes a router enrollment JWT to `/tmp/corp-a-router-1.jwt`. `--tunneler` is enabled by default (router hosts services). Use `--no-tunneler` only if running a separate hosting identity. Transfer the JWT to the host that will run the router: ```bash scp /tmp/corp-a-router-1.jwt user@router-host.corp-a.example.com:/tmp/ ``` ### Step 2. Install kziti and start the router on the new host On the host where the private router will run, install the `kziti` binary as in [the quickstart](../quickstart.mdx#step-1-install-kziti), then start it as a router: ```bash kziti deploy install --profile router \ --router-host router-host.corp-a.example.com \ --enrollment-token "$(cat /tmp/corp-a-router-1.jwt)" ``` The router enrolls with the controller using the JWT and starts hosting traffic for the network. ### Step 3. Verify On the controller host: ```bash kziti router list ``` The new router should appear with status `online` and the network attribute set. ## Rename a network ```bash kziti network rename net-corp-a "Corp A (renamed)" ``` The network ID does not change — only the display name. ## Delete a network Deleting a network removes its services, role attributes, and policies from the controller. Identities lose access to anything previously scoped to the network. Make sure no Kasm sessions depend on the network's services before deleting. ```bash kziti network delete net-corp-a ``` After deletion, tear down any private routers that were specific to the network using [Tear down a deployment](./teardown.mdx). --- ## Publish Services with kziti # Publish services with kziti ## Create a service ```bash kziti service create net-corp-a gitlab gitlab.corp-a.internal 443 \ --alias gitlab.corp-a.zt ``` Arguments, in order: - **Network ID** — the network this service belongs to (`net-corp-a`). The short form without the prefix (`corp-a`) also works. - **Service name** — the short name (`gitlab`). - **Destination** — the real DNS name or IP the private router will reach (`gitlab.corp-a.internal`). - **Ports** — single port (`443`), comma-separated list (`80,443`), or range (`8000-8100`). `--alias` is required and sets the **intercept address** — the hostname clients dial inside the Ziti tunnel. It must differ from the destination and does not need a real DNS entry; the Ziti tunnel resolves it locally. ## Service sets A **service set** groups related services. Grant access to the set once; add or remove services without touching user grants. Service sets are global — they can span multiple networks. ### Create a service set The set must exist before you can assign services to it: ```bash kziti service-set create devops "DevOps Services" ``` The role attribute `svcset-devops` is created and registered. Pass `--service-set` when creating services. The flag is repeatable — a service can belong to multiple sets: ```bash kziti service create net-corp-a gitlab gitlab.corp-a.internal 443 \ --alias gitlab.corp-a.zt --service-set devops kziti service create net-corp-a jira jira.corp-a.internal 443 \ --alias jira.corp-a.zt --service-set devops kziti service create net-corp-b wiki wiki.corp-b.internal 443 \ --alias wiki.corp-b.zt --service-set devops --service-set infra ``` The three services share the `svcset-devops` role attribute. A single `access grant` against `svcset-devops` gives an identity Dial access to all three, regardless of which network hosts them. ### List service sets ```bash kziti service-set list ``` ### Show a service set and its members ```bash kziti service-set show devops ``` Lists the set's metadata and every service currently in the set, with network and destination details. The **ID** column shows the `svc-` reference you pass to `add` and `remove`. ### Add an existing service to a set ```bash kziti service-set add devops svc-corp-a-gitlab ``` The argument is either the `svc-` shown by `service-set show` and `service list`, or the full service UUID. The short ID is `svc--` — for a service named `gitlab` in network `corp-a` it is `svc-corp-a-gitlab`. Both the service's role attributes and its dial policy are updated atomically. A service can belong to any number of sets. ### Remove a service from a set ```bash kziti service-set remove devops svc-corp-a-gitlab ``` Strips `svcset-devops` from the service's role attributes and from its dial policy. Membership in other sets, the network role, and any individually granted access are not affected. ### Delete a service set ```bash kziti service-set delete devops ``` Deletion is blocked if any services still carry the set's role attribute. Remove them from the set first, or delete the services. Deleting the set does not affect the services themselves. ## List services ```bash # All services across all networks kziti service list # Just the services in one network kziti service list --network corp-a ``` ## Search services ```bash kziti service search 'name contains "gitlab"' kziti service search 'name = "corp-a-web"' ``` Returns the same columns as `service list` (ID, name, network, destination, available-at). Use filter expressions supported by the [OpenZiti filter syntax](https://openziti.io/docs/reference/api/filtering) — `contains`, `=`, `startswith`, and boolean operators. ## Show service details ```bash kziti service show ``` The output includes the intercept config, host config, and any service-set membership. ## Rename a service ```bash kziti service update --name new-name ``` `update` only supports renaming. To change the destination, ports, or alias, delete and recreate the service. To change service-set membership, use `service-set add` and `service-set remove`. ## Delete a service ```bash kziti service delete ``` Deletion removes the service and its intercept and host configs. Identities that had access via the service ID lose it; identities scoped via the network or service set retain access to the remaining services. --- ## Recover from Quorum Loss with kziti # Recover from quorum loss When a Raft cluster loses too many members to maintain quorum (more than half the configured members are unreachable), the controllers that remain become read-only — the cluster cannot make decisions. This typically happens when an HA controller goes down hard before it can be cleanly removed from membership: hardware failure, terminated VM, network partition that does not heal. `kziti deploy ha recover` is the rescue path. It spins up a short-lived ephemeral peer that impersonates the dead member to restore quorum, runs the `remove-member` step, then cleans up. Edge state — users, services, routers, policies — is preserved. This procedure is for recovering from a node that is permanently gone or not coming back. If the missing node is just temporarily unreachable (network blip, host restart, planned maintenance), wait for it to return rather than running recovery. Removing a node that later rejoins creates split-brain risk. - You have a working [kziti](../kziti.mdx) deployment. - At least one controller in the cluster is still reachable; you will run the recovery command on that host. - You know the **node name** of the dead member (the value of `--node-name` from when it was originally added). ## Confirm quorum is lost On a surviving controller host, list cluster members: ```bash docker compose -f /opt/kziti/docker-compose.yml exec ziti-controller \ ziti agent cluster list ``` Quorum is lost if the dead member appears as `voter: true` and the cluster is unable to elect a leader. Pure read access (listing identities, services) typically still works; mutating commands fail with timeouts or quorum errors. ## Run recovery On a surviving controller host: ```bash kziti deploy ha recover --node ziti-c-2 ``` `--node` is the dead member's node name. The command performs the following steps: 1. Reads cluster state to confirm `ziti-c-2` is still a member. 2. Starts an ephemeral peer container with the same node identity, joining as a non-voter. 3. The cluster regains quorum once the ephemeral peer is connected. 4. `remove-member ziti-c-2` runs against the cluster leader. 5. The ephemeral peer is torn down. This typically completes in under a minute. ## Verify ```bash docker compose -f /opt/kziti/docker-compose.yml exec ziti-controller \ ziti agent cluster list ``` The dead node should be gone from the member list. The cluster should report a healthy leader and the remaining controllers should all be voters. Try a mutating operation to confirm write quorum is restored (read-only commands still work even when quorum is lost, so they do not prove recovery): ```bash kziti network create quorum-test "Quorum Test" && \ kziti network delete quorum-test --yes ``` If both commands complete without error, the cluster is accepting writes and is back to normal operation. ## After recovery Quorum is restored, but you are now running with one fewer controller than your target. To restore the original HA topology, [add a new HA controller](./add-ha-controller.mdx) on a fresh host (or on the recovered host if you have repaired it). --- ## Remove an HA Controller with kziti # Remove an HA controller Use this procedure when a controller is **healthy and you want to remove it cleanly** — host decommissioning, scaling down, or moving the cluster to different infrastructure. The controller is removed from Raft membership without losing quorum, and the docker compose stack on the host is then torn down. If the controller is already dead and quorum is lost, use [Recover from quorum loss](./recover-quorum.mdx) instead. - The controller you are removing is healthy and reachable. - The remaining controllers can maintain quorum without it (more than half of the surviving members must be voters). - You will need shell access on a remaining controller host and on the host being removed. ## Step 1. Remove the member from Raft On a remaining controller host, remove the target member from Raft membership: ```bash kziti deploy ha remove-member --node ziti-c-2 ``` `--node` is the node name of the controller being removed. The command tells the cluster leader to remove the target from membership; the target controller is no longer authoritative for any cluster state once this returns. Verify it has been removed: ```bash docker compose -f /opt/kziti/docker-compose.yml exec ziti-controller \ ziti agent cluster list ``` The removed node should no longer appear in the list. Remaining controllers should still report a healthy leader. ## Step 2. Tear down the removed host On the host that was removed, stop and uninstall the kziti stack: ```bash kziti deploy uninstall --remove-data --yes ``` This stops all containers, removes the docker compose project, and deletes the `/opt/kziti` data directory. The host no longer participates in the cluster in any way. If you intend to redeploy the same host as a fresh HA controller, you can omit `--remove-data` to retain the old data directory for inspection — but for a planned removal followed by a fresh install, removing data is the safer default. --- ## Tear Down a kziti Deployment # Tear down a kziti deployment Use this procedure when you want to stop and remove a `kziti`-managed OpenZiti deployment from a host entirely. This applies to single-controller setups, individual HA members, and standalone private router hosts. For removing a single HA controller while keeping the cluster running, see [Remove an HA controller](./remove-ha-controller.mdx) instead — you should run `remove-member` first, then teardown. ` --remove-data ` is destructive. It deletes the persistent OpenZiti state on the host (controller database, router certificates, identity material). Make sure you have any backups or exports you need before running with this flag. ## Stop the stack only To stop containers and remove the docker compose project, but keep the data directory in place: ```bash kziti deploy uninstall --yes ``` This is appropriate when you are reinstalling on the same host and want to preserve state, or when you are inspecting state offline. The data directory at `/opt/kziti/data` (or `/data` if you used a non-default `--install-dir`) is left intact. ## Stop and wipe To also remove the persistent data: ```bash kziti deploy uninstall --remove-data --yes ``` This stops all containers, removes the docker compose project, and deletes the data directory. The host is left clean — only the `kziti` binary remains on `PATH`. To remove the binary as well: ```bash sudo rm /usr/local/bin/kziti ``` --- ## kziti `kziti` is a CLI tool for deploying and operating an OpenZiti environment for Kasm Workspaces. This page explains the architecture that `kziti` deploys on your behalf, the deployment shape, and what stays in raw OpenZiti's domain. For setup, see the [quickstart](./quickstart.mdx). Administrators grant access to specific named services rather than to network ranges, and connectivity is brokered through identity-bound routers. The OpenZiti primitives (controllers, routers, identities, policies) are the building blocks. The grouping (public versus private routers, networks, service sets) is what `kziti` layers on top. For large or complex networks you may want to consider NetFoundry's official OpenZiti SAAS offering. ## kziti Deployment Shape `kziti` is an opinionated deployment: - **Public routers are pure transit.** They accept client connections at the edge and route fabric traffic. They do not host services. - **Private routers run alongside the resources they expose.** Outbound-only to the controller and public routers — no inbound firewall rules required at the resource site. - **Networks are the unit of grouping.** All resources for one team, customer, or environment live under one logical network. Access is granted at network, service-set, or individual-service granularity. - **Identity types are explicit.** Kasm users, Kasm workspaces, and external users are distinct types. ## The shape of a deployment ```mermaid flowchart TD Internet([Internet]) subgraph DMZ["Public edge — kziti-managed"] DMZUS[Public router — region 1] DMZEU[Public router — region 2] Controller[(OpenZiti HA Controller)] end subgraph CorpA["Network: corp-a"] PrivA[Private router] SvcA1[gitlab] SvcA2[jira] PrivA -.- SvcA1 PrivA -.- SvcA2 end subgraph CorpB["Network: corp-b"] PrivB[Private router] SvcB1[db-prod] PrivB -.- SvcB1 end Internet --> DMZUS Internet --> DMZEU DMZUS <==> Controller DMZEU <==> Controller PrivA -- outbound only --> Controller PrivA -- outbound only --> DMZUS PrivB -- outbound only --> Controller PrivB -- outbound only --> DMZEU ``` A deployment has three kinds of OpenZiti component: - **Controller(s)**: the control plane. Holds identities, services, and policies. Run with Raft consensus when you need high availability. - **Public routers**: the data plane at the edge. Public-facing listeners on a known port. Clients (Kasm sessions, external devices running the OpenZiti edge tunnel) connect here. - **Private routers**: the data plane next to your resources. Each private router is bound to a single network and makes only outbound connections. Two kinds of host connect on the Kasm side: - **Kasm sessions**: dial services from inside their session container, using a Ziti tunnel that the egress sidecar manages. - **External clients**: (optional) run the OpenZiti edge tunnel on a laptop or other device. They dial the same services from anywhere, with the same access controls. ## Tagging: how networks, services, and access are joined OpenZiti uses **role attributes** as the join key between identities, services, and policies. `kziti` assigns role attributes consistently so that policies stay declarative. Adding or revoking access changes attributes, not policy bodies. ### Router attributes In OpenZiti a private router is two distinct objects: the **edge router record** (the control-plane entry) and the **tunneler identity** (the SDK identity the router uses to connect outbound as a connector). `kziti` assigns different attributes to each, because SERPs reference router record attributes and ERPs reference identity attributes. **Edge router record** `roleAttributes`: - `#role-dmz`: public router (pure transit, no tunneler identity). - `#role-private`: private router. - `#net-corp-a`: marks this router as belonging to the corp-a network. Referenced by the per-network SERP to restrict which routers can carry corp-a service traffic. **Tunneler identity** `roleAttributes` (private routers only): - `#role-private`: mirrors the router record. - `#connector-corp-a`: the hosting (Bind) role for the corp-a network. Referenced by two per-network policies: the ERP `erp-corp-a-connectors` (grants the connector identity access to `#net-corp-a` private routers, which it needs in order to host) and the Bind service policy `sp-bind-corp-a` (authorizes it to host `#net-corp-a` services). Scoped per-network so a router enrolled in corp-b cannot host corp-a services. ### Service attributes - `#net-corp-a`: every service in the corp-a network. - `#svcset-devops`: a *service set* (a named, globally-scoped group of services that can span multiple networks). Service sets are not a first-class OpenZiti object; they are a shared attribute applied to the services in the group. - `#svc-corp-a-gitlab`: the individual service attribute. ### Client identity attributes Client identities (Kasm users, workspace images, external tunnel users) carry access attributes. The attribute name is the resource ID: - `#net-corp-a`: grants access to every service in the corp-a network. - `#svcset-devops`: grants access to every service carrying that service-set attribute. - `#svc-corp-a-gitlab`: grants access to a single service. To grant or revoke access, `kziti` adds or removes the corresponding resource attribute on the relevant identity. ## Identity types `kziti` distinguishes three identity types by metadata. You will see all three in the controller after `kziti` has reconciled an entitlement: - **Kasm user identity**: created when an entitled Kasm user is mapped to an OpenZiti egress provider. Used when that user accesses services through a Kasm session. - **Kasm workspace identity**: created when a workspace, rather than a user, is the unit of entitlement. Useful when a workspace image needs access regardless of which user launches it. - **External user identity**: for users running the OpenZiti edge tunnel on their own device, outside Kasm. The same access controls apply; only the launch context differs. All three types use the same role attribute scheme (`#net-*`, `#svcset-*`, `#svc-*`). They differ in how they are issued and where they are presented to the OpenZiti controller. ## The three policy axes OpenZiti has three independent policy types. **All three must permit traffic** before it flows. `kziti` generates and maintains these for you, but understanding the three axes helps you reason about why a connection succeeded or failed. | Axis | Question it answers | |---|---| | **Edge router policy (ERP)** | Which identities are allowed to use which routers to connect? | | **Service edge router policy (SERP)** | Which routers are allowed to carry traffic for which services? | | **Service policy (Dial / Bind)** | Which identities can connect to (Dial) or host (Bind) which services? | Three rules to keep in mind: 1. **All three must allow.** A Dial permission with no matching ERP gives an identity nothing — the client cannot even reach a router to attempt the connection. 2. **Policies are additive, not subtractive.** Granting matches add up; you cannot revoke with a deny rule. To take access away, remove the granting attribute or policy. 3. **Granularity lives in the Service Policy axis.** `kziti` maintains a universal client ERP (`#all` → `#role-dmz`) so any client can reach the DMZ routers, a per-network connector ERP (`#connector-corp-a` → `#net-corp-a`) so the private router's tunneler identity can reach its own private router to host services, and a per-network Bind service policy (`#connector-corp-a` → `#net-corp-a` services) to authorize hosting. SERPs are per-network (`#net-corp-a` services → `#role-dmz` + `#net-corp-a` routers). Every Dial entitlement you make is reflected in the Dial service policy: it grants access to any identity holding the matching `#net-*`, `#svcset-*`, or `#svc-*` attribute. Adding or revoking access is a single attribute change on the identity. ## Multi-tenant isolation The combination of policies provides hard tenant separation: - An identity without `#net-corp-a`, `#svcset-*`, or a `#svc-corp-a-*` attribute cannot reach any corp-a service. No Dial policy matches, so the controller refuses the connection before any router is involved. - Even with a matching Dial policy, traffic only flows if the SERP allows the chosen routers to carry that service's traffic. Misconfiguring a per-network SERP can limit routing options, but it cannot create cross-tenant access. - A private router for corp-a can only host (Bind) corp-a services. Even if compromised, it cannot be used as a pivot to host another tenant's services. - Public routers are pure transit. The universal client ERP that lets every identity reach any public router does not weaken isolation, because all three policy axes still gate traffic. ## kziti's scope, and what stays in raw OpenZiti `kziti` handles routers, role attributes, identities, and policies. Raw OpenZiti tooling remains available for auditing (ZAC, `ziti edge` read operations), custom topologies outside kziti's model, and recovery scenarios not covered by kziti's commands. If an operation feels like it should be a `kziti` command but isn't, report it. --- ## OpenZiti Quickstart for Kasm # OpenZiti Quickstart This walkthrough uses [`kziti`](./kziti-operations/cli-reference.mdx), a CLI that wraps OpenZiti behind an opinionated model, to stand up a small lab on a single VM and reach a private `nginx` from a Kasm workspace. You will: 1. Install `kziti` and bring up an OpenZiti controller and router. 2. Create a network and a private router that hosts your services. 3. Run an `nginx` container behind the private router and publish it as a service. 4. Configure Kasm to use OpenZiti as an egress provider. 5. Grant a Kasm-managed identity access to the service. 6. Validate traffic from a Kasm session. ## Prerequisites - A Linux VM (x86_64 or aarch64) with: - access to root/sudo - an internet accessible IPV4 address - a DNS record pointed at the IPV4 address - an installation of Docker - A Kasm deployment whose Manager and Agents can reach the Linux VM on ports: - `1280/tcp` - controller edge/client and management API. - `6262/tcp` - controller fabric port (used by routers). - `3022/tcp` - public edge router listener. - `3023/tcp` - private router listener. ## Step 1. Install kziti ```bash curl -fsSL https://kasmweb-build-artifacts.s3.amazonaws.com/kziti/install.sh | bash kziti --version ``` You should see a version printout: ``` $ kziti --version kziti 0.1.0.dev28+dc90047 commit: dc9004792a40 built: 2026-05-08T17:18:17Z ``` ## Step 2. Deploy the OpenZiti controller and public router Parameters: - ``: DNS record from prerequisites - ``: Generate yourself a secure alphanumeric password ```bash kziti deploy install \ --controller-host \ --router-host \ --admin-password '' \ --yes ``` This bootstraps: - An OpenZiti Controller on the controller hostname. - A Public Router on the router hostname. - An admin identity that `kziti` uses for every subsequent command on this host. The install runs in a few minutes and lives at `/opt/kziti` by default. It will conclude with `Installation complete`. ## Step 3. Create a network and a private router In `kziti`'s model a **network** groups related services. A **private router** sits next to the resources the network exposes and is the only thing that hosts services. Create the network record on the controller: ```bash kziti network create demo "Demo" ``` Provision a private router record for the network — this writes an enrollment JWT: ```bash kziti router private provision demo demo-router-1 --output-dir /tmp ``` For a single-host quickstart, run the private router on the same VM in a separate `kziti` install directory and compose project: Use --router-port 3023 to avoid conflicting with the public router already bound to port 3022: ```bash kziti deploy install \ --profile router \ --install-dir /opt/kziti-demo-router \ --project kziti-demo-router \ --router-host \ --router-port 3023 \ --enrollment-token "$(cat /tmp/demo-router-1.jwt)" \ --yes ``` Confirm the new router shows online: ```bash kziti router list ``` ## Step 4. Run a private nginx behind the router Run an `nginx` container attached to the private router's compose network so the router can reach it by container hostname: ```bash docker run -d \ --name private-nginx \ --network kziti-demo-router_ziti \ nginx:alpine ``` If your install used a different `--project` name, run `docker network ls` and pick the network whose name starts with the project you chose. ## Step 5. Publish the nginx service ```bash kziti service create demo private-nginx private-nginx 80 \ --alias private-nginx.demo.zt ``` `--alias` is the hostname Kasm sessions will dial; the Ziti tunnel resolves it, no DNS entry needed. ## Step 6. Generate a Kasm admin identity Kasm authenticates to the OpenZiti controller using an admin identity. Create and auto-enroll one: ```bash kziti identity create kasm_api --admin --auto-enroll --output-dir . ``` This writes `./kasm_api.json` — the identity file you will paste into Kasm in the next step. ## Step 7. Configure OpenZiti egress in Kasm 1. Go to **Infrastructure → Egress**. 2. Create an egress provider with type **OpenZiti**. 3. Open the provider and go to **OpenZiti Configuration**. 4. Open `./kasm_api.json` and paste the full JSON as the OpenZiti admin identity. Example admin identity JSON shape: ```json { "ztAPI": "https://ziti.example.com:1280/edge/client/v1", "id": { "cert": "pem:-----BEGIN CERTIFICATE-----...", "key": "pem:-----BEGIN PRIVATE KEY-----...", "ca": "pem:-----BEGIN CERTIFICATE-----..." } } ``` 5. Map the provider to target users or workspaces. ## Step 8. Grant the Kasm-managed identity access After mapping and reconciliation, Kasm creates identities named like: - `kasm-user---` - `kasm-workspace---` You can find the native OpenZiti UI located at `https://:1280/zac`. List the Kasm-managed identities and pick the one to grant: ```bash kziti identity list --type workspace ``` Grant it access to every service in the `demo` network: ```bash kziti access grant net-demo ``` To scope more narrowly, target a service set (`svcset-`) or individual service (`svc-`) instead. See [Grant access](./kziti-operations/grant-access.mdx). ## Step 9. Validate from Kasm session Open a browser inside a mapped Kasm workspace session and navigate to `http://private-nginx.demo.zt`. You should see the default nginx welcome page. If this fails, continue with the troubleshooting flow. ## Troubleshooting basics 1. Confirm the OpenZiti stack is healthy and the private router is online: ```bash kziti status kziti router list ``` 2. Confirm the service exists and the grant resolved: ```bash kziti service list --network demo kziti access list ``` 3. Check Kasm sidecar logs during session startup: - `/var/log/kasm-sidecar/network_sidecar.log` - `/var/run/kasm-sidecar/$container_namespace/ziti.log` 4. For deeper troubleshooting see the [OpenZiti troubleshooting guide](./troubleshooting.mdx). --- ## Troubleshoot OpenZiti Egress in Kasm # Troubleshoot OpenZiti egress in Kasm Common failure modes, ordered by traffic path: workspace → sidecar → tunneler → policy → router → destination. See [kziti architecture](./kziti.mdx) and the [integration deep dive](./kasm_integration_deep_dive.mdx) for background. ## Where to look first The four primary signals when troubleshooting are: - **Sidecar log on the Kasm host:** `/var/log/kasm-sidecar/network_sidecar.log` (network setup, identity injection, tunnel start). - **Per-session Ziti tunnel log:** `/var/run/kasm-sidecar/$container_namespace/ziti.log` (tunnel start, dial errors, policy failures). - **kziti status (on the Ziti host):** `kziti status` (overall controller and router health). - **OpenZiti controller and router logs:** `docker compose -f /opt/kziti/docker-compose.yml logs ziti-controller` and similarly for the router container. A useful first step is to find the namespace for a failing session: ```bash docker inspect -f '{{.NetworkSettings.SandboxKey}}' \ | grep -o -E '[a-f0-9]+$' ``` Then check both the per-session ziti log and the sidecar log for that namespace. ## A session reports an egress error at launch The Kasm UI shows an egress error when the workspace launches. **Most common causes:** 1. **No managed identity for this user or workspace.** Reconciliation has not yet run, or has run but not picked up the new mapping. List identities on the Ziti host: `kziti identity list | grep kasm-` and confirm one matches the expected `kasm-user-...` or `kasm-workspace-...` pattern. 2. **Identity present but Kasm has not received the JSON.** Restart the egress reconciliation in Kasm or re-save the mapping to force a refresh. 3. **Controller unreachable from the Kasm host.** The sidecar needs outbound TCP to `:1280` on the controller. Test from the Kasm host: `curl -k https://:1280/edge/client/v1/version`. A response with version metadata indicates connectivity. The session's `network-sidecar.log` will name the specific failure. Look for `failed to enroll`, `failed to authenticate`, or `failed to start ziti tunnel`. ## A session starts but cannot reach a service The session is up and the Kasm UI does not show an egress error, but the user cannot reach a service the policies say they should. Walk the policy axes in this order: ### Step 1. Confirm the identity has the right access attribute ```bash kziti access list ``` The output should show a role attribute (`net-*`, `svcset-*`, or `svc-*`) that covers the target service. If it is missing, the access grant was not made or the Kasm mapping has not reconciled. ### Step 2. Confirm the target service exists and the destination is reachable from the private router ```bash kziti service show ``` Verify the destination DNS name or IP is correct. Test reachability from the host running the relevant private router: `curl -k https://:` from inside the router host or via `docker compose exec`. ### Step 3. Confirm the policies match ```bash kziti ziti audit ``` The audit command checks that the universal edge router policy (`erp-clients-dmz`) exists, that every network has its Bind and Dial policies, and that no overly broad policies exist. Any `ERROR` finding is a hard blocker for connectivity; `WARN` findings indicate configuration drift. Under normal kziti-managed operations policy misconfigurations are uncommon, but adopting an existing controller or manual edits can introduce them. ### Step 4. Confirm the routers and edge-router policies allow the path ```bash kziti router list ``` The relevant private router should be `online`. The public routers should be `online`. If a router is `offline`, check its container logs. ### Step 5. Check the session's tunnel log In the Kasm session container's namespace dir on the Kasm host: ```text /var/run/kasm-sidecar/$container_namespace/ziti.log ``` A failed dial logs the service name and the reason. Common reasons: `not authorized`, `no terminators` (no router is hosting the service), `service not found` (intercept hostname does not match a service definition). ## Identity is created but does not appear online in ZAC The identity exists on the controller (visible via `kziti identity list` or in ZAC) but never reports online when a session is launched. **Most common causes:** - **The session never launched a Ziti tunnel.** Look in `network-sidecar.log` for `ziti tunnel run` or its absence. If the tunnel never started, the egress sidecar code path was not taken — confirm the workspace is mapped to the OpenZiti provider in Kasm. - **The tunnel started but failed enrollment.** Check `ziti.log` for the session's namespace. A signed JWT that has expired or been used produces a clear error. - **Network path to the public router is blocked.** The session container needs TCP `:3022` (or whatever port your public router listens on) reachable. Network policy on the Kasm host or its environment can block this. ## A private router is offline after recent infrastructure changes A private router that was previously healthy reports as `offline`. **Most common causes:** - **The router host lost outbound TCP** to the controller (`:6262`) or the public router (`:10080` for fabric link). Confirm with `nc -zv` from the router host. - **The controller IP changed** without a corresponding `--existing-controller-ip` update on the router host. If the router was provisioned when DNS resolution was different, you may need to update the router's compose override on its host. - **The router certificate is rotating.** OpenZiti routers occasionally re-enroll. The router log will say so. ## HA cluster commands time out Mutating commands fail with quorum or timeout errors but read-only commands still work. This is the quorum-loss signature. See [Recover from quorum loss](./kziti-operations/recover-quorum.mdx). Do not run recovery if the missing controller is just temporarily unreachable — wait for it to return. Recovery is for nodes that are permanently gone. ## When to escalate For raw policy bodies, Raft state, fabric link health, or PKI internals: [OpenZiti docs](https://openziti.io/docs/) and [issue tracker](https://github.com/openziti/ziti/issues). If you're on the Kasm-pinned v2 prerelease and suspect an upstream bug, report it to Kasm too. ## Related - [Operations with kziti](./kziti-operations/index.mdx) — day-2 admin tasks. - [Integration deep dive](./kasm_integration_deep_dive.mdx) — Kasm-side internals. - [OpenZiti egress provider](./index.mdx) — the user-facing concept page. --- ## Configure External Proxy for Kasm Workspaces # Configuring an External Proxy Administrators may deploy Kasm Workspaces in a corporate environment that has a forward proxy, such as a ZScaler or BlueCoat device, in these environments Admins may wish to send outbound Kasm user traffic through the corporate proxy. This document covers the necessary configuration to create a Desktop Image that has the browsers and desktop applications configured send outbound traffic through the proxy. It assumes you understand the process for [Building Custom Images](../workspaces-sessions/container-workspace/customization/building-images.mdx). The example URL: `http://10.10.1.1:3128` can be replaced with the URL of your forward proxy server. ## Creating the Custom Image 1. SSH to the Kasm Workspaces server and clone the example Git repository that has examples of custom images. ```Bash git clone https://github.com/kasmtech/workspaces-images cd workspaces-images ``` 2. Create a file named `proxy.json` with the following contents. Ensure that `http://10.10.1.1:3128` is replaced with the URL of your proxy server. This file will be copied into our image using the `COPY` command in our Dockerfile and will be used by the Chrome Browser. ```json { "ProxyMode": "fixed_servers", "ProxyServer": "10.10.1.1:3128", "ProxyBypassList": "" } ``` 3. Create a file named `policies.json` with the following contents. : Ensure that `http://10.10.1.1:3128` is replaced with the URL of your proxy server. This file will be copied into our image using the `COPY` command in our Dockerfile and will be used by the Firefox Browser. ```json { "policies": { "Proxy": { "Mode": "manual", "Locked": true, "HTTPProxy": "10.10.1.1:3128", "UseHTTPProxyForAllProtocols": true, "Passthrough": "" } } } ``` 4. Next we will create a Dockerfile that applies our proxy configs to the Browsers and the Desktop OS. In this example we are basing our image off the `kasmweb/desktop` image, but any image that has the desired browsers installed will work. Create a file named `Dockerfile` with the following contents. Ensure that `http://10.10.1.1:3128` is replaced with the URL of your proxy server. ```yml FROM kasmweb/desktop:[[release]] USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### # Install Custom Certificate Authority # COPY ./src/ubuntu/install/certificates $INST_SCRIPTS/certificates/ # RUN bash $INST_SCRIPTS/certificates/install_ca_cert.sh && rm -rf $INST_SCRIPTS/certificates/ ENV http_proxy http://10.10.1.1:3128 ENV https_proxy http://10.10.1.1:3128 ENV ftp_proxy http://10.10.1.1:3128 COPY ./proxy.json /etc/opt/chrome/policies/managed/proxy.json COPY ./policies.json /usr/lib/firefox/distribution/policies.json ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 5. If your proxy server is terminating SSL connections, you may need to load your custom root CA certificate onto your system. To do that you need to complete the following: 1. Place your certificate in the following directory, overwriting the placeholder file that is currently there `./src/ubuntu/install/certificates/ca.crt` (ensure it is named ca.crt). 2. Edit `Dockerfile` and uncomment the following lines – ( Remove the “#” characters ): ```Bash ... # Install Custom Certificate Authority # COPY ./src/ubuntu/install/certificates $INST_SCRIPTS/certificates/ # RUN bash $INST_SCRIPTS/certificates/install_ca_cert.sh && rm -rf $INST_SCRIPTS/certificates/ ... ``` ```Bash ... # Install Custom Certificate Authority COPY ./src/ubuntu/install/certificates $INST_SCRIPTS/certificates/ RUN bash $INST_SCRIPTS/certificates/install_ca_cert.sh && rm -rf $INST_SCRIPTS/certificates/ ... ``` 6. Build the image ```Bash sudo docker build -t desktop:custom -f Dockerfile . ``` 7. Register the new image in the Kasm UI. See [Building Custom Images](../workspaces-sessions/container-workspace/customization/building-images.mdx). --- ## IPVLAN Networking with Kasm: Configuration and Setup # IPVLAN Networking ### Summary By default Kasm uses docker bridge networking with NAT. While this makes networking and scaling very simple, it comes with the disadvantage that user generated traffic all comes from the single IP address of the Kasm Agent they are deployed on. A solution is to use Docker IPVLAN networks. Kasm allows you to assign Images to a docker network, making it possible to assign different groups of users to different VLANs on the physical network. ### Virtualization If your Kasm Agents are virtual machines, you must first setup your virtualization infrastructure to support trunking. This step can be skipped if Kasm is running on bare metal ### VMWare vSphere These instructions assume your vSphere is already setup with a Dswitch trunked to the physical network. 1. Navigate to the networking tab in the vSphere Web Client 2. Right click on the appropriate Dswitch that has connectivity to the target physical network. 3. Click Distributed Port Group -> New Distributed Port Group The new Distributed Port Group dialog has three pages. 1. Provide your new port group a name and hit next 2. In the VLAN section select “VLAN Trunking” for the VLAN Type and provide a trunk range. 3. Select Next to view the summary and then Finish to confirm. Next you need to associate the trunk to the VM. It is recommended to have two NICs on the VM. One is a normal access port for the Kasm management interface. This NIC will have an IP address and that IP will be used to facilitate communication between the Kasm API server and the Agent. User generated traffic inside of a Kasm desktop or browser will come from the trunk interface. 1. In the vSphere Web Client, Navigate to the target VM, right click, and Edit Settings. 2. Click Add Device, Network Adapter 3. Assign one NIC to the Trunk and one NIC to the Management VLAN ### Configure Kasm Agent OS for Trunking The following instructions add trunking capabilities for Ubuntu 22.04LTS. ```yml sudo apt-get install vlan sudo modprobe 8021q sudo su -c 'echo "8021q" >> /etc/modules' ``` Edit /etc/network/interfaces ```yml admin@kasm-agent-1:~$ cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto ens192 iface ens192 inet static address 192.168.10.1 netmask 255.255.255.0 network 192.168.10.0 broadcast 192.168.10.255 gateway 192.168.10.1 # dns-* options are implemented by the resolvconf package, if installed dns-nameservers 8.8.8.8 auto ens160 iface ens160 inet manual ``` In the example configuration above, ens192 is the management port and ens160 is the trunk. There is no need to define VLAN interfaces, docker will do this automatically and any attempt to create them will only interfere or break things. ### Docker Networking There are two types of docker networks that would allow placing containers on VLANs directly, macvlan and ipvlan. If you are running in a virtualized environment, using macvlan requires special configurations on the hypervisors, therefore, we recommend IPVLAN instead of macvlan. IPVLAN was an experimental feature prior to docker 19.03.0, released 2019-07-22. If you are using a version of docker prior to 19.03.0, you must enable experimental features by editing/creating the file /etc/docker/daemon.json
**Example of /etc/docker/daemon.json**
```yml { "experimental":true } ``` The following is an example of creating an IPVLAN docker network. ```yml sudo docker network create -d ipvlan --subnet=192.168.150.0/26 -- gateway=192.168.150.1 --ip-range=192.168.75.16/28 -o ipvlan_mode=12 -o parent=ens160.150 vlan150 ``` The proceeding command creates a docker network called “vlan150” on the parent network adapter ens160, sub interface 150 “-o parent=ens160.150”. The name “vlan150” can be any arbitrary name you desire. In this example the subnet is a /26 as configured with the --subnet option. However, you may have multiple Kasm agents and you will want each agent to use different IP addresses for their respective containers. Therefore, in the example we used the --ip-range option to specify a smaller /28 inside the /26 subnet. This particular agent will use ip address specified in the ip-range option for its containers. We recommend using larger IP spaces to allow for easier expansion. For example, if today you had 4 hosts, you may want to consider using a /22 for each VLAN, which would support up to 510 users, and each agent’s docker network would have a /25 within the subnet allowing each agent to support up to 128 users. --- ## Running Kasm Behind Organizr # Organizr Kasm can be run behind [Organizr](https://organizr.app) but may require some configuration during installation. If Organizer is running on port 443 Kasm can be installed on a separate port with this [guide](reverse-proxy.mdx). The guide will also explain how to install kasm behind a reverse proxy. This may also be useful for Organizr if Kasm access needs to be setup on a separate server name such as kasm.server.com. ## Setting up the Kasm Tab The Kasm tab can be setup as an Iframe in Organizr even if the test tab button returns false it may still work. Adding the URL of the Kasm is enough for the setup no other changes need to be made. ![Organizr Tab Setup](/img/organizr_tab.jpg) --- ## Replace Self-Signed Certificates in Kasm Workspaces # Replacing Self-Signed Certificates During installation, the system creates self-signed certificates that are used when connecting to the Web UI. Administrators may wish to replace these with valid, trusted certificates for the domain Kasm is to be published on. An alternative is to place Kasm Server behind a self-managed reverse proxy such as Nginx or Caddy. See the [Reverse Proxy](reverse-proxy.mdx) documentation for more details on this configuration. Acquiring valid certificates is outside the scope of this document, but once acquired, the following steps may be used to replace Kasm's self signed certificates. The certificate and key must be in **PEM** format.   For multi-server installations, repeat the following steps on each Web App role. ## Steps to Replace Certificates 1. **Stop the Kasm Services.** ```bash sudo systemctl stop kasm ``` 2. **Replace `kasm_nginx.crt` and `kasm_nginx.key` files.** ```bash sudo cp /opt/kasm/current/certs/kasm_nginx.crt sudo cp /opt/kasm/current/certs/kasm_nginx.key ``` 3. **Start the Kasm Services.** ```bash sudo systemctl start kasm ``` 4. **Test if nginx is running correctly. Wait 30 seconds.** ```bash sudo docker ps | grep kasm_proxy ``` 5. **Ensure that the container has been running for more than 30 seconds.** --- ## Video Tutorial This video walks you through installing an SSL certificate on your Kasm Workspaces instance using [Let's Encrypt](https://letsencrypt.org/). --- ## Restricting Kasm Workspaces to Specific Docker Networks # Restricting Workspaces to Docker Networks Workspaces allows the administrator to restrict certain Docker workspace images to only provision on specified custom docker networks. This may be useful if there is a need to use specialized networking such as [macvlan](https://docs.docker.com/network/macvlan/)/[ipvlan](https://docs.docker.com/network/ipvlan/) or [Bridged Network Source NAT](bridged-network-source-nat.mdx). But, it is also useful to provision sessions on groups of Agents to achieve a more simple multi-enclave architecture similar to what can be accomplished with the use of multiple [Deployment Zones](../infra-autoscale/deployment-zones.mdx) or with Agents that have certain characteristics (e.g specialized hardware) that are helpful to be grouped and associated with certain workspace images. In this guide we will demonstrate how to: 1. Create custom docker networks on Agents 2. Configure an image to use one or more custom networks 3. Allow the user to select a network at runtime ## Architecture For this example, we are using in multi-server deployment, with a single webapp, and 4 Agents, each in different enclaves. ![Multi Server Network Architecture](/img/docker_networks/architecture.png) ## Creating Custom Networks Workspaces installs a customer bridged docker network named `kasm_default_network`. By default, all sessions are created on this network. For this example, we will create an additional custom bridged docker network that represents the target enclave. 1. SSH to the desired Agent. 2. Create a custom docker network. ```Bash sudo docker network create z_enclave_2 ``` The docker network names used in this example are intentionally prefixed with `z_` . Due to a quirk `docker` will choose the default route for the container based on the name of the docker network ordered alphabetically. We name these custom networks accordingly so that they won't cause interruptions with the Kasm service containers or user workflow. 3. Repeat this step for each Agent. In our example, creating the `z_enclave_2` network on all the Agents in enclave 2 and `z_enclave_3` on all the Agents in enclave 3. ## Workspace Configuration 1. Log into the Workspaces UI as an admin. 2. Select **Workspaces** -> **Workspaces**. 3. Click **Edit** next to the desired Workspace from the arrow menu (e.g Chrome). 4. Check **Restrict Image to Docker Network** and add the custom networks (e.g `z_enclave_2` and `z_enclave_3`). Note. Custom networks will appear in this list a few minutes after they are created on an active Agent. 5. Check **Allow Network Selection**. This will allow the user to choose from the listed networks when they launch a session. ![Workspace Configuration](/img/docker_networks/workspace_configuration.webp) 6. Click **Save**. ## Launching the Workspace 1. From the Workspaces launcher, click on the previously modified Workspace. A dropdown will appear with a list of the networks defined. 2. Select the desired network and launch the session. Selecting **Auto** will provision the session on any Agent with one of the previously specified networks. ![Network Selection](/img/docker_networks/launch.webp) --- ## Reverse Proxy Setup: Nginx, Caddy, HAProxy, Apache # Reverse Proxy ## Overview Administrators may desire to run Kasm Workspaces behind a reverse proxy such as [Nginx](https://nginx.org/) or [Caddy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy) . A handful of configurations are required for communication to properly flow between the proxy and Kasm. Once Kasm is placed behind a reverse proxy, be sure to update the Zone configuration. See [Update Zones](#update-zones). Troubleshooting info can be found on the [Troubleshooting Page](../troubleshooting) ## Running Kasm Workspaces on a Non-Standard Port By default, Kasm Workspaces will listen on port 443. Administrators may wish to run the application on another port so that the reverse proxy can run on port 443. During the installation pass the **-L** flag to choose a different port. e.g `sudo bash kasm_release/install.sh -L 8443` Users will now access Kasm Workspaces via the defined port **https://kasm.server:8443** ## Example Nginx Config Below is an example Nginx config with the appropriate settings for Kasm annotated. In this example, Nginx is listening on port **443** and Kasm Workspaces is listening on port **8443**
Example Nginx Configuration
```yaml server { listen 443 ssl; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { # The following configurations must be configured when proxying to Kasm Workspaces # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Should match the listening port of this proxy proxy_set_header X-Forwarded-Port 443; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off; # Allow large requests to support file uploads to sessions client_max_body_size 10M; # Proxy to Kasm Workspaces running locally on 8443 using ssl proxy_pass https://127.0.0.1:8443 ; } } ``` ## Multiple Server Names Kasm supports proxying via subdomains (e.g [https://kasm1.example.com/](https://kasm1.example.com/) / [https://kasm2.example.com/](https://kasm2.example.com/)) or paths (e.g [https://example.com/kasm1/](https://example.com/kasm1/) / [https://example.com/kasm2/](https://example.com/kasm2/)) ### Proxy via Subdomain Use a dedicated `server_name` for traffic destined for Kasm. (e.g [https://kasm.example.com/](https://kasm.example.com/)). See [Nginx Server Names](http://nginx.org/en/docs/http/server_names.html) documentation for more details. #### Example Nginx Config
Multiple Server Names Example
```yaml server { listen 443 ssl; // highlight-next-line server_name app1.example.com; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { return 200 'App 1'; add_header Content-Type text/plain; } } server { listen 443 ssl; // highlight-next-line server_name kasm.example.com; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { # The following configurations must be configured when proxying to Kasm Workspaces # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Should match the listening port of this proxy proxy_set_header X-Forwarded-Port 443; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off; # Allow large requests to support file uploads to sessions client_max_body_size 10M; # Proxy to Kasm Workspaces running locally on 8443 using ssl proxy_pass https://127.0.0.1:8443 ; } } ``` #### Example Caddy Config Below is an example Caddy v2 config with the appropriate settings for Kasm. In this example, Caddy is configured to listen for requests on **kasm.example.com** and reverse proxy them to Kasm running on **https://127.0.0.1:8443** Note that we include the **tls_insecure_skip_verify** option to skip TLS certificate verification. For more information on configuring Caddy, check out the Caddy documentation at [https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#defaults](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#defaults)
Example Caddy Configuration
```json kasm.example.com { reverse_proxy https://127.0.0.1:8443 { transport http { tls_insecure_skip_verify } header_up Host {host} # Should match the listening port of this proxy header_up X-Forwarded-Port "443" header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} } } ``` #### Example HAProxy Config Below is an example HAProxy config with the appropriate settings for Kasm annotated. In this example HAProxy is listening on port **443** and Kasm Workspaces is listening on port **8443**
Example HAProxy config
```yaml global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend localhost bind *:443 ssl crt /tmp/all.pem alpn http/1.1 redirect scheme https if !{ ssl_fc } mode http default_backend node backend node mode http option forwardfor server kasm 127.0.0.1:8443 check ssl verify none http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } ``` #### Example Apache Config Below is an example Apache config with the appropriate settings for Kasm annotated. In this example, Apache is listening on port **443** and Kasm Workspaces is listening on port **8443**.
Example Apache Configuration
```yaml # Server and ssl ServerName kasm.example.com SSLEngine on SSLCertificateFile /etc/ssl/apache2/server.pem SSLCertificateKeyFile /etc/ssl/apache2/server.key # Websocket upgrade RewriteEngine on RewriteCond ${HTTP:Upgrade} websocket [NC] RewriteCond ${HTTP:Connection} upgrade [NC] RewriteRule .* "wss://127.0.0.1:8443/$1" [P,L] # Proxy SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off ProxyPreserveHost on ProxyPass / https://127.0.0.1:8443/ ProxyPassReverse / https://127.0.0.1:8443/ ProxyRequests off RequestHeader set X-Forwarded-Proto https # Should match the listening port of this proxy RequestHeader set X-Forwarded-Port 443 ``` ### Proxy via Path The same settings need to be sent as with subdomain proxies, we are sending the majority outside of the location block so that they apply to all the locations, but feel free to change this to suit your needs. #### Set Proxy Path global setting - Select **Settings > Global** from the navigation menu. - Find the **Proxy Path** setting and update the value to match the path for this server. The value should start with a trailing slash, therefore if the path url in the address bar looks like `https://example.com/kasm1/#/settings` then the value entered should be **/kasm1** Do not use paths that overlap, for example `/kasm` and `/kasm2` as it will cause issues. This is only the case for where it's an exact overlap from the beginning including the slash. `/kasm` and `/mykasm` would be fine, `/server` and `/servers-us` would not be. When setting up for the first time, on initial login a cookie will be set for the root `/` location. After setting a path value and logging out and logging in again, the correct cookie will be set, but the original root cookie will also still exist. It is recommended to clear cookies before logging in to prevent any conflicts when first setting up. #### Example Nginx Config
Multiple Paths Example
```yaml server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; # The following configurations must be configured when proxying to Kasm Workspaces # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Should match the listening port of this proxy proxy_set_header X-Forwarded-Port 443; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off; # Allow large requests to support file uploads to sessions client_max_body_size 10M; // highlight-next-line location /kasm1/ { # Proxy to Kasm Workspaces running locally on 8443 using ssl proxy_pass https://127.0.0.1:8443/; } // highlight-next-line location /kasm2/ { # Proxy to Kasm Workspaces running externally over ssl proxy_pass https://kasm.example.com/; } } ``` ## Update Zones In order for clients to properly make connections to Kasm sessions when using a reverse proxy, the **Upstream Auth Address** and **Proxy Port** settings for each [deployment zone](../../reference/glossary.mdx#deployment-zone) must be updated. Update the **Proxy Port** setting to 0, and Kasm Workspaces will attempt to automatically determine the correct port from window.location.port. Update the **Upstream Auth Address** with either the word "proxy" or the IP or FQDN of the Kasm Workspaces server if using a single-server installation or if using a multi-server deployment, using the IP or FQDN of the Web App role for that Zone. Updates to Zone settings are applied to new sessions created after the change. Resuming existing sessions will not have the changes applied. 1. Log into the Kasm Workspaces UI as an administrator. 2. Select **Infrastructure** -> **Zones**. 3. Edit the default Zone. 4. Change the **Upstream Auth Address** setting to the "proxy" or the IP or FQDN of the Kasm Workspaces server. If using reverse proxy via path then it needs to be the IP or FQDN that points directly to the upstream server if using a multiserver setup. 5. Change the **Proxy Port** setting to 0. 6. Repeat for each additional **Zone**. If you are using the [RDP local client workspace option](../workspaces-sessions/container-workspace/workspaces.mdx), make sure the [**Restrict RDP Client IP Address**](../infra-autoscale/deployment-zones.mdx) setting is disabled in Infrastructure / Zones. If it isn't may not be able to connect, as the IP stored with the request will differ due to the connection being over a reverse proxy. If this is the case it will be reported in the Error Logs with a message such as "Invalid Request. Wrong client IP." --- ## Kasm with Tailscale: Secure Remote Access # Running Kasm with Tailscale This guide will cover setting up a single server Kasm instance with a basic Tailscale configuration. If you are looking to run a Tailscale as a sidecar container to access other Tailscale devices only from stock Workspaces containers please see [VPN Sidecar Containers](vpn-sidecar.mdx). ## Network architecture overview For our setup we had three nodes. - An Ubuntu 22.04 LTS graphical desktop running chromium to access the Kasm UI. - An Ubuntu 22.04 LTS server that we will perform a single server install of Kasm on. - An Ubuntu 22.04 LTS server that we configured as a Tailscale exit node. (This is only used in [Configuring Kasm with a Tailscale exit node](#configuring-kasm-with-a-tailscale-exit-node) ) ### Tailscale This guide uses Tailscale version 1.18.2. This guide assumes you already have a Tailscale account and are familiar with using Tailscale. #### Kasm with Tailscale without an exit node ![Tailscale Without an Exit Node](/img/tailscale/Tailscale_no_exit_node.png) Setup a single server Kasm instance as described in the [single server installation guide](../../tutorials/install/single-server-install.mdx). Verify that you can access the Kasm web app running on port 443 at **https://\** Install Tailscale on the Kasm node following the instructions at [Tailscale Ubuntu 22.04 LTS install](https://tailscale.com/kb/1187/install-ubuntu-2204/) Take note of the Tailscale ip address for the Kasm server. ```bash sudo tailscale ip --4 ``` Verify you can access the Kasm web app at the Tailscale ip address from a Tailscale client. In order for clients to properly make connections to Kasm sessions when using a reverse proxy, the **Upstream Auth Address** setting for each [deployment zone](../../reference/glossary.mdx#deployment zone) must be updated. Update the **Upstream Auth Address** with the public (non-tailscale) IP or FQDN of the Kasm Workspaces server. See [Update Zones](reverse-proxy.mdx#update-zones) for more information. Kasm workspaces is now working with Tailscale. Outbound Kasm session traffic will go out the normal public ip, if the desire is to route traffic from Kasm sessions through a Tailscale exit node continue with [Configuring Kasm with a Tailscale exit node](#configuring-kasm-with-a-tailscale-exit-node). #### Configuring Kasm with a Tailscale exit node ![Tailscale With and Exit Node](/img/tailscale/Tailscale_with_exit_node.png) Perform the setup in [Kasm with Tailscale without an exit node](#kasm-with-tailscale-without-an-exit-node). Once that setup is complete ensure that you have a Tailscale exit node configured. Instructions are available at: [Exit Nodes (route all traffic)](https://tailscale.com/kb/1103/exit-nodes/) Update the Tailscale configuration for the Kasm server with the new exit node. ```bash sudo tailscale up --exit-node= --exit-node-allow-lan-access ``` Adding the `--exit-node-allow-lan-access` parameter is required to be able to access the Kasm web app. Next we will need the IP address of the Kasm proxy server to update the **Upstream Auth Address** in the zone configuration. ```bash sudo docker exec -it kasm_proxy ip a ``` Use the non loopback address and update each [deployment zone](../../reference/glossary.mdx#deployment zone) with the new **Upstream Auth Address**. See [Update Zones](reverse-proxy.mdx#update-zones) for more information. Uploading files to the Kasm session does not work with a Tailscale exit node configured. #### Troubleshooting During our configuration of Tailscale we ran into issues with DNS. We were able to solve our issue by adding a public DNS server to the Tailscale administration page under [DNS](https://login.tailscale.com/admin/dns) (This step may not apply to all configurations of Tailscale) --- ## Using VPNs from inside Kasm Workspaces containers # Using VPNs From Inside Kasm Workspaces Containers This how to guide will cover configuring a VPN to run from inside a Kasm Workspaces container. This will involve customizing one of the Kasm Workspaces existing docker images to add the VPN software. This works as an alternative to setting up a [VPN Sidecar](vpn-sidecar.mdx). Kasm also publishes Workspace images with OpenVPN, Wireguard and Tailscale VPNs built in. This provides a more streamlined workflow for using VPNs from within Workspace container sessions. See [Using a VPN With a Supported Kasm Workspace Container](byo-vpn-container.mdx) for more details. This guide will cover two VPN configurations using tailscale and using openVPN. This guide assumes basic familiarity with the process to [build and register new docker images](../workspaces-sessions/container-workspace/customization/building-images.mdx) in Kasm Workspaces ## Video Tutorial This video walks through configuring a VPN to run from inside a Kasm Workspaces container. ## Running Tailscale Inside a Kasm Workspaces Container 1. Create the dockerfile and build the image The example dockerfile uses the `kasmweb/ubuntu-jammy-desktop` image as the base with the [[release]] tag this image is based on Ubuntu 22.04 LTS. It should be possible to use this guide with other Kasm provided images by adapting the tailscale installation logic in the provided dockerfile. ```yml ARG BASE_TAG="[[release]]" FROM kasmweb/ubuntu-jammy-desktop:$BASE_TAG USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### # Install Tailscale RUN curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.gpg | apt-key add - RUN curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.list | tee -a /etc/apt/sources.list.d/tailscale.list RUN apt-get update && \\ apt-get install -y tailscale # Sudo is not strictly necessary when using docker exec to start tailscale but will be needed to start tailscale manually RUN apt-get update \\ && apt-get install -y sudo \\ && echo 'kasm-user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers \\ && rm -rf /var/lib/apt/list/* ######### End Customizations ########### RUN chown 1000:0 $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` The below lines from the dockerfile add the Tailscale Ubuntu Jammy repository to apt. Tailscale makes repositories available for many other OSs if using a Kasm image with a different OS look at https://pkgs.tailscale.com/stable/ for the appropriate package repository. ```yml RUN curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.gpg | apt-key add - RUN curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.list | tee -a /etc/apt/sources.list.d/tailscale.list ``` 2. Build the container with the command: ```yml docker build -t custom:tailscalevpn -f Dockerfile . ``` 3. Optionally add this image to a docker registry This allows sharing the image easily to multiple agents 4. In Kasm create a workspace for the new image 5. Use the following for the Docker Run Config on the **Add Workspace** screen ```json { "devices": [ "dev/net/tun", "/dev/net/tun" ] } ``` 6. Use the following for the Docker Exec Config on the **Add Workspace** screen Start tailscaled as root - notice the use of an [ephemeral key](https://tailscale.com/kb/1085/auth-keys/) so that the container can be auto connected to and removed from the tailscale network. These commands can also be put in a custom_startup script instead of using the Docker Exec Config. ```json { "first_launch": { "user": "root", "privileged": true, "cmd": "bash -c 'tailscaled & tailscale up --authkey=tskey-abc123'" } } ``` 7. Launch the container and run tailscale status, if everything is correct the status will show the container is connected you the tailscale network. ## Running OpenVPN inside a Kasm Workspaces Container 1. Create the dockerfile and build the image The example dockerfile uses the `kasmweb/ubuntu-jammy-desktop` image as the base with the [[release]] tag this image is based on Ubuntu 22.04 LTS. It should be possible to use this guide with other Kasm provided images by adapting the OpenVPN installation logic in the provided dockerfile. Modifying what connection profiles are used in this example docker file should allow using other VPN services. ```yml ARG BASE_TAG="[[release]]" FROM kasmweb/ubuntu-jammy-desktop:$BASE_TAG USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### # Install OpenVPN RUN apt-get update && \\ apt-get install -y openvpn # Copy the NordVPN OpenVPN connection profiles RUN cd /etc/openvpn && \\ wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip && \\ unzip ovpn.zip && \\ rm ovpn.zip ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` There are two important components to this dockerfile: `RUN apt-get update && apt-get install -y openvpn` installs the OpenVPN client from the default OS package repository. This can be adapted for other Kasm image OSs. `RUN cd /etc/openvpn && wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip && unzip ovpn.zip && rm ovpn.zip` installs the Nord VPN configuration. This can be adapted for other VPN services. 2. Build the container with the command: ```yml docker build -t custom:openvpn -f Dockerfile . ``` 3. Optionally add this image to a docker registry This allows sharing the image easily to multiple agents 4. In Kasm create a workspace for the new image 5. Use the following for the Docker Run Config on the **Add Workspace** screen The container must run in privileged mode so that the network stack can be modified when the VPN is attempting to connect. The example provides the container with the Nord DNS servers. ```json { "dns": [ "103.86.98.100", "103.86.99.100" ], "devices": [ "dev/net/tun", "/dev/net/tun" ], "user": "root", "privileged": true } ``` 6. Use the following for the Docker Exec Config on the **Add Workspace** screen In the Docker Exec Config tell the container to execute using one of the .ovpn files provided by nord (Each file in the zip extracted in the dockerfile is a NordVPN server in a different location.). Nord VPN provides a tool to look up the recommended server https://nordvpn.com/servers/tools/ ```json { "first_launch":{ "cmd":"bash -c '/usr/bin/desktop_ready && xfce4-terminal -T OpenVPN -x openvpn /etc/openvpn/ovpn_tcp/us9923.nordvpn.com.tcp.ovpn'", "user":"root" } } ``` The ovpn file from the example for NordVPN can be replaced by the ovpn file provided to connect to the desired endpoint for other VPN providers. If the ovpn file is present on the system building the docker image, for instance in /tmp/client1.ovpn, then add `COPY /tmp/client1.ovpn /etc/openvpn/client1.ovpn` to the Dockerfile replacing `RUN cd /etc/openvpn && wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip && unzip ovpn.zip && rm ovpn.zip`. Then modify the Docker Exec accordingly to point to the new connection profile file. 7. Launch the container and a terminal will automatically launch to connect to NordVPN. 8. Enter the account login details and connect to NordVPN ### Mapping in the NordVPN connection profiles Kasm Workspaces 1.13 added support for mapped files for container based workspaces. This feature can be leveraged to easily map in the NordVPN connection profiles rather than downloading them at docker image build time. There are three places that the profile file can be added as a file mapping, for the user, for the group, or for the workspace. When defined for the workspace, the administrator can easily create multiple workspaces that will each connect to a different VPN endpoint. When defined for the group, the administrator can define one workspace image, and have that image connect to the VPN endpoint based on which group the user is part of. Finally, when setting the file mapping by user, the administrator can have each user connect to their own specific VPN endpoint. When this is done for the user and group levels the file will be mapped into all container based sessions, so it is possible to have multiple OpenVPN enabled images, and have the user/group level file mapping apply to all the images. For non OpenVPN images the file will be mapped in but have no effect as OpenVPN will not be installed. In the example here this is used to map in NordVPN connection profiles, but this would apply the same to connection profiles from other VPN providers. 1. Remove the connection profile download from the dockerfile `RUN cd /etc/openvpn && wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip && unzip ovpn.zip && rm ovpn.zip` can be removed from the dockerfile used above. 2. Modify the Docker Exec for the image to: ```json { "first_launch":{ "cmd":"bash -c '/usr/bin/desktop_ready && xfce4-terminal -T OpenVPN -x openvpn /etc/openvpn/client1.ovpn'", "user":"root" } } ``` 3. Download the NordVPN connection profiles individually from https://nordvpn.com/ovpn/ or as a bundle from https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip. Follow the process in [file mappings](../workspaces-sessions/file-mappings.mdx) to add this file to the image, group or user as /etc/openvpn/client1.ovpn --- ## Kasm Workspaces: VPN Sidecar Container Integration Guide # VPN Sidecar Containers ## Intro For security reasons or to gain access to a remote network it might be required to give specific Kasm Workspaces access to a VPN. One way to do that would be to customize an existing Kasm core image with VPN tools, but then it requires many network level permissions and becomes a configuration nightmare. The Kasm team's recommended configuration would be to use an off the shelf or custom VPN docker container running alongside Kasm Workspaces while leveraging the existing desktop and application containers. Their traffic can then be forced through the external VPN container using a custom Docker exec config. This document will be covering three different ways to achieve this. Deployment time ~10 minutes. * [Option 1 Create a standalone openvpn setup](vpn-sidecar.mdx#option-1-create-a-standalone-openvpn-setup) + [The OpenVPN server](vpn-sidecar.mdx#the-openvpn-server) + [The OpenVPN sidecar container](vpn-sidecar.mdx#the-openvpn-sidecar-container) + [Finding the public IP OpenVPN](vpn-sidecar.mdx#finding-the-public-ip-openvpn) * [Option 2 using a popular VPN Vendor container](vpn-sidecar.mdx#option-2-using-a-popular-vpn-vendor-container) + [Setting up a VPN container (NordVPN)](vpn-sidecar.mdx#setting-up-a-vpn-container) + [Nord VPN Testing](vpn-sidecar.mdx#nord-vpn-testing) * [Option 3 Tailscale](vpn-sidecar.mdx#option-3-tailscale) + [Getting the Tailscale auth key](vpn-sidecar.mdx#getting-the-tailscale-auth-key) + [Setting up a Tailscale Docker container](vpn-sidecar.mdx#setting-up-a-tailscale-docker-container) + [Tailscale testing](vpn-sidecar.mdx#tailscale-testing) ## Option 1 Create a standalone openvpn setup This configuration is going to be using an off the shelf OpenVPN container for the server as the assumption is most users will already have an OpenVPN endpoint available. Then the example will show building a custom client container to act as the sidecar. ### The OpenVPN server Here [kylemanna/openvpn](https://hub.docker.com/r/kylemanna/openvpn/) is being used to be able to quickly spin up an endpoint on a remote server. Use the following commands to deploy and dump a usable client config file: ```yml sudo docker volume create --name Kasm_vpn sudo docker run -v Kasm_vpn:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://IP_OR_HOSTNAME sudo docker run -v Kasm_vpn:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki sudo docker run -v Kasm_vpn:/etc/openvpn -d -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn sudo docker run -v Kasm_vpn:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full Kasm nopass sudo docker run -v Kasm_vpn:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient Kasm > Kasm.ovpn ``` Please substitute the `IP_OR_HOSTNAME` for the actual server IP or hostname for the server. After filling out the prompted information for password protecting the certificates the `Kasm.ovpn` configuration file needed to connect the VPN sidecar client will be written to disk. ### The OpenVPN sidecar container Build a custom docker container to act as the VPN sidecar container on the Kasm Workspaces host. ```yml mkdir openvpn-client cd openvpn-client mkdir root ``` Here is the `Dockerfile`: ```yml FROM debian:latest RUN apt update && \ apt install -y \ iptables \ openvpn && \ apt clean # add local files COPY /root / VOLUME [ "/vpn/config"] ENTRYPOINT [ "/entrypoint.sh"] ``` And custom `root/entrypoint.sh`: ```yml #! /bin/sh # create tun device if [ ! -c /dev/net/tun]; then mkdir -p /dev/net mknod /dev/net/tun c 10 200 fi # Enable devices MASQUERADE mode iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE # start vpn client openvpn --config /vpn/config/${VPN_CONFIG} ``` Make sure the entrypoint is executable: ```yml chmod +x root/entrypoint.sh ``` The directory structure should look like this: ```yml openvpn-client/ ├─ root/ │ ├─ entrypoint.sh ├─ Dockerfile ``` Now build the container: ```yml sudo docker build -t openvpn-client . ``` On the Docker host running Kasm Workspaces (or Agent Server if using a Mult-Server Deploy) create a custom docker network: ```yml sudo docker network create \ --driver=bridge \ --opt icc=true \ --subnet=172.20.0.0/16 \ vpn-1 ``` And finally navigate to the folder containing the `Kasm.ovpn` config file and run the container: ```yml sudo docker run -d \ --cap-add NET_ADMIN \ --name open-vpn \ --net vpn-1 \ --ip 172.20.0.2 \ -e VPN_CONFIG=Kasm.ovpn \ -v $(pwd):/vpn/config \ --restart unless-stopped \ openvpn-client ``` ### Customizing Workspaces Login to the Workspaces web interface and click on "Workspaces -> Workspaces" from the Admin tab: ![Workspaces Location Admin](/img/vpn_sidecar/images.webp) Now select the arrow button next to the Workspace to be modified to use this network and select "Clone": ![Cloning a Workspace](/img/vpn_sidecar/clone.webp) This example will be modifying a AlmaLinux 8 desktop Workspace. First rename the `Friendly Name` to append that this is a special VPN enabled container `AlmaLinux 8 - VPN`. For some configurations it may be necessary to populate the DNS server addresses of the container. This will be indicated by DNS resolution failure inside the container. This can be done by modifying the `Docker Run Config Override (JSON)` and adding DNS server entries (This workspace already had the `"hostname": "kasm"` populated in this field): ```json { "dns": [ "8.8.8.8", "8.8.4.4" ] } ``` Here the public Google DNS servers are used, but these can be any DNS servers. Next change the `Docker Exec Config (JSON)` to: ```json { "first_launch":{ "user":"root", "privileged":true, "cmd":"bash -c 'ip route delete default && ip route add default via 172.20.0.2'" } } ``` Then select "Restrict Image to Docker Network" and choose the network created in the previous step (vpn-1). Once finished the Workspace settings should look something like this: ![Workspace Network Settings](/img/vpn_sidecar/settings.webp) Click on **Save** and hop back over to the Workspaces tab. The new `AlmaLinux 8 - VPN` workspace should be present: ![User Dashboard Launch Button](/img/vpn_sidecar/image.webp) OK the Workspace is ready to deploy, the same process can be followed for any of the Kasm Workspaces to pipe their network traffic through the VPN container. ### Testing Testing the VPN configuration in the container will vary depending on the provider or use case, but here are some tips. These examples will be using the `AlmaLinux 8 - VPN` Workspace configured earlier. #### Finding the public IP OpenVPN Click on Applications -> Terminal Emulator and enter: ```yml curl icanhazip.com ``` Make sure the IP returned is not the current public IP of the Kasm Workspaces Agent the container is running on. ## Option 2 using a popular VPN Vendor container This example will be using an off the shelf VPN container here specifically geared for [NordVPN](https://nordvpn.com/), but the steps should be similar depending on the desired provider or configuration. ### Setting up a VPN container On the Docker host running Kasm Workspaces (or Agent Server if using a Mult-Server Deploy) first create a custom docker network: ```yml docker network create \ --driver=bridge \ --opt icc=true \ --subnet=172.20.0.0/16 \ vpn-1 ``` Now spinup a NordVPN Docker container: A NordVPN token is required and can be obtained following these [instructions](https://support.nordvpn.com/1905092252) ```yml docker run -d \ --cap-add NET_ADMIN \ --cap-add NET_RAW \ --name nord-vpn \ --net vpn-1 \ --ip 172.20.0.2 \ -e TOKEN=NORDVPNTOKEN \ -e TECHNOLOGY=NordLynx \ --restart unless-stopped \ ghcr.io/bubuntux/nordvpn ``` ### Customizing Workspaces Login to the Workspaces web interface and click on "Workspaces -> Workspaces" from the Admin tab: ![Workspaces Location Admin](/img/vpn_sidecar/images.webp) Now select the arrow button next to the Workspace to be modified to use this network and select "Clone": ![Cloning a Workspace](/img/vpn_sidecar/clone.webp) This example will be modifying a AlmaLinux 8 desktop Workspace. First rename the `Friendly Name` to append that this is a special VPN enabled container `AlmaLinux 8 - VPN`. For some configurations it may be necessary to populate the DNS server addresses of the container. This will be indicated by DNS resolution failure inside the container. This can be done by modifying the `Docker Run Config Override (JSON)` and adding DNS server entries (This workspace already had the `"hostname": "kasm"` populated in this field): ```json { "dns": [ "8.8.8.8", "8.8.4.4" ] } ``` Here the public Google DNS servers are used, but these can be any DNS servers. Next change the `Docker Exec Config (JSON)` to: ```json { "first_launch":{ "user":"root", "privileged":true, "cmd":"bash -c 'ip route delete default && ip route add default via 172.20.0.2'" } } ``` Then select "Restrict Image to Docker Network" and choose the network created in the previous step (vpn-1). Once finished the Workspace settings should look something like this: ![Workspace Network Settings](/img/vpn_sidecar/settings.webp) Click on **Save** and hop back over to the Workspaces tab. The new `AlmaLinux 8 - VPN` workspace should be present: ![User Dashboard Launch Button](/img/vpn_sidecar/image.webp) OK the Workspace is ready to deploy, the same process can be followed for any of the Kasm Workspaces to pipe their network traffic through the VPN container. ### Testing Testing the VPN configuration in the container will vary depending on the provider or use case, but here are some tips. These examples will be using the `AlmaLinux 8 - VPN` Workspace configured earlier. #### Nord VPN Testing Most VPN providers' webpages will give some kind of indication that the browsing session is "protected" from their home page. This example uses a NordVPN, so open up Firefox from the desktop and navigate to [https://nordvpn.com](https://nordvpn.com), The page should display a `Protected` status: ![NordVPN Protected](/img/vpn_sidecar/protected.png) ## Option 3 Tailscale [Tailscale](https://tailscale.com/) is a zero configuration VPN solution that allows users to quickly connect to a network of remote computers by their Tailscale IP addresses. This example will be configuring a sidecar container to route traffic to the machines on the Tailscale network. It is important to note here this example does not configure an exit node here simply allowing configured VPN containers to route traffic out to the Tailscale network. ### Getting the Tailscale auth key Most users can skip this step when trying to connect Workspaces containers to existing Tailscale infrastructure. For those who are new to Tailscale sign up for an account with them [here](https://login.tailscale.com/start). After signed up a login screen will be presented: ![Add device Tailscale](/img/vpn_sidecar/welcome.png) Ignore the setup wizard and click the avatar on the top right of the screen and select "Billing": ![Billing Location](/img/vpn_sidecar/billing.png) From here click on "Keys" under "Personal Settings": ![Keys Setting Location](/img/vpn_sidecar/keys.png) Click on "Generate auth key...": ![Generate a Key](/img/vpn_sidecar/generate.png) The Kasm team recommends setting "Reusable" and "Ephemeral" but ultimately review the settings and decide the best settings: ![Generate Settings](/img/vpn_sidecar/keysettings.png) Copy the key created and move on to the next step. ### Setting up a Tailscale Docker container On the Kasm Workspaces host build a custom docker container to act as the VPN sidecar container. ```yml mkdir tailscale cd tailscale mkdir root ``` Here is the `Dockerfile`: ```yml FROM alpine:3.15 RUN \ apk add --no-cache \ bind-tools \ tailscale # add local files COPY /root / ENTRYPOINT [ "/entrypoint.sh"] ``` And custom `root/entrypoint.sh`: ```yml #! /bin/sh # create tun device if [ ! -c /dev/net/tun]; then mkdir -p /dev/net mknod /dev/net/tun c 10 200 fi # Enable devices MASQUERADE mode iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE iptables -t nat -A POSTROUTING -o tailscale+ -j MASQUERADE # start vpn client tailscaled ``` Make sure the entrypoint is executable: ```yml chmod +x root/entrypoint.sh ``` The directory structure should look like this: ```yml tailscale/ ├─ root/ │ ├─ entrypoint.sh ├─ Dockerfile ``` Now build the container: ```yml sudo docker build -t tailscaled . ``` On the Docker host running Kasm Workspaces (or Agent Server if using a Mult-Server Deploy) create a custom docker network: ```yml sudo docker network create \ --driver=bridge \ --opt icc=true \ --subnet=172.20.0.0/16 \ vpn-1 ``` Now spinup a Tailscale Docker container: ```yml sudo docker run -d \ --cap-add NET_ADMIN \ --name tailscaled \ --net vpn-1 \ --ip 172.20.0.2 \ --restart unless-stopped \ tailscaled ``` Now login using the auth key: ```yml sudo docker exec tailscaled tailscale up --authkey= ``` Now navigate [here](https://login.tailscale.com/admin/machines) and ensure the machine is listed: ![Machine View](/img/vpn_sidecar/machine.png) ### Customizing Workspaces Login to the Workspaces web interface and click on "Workspaces -> Workspaces" from the Admin tab: ![Workspaces Location Admin](/img/vpn_sidecar/images.webp) Now select the arrow button next to the Workspace to be modified to use this network and select "Clone": ![Cloning a Workspace](/img/vpn_sidecar/clone.webp) This example will be modifying a AlmaLinux 8 desktop Workspace. First rename the `Friendly Name` to append that this is a special VPN enabled container `AlmaLinux 8 - VPN`. For some configurations it may be necessary to populate the DNS server addresses of the container. This will be indicated by DNS resolution failure inside the container. This can be done by modifying the `Docker Run Config Override (JSON)` and adding DNS server entries (This workspace already had the `"hostname": "kasm"` populated in this field): ```json { "dns": [ "8.8.8.8", "8.8.4.4" ] } ``` Here the public Google DNS servers are used, but these can be any DNS servers. Next change the `Docker Exec Config (JSON)` to: ```json { "first_launch":{ "user":"root", "privileged":true, "cmd":"bash -c 'ip route delete default && ip route add default via 172.20.0.2'" } } ``` Then select "Restrict Image to Docker Network" and choose the network created in the previous step (vpn-1). Once finished the Workspace settings should look something like this: ![Workspace Network Settings](/img/vpn_sidecar/settings.webp) Click on **Save** and hop back over to the Workspaces tab. The new `AlmaLinux 8 - VPN` workspace should be present: ![User Dashboard Launch Button](/img/vpn_sidecar/image.webp) OK the Workspace is ready to deploy, the same process can be followed for any of the Kasm Workspaces to pipe their network traffic through the VPN container. ### Testing Testing the VPN in the container will vary depending on the provider or use case, but here are some tips. These examples will be using the `AlmaLinux 8 - VPN` Workspace configured earlier. #### Tailscale testing An easy way to test is to simply run a ping to another device on the Tailscale network from the workspace. In order to test this at least one other device connected to the Tailscale network will be needed. From the Tailscale dashboard [here](https://login.tailscale.com/admin/machines) the IPs of other connected devices can be seen. This example will be using `100.86.224.182`. Assuming the Workspace is a modified desktop Workspace and in particular that this container is using the AlmaLinux 8 example from above. Once launched into the session go ahead and open a terminal from Applications -> Terminal Emulator: ![Opening a Terminal](/img/vpn_sidecar/openterminal.png) Now run a ping command: ```yml ping 100.86.224.182 ``` There should be acks printed to the screen: ![Ping Response](/img/vpn_sidecar/pings.png) Any container with this configuration will have access to other machines on the connected Tailscale network. --- ## Kasm Workspaces: Admin Account Password Recovery # Admin Account Recovery Admins may find themselves locked out of their accounts by forgetting or mis-setting their account passwords. This guide will show show the steps for resetting the admin account password. 1. SSH to the Kasm Workspaces server and connect to the database with the following command: > ```Bash > sudo docker exec -it kasm_db psql -U kasmapp -d kasm > ``` 2. Reset the Admin password, clear WebAuthn credentials, clear TOTP credentials and exit the psql shell > ```Bash > update users set > pw_hash = 'fe519184b60a4ef9b93664a831502578499554338fd4500926996ca78fc7f522', > salt = '83d0947a-bf55-4bec-893b-63aed487a05e', > secret=NULL, set_two_factor=False, locked=False, > disabled=False, failed_pw_attempts = 0 where username ='admin@kasm.local'; > DELETE FROM webauthn_credentials WHERE user_id IN ( SELECT user_id FROM users WHERE username = 'admin@kasm.local' ); > \q > ``` 3. Login to the Workspaces UI using "admin@kasm.local" with the password "password" and reset your password to a secure password. ![Reset Password Location](/img/admin_account_recovery/password_change.webp) --- ## Kasm Workspaces: Data Loss Prevention (DLP) Guide # Data Loss Prevention There are many features of the Kasm Workspaces platform that lend themselves to the goal of preventing users from either taking data out of the Kasm Workspaces environment to their local system or from transferring data from their local system to the Kasm Workspaces environment. This guide covers the many disparate features and how they can be used together with these goals in mind. ## Group Settings Many features can be configured via [group settings](users-groups-mgmt/groups.mdx). Users can belong to multiple groups, overlapping settings are applied using the group's configured priority. The Group with the lower priority value takes precedent. This table covers the group settings which are related to data loss prevention. For example, allowing audio in and out provides additional avenues of potential data exhilaration. | allow_kasm_audio | Allow audio streaming for a Kasm. | | --- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | allow_kasm_clipboard_down | Allows users to paste text from the Kasm to their local computer. | | allow_kasm_clipboard_seamless | Allows users to copy and paste text without using Kasm control panel. This feature is only available on Chrome and Chromium-based client browsers | | allow_kasm_clipboard_up | Allow users to paste from their local computer to the Kasm. | | allow_kasm_downloads | Allow users to download files from a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_kasm_gamepad | Allow users to pass local gamepads into the Kasm session. See [Gamepad Passthrough](../workspaces-sessions/container-workspace/gamepad-passthrough.mdx) for more details. | | allow_kasm_microphone | Allow microphone passthrough to a Kasm. When enabled, users can pass their local microphone through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_kasm_printing | Allow printing of documents using local printers | | allow_kasm_rdp_client_file_transfer_clipboard | This setting only applies to RDP client Kasm sessions. In RDP file transfers are part of the clipboard and independent directional control of file transfers is not possible. This setting will enable file transfer in the directions that text clipboard has been enabled via **allow_kasm_clipboard_down** and **allow_kasm_clipboard_up**. | | allow_kasm_rdp_map_local_drives | Allow sessions using the RDP Gateway to map client local drives into the RDP target. This setting is an all or nothing setting. When enabled it will map all client drives into the rdp session. | | allow_kasm_sharing | Allow the user to share access to their session with other users. See [Session Sharing](../workspaces-sessions/sessions/session-sharing.mdx) for more details. | | allow_kasm_uploads | Allow users to upload files to a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_kasm_webcam | Allow webcam passthrough to a Kasm. When enabled, users can pass their local webcam through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_persistent_profile | Allow the use of persistent profiles if configured on the Workspace. See [Persistent Profiles](../data-storage/persistent-profiles.mdx) for details | | allow_user_storage_mapping | When enabled the user is allowed to configure their own [Storage Mappings](../data-storage/storage-mappings/index.mdx) via their profile. When disabled, new user configurations will not be allowed, nor will using any previously configured mappings be allowed when new sessions are created. | | enable_ui_server_logging | If enabled, log messages will be sent from client browser to the Kasm Workspaces server. | | expose_user_environment_vars | Expose KASM_USER and KASM_USER_ID environment variables inside the Kasm. | | session_time_limit | The amount of time (in seconds) a session will automatically expire. A countdown timer will be displayed to the user. | | usage_limit | Limits the total number of hours a user or group can have running sessions. **Type** - **Per User** - Each user of the group has their own limit. - **Per Group** - All members share the usage limit. **Interval** - **Daily** , **Weekly** , **Monthly** , **Total**. **Hours** - The number of hours allowed during each interval. | | web_filter_policy | Enabled web filtering and sets the [Web Filter Policy](web-filtering.mdx) to be used. Policies can also be set or force disabled on Workspaces. Policies assigned to Workspaces take priority over those defined via Group Settings. | ## KasmVNC DLP Policy While group settings provide basic on/off capability for features like the clipboard, KasmVNC DLP Policies allow for a greater level of control. For example, KasmVNC DLP settings allow for defining rate limits for the clipboard and keyboard input. For a full reference of the KasmVNC YAML configuration, see the [KasmVNC Docs](https://www.kasmweb.com/kasmvnc/docs/latest/configuration.html). See our how-to guide on [Applying KasmVNC DLP Policies](../workspaces-sessions/container-workspace/kasmvnc-dlp-policies.mdx) to a Kasm Workspaces by utilizing the [File Mapping](../workspaces-sessions/file-mappings.mdx) feature. The following shows the default settings for the DLP section of the KasmVNC configuration. For a detailed explanation of all settings, see the [KasmVNC Docs, DLP Section](https://www.kasmweb.com/kasmvnc/docs/latest/configuration.html#data-loss-prevention). ```yaml data_loss_prevention: visible_region: # top: 10 # left: 10 # right: -40 # bottom: -40 concealed_region: allow_click_down: false allow_click_release: false clipboard: delay_between_operations: none allow_mimetypes: - chromium/x-web-custom-data - text/html - image/png server_to_client: enabled: true size: unlimited primary_clipboard_enabled: false client_to_server: enabled: true size: unlimited keyboard: enabled: true rate_limit: unlimited logging: level: off watermark: # image: /etc/kasmvnc/picture.png # location: 10,10 # tint: 255,20,20,128 # repeat_spacing: 10 ``` ## RDP DLP Policy In addition to the existing Data Loss Prevention (DLP) capabilities within KasmVNC, the platform extends its security measures to Remote Desktop Protocol (RDP) sessions by providing both text and image based watermarking remote desktop access. For more details, see [RDP Session Watermarking](../../reference/settings.mdx#rdp-session-watermarking). ## Web URL Filter The built-in [Web Filter](web-filtering.mdx) feature allows the administrator to easily define and enforce URL filtering that is applied to Kasm Workspaces container based sessions. Using these policies you can, for example, ensure that users are unable to visit file sharing sites or only visit a whitelist of websites from inside a Kasm Workspaces session. ## Environmental Variables Container based Workspace environments have environmental variables that can be set in the [Workspace](../workspaces-sessions/container-workspace/workspaces.mdx) definition under the **Docker Run Config Override** setting. The following table shows a listing of available environmental variables that are applicable to DLP for containerized Workspace environments. | Name | Default | Description | |------|---------|-------------| | DLP_PROCESS_FAIL_SECURE | not set | If set to a value of `1`, the container will restart on the failure of any Kasm service running on the container. See the subsection below for more details. | | KASM_SVC_AUDIO | not set | If set to `0`, the audio out service is not started. This provides additional protection, above disabling audio output in Kasm group settings, by reducing the attack surface area of the container and potential data extraction vectors. | | KASM_SVC_AUDIO_INPUT | not set | If set to `0`, the audio in service is not started. This provides additional protection, above disabling audio input in Kasm group settings, by reducing the attack surface area of the container and potential data extraction vectors. | | KASM_SVC_UPLOADS | not set | If set to `0`, the upload in service is not started. This provides additional protection, above disabling uploads in Kasm group settings, by reducing the attack surface area of the container and potential data extraction vectors. | | KASM_SVC_GAMEPAD | not set | If set to `0`, the gamepad in service is not started. This provides additional protection, above disabling gamepad support in Kasm group settings, by reducing the attack surface area of the container and potential data extraction vectors. | ### Service Fail Secure Container based Workspace images have a number of services running that support audio in, audio out, uploads, KasmVNC, game pad, and other features. When one of these processes crash unexpectedly, the default behavior is to merely restart them. When DLP_PROCESS_FAIL_SECURE is enabled, the entire container will instead restart. When the container restarts, all processes are terminated and everything in RAM is lost. Everything on disk will persist once the container restarts. This mode of recovery ensures that potential memory resident malware is lost, but work written to the disk can be recovered. The following **Docker Run Override** setting on a Workspace image shows an example of enabling the `DLP_PROCESS_FAIL_SECURE` feature. ```json { "hostname": "kasm", "environment": { "DLP_PROCESS_FAIL_SECURE": 1 } } ``` The following shows how to also disable the restart policy on the container, this will result in the container being immediately destroyed if a Kasm service process terminates during runtime. ```json { "hostname": "kasm", "environment": { "DLP_PROCESS_FAIL_SECURE": 1 }, "restart_policy": { "Name": "no" } } ``` --- ## Securing Docker: STIG Compliance & Hardening # Docker Kasm Workspaces requires Docker and will install Docker if it is not already installed on the system. Organizations should consider this before installing Kasm, especially in offline environments. The standard Ubuntu 22.04 LTS and newer APT repository already has a version of Docker that is new enough to be used with Kasm Workspaces. For offline environments, we recommend that you install Docker from the APT repository prior to installing Kasm. This will ensure the offline system will be able to patch docker from your organization's internal APT repository. ```bash sudo apt-get install docker.io ``` To fully pass Docker STIGs, you must install Kasm on a non-default (443) port using the -L option, in addition to other options required for your specific deployment. ```bash sudo bash kasm_release/install.sh -L 8443 ``` Kasm Technologies has created [open-source hardening scripts](https://github.com/kasmtech/workspaces-stigs). The project includes one script that hardens the Docker daemon configuration and the other that hardens the Docker runtime of Kasm. Both scripts are targeting the DISA Docker Enterprise STIG checklist. The scripts also output a list of STIGs with vulnerability IDs and a pass/fail status. This can be used as an artifact for STIG checklists. Follow the instructions provided in the README of the project page. The following table lists all Docker EE STIGs and CIS Docker CE Benchmarks that are either fixed by the Kasm hardening scripts or that pass by default assuming the system was clean prior to installing Kasm. This has been tested on clean installs of Ubuntu 22.04LTS. | Vuln ID | CIS ID | |----------|------------| | V-235812 | 2.16, 5.21 | | V-235816 | 2.18, 5.25 | | V-235851 | 3.1 | | V-235861 | 3.11 | | V-235864 | 3.14 | | V-235865 | 3.15 | | V-235866 | 3.16 | | V-235867 | 3.17 | | V-235868 | 3.18 | | V-235869 | 3.19 | | V-235870 | 3.20 | | V-235853 | 3.3 | | V-235855 | 3.5 | | V-235859 | 3.9 | | V-235809 | 5.17 | | V-235817 | 5.30 | | V-235818 | 5.31 | | V-235805 | 5.9 | | V-235807 | 5.11 | | V-235791 | 2.15 | | V-235790 | 2.5 | | V-235844 | 2.7 | | V-235815 | 2.9, 5.24 | | V-235830 | 4.1 | | V-235827 | 4.6, 5.26 | | V-235799 | 5.1 | | V-235806 | 5.10 | | V-235820 | 5.13 | | V-235784 | 5.15 | | V-235785 | 5.16 | | V-235810 | 5.19 | | V-235811 | 5.20 | | V-235828 | 5.28 | | V-235801 | 5.3 | | V-235802 | 5.4 | | V-235837 | 5.8 | | V-235831 | | | V-235804 | | | | 2.6 | | V-235800 | 5.2 | | V-235783 | 5.5 | | V-235803 | 5.6 | | V-235813 | 5.22 | | V-235792 | 2.17 | | V-235814 | 5.23 | | | 2.10 | | | 2.3 | | | 7.1 | The following list of STIGs/CIS checks pass after running the Kasm hardening script or pass by default, however, they have additional notes that need to be considered per your specific deployment and security requirements. | Vuln ID | CIS ID | Explanation | |---|---|---| | V-235786 | 5.1 | The documented fix for this STIG is not compatible with all versions of Docker, therefore, it was removed from our hardening script. Clients will need to manually add this setting to the daemon.json file, if the version of Docker that is installed supports this feature. | | V-235808 | 5.12 | All Kasm service containers pass this check after the apply_kasm_stigs.sh script is ran on all Kasm systems. However, user Workspace containers are not set to read only. This is not practical on a desktop. We believe this check is intended and practical for the 99% of the use cases of docker, however, it does not apply nor is it intended for Desktop containers. If the authorizing official is not satisfied with this explanation, then there are two potential courses of action: 1) Use full stack VMs for user desktops (now supported by Kasm). Since a full stack VM would also not use a read-only file system, nor is there a STIG that requires this for a desktop operating system. We feel this solution provides no security benefit as related to this particular STIG, but it does bypass the STIG since user desktops would use VMs instead of containers. 2) An exception to policy. | | V-235860 | 3.10 | This check is applied by the apply_kasm_stigs.sh script, however, it is missing from the script output. Perform this command to validate, 'ls -l /etc/docker/certs' | | V-235862 | 3.12 | This check is applied by the apply_kasm_stigs.sh script, however, it is missing from the script output. Perform this command to validate, 'ls -l /etc/docker/certs' | | V-235863 | 3.13 | This check is applied by the apply_kasm_stigs.sh script, however, it is missing from the script output. Perform this command to validate, 'ls -l /etc/docker/certs' | | V-235833 | | See section on enterprise logging. | | | 2.12 | See section on enterprise logging. | | V-235800 | 5.2 | This is N/A for Ubuntu systems, which use AppArmor profiles instead. If SELinux is enabled by default in RHEL compatibale Operating Systems (i.e Rocky Linux), it is not disabled by Kasm. Therefore, systems should be compliant by default under normal curcumstances. | | V-235783 | 5.5 | The apply_docker_stigs.sh script will report if the system passes, but will not alter the system. | | V-235803 | 5.6 | The apply_docker_stigs.sh script will report if the system passes, but will not alter the system. | | V-235872 | 7.4 | Kasm Workspaces does not rely on Docker for underlying communications between containers on different nodes. All communications between componets on different nodes is encrypted with TLS. | | | 1.4 | Kasm does not add any users to the docker group, therefore, this check should pass unless you have modified the system. | | | 2.1 | Kasm does not use the default docker network for service containers or user containers. DO NOT implement the CIS recommended fix of disabling inter-container traffic at the dockerd level, this would break Kasm. If you are using the host only for Kasm, then this check is passed by default as the default docker network would not be used. Otherwise, you need to disable inter-contaienr communications only for the default network. | | | 2.8 | By default and with the STIG scripts applied, all containers run as an explicit user that is explicitly mapped to a known user on the host. The audit check says to look for containers running as a user that maps to root on the host. Again, by default and with STIG scripts applied, this would not be the case. It is still possible to configure a Kasm Workspace to run as root, see Check column. | | | 4.2 | A default installation will use all Kasm maintained images or official vendor maintained images for third party containers such as NGINX, and Postgres. The admin can define user Workspaces that use a non-Kasm maintained image. See the check column for details. | | V-235832 | | This is N/A on the latest version of Docker, as the max-file and max-size options are not supported by the log-drivers required by V-235831 | ## Docker Enterprise Kasm does not require Docker Enterprise and installs Docker CE if it is not already installed. If you decide to use Docker CE, you must then choose whether to apply the CIS Benchmarks for Docker CE, or use the DISA STIGs for Docker EE and mark checks as N/A where they apply only to EE. The STIG checklist refers to Docker **Enterprise** throughout, however, you must read the checks carefully to determine if they would apply to CE. The table we provide clearly marks which ones we believe only apply to Docker Enterprise, however, you will need to make that determination for yourself. ## Enterprise Logging and Audit Rules Both the DISA STIGs and CIS Benchmarks have you apply various configurations related to logging and audit rules. Some of these settings are at the docker daemon level and some are at the system level. Our guide assumes that your system is hardened and already meets operating system level STIGs which already enforce centralized logging for syslog as well as auditd installation and configuration. Our hardening script will configure dockerd to forward logs using syslog to 127.0.0.1:25224 over UDP. This allow the host to pass automated checks based on the DISA audit commands, however, this in and of itself is not enough to complete the configuration. You must either configure each host to listen on that port and then forward the logs, or you must change the /etc/docker/daemon.json configuration to forward the logs to another server. Another option would be to configure dockerd to log to a [json file](https://docs.docker.com/config/containers/logging/configure/), and then use a logging agent to forward the logs to a centralized logging solution. Once the logs are forwarded to a centralized logging solution, you should meet the controls related to alerts, assuming your enterprise logging solution is already configured to provide such alerting. To meet all STIG and CIS Benchmarks related to auditd rules, ensure the following lines are in /etc/audit/audit.rules: ```bash -w /usr/bin/docker -k docker -w /var/lib/docker -k docker -w /etc/docker -k docker -w /usr/lib/systemd/system/docker.service -k docker -w /usr/lib/systemd/system/docker.socket -k docker -w /etc/default/docker -k docker -w /etc/docker/daemon.json -k docker -w /usr/bin/docker-containerd -k docker -w /usr/bin/docker-runc -k docker ``` Then restart the audit daemon. ```bash service auditd restart ``` Kasm application logs are covered in the Kasm Workspaces section. ## Docker Swarm Kasm Workspaces does not require or configure Docker Swarm. With a default installation of Kasm and Docker, with our hardening scripts ran, the Docker Swarm checks should be N/A. --- ## Host-Based Security & Iptables Configuration # Host Based Security Protection Products such as HBSS may be required to install on the servers Kasm is running on. Products like HBSS will control iptables. This can result in confusion, since Docker and firewalld also control iptables. Ensure that both TCP ports 2375 and the port Kasm has been configured to listen on, are allowed by your host based security product. In our experience, iptables can occasionally get into a bad state, where HBSS, firewalld, and Docker are all modifying IP tables. Symptoms such as containers not being able to communicate outbound or receive inbound traffic can occur. Clearing all iptables rules and restarting docker usually clears up these issues. When docker restarts, it will reconstruct all iptables rules applicable to docker and containers it manages. Restarting firewalld may be required to rebuild rules managed by firewalld. Consult your HBSS documentation for guidance with HBSS. --- ## Security Overview: Hardening & Configuration # Security The Workspaces platform is a powerful and flexible system that can be configured and used in many different scenarios. This guide covers many different topics related to security, to include hardening of Docker, Postgres, underlying systems and the Kasm Workspaces configuration. This guide will also answer common security related questions that organizations have. Many organizations are required to implement secure baseline configuration, such as [DISA STIGs](https://public.cyber.mil/stigs/) or [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks/). There are existing STIG checklists and CIS Benchmarks for the components and/or dependencies used by Kasm. Kasm follows general DISA guidance provided in the [Application Security and Development Security STIGs](https://stigviewer.com/stigs/application_security_and_development) for the Kasm Workspaces product and our configuration guidance. --- ## Hardening Guide: Security Best Practices # Kasm Workspaces The following guide is an official hardening checklist for Kasm. Per DISA guidance, you may use the vendor provided hardening baseline guidance when applicable STIGs are not available. ## Global Settings The following tables cover [settings](../../reference/settings.mdx) that should be checked along with their default value and hardened value. After hardening of global settings, all Kasm services should be restarted. **Authentication** | Name | Severity | Default Setting | Recommended Setting | Rationale | |------|----------|-----------------|---------------------|-----------| | Enable Kasm Authorization | Critical | True | True | This is in reference to authentication of HTTPS requests that are sent to the user's container. Disabling Kasm Authentication would allow unauthenticated access to user container sessions. | | Kasm Authorization Domain | Low | $request_host$ | The domain name used by users to access the system. | Kasm dynamically uses the domain name in the user request. Using a hard coded domain name is more explicit and removes a potential attack vector. | | Max Login Attempts | Low | 5 | 3 | This applies only to Kasm Local Accounts. A setting of 3 is more in line with STIG guidance. | | Notice Message | Low | Empty | Organization required banner. | DoD STIGs and other guidance usually requires a login Banner. | | Session Lifetime | Medium | 288000 | 3600 | A user's token is refreshed every 5 minutes when actively using the application. If the user is idle, they will automatically be logged off after the idle session timeout, which is a group setting. If the user ungracefully terminates their browser, the token will not get refreshed and they will also not get auto logged off. This setting ensures the token is only good for 1 hour after the last refresh. | **Images** | Name | Severity | Default Setting | Recommended Setting | Rationale | |------|----------|-----------------|---------------------|-----------| | Add Images to Default Group | High | True | False | New Workspaces are automatically added to the All Users group, essentially giving all users access to all Workspaces. This might make sense for small deployments, however, in an Enterprise grade environment, Workspaces should be manually added to groups ensuring access management is explicitly granted by an administrator. | **Logging** By default, Kasm forwards all logs to managers, which then log them to the database. The database logs are fine for small deployments, however, they are not appropriate to meet enterprise grade logging, auditing, and alerting requirements. Kasm supports forwarding logs to Splunk using the Splunk native HEC protocol. This can be configured in the server global settings. A restart of each web app role server services is required after changing the global log settings. The alternative is to use a log forwarding agent on each server, such as logstash or Splunk Forwarder. Kasm stores all logs at `/opt/kasm/current/log` in both raw and json format. It is recommended to forward the json formatted files. Kasm utilizes rotated logs, therefore, it is only necessary to forward the current log file for each log file series. With centralized logging configured, the following settings can be used, which will reduce burden on the database. | Name | Default Setting | Recommended Setting | Rationale | |------|-----------------|---------------------|-----------| | Debug Log Retention | 4 | 0 | Large deployments will produce large amounts of debug logs that will overwhelm the database. With log forwarding configured, debug logs can be dropped from database logging. | | Log Host | | Hostname or IP address of Splunk HEC receiver | Configure if using Kasm's built in support for Splunk HEC log forwarding. | | Log Port | | The port number used by the Splunk HEC receiver | Configure if using Kasm's built in support for Splunk HEC log forwarding. | | Log Protocol | internal | splunk | Configure if using Kasm's built in support for Splunk HEC log forwarding. | | Log Retention | 7 | 5 | This controls the number of days worth of logs to keep in the Kasm database. With log forwarding configured, this can be reduced. Larger deployments should use a lower value. A value of 0 can be used to completely disable storing logs in the database. | **Manager** | Name | Severity | Default Setting | Recommended Setting | Rationale | |------|----------|-----------------|---------------------|-----------| | Update Check | Medium | True | False | Kasm periodically checks for updates and makes an API call to a public endpoint managed by Kasm. The API contains only the installation ID. For offline or internet restricted environments, this should be disabled. | ## Group Settings A user can belong to multiple groups. [Group Settings](users-groups-mgmt/groups.mdx#group-settings) are aggregated for all groups a user belongs to. Most settings can only be applied once, in which case the Group with the lowest priority value takes precedent. You can view a user's effective groups and group settings by viewing a user in the Users panel in the Admin dashboard. We recommend using the All Users group to define the most restrictive set of group settings. To override with less restrictive group settings, merely define the same setting on a group with a lower priority. The following table defines the recommended settings and values to be placed on the **All Users** group. This table only includes settings we believe are required under the general [Application Security and Development Security STIGs](https://stigviewer.com/stigs/application_security_and_development). Other values should also be set based on your organizations requirements, such as whether to allow audio in and out, clipboard in and out, uploads and downloads, and other settings. Some settings, such as password_expires, only apply to local user accounts and are not shown in the below table. To meet STIG requirements, an external authentication provider must be used, see the Authentication section for more details. | Name | Recommended Setting | Rationale | |------|---------------------|-----------| | idle_disconnect | 20 | The user will be logged out after this many minutes of no interaction. | | shared_session_full_control | False | Allows users to share their session with other users and provide full control of the desktop. | ## Workspace Images Kasm maintains three tags for each version of a Kasm Workspace image. One tag is the version, such as 'kasmweb/ubuntu-jammy-desktop:[[release]]', where [[release]] is the version. This version only tag is a point in time release that is never updated. The second tag has '-rolling-daily' on the end, such as 'kasmweb/ubuntu-jammy-desktop:[[release]]-rolling-daily', these rolling daily tagged images are updated daily. The third tag has '-rolling-weekly' on the end, these rolling weekly tagged images are updated weekly. If the Kasm Workspace definitions are configured to point to a Docker Registry, Kasm will automatically pull updates and start using them for new sessions. By default, Kasm uses the non-rolling tagged images. The reason for using non-rolling images is to ensure reliability for production environments. For security purposes, the use of rolling tags are recommended, however, for production environments, it is recommended to test image updates prior to updating. Many use cases will require the need for [custom images](../workspaces-sessions/container-workspace/customization/building-images.mdx), which are based on one of our core docker images. We recommend basing your images from a rolling tagged image. Kasm admins can create a "staging" Workspace for testing new image updates, prior to updating production Workspaces. We recommend using automated [CI/CD](../workspaces-sessions/container-workspace/image-maintenance.mdx) pipelines, to create the custom images, and to perform automated scans of the resulting images. ## Authentication In order to meet general requirements under the [Application Security and Development Security STIGs](https://stigviewer.com/stigs/application_security_and_development), you must use an external identity provider for authentication. Kasm supports [LDAP](users-groups-mgmt/ldap.mdx), [SAML](users-groups-mgmt/saml-authentication.mdx), and [OIDC](users-groups-mgmt/oidc.mdx) for authentication providers. The default local accounts will still be defined in Kasm. You should delete user@kasm.local in the Users table. Keeping the default admin@kasm.local would allow emergency access, should the external authentication provider be down. Kasm has built in MFA that can be used for local accounts and alerts could be established for login events for this user, with a central logging solution such as Splunk. Additionally, you could delete admin@kasm.local and create a different local account with a more obscure name that is not a known default username. These security controls can help mitigate the risk of leaving the default local account on the system. Check with your security team for guidance. --- ## Security-Focused Operating System Setup # Operating System Kasm Workspaces requires underlying Linux systems to run on. While Workspaces will run on a number of Linux based operating systems, organizations that are concerned with security and/or having to run in an air-gapped network without internet access, typically have more restrictions that will dictate which underlying operating system to use. The US Federal Government and Department of Defense (DoD) have historically been tied to RedHat, however that changed when DISA released a STIG checklist for [Ubuntu Pro](https://ubuntu.com/security/disa-stig), which was specifically created to help organizations meet FedRAMP, FISMA, FIPS and/or DISA-STIG compliance. Current STIG documentation from the DoD can be obtained on [its official public portal](https://www.cyber.mil/stigs/downloads). [Stigviewer](https://stigviewer.com/) is a community tool that provides a user-friendly interface for working with STIGs. The Kasm Technologies recommended operating system for organizations that need to meet DISA STIG requirements or NIST 800-53 controls in general, is Ubuntu 22.04 LTS with a strong preference for the paid support version, which is required to enable FIPS enforcement. Kasm Technologies has worked directly with many different DoD organizations using both Red Hat and Ubuntu 22.04 LTS and this recommendation is based on our experience. Kasm Technologies does **not** support the underlying operating system or the hardening of the operating system. The following table lists hardening requirements on the underlying operating system which need to be considered carefully on systems that support Kasm Workspaces: | Name | Severity | Summary | Caution | |------|----------|---------|---------| | [V-260517](https://stigviewer.com/stigs/canonical_ubuntu_22.04_lts/2025-03-03/finding/V-260517) | Medium | Configure rate limiting on the host-based firewall. | All Kasm components use HTTPS for client communication and inter-service communications. Given that Kasm is a server application that handles requests from many users, a high limit should be used on the Kasm port. The default port is 443, but per this guide, you should use a high port number during installation. The DISA documented method for rate limiting using ufw on Ubuntu is an on or off proposition. Kasm's recommendation is to place rate limiting on a traditional firewall in the security stack and/or the front-end reverse proxy. If rate limiting on each server is absolutely required, you will need to manually edit iptables, rather than using ufw for the port Kasm is listening on, in order to specify what the limits should be. A higher limit should be chosen, to accommodate high traffic demands expected for your deployment. | | [V-257939](https://stigviewer.com/stigs/red_hat_enterprise_linux_9/2025-02-27/finding/V-257939) | Medium | Configure rate limiting on the host-based firewall. | All Kasm components use HTTPS for client communication and inter-service communications. Given that Kasm is a server application that handles requests from many users, it would not be wise to rate limit the port Kasm listens on. The default port is 443, but per this guide, you should use a high port number during installation. A higher limit should be chosen for the port Kasm is listening on, to accommodate high traffic demands expected for your deployment. | --- ## Kasm Workspaces: PostgreSQL STIG Compliance & Security # Postgres Kasm Workspaces uses the official Postgres Docker image, which does not include the optional PG_AUDIT module required to meet many of the STIG requirements. The following table lists which STIGs pass with the default Kasm configuration and which require the optional pg_audit module. There are two options to meet the pg_audit checks. The first option is to use an external database, rather than the containerized version used for Kasm by default. Kasm currently ships with Postgres version 14. Kasm will also operate on Postgres compatible solutions such as AWS RDS, AWS Aurora, AWS Aurora Serverless V2, MS Azure Database for Postgres, and similar platforms. See our documentation on using an [external database](../../tutorials/install/remote-database.mdx). The second option is to use the Kasm Technologies maintained Postgres container, which includes the PG_AUDIT module. The [open-source project](https://github.com/kasmtech/kasm-db) for this Docker image, contains the instructions needed alter a deployment to use it. After the deployment is running on this database container, you will be able to edit the postgres configuration to meet the remaining STIG requirements. | Finding ID | Status | Severity | Title | Notes | |---|---|---|---|---| | [V-233511](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233511) | Pass | Medium | PostgreSQL must be configured to prohibit or restrict the use of organization-defined functions, ports, protocols, and/or services, as defined in the PPSM CAL and vulnerability assessments. | | | [V-233512](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233512) | pg_audit | Medium | PostgreSQL must produce audit records containing sufficient information to establish the outcome (success or failure) of the events. | | | [V-233513](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233513) | Pass (See Notes) | High | Security-relevant software updates to PostgreSQL must be installed within the time period directed by an authoritative source (e.g., IAVM, CTOs, DTMs, and STIGs). | On installation and upgrades to Kasm, the latest minor release for the current major version of Postgres used is pulled. | | [V-233514](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233514) | Pass | Medium | The audit information produced by PostgreSQL must be protected from unauthorized modification. | | | [V-233515](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233515) | See Notes | High | PostgreSQL must integrate with an organization-level authentication/access mechanism providing account management and automation for all users, groups, roles, and any other principals. | Kasm does not recommend nor support using another authentication provider for the kasmapp account used for service authentication to the database. The fix text does say that accounts that use authentication methods other than gss, sspi, or ldap should be docuemented with justification. Work with your ISSO to document the use of local authentication for the kasmapp account, used by Kasm micro services for authentication in your systems SSP. | | [V-233516](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233516) | Pass | Medium | PostgreSQL must provide non-privileged users with error messages that provide information necessary for corrective actions without revealing information that could be exploited by adversaries. | | | [V-233517](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233517) | Pass | Medium | Privileges to change PostgreSQL software modules must be limited. | | | [V-233518](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233518) | Pass | Medium | PostgreSQL must limit privileges to change functions and triggers, and links to software external to PostgreSQL. | | | [V-233519](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233519) | Pass | High | If passwords are used for authentication, PostgreSQL must transmit only encrypted representations of passwords. | | | [V-233520](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233520) | Pass | High | PostgreSQL must enforce approved authorizations for logical access to information and system resources in accordance with applicable access control policies. | | | [V-233521](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233521) | N/A (See Notes) | Medium | PostgreSQL must associate organization-defined types of security labels having organization-defined security label values with information in transmission. | The Kasm API service and manager service are the only services with access to the database. These services make decisions and enforce access to row level data. These enforcements are based on user group membership. For this reason, security labeling at the database level is not required. Per the check text, this STIG only applies if labeling is required. | | [V-233522](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233522) | Pass | Medium | PostgreSQL must limit the number of concurrent sessions to an organization-defined number per user for all accounts and/or account types. | | | [V-233523](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233523) | | Medium | The role(s)/group(s) used to modify database structure (including but not necessarily limited to tables, indexes, storage, etc.) and logic modules (functions, trigger procedures, links to software external to PostgreSQL, etc.) must be restricted to authorized users. | | | [V-233524](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233524) | Pass (See Notes) | Medium | PostgreSQL must uniquely identify and authenticate non-organizational users (or processes acting on behalf of non-organizational users). | By default, the Kasm Postgres database has only one user, used by the Kasm micro services. If admin access for individual users is required, you will need to define them. | | [V-233525](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233525) | N/A (See Notes) | Medium | PostgreSQL must associate organization-defined types of security labels having organization-defined security label values with information in storage. | The Kasm API service and manager service are the only services with access to the database. These services make decisions and enforce access to row level data. These enforcements are based on user group membership. For this reason, security labeling at the database level is not required. Per the check text, this STIG only applies if labeling is required. | | [V-233526](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233526) | N/A (See Notes) | Medium | PostgreSQL must check the validity of all data inputs except those specifically identified by the organization. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. The use of an ORM library ensures that database input is sanitized and meets validity checks prior to being written to the database. | | [V-233527](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233527) | N/A (See Notes) | Medium | PostgreSQL and associated applications must reserve the use of dynamic code execution for situations that require it. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. The use of an ORM library ensures that database input is sanitized and meets validity checks prior to being written to the database. | | [V-233528](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233528) | N/A (See Notes) | Medium | PostgreSQL and associated applications, when making use of dynamic code execution, must scan input data for invalid values that may indicate a code injection attack. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. The use of an ORM library ensures that database input is sanitized and meets validity checks prior to being written to the database. | | [V-233529](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233529) | | Medium | PostgreSQL must allocate audit record storage capacity in accordance with organization-defined audit record storage requirements. | Kasm writes postgres logs to /opt/kasm/current/log/postgres, ensure this location has space required and that logs are forwarded to a centralized logging solution. | | [V-233530](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233530) | | Medium | PostgreSQL must enforce discretionary access control policies, as defined by the data owner, over defined subjects and objects. | | | [V-233531](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233531) | Pass | Medium | The audit information produced by PostgreSQL must be protected from unauthorized deletion. | | | [V-233532](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233532) | Pass | Medium | PostgreSQL must record time stamps, in audit records and application data, that can be mapped to Coordinated Universal Time (UTC, formerly GMT). | | | [V-233533](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233533) | Pass | Medium | PostgreSQL must reveal detailed error messages only to the ISSO, ISSM, SA and DBA. | | | [V-233534](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233534) | | Medium | PostgreSQL must allow only the ISSM (or individuals or roles appointed by the ISSM) to select which auditable events are to be audited. | | | [V-233535](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233535) | | Medium | PostgreSQL must provide an immediate real-time alert to appropriate support staff of all audit log failures. | Kasm writes postgres logs to /opt/kasm/current/log/postgres, ensure this location has space required and that logs are forwarded to a centralized logging solution with proper alerting. | | [V-233538](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233538) | | Medium | PostgreSQL must maintain the confidentiality and integrity of information during reception. | SSL Client certificat authentication is not configured by default. Per the STIG guideance, work with your ISSO to properly document the exception or configure SSL Client cert authentication. | | [V-233539](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233539) | | Medium | Database objects (including but not limited to tables, indexes, storage, trigger procedures, functions, links to software external to PostgreSQL, etc.) must be owned by database/DBMS principals authorized for ownership. | | | [V-233540](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233540) | | High | The PostgreSQL software installation account must be restricted to authorized users. | | | [V-233541](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233541) | Pass | Medium | Database software, including PostgreSQL configuration files, must be stored in dedicated directories separate from the host OS and other applications. | | | [V-233542](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233542) | pg_audit | Medium | PostgreSQL must include additional, more detailed, organization-defined information in the audit records for audit events identified by type, location, or subject. | | | [V-233543](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233543) | N/A (See Notes) | Medium | Execution of software modules (to include functions and trigger procedures) with elevated privileges must be restricted to necessary cases only. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. | | [V-233544](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233544) | Pass | Medium | When invalid inputs are received, PostgreSQL must behave in a predictable and documented manner that reflects organizational and system objectives. | The kasm postgres database is configured to log syntax errors in SQL commands as shown in this findings check text. The Kasm application has exception handling and will log SQL syntax errors in the Kasm application logs as well. | | [V-233610](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233610) | See Notes | Medium | PostgreSQL must utilize centralized management of the content captured in audit records generated by all components of PostgreSQL. | The kasm postgres database is configured to log to file at /opt/kasm/current/log/postgres. There will be a log file for each day. A log forwarder should be installed and confirgured to forward those logs to a centralized logging solution. | | [V-233546](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233546) | | Medium | PostgreSQL must isolate security functions from non-security functions. | | | [V-233547](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233547) | pg_audit | Medium | PostgreSQL must produce audit records of its enforcement of access restrictions associated with changes to the configuration of PostgreSQL or database(s). | | | [V-233549](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233549) | Pass | Medium | The audit information produced by PostgreSQL must be protected from unauthorized read access. | The kasm postgres database is configured to log to file at /opt/kasm/current/log/postgres. Files at this location have 0600 permissions and are owned by the kasm_db (postgres) user. | | [V-233550](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233550) | Pass | Medium | When updates are applied to PostgreSQL software, any software components that have been replaced or made unnecessary must be removed. | Since Kasm uses a containerized database, updates to Postgres replace the entire container, thus no old components are left behind. | | [V-233551](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233551) | pg_audit | Medium | PostgreSQL must generate audit records when categorized information (e.g., classification levels/security levels) is accessed. | | | [V-233552](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233552) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to access security objects occur. | | | [V-233553](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233553) | See Notes | Medium | PostgreSQL must generate audit records when unsuccessful logons or connection attempts occur. | Edit /opt/kasm/current/conf/database/postgres.sql, change log_disconnections to on and log_connections to on.. Do not alter the current log_line_prefix as the configured format meets multiple STIGs including this one. | | [V-233554](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233554) | See Notes | Medium | PostgreSQL must generate audit records showing starting and ending time for user access to the database(s). | Edit /opt/kasm/current/conf/database/postgres.sql, change log_disconnections to on and log_connections to on.. Do not alter the current log_line_prefix as the configured format meets multiple STIGs including this one. | | [V-233555](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233555) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to modify security objects occur. | | | [V-233556](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233556) | pg_audit | Medium | PostgreSQL must generate audit records when privileges/permissions are added. | | | [V-233557](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233557) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to delete categorized information (e.g., classification levels/security levels) occur. | | | [V-233558](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233558) | See Notes | Medium | PostgreSQL must generate audit records when successful logons or connections occur. | Edit /opt/kasm/current/conf/database/postgres.sql, change log_disconnections to on and log_connections to on.. Do not alter the current log_line_prefix as the configured format meets multiple STIGs including this one. | | [V-233559](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233559) | pg_audit | Medium | PostgreSQL must generate audit records when security objects are deleted. | | | [V-233560](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233560) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to retrieve privileges/permissions occur. | | | [V-233561](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233561) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to delete privileges/permissions occur. | | | [V-233562](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233562) | pg_audit | Medium | PostgreSQL must be able to generate audit records when privileges/permissions are retrieved. | | | [V-233563](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233563) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to modify categorized information (e.g., classification levels/security levels) occur. | | | [V-233564](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233564) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful accesses to objects occur. | | | [V-233565](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233565) | pg_audit | Medium | PostgreSQL must generate audit records for all privileged activities or other system-level access. | | | [V-233566](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233566) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to access categorized information (e.g., classification levels/security levels) occur. | | | [V-233567](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233567) | pg_audit | Medium | PostgreSQL must be able to generate audit records when security objects are accessed. | | | [V-233568](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233568) | pg_audit | Medium | PostgreSQL must generate audit records when privileges/permissions are deleted. | | | [V-233569](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233569) | See Notes | Medium | PostgreSQL must generate audit records when concurrent logons/connections by the same user from different workstations occur. | Edit /opt/kasm/current/conf/database/postgres.sql, change log_disconnections to on and log_connections to on.. Do not alter the current log_line_prefix as the configured format meets multiple STIGs including this one. | | [V-233570](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233570) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to delete security objects occur. | | | [V-233571](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233571) | pg_audit | Medium | PostgreSQL must generate audit records when privileges/permissions are modified. | | | [V-233572](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233572) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to execute privileged activities or other system-level access occur. | | | [V-233573](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233573) | pg_audit | Medium | PostgreSQL must generate audit records when security objects are modified. | | | [V-233574](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233574) | pg_audit | Medium | PostgreSQL must generate audit records when categorized information (e.g., classification levels/security levels) is modified. | | | [V-233575](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233575) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to modify privileges/permissions occur. | | | [V-233576](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233576) | pg_audit | Medium | PostgreSQL must generate audit records when unsuccessful attempts to add privileges/permissions occur. | | | [V-233577](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233577) | N/A | Medium | PostgreSQL, when utilizing PKI-based authentication, must validate certificates by performing RFC 5280-compliant certification path validation. | | | [V-233578](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233578) | Pass | Medium | PostgreSQL must produce audit records containing sufficient information to establish where the events occurred. | | | [V-233579](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233579) | Pass | Medium | PostgreSQL must maintain the confidentiality and integrity of information during preparation for transmission. | | | [V-233580](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233580) | pg_audit | Medium | PostgreSQL must provide audit record generation capability for DoD-defined auditable events within all DBMS/database components. | | | [V-233581](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233581) | Pass | Medium | PostgreSQL must generate time stamps, for audit records and application data, with a minimum granularity of one second. | | | [V-233582](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233582) | Pass | Medium | PostgreSQL must produce audit records containing sufficient information to establish the identity of any user/subject or process associated with the event. | | | [V-233583](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233583) | See Notes | High | PostgreSQL must implement NIST FIPS 140-2 or 140-3 validated cryptographic modules to generate and validate cryptographic hashes. | This is a system level setting, ensure FIPS mode is enabled on the OS. | | [V-233585](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233585) | See Notes | High | PostgreSQL must implement NIST FIPS 140-2 or 140-3 validated cryptographic modules to protect unclassified information requiring confidentiality and cryptographic protection, in accordance with the data owners requirements. | This is a system level setting, ensure FIPS mode is enabled on the OS. | | [V-233586](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233586) | Pass (See Notes) | High | PostgreSQL must protect the confidentiality and integrity of all information at rest. | Kasm encrypts sensitive fields at the application layer. Since the STIG guidance seems to provide leeway in the implementation, we believe our native encryption of sensitive data meets the requirement, however, your system owner may desire full disk encryption.. If the system owner wants full database encryption, you will need to use an externally managed Postgres database, such as AWS RDS, Azure Database Postgres, or a traditional Postgres database server. | | [V-233587](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233587) | | Medium | PostgreSQL must prohibit user installation of logic modules (functions, trigger procedures, views, etc.) without explicit privileged status. | | | [V-233588](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233588) | | Medium | PostgreSQL must separate user functionality (including user interface services) from database management functionality. | | | [V-233589](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233589) | pg_audit | Medium | PostgreSQL must initiate session auditing upon startup. | | | [V-233590](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233590) | See Notes | Medium | PostgreSQL must implement cryptographic mechanisms to prevent unauthorized modification of organization-defined information at rest (to include, at a minimum, PII and classified information) on organization-defined information system components. | Read the finding details to see if this check applies to your system or not. Then read the notes column of this table for V-233586. | | [V-233591](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233591) | Pass | Medium | PostgreSQL must produce audit records containing sufficient information to establish the sources (origins) of the events. | | | [V-233592](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233592) | Pass | Medium | Unused database components, PostgreSQL software, and database objects must be removed. | Kasm uses a containerized postgres database, no additional software is included in the image. | | [V-233593](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233593) | Pass | Medium | Access to external executables must be disabled or restricted. | | | [V-233594](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233594) | Pass | Medium | Unused database components which are integrated in PostgreSQL and cannot be uninstalled must be disabled. | Kasm uses a containerized postgres database, no additional software is included in the image. | | [V-233595](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233595) | N/A (See Notes) | Medium | PostgreSQL must associate organization-defined types of security labels having organization-defined security label values with information in process. | The Kasm API service and manager service are the only services with access to the database. These services make decisions and enforce access to row level data. These enforcements are based on user group membership. For this reason, security labeling at the database level is not required. Per the check text, this STIG only applies if labeling is required. | | [V-233596](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233596) | Pass | High | If passwords are used for authentication, PostgreSQL must store only hashed, salted representations of passwords. | | | [V-233597](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233597) | | Medium | PostgreSQL must enforce access restrictions associated with changes to the configuration of PostgreSQL or database(s). | | | [V-233598](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233598) | pg_audit | Medium | PostgreSQL must protect against a user falsely repudiating having performed organization-defined actions. | | | [V-233599](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233599) | See Notes | Medium | The system must provide a warning to appropriate support staff when allocated audit record storage volume reaches 75% of maximum audit record storage capacity. | This is a system level control or a control that applies to your centalized logging solution. | | [V-233601](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233601) | | Medium | PostgreSQL must require users to reauthenticate when organization-defined circumstances or situations require reauthentication. | The STIG does not seem to provide a Fix Text with implementation. | | [V-233602](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233602) | See Notes | High | PostgreSQL must enforce authorized access to all PKI private keys stored/utilized by PostgreSQL. | The postgres database will show /etc/ssl/certs/db_server.crt and /etc/ssl/certs/db_server.key for the cert file and key file respectively. These are mapped into the container and stored on the host at /opt/kasm/current/certs/. If your organization requires storing these files on a FIPS 140-2 or 140-3 cryptographic module, you will need to move these files to the location on the file system that the device is mounted to. After moving the files, you will need to stop the Kasm services by running 'sudo systemctl stop kasm', then edit /opt/kasm/current/docker/docker-compose.yaml and changing the volume mappings in the kasm_db service, for the two files. Then start the Kasm services backup, 'sudo systemctl start kasm'. This needs to be done only on the database server. | | [V-233603](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233603) | See Notes | Medium | PostgreSQL must only accept end entity certificates issued by DoD PKI or DoD-approved PKI Certification Authorities (CAs) for the establishment of all encrypted sessions. | To swap the Kasm generated certs with DoD approved certificates, stop the Kasm services by running 'sudo systemctl stop kasm', then rename the /opt/kasm/current/certs/db_server.crt and /opt/kasm/current/certs/db_server.key files and place your cert and key file at this loction using teh db_server.crt and .key filenames. Start the kasm services back up using 'sudo systemctl start kasm' | | [V-233604](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233604) | pg_audit | Medium | PostgreSQL must produce audit records containing sufficient information to establish what type of events occurred. | | | [V-233605](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233605) | | Medium | PostgreSQL must implement cryptographic mechanisms preventing the unauthorized disclosure of organization-defined information at rest on organization-defined information system components. | Read the finding details to see if this check applies to your system or not. Then read the notes column of this table for V-233586. | | [V-233606](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233606) | See Notes | Medium | PostgreSQL must invalidate session identifiers upon user logout or other session termination. | Edit /opt/kasm/current/conf/database/postgres.sql per the STIG Fix Text. Restart the kasm database, 'sudo docker restart kasm_db' | | [V-233607](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233607) | pg_audit | Medium | PostgreSQL must protect its audit features from unauthorized access. | | | [V-233608](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233608) | pg_audit | Medium | PostgreSQL must produce audit records containing time stamps to establish when the events occurred. | | | [V-233609](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233609) | pg_audit | Medium | PostgreSQL must protect its audit features from unauthorized removal. | | | [V-233610](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233610) | See Notes | Medium | PostgreSQL must off-load audit data to a separate log management facility; this must be continuous and in near real time for systems with a network connection to the storage facility and weekly or more often for stand-alone systems. | The kasm postgres database is configured to log to file at /opt/kasm/current/log/postgres. There will be a log file for each day. A log forwarder should be installed and confirgured to forward those logs to a centralized logging solution. | | [V-233611](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233611) | Pass | Medium | PostgreSQL must maintain the authenticity of communications sessions by guarding against man-in-the-middle attacks that guess at Session ID values. | | | [V-233612](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233612) | See Notes | Medium | PostgreSQL must uniquely identify and authenticate organizational users (or processes acting on behalf of organizational users). | End users never access the Kasm database. The kasm application layer implements its own authentication and authorization check for all data access. | | [V-233613](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233613) | | Medium | PostgreSQL must automatically terminate a user session after organization-defined conditions or trigger events requiring session disconnect. | | | [V-233614](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233614) | See Notes | High | PostgreSQL must prevent non-privileged users from executing privileged functions, to include disabling, circumventing, or altering implemented security safeguards/countermeasures. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. The use of an ORM library ensures that database input is sanitized and meets validity checks prior to being written to the database. End users do not have access to the database. The Kasm application layer enforces authentication and authorization for data retrieved from the database on behalf of the user. | | [V-233615](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233615) | See Notes | Medium | PostgreSQL must map the PKI-authenticated identity to an associated user account. | Kasm utilizes a Object Relational Mapper (ORM) framework called SQLAlchemy and does not directly call database functions or stored procedures. The use of an ORM library ensures that database input is sanitized and meets validity checks prior to being written to the database. End users do not have access to the database. The Kasm application layer enforces authentication and authorization for data retrieved from the database on behalf of the user. Kasm applicaiton logs cotain all requests by users with the data required for application logging, including username, timestamp, requested data, result of request, and more. | | [V-233616](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233616) | | Medium | Database contents must be protected from unauthorized and unintended information transfer by enforcement of a data-transfer policy. | | | [V-233617](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233617) | Pass | Medium | Access to database files must be limited to relevant processes and to authorized, administrative users. | | | [V-233618](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233618) | Pass | Medium | PostgreSQL must protect its audit configuration from unauthorized modification. | | | [V-233619](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233619) | See Notes | High | PostgreSQL must use NIST FIPS 140-2 or 140-3 validated cryptographic modules for cryptographic operations. | This is a system level setting, ensure FIPS mode is enabled on the OS. | | [V-233620](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233620) | pg_audit | Medium | Audit records must be generated when categorized information (e.g., classification levels/security levels) is deleted. | | | [V-233621](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233621) | pg_audit | Medium | PostgreSQL must generate audit records when successful accesses to objects occur. | | | [V-233622](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233622) | pg_audit | Medium | PostgreSQL must generate audit records for all direct access to the database(s). | | | [V-233623](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233623) | See Notes | High | The DBMS must be configured on a platform that has a NIST certified FIPS 140-2 or 140-3 installation of OpenSSL. | This is a system level setting, ensure FIPS mode is enabled on the OS. Kasm recommends using Ubuntu 22.04LTS Advantage. | | [V-233584](https://www.stigviewer.com/stigs/crunchy_data_postgresql/2024-08-27/finding/V-233584) | Pass | Medium | PostgreSQL must use NSA-approved cryptography to protect classified information in accordance with the data owners requirements. | This passes with default Kasm configs according to the STIG check, however, the underlying system really should have FIPS mode is enabled. | --- ## Reverse Proxy Security & NGINX Hardening # Reverse Proxy Security Kasm WebApp roles servers come with an NGINX container (kasm_proxy) that sits in front of service containers and other components within the system. This is a required component, however, organizations may wish to either harden the nginx configuration or place the Kasm Workspaces application behind an Enterprise grade reverse proxy or load balancer. ## F5 BIG-IP By deploying [F5 BIG-IP](https://www.f5.com) in front of Kasm Workspaces, organizations can leverage Advanced Web Application Firewall (AWAF) capabilities, DDoS protection, and Zero Trust Access Controls to safeguard virtual workspace environments against modern cyber threats. BIG-IP’s iRules and SSL/TLS Offloading provide enterprises with granular control over traffic flows while reducing the processing burden on backend Kasm servers, resulting in both improved security posture and optimized resource utilization. **Seamless Authentication and Secure Access Management** BIG-IP integrates seamlessly with enterprise authentication solutions such as SAML, OAuth, and LDAP, ensuring that access to Kasm Workspaces aligns with corporate identity and access management (IAM) policies. With BIG-IP Access Policy Manager (APM), organizations can enforce conditional access policies based on device posture, user location, and risk scores, preventing unauthorized access and mitigating insider threats. By acting as a centralized authentication gateway, BIG-IP enables Multi-Factor Authentication (MFA) enforcement without modifying Kasm’s internal authentication mechanisms, enhancing security without disrupting user experience. **Traffic Optimization and Performance Enhancements** Enterprises leveraging Kasm Workspaces at scale need a high-performance, low-latency connection experience for remote users. BIG-IP’s intelligent load balancing ensures traffic is distributed efficiently across multiple Kasm Workspace nodes, preventing bottlenecks and ensuring high availability (HA). Features like TCP optimization, HTTP/2 support, and advanced caching minimize \latency while improving the responsiveness of virtualized desktops and applications. With built-in Global Server Load Balancing (GSLB), BIG-IP can also facilitate geo-distributed Kasm deployments, dynamically directing users to the nearest or healthiest data center based on real-time availability. **Enterprise-Grade Threat Intelligence and Compliance** For organizations operating in regulated industries, compliance with security standards such as NIST, ISO 27001, HIPAA, and GDPR is critical. F5 BIG-IP provides automated threat intelligence, real-time bot mitigation, and traffic anomaly detection, ensuring that Kasm Workspaces are protected from credential stuffing, malware injection, and brute force attacks. Enterprises can configure custom security policies to enforce compliance mandates while benefiting from detailed logging, analytics, and SIEM integration to maintain full visibility into workspace access and usage. ### Configuring F5 BIG-IP The following video walks through the deployment of Kasm Workspaces behind a F5 BIG-IP using FAST Templates. This [F5 Guide](https://techdocs.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/ltm-implementations-12-1-0/17.html) steps through configuring your BIG-IP to server as a reverse proxy. ## NGINX The default configuration of the Kasm NGINX service is fairly well secured, however, there are certain configurations that we cannot harden out of the box because the hardening may break certain use cases and/or degrade compatibility. Organizations that choose to directly expose Kasm Worksapces without placing it behind an Enterprise grade layer 7 security appliance may wish to harden the Kasm NGINX configuration. This guide walks through some of the settings that you may run into with different hardening guides or benchmark frameworks that exist. This is not an all encompassing list, as there is a lot of guidance out there from a number of different sources. We focus on US DoD STIG benchmarks that are released by DISA. ### X-Frame-Options Header Including the [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) header will allow you to block other sites embedding your deployment of Kasm in an iframe within another site. This is not configured by default in Kasm, because many clients wish to embed Kasm in their own website. The following example will configure NGINX to add the X-Frame-Options header to same origin, which will require the parent page to be on the same domain. See the link above for more details on other configurations, such specifying explicit domain names to be allowed for the parent site. Add this line to each NGINX configuration file that currently defines `add_header` directives in this directory and subdirectories within /opt/kasm/current/conf/nginx. ``` add_header X-Frame-Options SAMEORIGIN always; ``` After making modifications, restart the kasm_proxy container. ``` sudo docker restart kasm_proxy ``` ### Content Security Policy Admins may desire to define a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). The following header is commented out in `/opt/kasm/current/conf/nginx/services.d/website.conf` and in two locations in `/opt/kasm/current/conf/nginx/services.d/upstream_proxy.conf`, remove the proceeding `#` before the add_header statement in all three locations. ``` add_header 'Content-Security-Policy' "default-src 'unsafe-inline' 'unsafe-eval' 'self' blob: data:;"; ``` You also need to uncomment the following line, there is only one in `/opt/kasm/current/conf/nginx/services.d/upstream_proxy.conf`. ``` proxy_hide_header 'Content-Security-Policy' ``` After uncommenting the total of 4 lines in the two nginx configuration files, restart the kasm_proxy container. ```bash sudo docker restart kasm_proxy ``` ### Cross Origin Embedder Policy Admins may desire to define a [Cross Origin Embedder Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy). The following header is commented out in `/opt/kasm/current/conf/nginx/services.d/website.conf` and in two locations in `/opt/kasm/current/conf/nginx/services.d/upstream_proxy.conf`, remove the proceeding `#` before the add_header statement in all three locations. ``` add_header 'Cross-Origin-Embedder-Policy' 'require-corp'; ``` You also need to uncomment the following line, there is only one in `/opt/kasm/current/conf/nginx/services.d/upstream_proxy.conf`. ``` proxy_hide_header 'Cross-Origin-Embedder-Policy'; ``` After uncommenting the total of 4 lines in the two nginx configuration files, restart the kasm_proxy container. ```bash sudo docker restart kasm_proxy ``` ### TLS Settings Kasm ships with a default cipher suite and SSL settings that meet a high degree of security compliance out of the box, however, organizations may wish to define more restrictive SSL cipher suites. The cipher suites are defined on each WebApp server in the file `/opt/kasm/current/conf/nginx/orchestration.conf`. Kasm's default SSL Configuration: ``` ssl_certificate /etc/ssl/certs/kasm_nginx.crt; ssl_certificate_key /etc/ssl/private/kasm_nginx.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; ssl_stapling on; ssl_stapling_verify on; ``` Here is an example of a more secure configuration. **Warning**: More restrictive cipher suites may break compatibility with older clients. ``` ssl_protocols TLSv1.3 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ecdh_curve secp521r1:secp384r1; ssl_ciphers EECDH+AESGCM:EECDH+AES256; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_session_cache shared:TLS:2m; ssl_buffer_size 4k; ssl_stapling on; ssl_stapling_verify on; ``` In order to configure `ssl_dhparam` you will need to generate the dhparam.pem file referenced in the above configuration. ``` sudo openssl dhparam -out /opt/kasm/current/certs/dhparam.pem 4096 sudo chown kasm:kasm /opt/kasm/current/certs/dhparam.pem ``` Next, edit the `/opt/kasm/current/docker/docker-compose.yaml` file to map in the dhparam.pem file into the nginx configuration. The following snippet shows only the relevant portions of the yaml configuration. Add the volume mapping shown on the last line of the below snippet to the proxy definition in the yaml file. ```yaml proxy: container_name: kasm_proxy image: "kasmweb/nginx:1.25.1" volumes: - /opt/kasm/current/certs/dhparam.pem:/etc/ssl/certs/dhparam.pem ``` Next remove the kasm_proxy container and start kasm services back up. ``` sudo docker rm -f kasm_proxy sudo systemctl start kasm ``` ### SSL Certificates Kasm uses self-signed certificates that are generated during the installation process. The cert and key are stored on each host at `/opt/kasm/current/certs/kasm_nginx.crt` and `/opt/kasm/current/certs/kasm_nginx.key` respectively. Clients may wish to replace these certs with properly signed public SSL certs or certs generated by their organizations certificate authority. You can replace the cert and key mentioned above with files named the same as those above, in the PEM format. Ensure both files are owned by the `kasm` user. ``` cd /opt/kasm/current/certs mv kasm_nginx.crt kasm_nginx.crt.bak mv kasm_nginx.key kasm_nginx.key.bak cp /my/cert/location/mycert.pem ./kasm_nginx.crt cp /my/key/location/mykey.pem ./kasm_nginx.key chown kasm:kasm /opt/kasm/current/certs/kasm_nginx.crt chown kasm:kasm /opt/kasm/current/certs/kasm_nginx.key ``` Next restart the services. ``` sudo systemctl restart kasm ``` If you already have certificates stored on any host prior to installation, there are two shortcut flags available which will reuse your existing cert and key without the need to restart services later. Ensure you have both the cert and key in PEM format as described above and supply two flags, `--ssl-public-cert` and `--ssl-private-key`, to the install command with the path to each file (e.g., `install.sh --role app --ssl-public-cert /etc/ssl/certs/kasm_nginx.crt --ssl-private-key /etc/ssl/certs/kasm_nginx.key`). ### Referrer Policy You may wish to define a [referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) which will keep client browsers from passing the referrer header to external sites. Add this line to each NGINX configuration file that currently defines `add_header` directives in /opt/kasm/current/conf/nginx/services.d/. ``` add_header Referrer-Policy 'same-origin'; ``` ### Rate Limiting Many organizations will require rate limiting. NGINX supports rate limiting of requests, see the [NGINX documentation](https://www.nginx.com/blog/rate-limiting-nginx/) for full details. Kasm Workspaces does not ship with rate limiting enabled, mostly due to the fact that some context of the deployment is needed to configure it properly. First, you need to know if Kasm's WebApp servers are directly accessible via clients, or if there is a load balancer of some other device between the clients and the web app servers. If there is a device between the client and the Kasm WebApp servers, NGINX may not see the original source IP address of the client, this must be considered when considering which rate limiting approach to take. If clients access the Kasm WebApp servers directly, then you can create a simple rate limiting policy that imposes a request rate limit per client based on the source IP address of the client. The following configuration would be placed above the `server` directive within the file `/opt/kasm/current/conf/nginx/orchestration.conf`. ``` limit_req_zone $binary_remote_addr zone=mylimit:10m rate=100r/s; server { } ``` If there is a reverse proxy or load balancer in front of the Kasm WebApp servers, you may want to place the rate limiting on the front facing load balancer instead. NGINX can, however, use the X-Forwarded-For header for rate limiting, assuming the front facing reverse proxy/load-balancer injects this header on proxied requests. ``` limit_req_zone $http_x_forwarded_for zone=zone:10m rate=100r/s; ``` After implementing one of the two lines above, you must apply it to each proxied location. Within each `.conf` file located at `/opt/kasm/current/conf/nginx/services.d/`, place the following line under each location stanza. ``` location / { limit_req zone=mylimit burst=20 nodelay; } ``` ### CORS Headers Kasm implements proper CORS headers, however, we must use a dynamic origin value. This is considered a low severity security finding. The following is the offending line, which can be found in multiple files under `/opt/kasm/current/conf/nginx/services.d/` ``` add_header 'Access-Control-Allow-Origin' $http_origin always; ``` Replace the above line with the following, replace `example.com` with your domain name. ``` add_header 'Access-Control-Allow-Origin' 'https://example.com' always; ``` This may affect deployments that use sub domains for different [Zones](../infra-autoscale/deployment-zones.mdx). The following more complex example may be used if you must clear this vulnerability and also support multiple domain names with CORs. This uses a dynamic Access-Control-Allow-Origin header value, but whitelists it to a list of regular expressions. ``` map $http_origin $allow_origin { ~^https?://(.*\.)?example.com(:\d+)?$ $http_origin; ~^https?://(.*\.)?example2.com(:\d+)?$ $http_origin; default ""; } location / { add_header 'Access-Control-Allow-Origin' $allow_origin always; } --- ## Administration Groups: Common Permissions | Developer Guide # {/* to keep default heading blank */} The following table lists each permission and its description. | Name | Description | |------|-------------| | User | Default level of permissions for normal users. | | Global Admin | Global Administrator with all permissions. | | Users View | View users and user information. | | Users Modify | Modify existing users. | | Users Create | Create new users. | | Users Delete | Delete exiting users. | | Users Modify Admin | Modify users with Global Admin permissions. | | Users Auth Session | Login and logout on behalf of another user. | | Groups View | View groups, group members, and group settings. | | Groups Modify | Modify group members and settings. | | Groups Create | Create new groups. | | Groups Delete | Delete existing groups. | | Groups View IfMember | View groups you are a member of, excluding system groups. | | Groups Modify IfMember | Modify groups you are a member of, excluding system groups. | | Groups View System | View groups, group members and group settings of system defined groups. | | Groups Modify System | Modify group members and settings of system groups. | | Groups Delete System | Delete a system group. | | Agents View | View agents and agent settings. | | Agents Modify | Modify agent settings. | | Agents Create | Create agents. | | Agents Delete | Delete existing agents. | | Staging View | View staging list and stage configuration settings. | | Staging Modify | Modify existing staging settings. | | Staging Create | Create new staging configurations. | | Staging Delete | Delete existing staging configurations. | | Casting View | View casting list and casting configuration settings. | | Casting Modify | Modify existing casting settings. | | Casting Create | Create new casting configurations. | | Casting Delete | Delete existing casting configurations. | | Sessions View | View all user sessions. | | Sessions Modify | Perform modifications to a session of another user. | | Sessions Delete | Delete the session of another user. | | Session Recordings View | View user session recordings. | | Images View | View images | | Images Modify | Modify image configurations. | | Images Create | Create new images. | | Images Delete | Delete existing images. | | Images Modify Resources | Modify image resource settings, such as CPU and Memory settings. | | DevAPI View | View developer API list. | | DevAPI Modify | Modify developer API configurations. | | DevAPI Create | Create a new developer API key. | | DevAPI Delete | Delete an existing developer API key. | | Webfilters View | View webfilters | | Webfilters Modify | Modify existing webfilters | | Webfilters Create | Create a new webfilter. | | Webfilters Delete | Delete an existing webfilter | | Brandings View | View branding configurations. | | Brandings Modify | Modify existing branding configurations. | | Brandings Create | Create new branding configurations. | | Brandings Delete | Delete existing branding configurations. | | Settings View | View global settings. | | Settings Modify | Modify global settings in all categories. | | Settings Modify Auth | Modify global settings in the authentication category. | | Settings Modify Auth Captcha | Modify global settings in the authentication captcha category. | | Settings Modify Cast | Modify global settings in the casting category. | | Settings Modify Images | Modify global settings in the images category. | | Settings Modify License | Modify global settings in the license category. | | Settings Modify Logging | Modify global settings in the logging category. | | Settings Modify Manager | Modify global settings in the manager category. | | Settings Modify Scale | Modify global settings in the scale category. | | Settings Modify Subscription | Modify global settings in the subscription category. | | Settings Modify Filter | Modify global settings in the filter category. | | Settings Modify Storage | Modify global settings in the storage category. | | Settings Modify Connections | Modify global settings in the connections category. | | Settings Modify Theme | Modify global settings in the theme category. | | Auth View | View LDAP/OIDC/SAML configurations. | | Auth Modify | Modify LDAP/OIDC/SAML configurations. | | Auth Create | Create LDAP/OIDC/SAML configurations. | | Auth Delete | Delete LDAP/OIDC/SAML configurations. | | Licenses View | View licenses. | | Licenses Create | Add new licenses. | | Licenses Delete | Delete licenses. | | System View | View system information. | | System Export Schema | Export system schema. | | System Import Data | Import system data. | | System Export Data | Export system data. | | Reports View | View system reports and logging. **Warning**: Providing access to logs can provide a lot of potentially sensitive information. | | Managers View | View the managers. | | Managers Modify | Modify existing managers. | | Managers Create | Create a new manager. | | Managers Delete | Delete existing managers. | | Zones View | View Zones and Zone settings. | | Zones Modify | Modify Zone settings. | | Zones Create | Create new Zones. | | Zones Delete | Delete existing Zones. | | Companies View | View companies. | | Companies Modify | Modify existing company. | | Companies Create | Create a new company. | | Companies Delete | Delete an existing company. | | Connection Proxy View | View connection proxies. | | Connection Proxy Modify | Modify connection proxies. | | Connection Proxy Create | Create a connection proxy. | | Connection Proxy Delete | Delete an existing connection proxy. | | Physical Tokens View | View physical 2FA tokens. | | Physical Tokens Modify | Assign/Unassign physical 2FA tokens. | | Physical Tokens Create | Import or create physical 2FA tokens. | | Physical Tokens Delete | Delete a physical 2FA token. | | Servers View | View servers. | | Servers Modify | Modify existing servers. | | Servers Create | Create new servers. | | Servers Delete | Delete servers. | | Server Pools View | View server pools. | | Server Pools Modify | Modify server pools. | | Server Pools Create | Create a new server pool. | | Server Pools Delete | Delete a server pool. | | Autoscale View | View AutoScale configurations. | | Autoscale Modify | Modify an existing AutoScale configuration. | | Autoscale Create | Create a new AutoScale configuration. | | Autoscale Delete | Delete AutoScale configurations. | | VM Provider View | View VM Provider configurations. | | VM Provider Modify | Modify VM Provider configurations. | | VM Provider Create | Create new VM Provider configurations. | | VM Provider Delete | Delete VM Provider configurations. | | Autoscale Schedule View | View an AutoScale schedule. | | Autoscale Schedule Modify | Modify an AutoScale schedule. | | Autoscale Schedule Create | Create an AutoScale schedule. | | Autoscale Schedule Delete | Delete an AutoScale schedule. | | DNS Providers View | View DNS provider configurations. | | DNS Providers Modify | Modify DNS provider configurations. | | DNS Providers Create | Create new DNS Provider configurations. | | DNS Providers Delete | Delete DNS Provider configurations. | | Registries View | View Workspace Registries. | | Registries Modify | Modify existing Workspace Registries. | | Registries Create | Add new Workspace Registries | | Registries Delete | Delete a Workspace Registry | | Storage Providers View | View Storage Providers. | | Storage Providers Modify | Modify existing Storage Providers. | | Storage Providers Create | Create new Storage Providers. | | Storage Providers Delete | Delete an existing Storage Provider. | | Egress Providers View | View Egress Providers. | | Egress Providers Modify | Modify existing Egress Providers. | | Egress Providers Create | Create new Egress Providers. | | Egress Providers Delete | Delete an existing Egress Provider. | | Egress Gateways View | View Egress Gateways. | | Egress Gateways Modify | Modify existing Egress Gateways. | | Egress Gateways Create | Create new Egress Gateways. | | Egress Gateways Delete | Delete an existing Egress Gateway. | | Egress Credentials View | View Egress Credentials. | | Egress Credentials Modify | Modify existing Egress Credentials. | | Egress Credentials Create | Create new Egress Credentials. | | Egress Credentials Delete | Delete an existing Egress Credential. | | Banners View | View banners. | | Banners Modify | Modify existing banners. | | Banners Create | Create new banners. | | Banners Delete | Delete an existing banner. | | AD User Management View | View AD User Management Configurations. | | AD User Management Modify | Modify existing AD User Management Configurations. | | AD User Management Create | Create new AD User Management Configurations. | | AD User Management Delete | Delete an existing AD User Management Configuration. | ### Permission changes Kasm embeds a user's permissions in their session token, which is generated on login. The **Session Lifetime** global setting controls the token lifetime. The UI requests a new session token every 5 minutes. To apply new permissions fastest, have the user log out and log back in. Otherwise, the change applies within 5 minutes. ### Permission dependencies Most permissions stand alone, but some permissions depend on others. Generally, a `Modify`, `Create`, or `Delete` permission needs the corresponding `View` permission. The following additional dependencies require you to grant multiple permissions to achieve the desired effect. - `Licenses View` requires `System View` - `Permissions View` requires `Groups View` - `Registries View` requires `Images View`, `System View`, and `Agents View` - `Autoscale View` requires `Server Pools View` - `Autoscale Schedule View` requires `Server Pools View` - `DNS Providers View` requires `Server Pools View` - `VM Providers View` requires `Server Pools View` and `Autoscale View` - `Users Delete` requires `Sessions Delete` if the target user has running sessions and `Users Modify` - `Users Delete` requires `Users Modify Admin` to delete a user that has the `Global Admin` permission - `Egress Gateways Create`, `Egress Gateways Modify`, `Egress Gateways Delete`, `Egress Credentials Create`, `Egress Credentials Modify` and `Egress Credentials Delete` require `Egress Providers Modify`. - `Servers View` and `Server Templates View` requires `Server Pools View` and `Zones View` In many cases multiple permissions are not required. However, Kasm hides certain UI elements when the user lacks the permissions to view them. For example, a user may have `View Images` permissions but not `View Servers` permissions. When that user views an individual Workspace Image that targets a Server, the drop-down to view or edit the targeted server stays hidden. ### Special permissions Groups offer more permissions beyond the basic View, Create, Modify, and Delete actions. The `Groups View IfMember` and `Groups Modify IfMember` permissions allow a user to view or modify a group when they are a member of that group. This access does not extend to built-in system groups (All Users and Administrator). To edit or view system groups, the user also needs the Groups View/Modify System permission. An additional permission protects the modification of users with the `Global Admin` permission. To modify a `Global Admin`, the requesting user must be a `Global Admin` or hold the `User Modify Admin` permission. Two permissions allow modifications to Workspace Images: `Images Modify` and `Images Modify Resources`. The `Images Modify` permission allows modification of all Image settings except those that change the physical or virtual compute resources. The following settings require the `Images Modify Resources` permission to edit: - GPU Count - Cores - Memory - CPU Allocation Method - Uncompressed Image Size - Docker Registry - Docker Registry Username - Docker Registry Password - Hash - Volume Mappings - Docker Run Config Override - Docker Exec Config --- ## Group Permissions: Configuration and Management | Docusaurus # {/* to keep default heading blank */} ## Group permissions Groups have an optional list of permissions attached to them. When a user logs in, Kasm aggregates all permissions across the groups the user belongs to, which determine the actions the user is authorized for. There are two built-in groups, `Administrators` and `All Users`. The Administrators group has the Global Admin permission, and the built-in `All Users` group has the User permission. All users are members of the `All Users` group automatically. To configure group permissions: 1. Log in to the UI as an administrator. 2. Select **Groups**. 3. Next to the desired group, select **Edit** from the actions menu. 4. Select the **Permissions** tab to view and edit the permissions applied to the group. The following table lists each permission and its description. | Name | Description | |------|-------------| | User | Default level of permissions for normal users. | | Global Admin | Global Administrator with all permissions. | | Users View | View users and user information. | | Users Modify | Modify existing users. | | Users Create | Create new users. | | Users Delete | Delete exiting users. | | Users Modify Admin | Modify users with Global Admin permissions. | | Users Auth Session | Login and logout on behalf of another user. | | Groups View | View groups, group members, and group settings. | | Groups Modify | Modify group members and settings. | | Groups Create | Create new groups. | | Groups Delete | Delete existing groups. | | Groups View IfMember | View groups you are a member of, excluding system groups. | | Groups Modify IfMember | Modify groups you are a member of, excluding system groups. | | Groups View System | View groups, group members and group settings of system defined groups. | | Groups Modify System | Modify group members and settings of system groups. | | Groups Delete System | Delete a system group. | | Agents View | View agents and agent settings. | | Agents Modify | Modify agent settings. | | Agents Create | Create agents. | | Agents Delete | Delete existing agents. | | Staging View | View staging list and stage configuration settings. | | Staging Modify | Modify existing staging settings. | | Staging Create | Create new staging configurations. | | Staging Delete | Delete existing staging configurations. | | Casting View | View casting list and casting configuration settings. | | Casting Modify | Modify existing casting settings. | | Casting Create | Create new casting configurations. | | Casting Delete | Delete existing casting configurations. | | Sessions View | View all user sessions. | | Sessions Modify | Perform modifications to a session of another user. | | Sessions Delete | Delete the session of another user. | | Session Recordings View | View user session recordings. | | Images View | View images | | Images Modify | Modify image configurations. | | Images Create | Create new images. | | Images Delete | Delete existing images. | | Images Modify Resources | Modify image resource settings, such as CPU and Memory settings. | | DevAPI View | View developer API list. | | DevAPI Modify | Modify developer API configurations. | | DevAPI Create | Create a new developer API key. | | DevAPI Delete | Delete an existing developer API key. | | Webfilters View | View webfilters | | Webfilters Modify | Modify existing webfilters | | Webfilters Create | Create a new webfilter. | | Webfilters Delete | Delete an existing webfilter | | Brandings View | View branding configurations. | | Brandings Modify | Modify existing branding configurations. | | Brandings Create | Create new branding configurations. | | Brandings Delete | Delete existing branding configurations. | | Settings View | View global settings. | | Settings Modify | Modify global settings in all categories. | | Settings Modify Auth | Modify global settings in the authentication category. | | Settings Modify Auth Captcha | Modify global settings in the authentication captcha category. | | Settings Modify Cast | Modify global settings in the casting category. | | Settings Modify Images | Modify global settings in the images category. | | Settings Modify License | Modify global settings in the license category. | | Settings Modify Logging | Modify global settings in the logging category. | | Settings Modify Manager | Modify global settings in the manager category. | | Settings Modify Scale | Modify global settings in the scale category. | | Settings Modify Subscription | Modify global settings in the subscription category. | | Settings Modify Filter | Modify global settings in the filter category. | | Settings Modify Storage | Modify global settings in the storage category. | | Settings Modify Connections | Modify global settings in the connections category. | | Settings Modify Theme | Modify global settings in the theme category. | | Auth View | View LDAP/OIDC/SAML configurations. | | Auth Modify | Modify LDAP/OIDC/SAML configurations. | | Auth Create | Create LDAP/OIDC/SAML configurations. | | Auth Delete | Delete LDAP/OIDC/SAML configurations. | | Licenses View | View licenses. | | Licenses Create | Add new licenses. | | Licenses Delete | Delete licenses. | | System View | View system information. | | System Export Schema | Export system schema. | | System Import Data | Import system data. | | System Export Data | Export system data. | | Reports View | View system reports and logging. **Warning**: Providing access to logs can provide a lot of potentially sensitive information. | | Managers View | View the managers. | | Managers Modify | Modify existing managers. | | Managers Create | Create a new manager. | | Managers Delete | Delete existing managers. | | Zones View | View Zones and Zone settings. | | Zones Modify | Modify Zone settings. | | Zones Create | Create new Zones. | | Zones Delete | Delete existing Zones. | | Companies View | View companies. | | Companies Modify | Modify existing company. | | Companies Create | Create a new company. | | Companies Delete | Delete an existing company. | | Connection Proxy View | View connection proxies. | | Connection Proxy Modify | Modify connection proxies. | | Connection Proxy Create | Create a connection proxy. | | Connection Proxy Delete | Delete an existing connection proxy. | | Physical Tokens View | View physical 2FA tokens. | | Physical Tokens Modify | Assign/Unassign physical 2FA tokens. | | Physical Tokens Create | Import or create physical 2FA tokens. | | Physical Tokens Delete | Delete a physical 2FA token. | | Servers View | View servers. | | Servers Modify | Modify existing servers. | | Servers Create | Create new servers. | | Servers Delete | Delete servers. | | Server Pools View | View server pools. | | Server Pools Modify | Modify server pools. | | Server Pools Create | Create a new server pool. | | Server Pools Delete | Delete a server pool. | | Autoscale View | View AutoScale configurations. | | Autoscale Modify | Modify an existing AutoScale configuration. | | Autoscale Create | Create a new AutoScale configuration. | | Autoscale Delete | Delete AutoScale configurations. | | VM Provider View | View VM Provider configurations. | | VM Provider Modify | Modify VM Provider configurations. | | VM Provider Create | Create new VM Provider configurations. | | VM Provider Delete | Delete VM Provider configurations. | | Autoscale Schedule View | View an AutoScale schedule. | | Autoscale Schedule Modify | Modify an AutoScale schedule. | | Autoscale Schedule Create | Create an AutoScale schedule. | | Autoscale Schedule Delete | Delete an AutoScale schedule. | | DNS Providers View | View DNS provider configurations. | | DNS Providers Modify | Modify DNS provider configurations. | | DNS Providers Create | Create new DNS Provider configurations. | | DNS Providers Delete | Delete DNS Provider configurations. | | Registries View | View Workspace Registries. | | Registries Modify | Modify existing Workspace Registries. | | Registries Create | Add new Workspace Registries | | Registries Delete | Delete a Workspace Registry | | Storage Providers View | View Storage Providers. | | Storage Providers Modify | Modify existing Storage Providers. | | Storage Providers Create | Create new Storage Providers. | | Storage Providers Delete | Delete an existing Storage Provider. | | Egress Providers View | View Egress Providers. | | Egress Providers Modify | Modify existing Egress Providers. | | Egress Providers Create | Create new Egress Providers. | | Egress Providers Delete | Delete an existing Egress Provider. | | Egress Gateways View | View Egress Gateways. | | Egress Gateways Modify | Modify existing Egress Gateways. | | Egress Gateways Create | Create new Egress Gateways. | | Egress Gateways Delete | Delete an existing Egress Gateway. | | Egress Credentials View | View Egress Credentials. | | Egress Credentials Modify | Modify existing Egress Credentials. | | Egress Credentials Create | Create new Egress Credentials. | | Egress Credentials Delete | Delete an existing Egress Credential. | | Banners View | View banners. | | Banners Modify | Modify existing banners. | | Banners Create | Create new banners. | | Banners Delete | Delete an existing banner. | | AD User Management View | View AD User Management Configurations. | | AD User Management Modify | Modify existing AD User Management Configurations. | | AD User Management Create | Create new AD User Management Configurations. | | AD User Management Delete | Delete an existing AD User Management Configuration. | ### Permission changes Kasm embeds a user's permissions in their session token, which is generated on login. The **Session Lifetime** global setting controls the token lifetime. The UI requests a new session token every 5 minutes. To apply new permissions fastest, have the user log out and log back in. Otherwise, the change applies within 5 minutes. ### Permission dependencies Most permissions stand alone, but some permissions depend on others. Generally, a `Modify`, `Create`, or `Delete` permission needs the corresponding `View` permission. The following additional dependencies require you to grant multiple permissions to achieve the desired effect. - `Licenses View` requires `System View` - `Permissions View` requires `Groups View` - `Registries View` requires `Images View`, `System View`, and `Agents View` - `Autoscale View` requires `Server Pools View` - `Autoscale Schedule View` requires `Server Pools View` - `DNS Providers View` requires `Server Pools View` - `VM Providers View` requires `Server Pools View` and `Autoscale View` - `Users Delete` requires `Sessions Delete` if the target user has running sessions and `Users Modify` - `Users Delete` requires `Users Modify Admin` to delete a user that has the `Global Admin` permission - `Egress Gateways Create`, `Egress Gateways Modify`, `Egress Gateways Delete`, `Egress Credentials Create`, `Egress Credentials Modify` and `Egress Credentials Delete` require `Egress Providers Modify`. - `Servers View` and `Server Templates View` requires `Server Pools View` and `Zones View` In many cases multiple permissions are not required. However, Kasm hides certain UI elements when the user lacks the permissions to view them. For example, a user may have `View Images` permissions but not `View Servers` permissions. When that user views an individual Workspace Image that targets a Server, the drop-down to view or edit the targeted server stays hidden. ### Special permissions Groups offer more permissions beyond the basic View, Create, Modify, and Delete actions. The `Groups View IfMember` and `Groups Modify IfMember` permissions allow a user to view or modify a group when they are a member of that group. This access does not extend to built-in system groups (All Users and Administrator). To edit or view system groups, the user also needs the Groups View/Modify System permission. An additional permission protects the modification of users with the `Global Admin` permission. To modify a `Global Admin`, the requesting user must be a `Global Admin` or hold the `User Modify Admin` permission. Two permissions allow modifications to Workspace Images: `Images Modify` and `Images Modify Resources`. The `Images Modify` permission allows modification of all Image settings except those that change the physical or virtual compute resources. The following settings require the `Images Modify Resources` permission to edit: - GPU Count - Cores - Memory - CPU Allocation Method - Uncompressed Image Size - Docker Registry - Docker Registry Username - Docker Registry Password - Hash - Volume Mappings - Docker Run Config Override - Docker Exec Config --- ## Group Properties in Administration Groups # {/* to keep default heading blank */} ## Group properties | Property | Description | | --- | --- | | Name | The name of the group. | | Description | The description of the group. | | Priority | Sets the priority of the settings over other groups. | | Is System | A system-level group that cannot be deleted. | --- ## Kasm Workspaces: Understanding and Configuring Group Settings # {/* to keep default heading blank */} ## Group settings To change the settings for a specific group, select the groups tab, click the edit icon on the desired group, and click **Add Settings** in the Group Settings card. Delete and edit icons appear to the right of each setting. When a user belongs to multiple groups, the setting on the group with the lowest priority takes effect. For settings such as `volume_mapping`, all settings are combined across the groups a user belongs to. The following video gives an overview of groups and group settings. To configure group settings: - Log into the UI as an administrator. - Select **Groups** - Next to the desired group select **View** from the actions menu. - Scroll down to the Group Settings panel. Update settings as desired. | Variable Name | Description | | :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | allow_2fa_self_enrollment | Allow users to self enroll two factor devices in the profile settings page when enabled. | | allow_kasm_audio | Allow audio streaming for a Kasm. | | allow_kasm_clipboard_down | Allows users to paste text from the Kasm to their local computer. | | allow_kasm_clipboard_seamless | Allows users to copy and paste text without using Kasm control panel. This feature is only available on Chrome and Chromium-based client browsers | | allow_kasm_clipboard_up | Allow users to paste from their local computer to the Kasm. | | allow_kasm_delete | If enabled, users are allowed to delete their running sessions. | | allow_kasm_downloads | Allow users to download files from a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_kasm_force_delete | If enabled, users are allowed to force-delete sessions that are stuck in the deleting state | | allow_kasm_gamepad | Allow users to pass local gamepads into the Kasm session. See Gamepad Passthrough for more details. | | allow_kasm_microphone | Allow microphone passthrough to a Kasm. When enabled, users can pass their local microphone through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_kasm_rdp_client_file_transfer_clipboard | This setting only applies to RDP client Kasm sessions. In RDP file transfers are part of the clipboard and independent directional control of file transfers is not possible. This setting will enable file transfer in the directions that text clipboard has been enabled via **allow_kasm_clipboard_down** and **allow_kasm_clipboard_up**. | | allow_kasm_rdp_map_local_drives | Allow sessions using the RDP Gateway to map client local drives into the RDP target. This setting is an all or nothing setting. When enabled it will map all client drives into the rdp session. | | allow_kasm_smart_card_passthrough | Allow sessions to pass smart cards through for authentication and signing. Supports RDP sessions via RDP Gateway or web native client, and container workspaces with the Kasm Native Smartcard Client. See Smart Card Passthrough for details. | | allow_kasm_rdp_webauthn_passthrough | Allow sessions using the RDP Gateway to pass webauthn requests from the RDP target to the client. This only works for Windows clients running the builtin mstsc.exe RDP client. | | allow_kasm_webcam | Allow webcam passthrough to a Kasm. When enabled, users can pass their local webcam through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_kasm_printing | Allow printing of documents using local printers | | allow_kasm_pause | If enabled, users are allowed to pause their running sessions. | | allow_kasm_sharing | Allow the user to share access to their session with other users. See Session Sharing for more details. | | allow_kasm_stop | If enabled, users are allowed to stop their running sessions. | | allow_kasm_uploads | Allow users to upload files to a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_persistent_profile | Allow the use of persistent profiles if configured on the Workspace. See Persistent Profiles for details | | allow_point_of_presence | Allow the user to use point of presence features for certain Workspaces. | | allow_totp_2fa | Allow for TOTP tokens (e.g.: Google Authenticator) to be used as a two factor authentication method for the group. | | allow_user_storage_mapping | When enabled the user is allowed to configure their own Storage Mappings via their profile. When disabled, new user configurations will not be allowed, nor will using any previously configured mappings be allowed when new sessions are created. | | allow_webauthn_2fa | Allow for WebAuthn devices (e.g. YubiKeys) to be used as a two factor authentication method for the group. | | allow_zone_selection | Allow the user to specify the deployment zone when creating a session. A dropdown will appear on the user dashboard with the available Zones. **Auto** represents the default behavior which is to provision in current Zone. If a Zone is specified, the request will not search alternate zones if no resources are available in the requested Zone. | | auto_add_local_user | When enabled, local users will automatically be added to this group when created and upon each authentication. | | auto_login_to_kasm | Sends users directly to kasm using default workspace after login | | control_panel. advanced_settings. show_game_mode | Whether the game mode option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_ime_input_mode | Whether the ime input mode option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_keyboard_controls | Whether the keyboard controls option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_pointer_lock | Whether the pointer lock option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_prefer_local_cursor | Whether the prefer local cursor option is present in the advanced menu on the Kasm Session control panel. | | control_panel.show_fullscreen | Whether the fullscreen option is present on the Kasm Session control panel. | | control_panel. show_delete_session | Whether the delete session option is present on the Kasm Session control panel. | | control_panel. show_display_manager | Whether the display manager is present on the Kasm Session control panel. The display manager allows the user to add and remove additional displays. | | control_panel.show_logout | Whether the logout option is present on the Kasm Session control panel. | | control_panel. show_return_to_workspaces | Whether the return to workspaces option is present on the Kasm Session control panel. | | control_panel. show_streaming_quality | Whether the show streaming quality workspaces option is present on the Kasm Session control panel. | | control_panel.pwa_install_option | Whether the user must be presented with the option to install per-workspace PWAs. | | dashboard_redirect | If configured, standard users will be redirected to the defined external website instead of being shown the main dashboard screen. | | default_image | The default Workspace used when the **/go** url is called. This is also used for the auto_login_to_kasm setting. The system will create a Workspace if one does not exist. If the user already has a Workspace, the session is resumed | | default_ui_language | The default UI language to set for the group. This is applied at next user login and is also overridden if the user sets the language in their profile. | | delete_anon_user_on_expiry_with_active_session | If enabled, anonymous users are deleted immediately upon expiration even if they have an active session. If disabled, deletion is deferred until all active sessions have ended. | | display_ui_errors | If enabled, detailed information will be displayed on the client browser in the event of an error. | | enable_container_logging | If enabled, each workspace container will log to the database. | | enable_ui_server_logging | If enabled, log messages will be sent from client browser to the Kasm Workspaces server. | | expose_user_environment_vars | Expose KASM_USER and KASM_USER_ID environment variables inside the Kasm. | | idle_disconnect | Disconnect the Kasm connection if idle for this long. Time specified in minutes. | | inject_ssh_keys | When enabled the system will inject the user's SSH public and private keys into new sessions automatically. Users can update their keys via the Profile. | | kasm_audio_default_on | Default to audio enabled on Kasm start | | kasm_ime_mode_default_on | Default to IME enabled on Kasm start | | kasmvnc_mode_preference | Set the KasmVNC streaming modes available and the preferred order. See Kasm Performance for more details. | | keepalive_expiration | The number of seconds a Kasm will stay alive unless a keeplive request is sent from the client. | | keepalive_expiration_action | The action the system should take when a session expires according to the keepalive_expiration. Valid options are `delete`, `stop`, and `pause`. `stop` and `pause` actions are only valid for container based Workspaces. All other Workspaces will utilize `delete` regardless of what is defined. | | keepalive_interval | The number of seconds in between keepalive requests from the client when the user is actively in a session. | | lock_sharing_video_mode | Locks video quality to static resolution of 720p when sharing is enabled. Recommended for best performance. | | max_kasms_per_user | The maximum number of simultaneous sessions a users is allowed to provision. | | max_user_storage_mappings | The maximum number of Storage Mappings a user is allowed to have registered to their account. | | read_only_user_storage_mappings | When enabled, any storage mappings configured on the user account will be forced to read-only. | | require_2fa | Enables two factor authentication for group. Users will be prompted to set Key on next log on. | | run_config | Specify arbitrary docker run params. The settings for run_config on a group will override the run_config settings on an image. See Docker Run Config for more details | | session_time_limit | The amount of time (in seconds) a session will automatically expire. A countdown timer will be displayed to the user. | | staged_session_language_and _timezone_preference_override | When launching a workspace Kasm will by default try to match the user language and timezone to a staged session. If a staged session does not exist that has the matching language and timezone then Kasm will create a new session with the specified language and timezone. If the override is set to true then Kasm will use a staged session for the selected workspace even if the language and timezone do not match. This overrides the user setting in the user profile. | | usage_limit | Limits the total number of hours a user or group can have running sessions. See the `usage_limit`_ documentation below for more details. **Type** - **Per User** - Each user of the group has their own limit. - **Per Group** - All members share the usage limit. **Interval** - **Daily** , **Weekly** , **Monthly** , **Total**. **Hours** - The number of hours allowed during each interval. | | volume_mapping | Map a local server directory to Kasm. Details available in the Volume Mapping Guide | | web_filter_policy | Enabled web filtering and sets the Web Filter Policy to be used. Policies can also be set or force disabled on Workspaces. Policies assigned to Workspaces take priority over those defined via Group Settings. | :::caution The `allow_kasm_clipboard_up` setting (Control Panel clipboard) is subject to browser-side limitations. Very large clipboard payloads, typically above ~15 MiB, can overwhelm the browser WebSocket send buffer and delay client heartbeats, which results in a temporary session disconnect and automatic reconnection. This does not affect Seamless Clipboard behavior. For best reliability, enable `allow_kasm_clipboard_seamless` for workflows that paste very large text payloads. ::: ### Session time limits Several settings in the table above control Kasm session lifetime. The following sections describe them and their relationship to each other. #### keepalive_expiration This can also be described as the session timeout. This value determines how long Kasm will wait before destroying, stopping or pausing a session if no keepalive is received from the client. Keepalives are sent whenever a user is connected to a Kasm session even if the user is not actively using the Kasm Session. This value should be at least twice the keepalive_interval. This setting is 1 hour by default in the "All Users Group". The action taken is determined by the `keepalive_expiration_action` Group Setting. #### keepalive_expiration_action Administrators can decide what happens to sessions once they expire. Valid options are: - `delete` - The session is destroyed. - `pause` - The session is paused, preserving the disk, process and memory state. Paused sessions will still consume resources in physical memory and/or swap. Sessions resumed from a paused state will still have the previous programs launched and active. This action is valid for container-based sessions only. All other types will utilize the `delete` action. - `stop` - The session is stopped, preserving the disk state. Sessions resumed from a stopped state will have the previous files intact, but previously running programs will need to be restarted. This action is valid for container-based sessions only. All other types will utilize the `delete` action. :::note When sessions are stopped or paused, the CPU and RAM resources on the agent become available for other requests to create new sessions. This can prevent a user from resuming a paused or stopped session when the agent's resources are consumed by other running sessions. With cloud AutoScale, the system does not destroy agents that have stopped or paused sessions, and it allows other sessions to be provisioned on the agent. When this is undesirable, do not give users the `allow_kasm_pause` and `allow_kasm_stop` permissions. ::: #### keepalive_interval The keepalive_interval is how often the client will send a keepalive request to Kasm when the user is actively using a session. This setting is 300 seconds by default for the "All Users Group". #### idle_disconnect This setting is the number of minutes Kasm will wait when the user is idle before taking an action. This action will depend on the user context. If the user is in a Kasm session when the idle timeout expires the user is disconnected from the Kasm session and sent back to the dashboard. Any Kasm sessions that the user was connected to will be disconnected and those sessions will be subject to the keepalive_expiration. If the user is at the dashboard when the idle timeout expires the user is logged out of Kasm. This setting is set to 20 minutes by default in the "All Users Group". This setting must be higher than the keepalive_interval setting to function properly. #### usage_limit The usage_limit setting is a highly flexible option allowing the administrator to configure a maximum usage number of hours either for each user in the group or for the entire group collectively to use over a set time period. This setting is a decimal value. When using the usage_limit setting all time that a Kasm session is running is counted against the total, this includes when the user is not actively connected to the session but the session is still running. This setting is for use cases where user workspace access should be metered. This setting is not enabled by default. :::note Accounting for paused or stopped sessions is unchanged. Users are charged for the full duration of the session, even when the session is paused or stopped. ::: The user can see how much time they have used/have remaining on the user dashboard: Clicking on this icon will bring up a more detailed display. #### session_time_limit The session_time_limit is a set amount of time that a workspace will be allowed to run once that workspace is created. This time limit is irrespective of whether the user is actively using the session or if the session is disconnected and running in the background. When session_time_limit is configured, the keepalive_expiration setting is not used. This setting is not enabled by default --- ## Managing User Access with Groups # Groups Groups are used to define roles for specific sets of users in Kasm Workspaces. By default there are two groups created by the system, the Administrators group and the All Users group, the All Users group is the default group for every user where statewide settings can be set. Groups can be used to specify Kasm images and settings for different sets of users. For example, you may have a custom image for developers with pre-installed developer tools. You can tie that image to a group. You can define settings for that group, such as enabling bi-directional clipboard. ## Create Group Steps to create individual groups for sections of users. - Select **Access Management > Groups** tab from navigation menu - Select **Add Group** from the top right of the table - Specify Group properties listed below ## Group properties | Property | Description | | --- | --- | | Name | The name of the group. | | Description | The description of the group. | | Priority | Sets the priority of the settings over other groups. | | Is System | A system-level group that cannot be deleted. | Note that group name and priority number must be unique. For help identifying what group priority numbers are available, use the Filters tool in the Group view to sort by **Priority**. There is a **Users** tab in the edit group page that allows for the selection of its users. ## Group settings To change the settings for a specific group, select the groups tab, click the edit icon on the desired group, and click **Add Settings** in the Group Settings card. Delete and edit icons appear to the right of each setting. When a user belongs to multiple groups, the setting on the group with the lowest priority takes effect. For settings such as `volume_mapping`, all settings are combined across the groups a user belongs to. The following video gives an overview of groups and group settings. To configure group settings: - Log into the UI as an administrator. - Select **Groups** - Next to the desired group select **View** from the actions menu. - Scroll down to the Group Settings panel. Update settings as desired. | Variable Name | Description | | :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | allow_2fa_self_enrollment | Allow users to self enroll two factor devices in the profile settings page when enabled. | | allow_kasm_audio | Allow audio streaming for a Kasm. | | allow_kasm_clipboard_down | Allows users to paste text from the Kasm to their local computer. | | allow_kasm_clipboard_seamless | Allows users to copy and paste text without using Kasm control panel. This feature is only available on Chrome and Chromium-based client browsers | | allow_kasm_clipboard_up | Allow users to paste from their local computer to the Kasm. | | allow_kasm_delete | If enabled, users are allowed to delete their running sessions. | | allow_kasm_downloads | Allow users to download files from a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_kasm_force_delete | If enabled, users are allowed to force-delete sessions that are stuck in the deleting state | | allow_kasm_gamepad | Allow users to pass local gamepads into the Kasm session. See Gamepad Passthrough for more details. | | allow_kasm_microphone | Allow microphone passthrough to a Kasm. When enabled, users can pass their local microphone through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_kasm_rdp_client_file_transfer_clipboard | This setting only applies to RDP client Kasm sessions. In RDP file transfers are part of the clipboard and independent directional control of file transfers is not possible. This setting will enable file transfer in the directions that text clipboard has been enabled via **allow_kasm_clipboard_down** and **allow_kasm_clipboard_up**. | | allow_kasm_rdp_map_local_drives | Allow sessions using the RDP Gateway to map client local drives into the RDP target. This setting is an all or nothing setting. When enabled it will map all client drives into the rdp session. | | allow_kasm_smart_card_passthrough | Allow sessions to pass smart cards through for authentication and signing. Supports RDP sessions via RDP Gateway or web native client, and container workspaces with the Kasm Native Smartcard Client. See Smart Card Passthrough for details. | | allow_kasm_rdp_webauthn_passthrough | Allow sessions using the RDP Gateway to pass webauthn requests from the RDP target to the client. This only works for Windows clients running the builtin mstsc.exe RDP client. | | allow_kasm_webcam | Allow webcam passthrough to a Kasm. When enabled, users can pass their local webcam through to the Kasm session. On `RDP local client` workspaces this only works with desktop editions of Windows. | | allow_kasm_printing | Allow printing of documents using local printers | | allow_kasm_pause | If enabled, users are allowed to pause their running sessions. | | allow_kasm_sharing | Allow the user to share access to their session with other users. See Session Sharing for more details. | | allow_kasm_stop | If enabled, users are allowed to stop their running sessions. | | allow_kasm_uploads | Allow users to upload files to a Kasm. On `RDP local client` workspaces this has no effect see **allow_kasm_rdp_client_file_transfer_clipboard**. | | allow_persistent_profile | Allow the use of persistent profiles if configured on the Workspace. See Persistent Profiles for details | | allow_point_of_presence | Allow the user to use point of presence features for certain Workspaces. | | allow_totp_2fa | Allow for TOTP tokens (e.g.: Google Authenticator) to be used as a two factor authentication method for the group. | | allow_user_storage_mapping | When enabled the user is allowed to configure their own Storage Mappings via their profile. When disabled, new user configurations will not be allowed, nor will using any previously configured mappings be allowed when new sessions are created. | | allow_webauthn_2fa | Allow for WebAuthn devices (e.g. YubiKeys) to be used as a two factor authentication method for the group. | | allow_zone_selection | Allow the user to specify the deployment zone when creating a session. A dropdown will appear on the user dashboard with the available Zones. **Auto** represents the default behavior which is to provision in current Zone. If a Zone is specified, the request will not search alternate zones if no resources are available in the requested Zone. | | auto_add_local_user | When enabled, local users will automatically be added to this group when created and upon each authentication. | | auto_login_to_kasm | Sends users directly to kasm using default workspace after login | | control_panel. advanced_settings. show_game_mode | Whether the game mode option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_ime_input_mode | Whether the ime input mode option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_keyboard_controls | Whether the keyboard controls option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_pointer_lock | Whether the pointer lock option is present in the advanced menu on the Kasm Session control panel. | | control_panel. advanced_settings. show_prefer_local_cursor | Whether the prefer local cursor option is present in the advanced menu on the Kasm Session control panel. | | control_panel.show_fullscreen | Whether the fullscreen option is present on the Kasm Session control panel. | | control_panel. show_delete_session | Whether the delete session option is present on the Kasm Session control panel. | | control_panel. show_display_manager | Whether the display manager is present on the Kasm Session control panel. The display manager allows the user to add and remove additional displays. | | control_panel.show_logout | Whether the logout option is present on the Kasm Session control panel. | | control_panel. show_return_to_workspaces | Whether the return to workspaces option is present on the Kasm Session control panel. | | control_panel. show_streaming_quality | Whether the show streaming quality workspaces option is present on the Kasm Session control panel. | | control_panel.pwa_install_option | Whether the user must be presented with the option to install per-workspace PWAs. | | dashboard_redirect | If configured, standard users will be redirected to the defined external website instead of being shown the main dashboard screen. | | default_image | The default Workspace used when the **/go** url is called. This is also used for the auto_login_to_kasm setting. The system will create a Workspace if one does not exist. If the user already has a Workspace, the session is resumed | | default_ui_language | The default UI language to set for the group. This is applied at next user login and is also overridden if the user sets the language in their profile. | | delete_anon_user_on_expiry_with_active_session | If enabled, anonymous users are deleted immediately upon expiration even if they have an active session. If disabled, deletion is deferred until all active sessions have ended. | | display_ui_errors | If enabled, detailed information will be displayed on the client browser in the event of an error. | | enable_container_logging | If enabled, each workspace container will log to the database. | | enable_ui_server_logging | If enabled, log messages will be sent from client browser to the Kasm Workspaces server. | | expose_user_environment_vars | Expose KASM_USER and KASM_USER_ID environment variables inside the Kasm. | | idle_disconnect | Disconnect the Kasm connection if idle for this long. Time specified in minutes. | | inject_ssh_keys | When enabled the system will inject the user's SSH public and private keys into new sessions automatically. Users can update their keys via the Profile. | | kasm_audio_default_on | Default to audio enabled on Kasm start | | kasm_ime_mode_default_on | Default to IME enabled on Kasm start | | kasmvnc_mode_preference | Set the KasmVNC streaming modes available and the preferred order. See Kasm Performance for more details. | | keepalive_expiration | The number of seconds a Kasm will stay alive unless a keeplive request is sent from the client. | | keepalive_expiration_action | The action the system should take when a session expires according to the keepalive_expiration. Valid options are `delete`, `stop`, and `pause`. `stop` and `pause` actions are only valid for container based Workspaces. All other Workspaces will utilize `delete` regardless of what is defined. | | keepalive_interval | The number of seconds in between keepalive requests from the client when the user is actively in a session. | | lock_sharing_video_mode | Locks video quality to static resolution of 720p when sharing is enabled. Recommended for best performance. | | max_kasms_per_user | The maximum number of simultaneous sessions a users is allowed to provision. | | max_user_storage_mappings | The maximum number of Storage Mappings a user is allowed to have registered to their account. | | read_only_user_storage_mappings | When enabled, any storage mappings configured on the user account will be forced to read-only. | | require_2fa | Enables two factor authentication for group. Users will be prompted to set Key on next log on. | | run_config | Specify arbitrary docker run params. The settings for run_config on a group will override the run_config settings on an image. See Docker Run Config for more details | | session_time_limit | The amount of time (in seconds) a session will automatically expire. A countdown timer will be displayed to the user. | | staged_session_language_and _timezone_preference_override | When launching a workspace Kasm will by default try to match the user language and timezone to a staged session. If a staged session does not exist that has the matching language and timezone then Kasm will create a new session with the specified language and timezone. If the override is set to true then Kasm will use a staged session for the selected workspace even if the language and timezone do not match. This overrides the user setting in the user profile. | | usage_limit | Limits the total number of hours a user or group can have running sessions. See the `usage_limit`_ documentation below for more details. **Type** - **Per User** - Each user of the group has their own limit. - **Per Group** - All members share the usage limit. **Interval** - **Daily** , **Weekly** , **Monthly** , **Total**. **Hours** - The number of hours allowed during each interval. | | volume_mapping | Map a local server directory to Kasm. Details available in the Volume Mapping Guide | | web_filter_policy | Enabled web filtering and sets the Web Filter Policy to be used. Policies can also be set or force disabled on Workspaces. Policies assigned to Workspaces take priority over those defined via Group Settings. | :::caution The `allow_kasm_clipboard_up` setting (Control Panel clipboard) is subject to browser-side limitations. Very large clipboard payloads, typically above ~15 MiB, can overwhelm the browser WebSocket send buffer and delay client heartbeats, which results in a temporary session disconnect and automatic reconnection. This does not affect Seamless Clipboard behavior. For best reliability, enable `allow_kasm_clipboard_seamless` for workflows that paste very large text payloads. ::: ### Session time limits Several settings in the table above control Kasm session lifetime. The following sections describe them and their relationship to each other. #### keepalive_expiration This can also be described as the session timeout. This value determines how long Kasm will wait before destroying, stopping or pausing a session if no keepalive is received from the client. Keepalives are sent whenever a user is connected to a Kasm session even if the user is not actively using the Kasm Session. This value should be at least twice the keepalive_interval. This setting is 1 hour by default in the "All Users Group". The action taken is determined by the `keepalive_expiration_action` Group Setting. #### keepalive_expiration_action Administrators can decide what happens to sessions once they expire. Valid options are: - `delete` - The session is destroyed. - `pause` - The session is paused, preserving the disk, process and memory state. Paused sessions will still consume resources in physical memory and/or swap. Sessions resumed from a paused state will still have the previous programs launched and active. This action is valid for container-based sessions only. All other types will utilize the `delete` action. - `stop` - The session is stopped, preserving the disk state. Sessions resumed from a stopped state will have the previous files intact, but previously running programs will need to be restarted. This action is valid for container-based sessions only. All other types will utilize the `delete` action. :::note When sessions are stopped or paused, the CPU and RAM resources on the agent become available for other requests to create new sessions. This can prevent a user from resuming a paused or stopped session when the agent's resources are consumed by other running sessions. With cloud AutoScale, the system does not destroy agents that have stopped or paused sessions, and it allows other sessions to be provisioned on the agent. When this is undesirable, do not give users the `allow_kasm_pause` and `allow_kasm_stop` permissions. ::: #### keepalive_interval The keepalive_interval is how often the client will send a keepalive request to Kasm when the user is actively using a session. This setting is 300 seconds by default for the "All Users Group". #### idle_disconnect This setting is the number of minutes Kasm will wait when the user is idle before taking an action. This action will depend on the user context. If the user is in a Kasm session when the idle timeout expires the user is disconnected from the Kasm session and sent back to the dashboard. Any Kasm sessions that the user was connected to will be disconnected and those sessions will be subject to the keepalive_expiration. If the user is at the dashboard when the idle timeout expires the user is logged out of Kasm. This setting is set to 20 minutes by default in the "All Users Group". This setting must be higher than the keepalive_interval setting to function properly. #### usage_limit The usage_limit setting is a highly flexible option allowing the administrator to configure a maximum usage number of hours either for each user in the group or for the entire group collectively to use over a set time period. This setting is a decimal value. When using the usage_limit setting all time that a Kasm session is running is counted against the total, this includes when the user is not actively connected to the session but the session is still running. This setting is for use cases where user workspace access should be metered. This setting is not enabled by default. :::note Accounting for paused or stopped sessions is unchanged. Users are charged for the full duration of the session, even when the session is paused or stopped. ::: The user can see how much time they have used/have remaining on the user dashboard: Clicking on this icon will bring up a more detailed display. #### session_time_limit The session_time_limit is a set amount of time that a workspace will be allowed to run once that workspace is created. This time limit is irrespective of whether the user is actively using the session or if the session is disconnected and running in the background. When session_time_limit is configured, the keepalive_expiration setting is not used. This setting is not enabled by default ## Group permissions Groups have an optional list of permissions attached to them. When a user logs in, Kasm aggregates all permissions across the groups the user belongs to, which determine the actions the user is authorized for. There are two built-in groups, `Administrators` and `All Users`. The Administrators group has the Global Admin permission, and the built-in `All Users` group has the User permission. All users are members of the `All Users` group automatically. To configure group permissions: 1. Log in to the UI as an administrator. 2. Select **Groups**. 3. Next to the desired group, select **Edit** from the actions menu. 4. Select the **Permissions** tab to view and edit the permissions applied to the group. The following table lists each permission and its description. | Name | Description | |------|-------------| | User | Default level of permissions for normal users. | | Global Admin | Global Administrator with all permissions. | | Users View | View users and user information. | | Users Modify | Modify existing users. | | Users Create | Create new users. | | Users Delete | Delete exiting users. | | Users Modify Admin | Modify users with Global Admin permissions. | | Users Auth Session | Login and logout on behalf of another user. | | Groups View | View groups, group members, and group settings. | | Groups Modify | Modify group members and settings. | | Groups Create | Create new groups. | | Groups Delete | Delete existing groups. | | Groups View IfMember | View groups you are a member of, excluding system groups. | | Groups Modify IfMember | Modify groups you are a member of, excluding system groups. | | Groups View System | View groups, group members and group settings of system defined groups. | | Groups Modify System | Modify group members and settings of system groups. | | Groups Delete System | Delete a system group. | | Agents View | View agents and agent settings. | | Agents Modify | Modify agent settings. | | Agents Create | Create agents. | | Agents Delete | Delete existing agents. | | Staging View | View staging list and stage configuration settings. | | Staging Modify | Modify existing staging settings. | | Staging Create | Create new staging configurations. | | Staging Delete | Delete existing staging configurations. | | Casting View | View casting list and casting configuration settings. | | Casting Modify | Modify existing casting settings. | | Casting Create | Create new casting configurations. | | Casting Delete | Delete existing casting configurations. | | Sessions View | View all user sessions. | | Sessions Modify | Perform modifications to a session of another user. | | Sessions Delete | Delete the session of another user. | | Session Recordings View | View user session recordings. | | Images View | View images | | Images Modify | Modify image configurations. | | Images Create | Create new images. | | Images Delete | Delete existing images. | | Images Modify Resources | Modify image resource settings, such as CPU and Memory settings. | | DevAPI View | View developer API list. | | DevAPI Modify | Modify developer API configurations. | | DevAPI Create | Create a new developer API key. | | DevAPI Delete | Delete an existing developer API key. | | Webfilters View | View webfilters | | Webfilters Modify | Modify existing webfilters | | Webfilters Create | Create a new webfilter. | | Webfilters Delete | Delete an existing webfilter | | Brandings View | View branding configurations. | | Brandings Modify | Modify existing branding configurations. | | Brandings Create | Create new branding configurations. | | Brandings Delete | Delete existing branding configurations. | | Settings View | View global settings. | | Settings Modify | Modify global settings in all categories. | | Settings Modify Auth | Modify global settings in the authentication category. | | Settings Modify Auth Captcha | Modify global settings in the authentication captcha category. | | Settings Modify Cast | Modify global settings in the casting category. | | Settings Modify Images | Modify global settings in the images category. | | Settings Modify License | Modify global settings in the license category. | | Settings Modify Logging | Modify global settings in the logging category. | | Settings Modify Manager | Modify global settings in the manager category. | | Settings Modify Scale | Modify global settings in the scale category. | | Settings Modify Subscription | Modify global settings in the subscription category. | | Settings Modify Filter | Modify global settings in the filter category. | | Settings Modify Storage | Modify global settings in the storage category. | | Settings Modify Connections | Modify global settings in the connections category. | | Settings Modify Theme | Modify global settings in the theme category. | | Auth View | View LDAP/OIDC/SAML configurations. | | Auth Modify | Modify LDAP/OIDC/SAML configurations. | | Auth Create | Create LDAP/OIDC/SAML configurations. | | Auth Delete | Delete LDAP/OIDC/SAML configurations. | | Licenses View | View licenses. | | Licenses Create | Add new licenses. | | Licenses Delete | Delete licenses. | | System View | View system information. | | System Export Schema | Export system schema. | | System Import Data | Import system data. | | System Export Data | Export system data. | | Reports View | View system reports and logging. **Warning**: Providing access to logs can provide a lot of potentially sensitive information. | | Managers View | View the managers. | | Managers Modify | Modify existing managers. | | Managers Create | Create a new manager. | | Managers Delete | Delete existing managers. | | Zones View | View Zones and Zone settings. | | Zones Modify | Modify Zone settings. | | Zones Create | Create new Zones. | | Zones Delete | Delete existing Zones. | | Companies View | View companies. | | Companies Modify | Modify existing company. | | Companies Create | Create a new company. | | Companies Delete | Delete an existing company. | | Connection Proxy View | View connection proxies. | | Connection Proxy Modify | Modify connection proxies. | | Connection Proxy Create | Create a connection proxy. | | Connection Proxy Delete | Delete an existing connection proxy. | | Physical Tokens View | View physical 2FA tokens. | | Physical Tokens Modify | Assign/Unassign physical 2FA tokens. | | Physical Tokens Create | Import or create physical 2FA tokens. | | Physical Tokens Delete | Delete a physical 2FA token. | | Servers View | View servers. | | Servers Modify | Modify existing servers. | | Servers Create | Create new servers. | | Servers Delete | Delete servers. | | Server Pools View | View server pools. | | Server Pools Modify | Modify server pools. | | Server Pools Create | Create a new server pool. | | Server Pools Delete | Delete a server pool. | | Autoscale View | View AutoScale configurations. | | Autoscale Modify | Modify an existing AutoScale configuration. | | Autoscale Create | Create a new AutoScale configuration. | | Autoscale Delete | Delete AutoScale configurations. | | VM Provider View | View VM Provider configurations. | | VM Provider Modify | Modify VM Provider configurations. | | VM Provider Create | Create new VM Provider configurations. | | VM Provider Delete | Delete VM Provider configurations. | | Autoscale Schedule View | View an AutoScale schedule. | | Autoscale Schedule Modify | Modify an AutoScale schedule. | | Autoscale Schedule Create | Create an AutoScale schedule. | | Autoscale Schedule Delete | Delete an AutoScale schedule. | | DNS Providers View | View DNS provider configurations. | | DNS Providers Modify | Modify DNS provider configurations. | | DNS Providers Create | Create new DNS Provider configurations. | | DNS Providers Delete | Delete DNS Provider configurations. | | Registries View | View Workspace Registries. | | Registries Modify | Modify existing Workspace Registries. | | Registries Create | Add new Workspace Registries | | Registries Delete | Delete a Workspace Registry | | Storage Providers View | View Storage Providers. | | Storage Providers Modify | Modify existing Storage Providers. | | Storage Providers Create | Create new Storage Providers. | | Storage Providers Delete | Delete an existing Storage Provider. | | Egress Providers View | View Egress Providers. | | Egress Providers Modify | Modify existing Egress Providers. | | Egress Providers Create | Create new Egress Providers. | | Egress Providers Delete | Delete an existing Egress Provider. | | Egress Gateways View | View Egress Gateways. | | Egress Gateways Modify | Modify existing Egress Gateways. | | Egress Gateways Create | Create new Egress Gateways. | | Egress Gateways Delete | Delete an existing Egress Gateway. | | Egress Credentials View | View Egress Credentials. | | Egress Credentials Modify | Modify existing Egress Credentials. | | Egress Credentials Create | Create new Egress Credentials. | | Egress Credentials Delete | Delete an existing Egress Credential. | | Banners View | View banners. | | Banners Modify | Modify existing banners. | | Banners Create | Create new banners. | | Banners Delete | Delete an existing banner. | | AD User Management View | View AD User Management Configurations. | | AD User Management Modify | Modify existing AD User Management Configurations. | | AD User Management Create | Create new AD User Management Configurations. | | AD User Management Delete | Delete an existing AD User Management Configuration. | ### Permission changes Kasm embeds a user's permissions in their session token, which is generated on login. The **Session Lifetime** global setting controls the token lifetime. The UI requests a new session token every 5 minutes. To apply new permissions fastest, have the user log out and log back in. Otherwise, the change applies within 5 minutes. ### Permission dependencies Most permissions stand alone, but some permissions depend on others. Generally, a `Modify`, `Create`, or `Delete` permission needs the corresponding `View` permission. The following additional dependencies require you to grant multiple permissions to achieve the desired effect. - `Licenses View` requires `System View` - `Permissions View` requires `Groups View` - `Registries View` requires `Images View`, `System View`, and `Agents View` - `Autoscale View` requires `Server Pools View` - `Autoscale Schedule View` requires `Server Pools View` - `DNS Providers View` requires `Server Pools View` - `VM Providers View` requires `Server Pools View` and `Autoscale View` - `Users Delete` requires `Sessions Delete` if the target user has running sessions and `Users Modify` - `Users Delete` requires `Users Modify Admin` to delete a user that has the `Global Admin` permission - `Egress Gateways Create`, `Egress Gateways Modify`, `Egress Gateways Delete`, `Egress Credentials Create`, `Egress Credentials Modify` and `Egress Credentials Delete` require `Egress Providers Modify`. - `Servers View` and `Server Templates View` requires `Server Pools View` and `Zones View` In many cases multiple permissions are not required. However, Kasm hides certain UI elements when the user lacks the permissions to view them. For example, a user may have `View Images` permissions but not `View Servers` permissions. When that user views an individual Workspace Image that targets a Server, the drop-down to view or edit the targeted server stays hidden. ### Special permissions Groups offer more permissions beyond the basic View, Create, Modify, and Delete actions. The `Groups View IfMember` and `Groups Modify IfMember` permissions allow a user to view or modify a group when they are a member of that group. This access does not extend to built-in system groups (All Users and Administrator). To edit or view system groups, the user also needs the Groups View/Modify System permission. An additional permission protects the modification of users with the `Global Admin` permission. To modify a `Global Admin`, the requesting user must be a `Global Admin` or hold the `User Modify Admin` permission. Two permissions allow modifications to Workspace Images: `Images Modify` and `Images Modify Resources`. The `Images Modify` permission allows modification of all Image settings except those that change the physical or virtual compute resources. The following settings require the `Images Modify Resources` permission to edit: - GPU Count - Cores - Memory - CPU Allocation Method - Uncompressed Image Size - Docker Registry - Docker Registry Username - Docker Registry Password - Hash - Volume Mappings - Docker Run Config Override - Docker Exec Config ## Group Workspaces Administrators can define which Workspaces are available to each group. By default newly created workspaces are automatically assigned to the **All Users** group. This behavior can be changed by modifying the **Add Images To Default Group** global [Settings](../../../reference/settings.mdx). ## SSO Group Mappings Administrators can configure the system to automatically map users that authenticate with an SSO provider (e.g SAML, OpenID, LDAP) into Kasm Groups. If **Assign All Users** is selected, any user that authenticates with the defined SSO provider will be added to the Kasm group. Otherwise, only users that have the defined **Group Attributes** passed in by the SSO provider will be added to the group. These group mappings are evaluated and updated at each user login. If a mapping is defined and a user does not have the group attributes listed, the user will be removed from the group. ## Group File Mappings File Mappings allow the administrator to manage files to be mapped to the inside of a user's container based Workspace session. File Mappings can be defined on a User, Group, and/or Workspace. See the primary documentation on [File mappings](../../workspaces-sessions/file-mappings.mdx) for more details. When a user belongs to multiple Groups that define a File Mapping with the same destination, the group with the lowest priority value gets mapped into the user's container. The following is an example File Mapping of a Chrome Managed Policy to define bookmarks in Chrome. --- ## Active Directory ## Active Directory / OpenLDAP The following section gives an example of a typical LDAP configuration of users and groups using Active Directory. Consider the following domain “kasm.core” with the following structure ![Domain Structure](/img/ldap/fake_ldap_domain.jpg) - MyOrg : Top level OU in the kasm.core domain - all_kasm_app_users : Security Group under the MyOrg OU that houses all users and groups that should be allowed access to the Kasm App. If a user is not a member of this group they should not be allowed to log into the app. - kasm_group_1 : A Security group that is a member of the all_kasm_app_users Group. Members of this group should automatically be mapped to a group in Kasm named Ldap Group 1 - Test_user_1 : A user that is a member of kasm_group_1 - Test_user_2 : A user that is a member of all_kasm_app_users. This user should be allowed to access the Kasm app but is not automatically placed in to special groups - test_user_3 : This user is not a member of the all_kasm_app_users group and therefore not be allowed to log in to the Kasm application - ldap_service_account : This user will be used as a service or ‘bot’ account do to LDAP queries ![LDAP Domain](/img/ldap/ldap_domain.png) ### Configure the LDAP Configuration (Active Directory) * Log into the Kasm Web UI as an administrator * Click Access Management -> Authentication -> LDAP * Click on Add Configuration * The configurations for Microsoft Active Directory are as follows | **Property** | **Value** | | --- | --- | | Name | Kasm Test LDAP Settings | | URL | ldaps://ldap.kasm.core:636 | | Search Base | OU=MyOrg,DC=kasm,DC=core | | Search Filter | &(objectClass=user)(sAMAccountName={"{"}0{"}"})(memberof:1.2.840.113556.1.4.1941:=CN=all_kasm_app_users,OU=MyOrg,DC=kasm,DC=core) | | Group Membership Filter | &(objectClass=group)(member:1.2.840.113556.1.4.1941:={"{"}0{"}"}) | | Email Attribute | mail | | Service Account DN | CN=ldap_service_account,OU=MyOrg,DC=kasm,DC=core | | Service Account Password | password | | Search Subtree | Checked | | Auto Create App User | Checked | | Enabled | Checked | The placeholder '\{0\}' is substituted with a user's username (ex: test_user_1@kasm.core). The placeholder '\{0\}' is required to appear in the Search Filter. A Search Filter must result in exactly one user result. 1.2.840.113556.1.4.1941 is a special OID allowing for recursive enumeration of objects. Effectively this allows users to be determined to members of members. Otherwise the user would need to be a direct member of the specified group. See [Microsoft Docs](https://docs.microsoft.com/en-us/windows/desktop/adsi/search-filter-syntax) for details ### Configure the LDAP Configuration (OpenLDAP / IDM) - Log into the Kasm Web UI as an administrator * Click Access Management -> Authentication -> LDAP - Click on Add Configuration - The configurations for OpenLDAP or IDM are as follows | **Property** | **Value** | | --- | --- | | Name | Kasm Test LDAP Settings | | URL | ldaps://ldap.kasm.core:636 | | Search Base | OU=MyOrg,DC=kasm,DC=core | | Search Filter | (&(objectClass=posixAccount)(uid={"{"}0{"}"}) | | Group Membership Filter | (&(objectClass=groupOfNames)(member={"{"}0{"}"})) | | Email Attribute | mail | | Service Account DN | CN=ldap_service_account,OU=MyOrg,DC=kasm,DC=core | | Service Account Password | password | | Search Subtree | Checked | | Auto Create App User | Checked | | Enabled | Checked | Kasm only supports the "groupOfNames" or "groupOfUniqueNames" objectClasses in OpenLDAP/IDM, linking to a "posixGroup" objectClass is not currently supported. ### Configure an LDAP Enabled Group The following settings can be used to create a group in Kasm named **“LDAP Group 1”**. It will be mapped to LDAP group **kasm_group_1**. When LDAP users that are members of **kasm_group_1** sign in they will automatically be put in the **LDAP Group 1** Kasm group. Settings for the group creation screen: | **Property** | **Description** | | --- | --- | | Name | LDAP Group 1 | | Description | Group mapped to kasm_group_1 in Active Directory | | Priority | 100 | Settings for the **SSO Group Mapping** screen | **Property** | **Description** | | --- | --- | | SSO Provider | LDAP - Kasm Test LDAP Settings | | Assign All Users | Unchecked | | Group Attributes | CN=kasm_group_1,OU=MyOrg,DC=kasm,DC=core | ### Verifying Configurations **Discovering and Authenticating Users** - Log into the Kasm Web UI as an administrator * Click Access Management -> Authentication -> LDAP - Click the arrow for the LDAP Configuration you want to test and then Test LDAP Connection - Enter test_user_1@kasm.core and the correct password - The test should succeed. test_user_1 is a member of kasm_group_1 which is a member of all_kasm_app_users - Enter test_user_2@kasm.core and the correct password - The test should succeed. test_user_2 is a member of all_kasm_app_users - Enter test_user_3@kasm.core and the correct password - The test should fail. test_user_3 is NOT a member of all_kasm_app_users group or any group that is a member of that group ### Group Assignment - Log out of the Kasm Application and Log in as test_user_1@kasm.core - Click Profile. Notice the user is a member of All Users ( set by default) and LDAP Group 1 - Log out of the Kasm Application and Log in as test_user_2@kasm.core - Login will succeed. - Click Profile. Notice the user is only a member of the All Users Group (Set by default) but is not a member of any additional groups - Log out of the Kasm Application. Attempt to log in as test_user_3@kasm.core - Access is denied. test_user_3 is not a member of the required all_kasm_app_user group so is denied access because the LDAP query cant find the user. --- ## Jumpcloud # JumpCloud This example assumes the use of JumpCloud LDAP-as a Service with the following configurations. - A **User Group** named **Kasm Users** that is bound to LDAP. Only users that are members of this group should be allowed to authenticate to Kasm - Users named **kasm-user-1** and **kasm-admin-1** are a member of this group. - A **User Group** group named **Kasm Admins** that is bound to LDAP. Users that are a member of this group will be placed in Kasm's **Administrators** group - A user named **kasm-admin-1** is a member of this group. - A user account named **kasm-ldap-svc** is configured as an [LDAP Binding User](https://support.jumpcloud.com/support/s/article/using-jumpclouds-ldap-as-a-service1) ### Kasm LDAP Configuration - Log into the Kasm Web UI as an administrator * Click Access Management -> Authentication -> LDAP - Click on Add Configuration - Enter the following information , substituting the example **Organization ID** `633df00190c6d619236d3ae1` with your own. | **Property** | **Value** | | --- | --- | | Name | JumpCloud | | URL | ldaps://ldap.jumpcloud.com:636 | | Search Base | ou=Users,o=633df00190c6d619236d3ae1,dc=jumpcloud,dc=com | | Search Filter | &(objectClass=inetOrgPerson)(uid={"{"}0{"}"})(memberOf=cn=Kasm Users,ou=Users,o=633df00190c6d619236d3ae1,dc=jumpcloud,dc=com) | | Group Membership Filter | (&(objectClass=groupOfNames)(member={"{"}0{"}"})) | | Email Attribute | mail | | Service Account DN | uid=kasm-ldap-svc,ou=Users,o=633df00190c6d619236d3ae1,dc=jumpcloud,dc=com | | Service Account Password | password | | Search Subtree | Checked | | Auto Create App User | Checked | | Enabled | Checked | ### LDAP Group Mapping The following settings can be used to map the JumpCloud **Kasm Admins** group to the Kasm Workspaces build in **Administrators** Group. See [Create LDAP linked Group](../ldap.mdx#create-ldap-linked-group) for more details. Settings for the **SSO Group Mapping** screen | **Property** | **Description** | | --- | --- | | SSO Provider | LDAP - Kasm Test LDAP Settings | | Assign All Users | Unchecked | | Group Attributes | cn=Kasm Admins,ou=Users,o=633df00190c6d619236d3ae1,dc=jumpcloud,dc=com | ### Verifying Configurations - Verify you can log into the Workspaces UI with user. **kasm-user-1@jumpcloud.com**. - Verify you can log into the Workspaces UI with user. **kasm-admin-1@jumpcloud.com**. Once authenticated the user should now have access to administrative functions within the app. - Attempting to log into Workspaces as any other user that is NOT a member of the JumpCloud **Kasm Users** group should not succeed. ### Helpful References - https://support.jumpcloud.com/support/s/article/using-jumpclouds-ldap-as-a-service1 - https://support.jumpcloud.com/support/s/article/filtering-by-user-or-group-in-ldap-search-filters1 - https://support.jumpcloud.com/support/s/article/using-ldapsearch-with-jumpcloud1 - https://support.jumpcloud.com/support/s/article/user-attributes-2019-08-21-10-36-47 --- ## LDAP & Active Directory (AD) Authentication # LDAP Authentication ## Create an LDAP Configuration The first step in configuring Kasm to use LDAP for authentication is to set up an LDAP configuration. - Log into the Kasm Web UI as an administrator - Click Access Management -> Authentication -> LDAP - Click Add Configuration ![LDAP Config](/img/ldap/ldap_config.webp) | **Property** | **Description** | | --- | --- | | Name | A name given to the configuration | | URL | The LDAP connection URL to the LDAP server | | Search Base | The Base OU used for searching for objects. Kasm will use the search base DCs to identify users to the applicable LDAP Configuration. i.e `DC=kasm,DC=core` will map to `@kasm.core` | | Search Filter | The search filter used to identify user account names | | Group Membership Filter | This query is used to identify if the user is a member of a particular group. Used for Kasm group to LDAP group mapping | | Email Attribute | The user attribute used to denote the users email address | | Alternate Username Domains | Comma separated list of additional domain names that usernames should match on. Use an asterisks to match usernames without a domain name. See section below on domain name matching. | | Service Account DN | The service or ‘bot’ account used to issue queries to the LDAP server | | Service Account Password | The service or ‘bot’ account password | | Search Subtree | If enabled, objects beneath the Search Base will be discovered | | Auto Create App User | If enabled, Kasm will create an associated user account inside the application when the user first logs in. | | Enabled | Enable or disable this configuration | In order for password resets to work with LDAP accounts, the service account must be provided the authority to reset user passwords in Active Directory and the connection must be made over a secure LDAPS connection. ## User Domain Name Matching Users are expected to login with usernames in the format of username@domain.name. The domain-name portion of the username is used to find the appropriate LDAP configuration based on the domain name specified in the `Search Base` field. There are situations where it is desirable for the usernames to have a different domain name that what is Active Directory. In that case administrators can use the `Alternate Username Domains` field to specify a list of alternate domain names in the username that should be used to match to this LDAP configuration. For example 'greenearth.com,acquired_company.com' would be used with users logging in with username@greenearth.com and username@acquired_company.com in addition to the domain in the `Search Base` field. An asterisks in the `Alternate Username Domains` is supported. An asterisks signifies that usernames that do not have a domain name at all should be matched to this LDAP configuration. Administrators can configure multiple LDAP configurations with an asterisks in the `Alternate Username Domains`, as long as they all point to the same domain. This can be done for redundancy, for example. However, you should not have multiple LDAP configurations that specify an asterisks in the `Alternate Username Domains` field, when they are pointed to different domains. This would result in nondeterministic behavior in matching users to the appropriate LDAP configuration. ## Test Authentication After creating an LDAP configuration, you can test the settings by clicking the Test LDAP Connection icon on the LDAP Configurations Page. ![Test LDAP Config](/img/ldap/test_ldap.webp) Enter known valid user credentials ## Common Errors | **Error** | **Notes** | | --- | --- | | Authentication Error : socket connection error while opening: timed out | The Kasm API server cannot make a connection to the specified LDAP URL. Verify the URL is correct, and network connectivity between the two end points. | | Authentication Error : automatic bind not successful - invalid Credentials | The password for the LDAP service account is invalid. Verify the password is correct and that the account is not locked out. Verify the Service Account DN is correct | | Authentication Error : socket ssl wrapping error : [Errno 104] Connection reset by peer | LDAPS was specified in the LDAP URL but the LDAP server is not communicating over SSL | | Authentication Error : error recieving data : [Errno 104] Connection reset by peer | The LDAP server rejected the connection. Verify that the port specified in the URL is correct. Verify that protocol LDAP or LDAPS is correct in the URL | | Unable to locate user (test@kasm.local) | The user could not be located. Verify the Search Base and Search Filter parameters are correct | | LDAP Login failed for user (test@kam.local) : `({'message':'80090308: LdapErr:DSID-0C09042A, comment: AcceptSecurityContext error, data 52e, v3839\x00','saslCreds': None, 'result':49,'dn':", 'description': 'InvalidCredentials','type': 'bindResponse','refferals':None})` | The provided credentials are invalid or the account is locked out. | | LDAP password reset failed:`({'result': 53, 'description': 'unwillingToPerform', 'dn': '', 'message': '0000001F: SvcErr: DSID-031A124C, problem 5003 (WILL_NOT_PERFORM), data 0\n\x00', 'referrals': None, 'type': 'modifyResponse'})` . | LDAP without SSL was used in the connection, and password reset for a user was attempted. Windows servers only support changing passwords over secure LDAPS connections. | ## Create LDAP linked Group Kasm Workspaces can be configured to automatically map LDAP users to specific Kasm application groups via their LDAP group membership. The mapping is updated for each user when the user logs into the Kasm Web Application. The mapping functionality can be accessed by using the arrow menu and selecting edit for the group you want to add a mapping to. Then selecting the **SSO Group Mappings** tab and click **Add SSO Mapping**. The **Add SSO Mapping Screen** is presented the following fields are available to be filled in: ![Edit Group](/img/groups/edit_group.webp) ![SSO Group Mappings](/img/groups/sso_group_mappings.webp) ![Add SSO Group Mapping](/img/groups/add_sso_group_mapping_config.webp) | **Property** | **Description** | | --- | --- | | SSO Provider | A dropdown of the available SSO identity providers (LDAP, SAML, OpenID) configured in the system. | | Assign All Users | A checkbox that indicates any user that authenticates with the defined SSO provider will be added to the Kasm group | | Group Attributes | The LDAP DN to the desired group | ## LDAP Attribute Mapping Additional LDAP user attributes are returned by the authentication request to the LDAP server. These LDAP user attributes can be mapped to Kasm User fields. Every time the user logs in, the Kasm user fields will be updated with the values returned by the LDAP server. See the documentation for your LDAP provider for a listing of user attributes. These can be configured by editing an existing LDAP Authentication configuration, if creating a new configuration you will need to submit and edit to add them. The following Kasm User fields can be populated with values from LDAP user attributes. - First Name - Last Name - Phone - Organization - Notes - City - State - Country - Email - Custom Attribute 1 - Custom Attribute 2 - Custom Attribute 3 ![LDAP Attribute Mapping](/img/ldap/ldap_attribute_mapping.webp) Kasm can log all LDAP user attributes present in the login event, this is helpful for determining the attribute names. Add a LDAP Attribute Mapping with an attribute name of 'debug' and target any user field. The next time a user logs in, all LDAP user attributes and values will be logged by Kasm. ## AD Sync Kasm can manage user accounts in Microsoft Active Directory by automatically creating user accounts in AD and resetting the user's password in AD to a randomly generated password on each login. This is primarily used in scenarios where the user is authenticated from a SAML or OIDC identity provider and you want Kasm to then create an associated user in AD. This is useful for deployments where Active Directory is required for various purposes, but where AD is not the primary source of identity and access management for the organization. Because Kasm sets a random password for the user in AD each time they login to Kasm, Kasm is able to provide single sign-on to Windows servers that are part of the same AD. The first step in configuring AD Sync is to create an LDAP configuration under Access Management->LDAP, in the administrator panel. See the LDAP configuration sections for details on configuring LDAP. LDAP configurations are normally used in Kasm for authenticating users, but in this case we don't want users to be able to use their AD credentials to log into Kasm. Therefore, the recommendation is to disable the LDAP configuration in Kasm, which will keep this LDAP configuration from being used for authentication to Kasm. The service account used in the LDAP configuration must have the authority to reset user accounts in AD. If you have enabled user account creation or managing group membership, the service account will need proper authority to create users and/or add and remove users from groups. The LDAP Configuration needs to specify **Alternative User Domains**, which is a comma separated list of domain names within a username that will get mapped to the domain configured by the LDAP configuration. For example, you may have a SAML identity provider where usernames are in the format username@company.com, but your Active Directory domain is company.local. Specifying an Alternative User Domain value of `company.com` will cause Kasm to search for the user in AD as `username@company.local`. After the LDAP Configuration is created, Edit the configuration and switch to the **AD Sync** tab. Click the Add button to create an AD Sync configuration. AD Sync configurations have the following properties. | Property | Description | | -------- | ----------- | | Type | The source of identities for Kasm to synchronize. Valid options are local, saml, or oidc. | | Enable Random Password on Login | Kasm will reset the password on the associated AD user account, each time the user logs into Kasm. | | Enable Create User | Kasm will automatically create the user in AD if it does not already exist. | | Enable AD Group Management | Kasm will automatically add/remove users from groups in AD, based on group mappings in Kasm. | | Password Length | Kasm will use a randomly generated password of this length for AD users managed by Kasm. | | User Container DN | The DN of the container in AD to create new users within. Existing users do not need to be in this container. Example: OU=MyOrg,DC=kasmweb,DC=local | ![AD Sync Configuration](/img/ldap/ad_sync_configuration.webp) Turning off Random Password on Login will break single sign-on to servers in Kasm that are joined to the same Active Directory domain and is not a recommended configuration. ### Synchronize AD Groups If enabled, Kasm will add and remove users to/from groups in AD, based on group mappings defined in Kasm. In order for a group in Kasm to be eligible for synchronization, it must have two SSO group mappings, one pointing to the [LDAP](../../workspaces-sessions/pwa/index.mdx) configuration with the target AD Sync and one pointing to the source [SAML](saml-authentication.mdx#group-assignment) or [OIDC](oidc.mdx#group-assignment) configuration. In addition to the Kasm group having the two SSO Group Mappings, the user must also be a member of that group in Kasm, in order for them to get added to the associated group in AD. Users will be removed from the associated group in AD if they are not a member of the associated Kasm group. ![LDAP AD Sync Group Mappings](/img/ldap/sso_group_mappings_adsync.webp) ### AD User Attributes By default, Kasm creates users with the following AD attributes and values. - **displayName** - The displayName is set to the username as seen in Kasm, unmodified. - **sAMAccountName** - Set to the same value as the `name` attribute. - **name** - By default Kasm creates an AD name using the first 9 alpha numeric characters of the Kasm username, domain name excluded, followed by a hyphen and the first 10 characters of the Kasm user ID. For example, a user that logs into Kasm as `john.smith@company.com` would have a Windows sAMAccountName of `john-smit-abc1234567`. Use an attribute mapping to `name` to override both the `name` and `sAMAccountName` LDAP Attributes with a username defined by the IdP. See details below for defining attribute mappings. - **userPrincipalName** - The sAMAccountName with the domain name appended, see the above definition for sAMAccountName for how that value is derived. Example, john.smith@company.com where the LDAP Configuration **Search Base** field is `OU=MyOrg,DC=company,DC=local` would result in a value of `john-smit-abc1234567@company.local`. - **givenName** - The `First Name` field on the Kasm User is used if present. - **sn** - The `Last Name` field on the Kasm User is used if present. [LDAP attribute mappings](../../workspaces-sessions/pwa/index.mdx) can be used to map additional Kasm User fields to AD User attributes and/or overwrite the above defaults. If the source users come from a [SAML](saml-authentication.mdx#saml-attribute-mapping) or [OIDC](oidc.mdx#openid-attribute-mapping) identity provider, administrators can configure attribute mappings, so that the Kasm users will have fields such as `First Name` and `Last Name` populated by the SAML/OIDC IdP. This is a screenshot of [SAML Attribute Mappings](saml-authentication.mdx#saml-attribute-mapping) that cause the Kasm user attributes `First Name`, `Last Name`, and `Custom Attribute 1` fields to get populated by data provided by the SAML Identity Provider. ![SAML Attribute Mappings](/img/ldap/saml_attribute_mappings_adsync.webp) This screenshot shows a [LDAP Attribute Mapping](../../workspaces-sessions/pwa/index.mdx) defined for taking the value in the Kasm User `Custom Attribute 1` field and populating the `displayName` in the AD user created by Kasm. In the previous screenshot, you can see that the SAML Identity Provider provides that value through its configured attribute mapping. ![LDAP Attribute Mappings](/img/ldap/ldap_attribute_mapping_adsync.webp) Changes to AD user attributes are synchronized on each login. ## Configuration Examples - [Active Directory / OpenLDAP](ldap/active-directory.mdx) - [JumpCloud](ldap/jumpcloud.mdx) --- ## Login Configuration: Auth & Notices # Login Configurations Kasm offers several alternate authentication methods for users with either [Two Factor](two-factor.mdx), [SAML 2.0](saml-authentication.mdx) or [LDAP](ldap.mdx) integration. ![Login with Banner and Help Link](/img/login/login_page.webp) ## Login Notice The login notice is a message displayed at the bottom of the login form. This message can be configured using the **Notice Title** and **Notice Message** in the global [Settings](../../../reference/settings.mdx). This message can be used to display a legal notice, terms of service, and other information that needs to be displayed to a user prior to login. ## Login Assistance Login assistance can be setup for users giving them an easily accessible link on the login page. The login help page must be created in a separate link that can be passed to the login panel through the login_assistance [Setting](../../../reference/settings.mdx) under the Authentication section. Change this setting back to 'None' to hide the login assistance link. --- ## Auth0 ## Auth0 OpenID Setup This guide walks through a basic setup allowing Auth0 users to authenticate with a Kasm deployment. Reference Docs: - [https://auth0.com/docs/authenticate/protocols/openid-connect-protocol](https://auth0.com/docs/authenticate/protocols/openid-connect-protocol) - [https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes](https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes) ### Creating an Auth0 OAuth App 01. Login to the Auth0 portal as an Admin. 02. Expand **Authentication** and select **Applications**. 03. Click **Create Application**. ![Create Application](/img/oidc/auth0/create_application.png) 04. Give the app a name (e.g `Kasm`), select **Regular Web Application** and click **Create**. ![Create Web Application](/img/oidc/auth0/create_web_application.png) 05. Select the **Settings** Tab. 06. Take note of the **Client ID** and **Client Secret** values. These will be used in later steps. ![Create ID and Secret](/img/oidc/auth0/client_id.png) 07. In the **Application URIs** section, **Allowed Callback URLs**, add the deployment's Kasm callback endpoint. Ex: `https://kasm.example.com/api/oidc_callback` 08. In the **Application URIs** section, **Allowed Logout URLs**, add the root of the Kasm deployment. Ex: `https://kasm.example.com/` ![Callback URL and Logout URL](/img/oidc/auth0/application_uris.png) 09. If using Auth0 `enterprise`, in the **Backchannel Logout** section, configure the **Back-Channel Logout URI** with the deployment's endpoint, ex. `https://kasm.example.com/api/oidc_backchannel_logout`. Select any or all supported logout-initiating events. ![Back-Channel Logout URI](/img/oidc/auth0/backchannel_slo.webp) Back-channel logout will fail with vague errors in the Auth0 console if the Kasm is configured with insecure HTTPS certificates, e.g. if the certificates are self-signed. 10. Scroll down and expand **Advanced Settings**, the select **Endpoints**. Take note of the **OAuth Authorization URL**, **OAuth Token URL**, and **OAuth User Info URL**, and **OpenID Configuration**. These will be used in later steps. ![OAuth Endpoints](/img/oidc/auth0/endpoints.png) 11. Click **Save Changes**. 12. In a separate tab, navigate to the URL value obtained from the **OpenID Configuration** field earlier. 13. Find and save off the value for `"issuer"`, for use in a later step. ### (Optional) Configuring Auth0 to forward User Roles In many cases it may be desireable to place SSO users in specific Kasm Groups based on their Roles as defined within Auth0. The following steps may be used to configure Auth0 to provide Kasm with the User's Role during authentication. 01. From the Auth0 admin console expand **Actions**, select **Library** and click **Build Custom**. ![Build Custom Action](/img/oidc/auth0/build_custom.png) 02. In the Create Action popup, enter a name (e.g `Add User Roles`) , select `Login / Post Login` as the **Trigger** and the recommended runtime (e.g `Node 18 Recommended`). ![Create Action](/img/oidc/auth0/create_action.png) 03. Click **Create**. 04. Replace the contents of editor with the following code snippet and click **Deploy** . ```Javascript exports.onExecutePostLogin = async (event, api) => { const namespace = 'auth0'; if (event.authorization) { api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles); api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles); } } ``` ![Deploy Action](/img/oidc/auth0/deploy_action.png) This example is pulled from the Auth0 Documentation: https://auth0.com/docs/manage-users/access-control/sample-use-cases-actions-with-authorization#add-user-roles-to-tokens The `namespace` can be changed as desired. Per the example `auth0` is used which will result in the **Groups Attrbute** setting in the Kasm OIDC config being `auth0/roles`. 05. In the main menu, expand **Actions**, select **Flows**, then click **Login**. ![Login Flow](/img/oidc/auth0/login_flow.png) 06. In the **Add Action** section, select **Custom**. The recently created action (e.g `Add User Roles`) should be visible. ![Login Flow](/img/oidc/auth0/configure_login_flow_1.png) 07. Drag the action into the workflow and click **Apply**. ![Login Flow](/img/oidc/auth0/configure_login_flow_2.png) ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | --- | --- | | **Enabled** | Checked | | **Display Name** | Continue with Auth0 | | **Logo URL** | `https://cdn.auth0.com/website/new-homepage/dark-favicon.png` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `` | | **Token URL** | `` | | **User Info URL** | `` | | **Scope** | `openid` `email` `profile` | | **Username Attribute** | `email` | | **Groups Attribute** | `auth0/roles` | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | `` | | **Logout with OIDC Provider** | Checked | | **Enable OIDC SLO Frontchannel Endpoint** | Unchecked | ![Kasm OIDC Configurations](/img/oidc/auth0/kasm_oidc_configuration.webp) 6) Click **Save** to save the changes. ### Auth0 Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. ![Login Screen](/img/oidc/auth0/login.png) 2. Click **Continue with Auth0** 3. The user is redirected to Auth0 for auth. ![Auth0 Auth](/img/oidc/auth0/authorization.png) 4. Upon completion, the user is logged into the Kasm app. ### Group Mapping In a previous section Auth0 was configured to send a list of **Roles** the user belongs to during the OpenID auth workflow. We can now configure Kasm Groups with the Role associations so that users are automatically added/removed based on their Auth0 Membership. 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups** -> **Add Group**. 3. Name the Group **Premium**, and define a priority. 4. Click **Save** to create the group. ![Group Configuration](/img/oidc/auth0/groups.png) 1. On the groups screen, using the arrow menu select **Edit** on the group that was just created. 2. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 3. Select the OpenID IDP that was created above `OpenID - Continue with Auth0` for the **SSO Provider**. 4. Then enter the Auth0 group name desired in the **Group Attributes** field, e.g `Kasm Premium`. 5. Click **Submit** ![Add SSO Group Mapping](/img/oidc/auth0/sso_group_mapping.png) The Example Role as defined in Auth0. ![Auth0 Role SSO](/img/oidc/auth0/sso_role_config.png) 1. Logout, then login via the Auth0 Open ID login with a user that is a member of the specified group. 2. View the users group membership to ensure they are added to the newly created group. --- ## Github ## Github OpenID Setup :::warning Be mindful when configuring public OpenID providers. Any user who authenticates with the provider gains access to your Kasm Workspaces deployment. Kasm group permissions can restrict access to Workspace apps and desktops, but any user of the public authentication provider can still log in to your deployment. Use a private OpenID provider unless you intend to allow access to all users of the OpenID platform provider. ::: This guide walks through a basic setup allowing Github users to authenticate with your Kasm deployment Github OpenID does not support OIDC Single Logout. Reference Docs: - [https://docs.github.com/en/developers/apps/building-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps) ### Creating a Github OAuth App 1. Login to Github and select **Settings** from the profile dropdown: [https://github.com/settings/profile](https://github.com/settings/profile) 2. Select **Developer Settings**. 3. Select **OAuth Apps**, then click **New OAuth App**. 4. Give the application a name (e.g `Kasm`), enter the URL of the deployment in the Homepage URL, and the Authorization callback to be `https:///api/oidc_callback`. ![New OAuth Application](/img/oidc/github/new_oauth_app.png) 5. Select **Register Application**. 6. On the next page note the **Client ID**. It will be needed for upcoming configurations. 7. Click **Generate a new client secret** and note the value. It will be needed for upcoming configurations. ![Client ID an Client Secret](/img/oidc/github/client_secret.png) ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | --- | --- | | **Enabled** | Checked | | **Display Name** | Continue with Github | | **Logo URL** | `https://github.com/favicon.ico` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `https://github.com/login/oauth/authorize` | | **Token URL** | `https://github.com/login/oauth/access_token` | | **User Info URL** | `https://api.github.com/user` | | **Scope** | `user:email` | | **Username Attribute** | `email` | | **Groups Attribute** | `` | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | Blank | | **Logout with OIDC Provider** | Unchecked | | **Enable OIDC SLO Frontchannel Endpoint** | Unchecked | ![Kasm OIDC Configurations](/img/oidc/github/kasm_oidc_configuration.webp) 6. Click **Save** to save the changes. ### Github Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. ![Login Screen](/img/oidc/github/login.webp) 2. Click **Continue with Github**. 3. The user is redirected to Github. Login if necessary. The first time the user utilizes the OpenID auth, they will be prompted to accept the access requested. Select **Authorize** ![Github Auth](/img/oidc/github/authorization.png) 4. Upon compleation, the user is logged into the Kasm app. --- ## Google ## Google OpenID Setup :::warning Be mindful when configuring public OpenID providers. Any user who authenticates with the provider gains access to your Kasm Workspaces deployment. Kasm group permissions can restrict access to Workspace apps and desktops, but any user of the public authentication provider can still log in to your deployment. Use a private OpenID provider unless you intend to allow access to all users of the OpenID platform provider. ::: This guide walks through a basic setup allowing Google users to authenticate with your Kasm deployment. Google OpenID does not support OIDC Single Logout. Reference Docs: - [https://developers.google.com/identity/protocols/oauth2](https://developers.google.com/identity/protocols/oauth2) ### Creating a Google OAuth App 1. Login to the Google Developer Console: [https://console.developers.google.com](https://console.developers.google.com) 2. Select **OAuth consent screen**. 3. Select **External** then click **Create**. In this example, we walk through creating an integration where any Google user can auth with the Kasm app. This is ideal for a public facing deployment. Choose **Internal** if only user from your Google Workspaces corporate account should be allowed to authenticate. ![OAuth Consent](/img/oidc/google/oauth_consent_create.png) 4. Provide values for the **App Name** , **User support email**, and **Developer Contact email**. 5. In the **Authorized Domains** section, enter your deployment's top private domain (e.g `example.com`). 6. Click **Save and Continue**. ![App Registration](/img/oidc/google/oauth_consent_registration.png) 7. Click **Add or Remove Scopes**. 8. In the **Update Selected Scopes** window check `.../auth/userinfo.email` , then click Update. ![Update Selected Scopes](/img/oidc/google/oauth_consent_scopes.png) 09. Click **Save and Continue**. 10. Until the app is fully verified and published it can only be used to auth specific test accounts. Click **Add Users** to authorize several test google accounts. 11. Click **Save and Continue**. 12. In the **APIs & Services** menu, select **Credentials**. 13. Select **Create Credentials**, then **OAuth client ID**. ![Create Credentials](/img/oidc/google/select_oauth_client_id.png) 14. Select `Web Application` as the **Application type**, then give the client a name (e.g `Kasm`). 15. Click **Add URI** in the **Authorized redirect URIs** section, and enter `https:///api/oidc_callback`. 16. Click **Create**. ![Create OAuth Client](/img/oidc/google/create_oauth_client.png) 17\. A dialogue will display with a **Client ID** and **Client Secret**. Save these values for the next configuration steps. The JSON download will also include URLs needed for the next configuration steps. ![Client ID and Client Secret](/img/oidc/google/client_secret.png) ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | --- | --- | | **Enabled** | Checked | | **Display Name** | Continue with Google | | **Logo URL** | `https://www.google.com/favicon.ico` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `https://accounts.google.com/o/oauth2/auth` | | **Token URL** | `https://oauth2.googleapis.com/token` | | **User Info URL** | `https://www.googleapis.com/oauth2/v1/userinfo` | | **Scope** | `openid` `https://www.googleapis.com/auth/userinfo.email` `https://www.googleapis.com/auth/userinfo.profile` | | **Username Attribute** | `email` | | **Groups Attribute** | Unchecked | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | Blank | | **Logout with OIDC Provider** | Unchecked | | **Enable OIDC SLO Frontchannel Endpoint** | Unchecked | ![Kasm OIDC Configurations](/img/oidc/google/kasm_oidc_configuration.webp) 6. Click **Save** to save the changes. ### Google Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. ![Login Screens](/img/oidc/google/login.webp) 2. Click **Continue with Google**. 3. The user is redirected to Google for auth. ![Google Auth](/img/oidc/google/authorization.png) 4. Upon completion, the user is logged into the Kasm app. --- ## Keycloak ## Keycloak OpenID Setup :::warning Be mindful when configuring public OpenID providers. Any user who authenticates with the provider gains access to your Kasm Workspaces deployment. Kasm group permissions can restrict access to Workspace apps and desktops, but any user of the public authentication provider can still log in to your deployment. Use a private OpenID provider unless you intend to allow access to all users of the OpenID platform provider. ::: This guide walks through a basic setup allowing Keycloak users to authenticate with your Kasm deployment. Reference Docs: - [https://www.keycloak.org/docs/latest/securing_apps/#_oidc](https://www.keycloak.org/docs/latest/securing_apps/#_oidc) ### Creating a Keycloak OAuth App 01. Login to the Keycloak portal as an Admin. 02. Under the the desired realm (e.g **Master**) , select **Realm Settings**. 03. Click **OpenID Endpoint Configuration** next to Endpoints. 04. Save off the urls for `issuer`, `authorization_endpoint` , `token_endpoint`, and `userinfo_endpoint`. These will be used in future steps. 05. Back in the console, select **Clients** under the Realm. 06. Select **Create**. 07. Define a **Client ID** , e.g `kasm-12345`. Select `openid-connect` for **Client Protocol** and enter the URL for the Kasm deployment under **Root URL** (e.g `https://kasm.example.com`). 08. In the client settings, change **Access Type** to `confidential`, then slick **Save**. 09. In the **Settings** section, at the bottom, under **Logout**, choose one of the following: Backchannel Logout is recommended as it is more stable and secure than front-channel. Choose front-channel if backchannel is not possible, e.g. keycloak is unable to make a direct HTTPS request to Kasm. 01. Front-channel Logout - Set **Front-channel logout** to **On** - Fill out **Front-channel logout URL** with the endpoint URL for the kasm deployment (e.g. `https://kasm.example.com/api/oidc_frontchannel_logout`) - Click **Save** 02. Backchannel Logout - Set **Front channel logout** to **Off** - Fill out **Backchannel logout** with the endpoint URL for the kasm deployment (e.g. `https://kasm.example.com/api/oidc_backchannel_logout`) - Set **Backchannel logout session required** to **On** - Click **Save** 10. Select **Credentials**. Save off the **Secret**. It will be used in future steps. 11. In the client settings, select **Mappers**, then click **Create**. 12. Enter `groups` for **Name**, and select **Group Membership** from the Mapper Type. Enter `groups` for **Token Claim Name**, then select **Save**. ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | :----------------------- | :-------------------------------------------------------------- | | **Enabled** | Checked | | **Display Name** | Continue with Keycloak | | **Logo URL** | `https://www.keycloak.org/resources/favicon.ico` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `` | | **Token URL** | `` | | **User Info URL** | `` | | **Scope** | `openid` `email` `profile` | | **Username Attribute** | `preferred_username` | | **Groups Attribute** | `groups` | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | `` | | **Logout with OIDC Provider** | Checked | | **Enable OIDC SLO Frontchannel Endpoint** | Checked if Frontchannel Logout was chosen in the previous section | 6) Click **Save** to save the changes. ### Keycloak Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. 2. Click **Continue with Keycloak** 3. The user is redirected to Keycloak for auth. 4. Upon completion, the user is logged into the Kasm app. ### Group Mapping The previous configurations will instruct the identity provider to send a list of **Security Group ID** the user belongs to during the OpenID auth workflow. We can configure Kasm Groups with the Security Group IDs from Azure AD so that users are automatically added/removed based on their Azure AD group Membership. 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups** -> **Add Group**. 3. Name the Group **Group Test**, and define a priority. 4. Click **Save** to create the group. 1. On the groups screen, using the arrow menu select **Edit** on the group that was just created. 2. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 3. Select the OpenID IDP that was created above "OpenID - Continue with Keycloak" for the **SSO Provider**. 4. Then enter the Keycloak group name desired in the **Group Attributes** field, e.g `/Kasm-Test`. Note the slash. This is needed when **Full group path** is set in the Keycloak Client Mapper which is the default. 1. Click **Submit** 1. Logout, then login via the Keycloak Open ID login with a user that is a member of the specified group. 2. View the users group membership to ensure they are added to the newly created group. --- ## Microsoft Internal ## Microsoft (Internal) OpenID Setup This guide walks through a basic setup allowing Microsoft users to authenticate with your Kasm deployment. Reference Docs: - [https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) - [https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols) - [https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims) ### Creating a Microsoft OAuth App 01. Login to the Microsoft Azure Portal: [https://portal.azure.com/](https://portal.azure.com/) 02. Select **Azure Active Directory**. ![Azure Active Directory](/img/oidc/microsoft/azure_ad.png) 03. Select **App Registrations**. ![App Registration](/img/oidc/microsoft/app_registrations.png) 04. Select New Registration. 05. Give the app a Name (e.g `Kasm`) 06. In the **Supported account types** select **Accounts in this organizational directory only...**. ![Register App](/img/oidc/microsoft_internal/register_app.png) 07. On the next page, the **Application (client) ID** is shown, save this value as the Client ID to be used in the next section. 08. Select **Endpoints**. Note the **OAuth 2.0 authorization endpoint (v2)**, **OAuth 2.0 token endpoint (v2)**, and **OpenID Connect metadata document** values to be used in the next section. 09. Select **Add a certificate or secret** next to **Client credentials**. ![Client Credentials](/img/oidc/microsoft/client_credentials.png) 10. Select the **Client secrets** tab, then slick **New client secret**. 11. Enter a description and expiration then click **Add**. 12. The credentials are shown, save the **Value** as the **Client Secret** to be used in the next section. ![Client Secret](/img/oidc/microsoft/client_secret.png) 13. Select **Token configuration**. 14. Select **Add groups claim**. 15. Check **Security groups**, then click **Add**. ![Group Claims](/img/oidc/microsoft_internal/group_claims.png) 16. Select **Add Optional Claim** 17. Under **Token Type** select **ID**, then check the box for **sid**. Click **Add**. ``` {figure} /img/oidc/microsoft_internal/sid_claim.webp :align: center **SID Claim** ``` ![Claims Configured](/img/oidc/microsoft_internal/all_claims_added.png) 18. Select **Authentication** 19. In **Front-channel Logout URL**, provide the Kasm `/api/oidc_frontchannel_logout` endpoint as shown. Click **Save**. ![Front-channel Logout URL](/img/oidc/microsoft_internal/frontchannel_endpoint.webp) 18. In another browser tab, navigate to the **OpenID Connect metadata document** URL value saved from earlier. Find and save off the value for the `"issuer"` field in the response, to be used in the next section. ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | --- | --- | | **Enabled** | Checked | | **Display Name** | Continue with Microsoft | | **Logo URL** | `https://www.microsoft.com/favicon.ico` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `` | | **Token URL** | `` | | **User Info URL** | `https://graph.microsoft.com/oidc/userinfo` | | **Scope** | `openid` `email` `profile` | | **Username Attribute** | `email` | | **Groups Attribute** | `groups` | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | `` | | **Logout with OIDC Provider** | Checked | | **Enable OIDC SLO Frontchannel Endpoint** | Checked | ![Kasm OIDC Configurations](/img/oidc/microsoft_internal/kasm_oidc_configuration.webp) 6) Click **Save** to save the changes. ### Microsoft Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. ![Login Screen](/img/oidc/microsoft/login.webp) 2. Click **Continue with Microsoft** 3. The user is redirected to Microsoft for auth. ![Microsoft Auth](/img/oidc/microsoft/authorization.png) 4. Upon completion, the user is logged into the Kasm app. ### Group Mapping The previous configurations will instruct the identity provider to send a list of **Security Group ID** the user belongs to during the OpenID auth workflow. We can configure Kasm Groups with the Security Group IDs from Azure AD so that users are automatically added/removed based on their Azure AD group Membership. 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups** -> **Add Group**. 3. Name the Group **Group Test**, and define a priority. 4. Click **Save** to create the group. ![Add Group](/img/oidc/microsoft_internal/groups.webp) 1. On the groups screen, using the arrow menu select **Edit** on the group that was just created. 2. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 3. Select the OpenID IDP that was created above "OpenID - Continue with Microsoft" for the **SSO Provider**. 4. Then enter the Azure AD security group ID desired in the **Group Attributes** field. ![Add SSO Group Mapping](/img/oidc/microsoft_internal/sso_group_mapping.webp) 1. Click **Submit** 2. Logout, then login via the Microsoft Open ID login with a user that is a member of the specified group. 3. View the users group membership to ensure they are added to the newly created group. --- ## Microsoft ## Microsoft (Public) OpenID Setup :::warning Be mindful when configuring public OpenID providers. Any user who authenticates with the provider gains access to your Kasm Workspaces deployment. Kasm group permissions can restrict access to Workspace apps and desktops, but any user of the public authentication provider can still log in to your deployment. Use a private OpenID provider unless you intend to allow access to all users of the OpenID platform provider. ::: This guide walks through a basic setup allowing Microsoft users to authenticate with your Kasm deployment. Reference Docs: - [https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) - [https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols) ### Creating a Microsoft OAuth App 1. Login to the Microsoft Azure Portal: [https://portal.azure.com/](https://portal.azure.com/) 2. Select **Azure Active Directory**. ![Azure Active Directory](/img/oidc/microsoft/azure_ad.png) 3. Select **App Registrations**. ![App Registration](/img/oidc/microsoft/app_registrations.png) 4. Select New Registration. 5. Give the app a Name (e.g `Kasm`). 6. In the **Supported account types** select **Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)**. In this example, we walk through creating an integration where any Microsoft user can auth with the Kasm app. This is ideal for a public facing deployment. Other options are available for single-tenant and multi-tenant configurations. ![Register App](/img/oidc/microsoft/register_app.png) 7. On the next page, the **Application (client) ID** is shown, save this value as the Client ID to be used in the next section. 8. Select **Add a certificate or secret** next to **Client credentials**. ![Client Credentials](/img/oidc/microsoft/client_credentials.png) 09. Select the **Client secrets** tab, then slick **New client secret**. 10. Enter a description and expiration then click **Add**. 11. The credentials are shown, save the **Value** as the **Client Secret** to be used in the next section. ![Client Secret](/img/oidc/microsoft/client_secret.png) 12. Select **Token configuration**. 13. Select **Add Optional Claim** 14. Under **Token Type** select **ID**, then check the box for **sid**. Click **Add**. ``` {figure} /img/oidc/microsoft/sid_claim.webp :align: center **SID Claim** ``` 15. Select **Authentication** 16. In **Front-channel Logout URL**, provide the Kasm `/api/oidc_frontchannel_logout` endpoint as shown. Click **Save**. ![Front-channel Logout URL](/img/oidc/microsoft_internal/frontchannel_endpoint.webp) ### Kasm OpenID Config 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **OpenID** -> **Add Config**. 3. Update the form with the following entries, using the **Client ID** and **Client Secret** gathered in the previous section. | **Property** | **Value** | | --- | --- | | **Enabled** | Checked | | **Display Name** | Continue with Microsoft | | **Logo URL** | `https://www.microsoft.com/favicon.ico` | | **Auto Login** | Unchecked | | **Hostname** | `` | | **Default** | Checked | | **Client ID** | `` | | **Client Secret** | `` | | **Authorization URL** | `https://login.microsoftonline.com/common/oauth2/v2.0/authorize` | | **Token URL** | `https://login.microsoftonline.com/common/oauth2/v2.0/token` | | **User Info URL** | `https://graph.microsoft.com/oidc/userinfo` | | **Scope** | `openid` `email` `profile` | | **Username Attribute** | `email` | | **Groups Attribute** | Unchecked | | **Debug** | Unchecked | | **Redirect URL** | `https:///api/oidc_callback` | | **OpenID Connect Issuer** | `https://login.microsoftonline.com/common/v2.0` | | **Logout with OIDC Provider** | Checked | | **Enable OIDC SLO Frontchannel Endpoint** | Checked | ![Kasm OIDC Configurations](/img/oidc/microsoft/kasm_oidc_configuration.webp) 6. Click **Save** to save the changes. ### Microsoft Login Test 1. Logout of the Kasm to display the login screen. The OpenID configuration should be shown. ![Login Screen](/img/oidc/microsoft/login.webp) 2. Click **Continue with Microsoft** 3. The user is redirected to Microsoft for auth. ![Microsoft Auth](/img/oidc/microsoft/authorization.png) 4. Upon completion, the user is logged into the Kasm app. --- ## Configuring OpenID Authentication for Kasm Workspaces # OpenID Authentication Kasm can utilize external authentication providers using OAuth, including OpenID Connect (OIDC) providers. :::warning Be mindful when configuring public OpenID providers. Any user who authenticates with the provider gains access to your Kasm Workspaces deployment. Kasm group permissions can restrict access to Workspace apps and desktops, but any user of the public authentication provider can still log in to your deployment. Use a private OpenID provider unless you intend to allow access to all users of the OpenID platform provider. ::: ## Configuration OpenID configuration can be found under the Access Management -> Authentication tab in the Admin Navigation Bar. | **Property** | **Description** | | :----------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enabled** | When checked this configuration will be active. | | **Display Name** | This name is displayed on the login page to represent the authentication provider. (e.g `Continue with Github`) | | **Logo URL** | A URL to a login logo image for the authentication provider. (e.g `https://github.com/favicon.ico`) | | **Auto Login** | When checked, the user will be automatically navigated to the OIDC provider when they view the login screen. This only applies if a single authentication provider is visible. If this configuration is set, the fixed login page (without redirection) can be accessed via `/#/staticlogin` | | **Hostname** | The URL hostname (e.g kasm.example.com) of the deployment. This OIDC config will only be displayed when the deployment is accessed via this URL host name. This allows for a single deployment to service multiple tenants who may need different OIDC configurations. If Default is defined, this config will apply regardless of the host name. | | **Default** | If checked this OIDC config will be shown on the login screen of the deployment when access with any hostname, unless another config is defined with the specific hostname. | | **Client ID** | The Client ID received from the authentication provider. | | **Client Secret** | The Client Secret received from the authentication provider. | | **Authorization URL** | The authorization url for the authentication provider. (e.g `https://github.com/login/oauth/authorize`) | | **Token URL** | The token url for the authentication provider. (e.g `https://github.com/login/oauth/access_token`) | | **User Info URL** | The user info url for the authentication provider. (e.g `https://api.github.com/user`). This service will be queried if the **Username Attribute** or **Groups Attribute** are not provided by the identity provider in the id or access tokens. | | **Scope** | The OIDC Scopes for the authentication provider. Enter one scope per line. e.g: `openid` `email` | | **Username Attribute** | The attribute from the authentication provider to use for the username within Kasm (e.g `email`). The system will search the access_token, id_token and user_info api for this property. | | **Groups Attribute** | The attribute from the authentication provider to user for group membership mapping within Kasm (e.g `groups`). The system will search the access_token, id_token and user_info api for this property. This field is optional, but if defined, authentication will fail if the group attribute is not found. | | **Debug** | When checked, the OIDC access and id tokens are logged as well as the response from the user_info api if queried. TLS Verification is disabled for the Authorization URL, Token URL, and URL Info URL API interactions. This feature should remain disabled unless needed for troubleshooting. | | **Redirect URL** | The identify provider can be configured to allow access to redirect to this URL. `https:///api/oidc_callback` | | **OpenID Connect Issuer** | An OIDC provider has an issuer value. This is a complete URL, e.g: `https://oidc.host/realms/master` | | **Logout with OIDC Provider** | If checked, the user will be redirected to the OIDC provider's logout page after logging out of their Kasm session. Requires `OpenID Connect Issuer` to be configured. | | **Enable OIDC SLO Frontchannel Endpoint** | If checked, Kasm will honor frontchannel logout requests from the OIDC provider. If available, also configure `OpenID Connect Issuer` for verification. Note: where possible, backchannel logout is recommended over frontchannel as it is more stable and secure. | A non redirecting login page is at [https://hostname/#/staticlogin](https://hostname/#/staticlogin) when auto login is enabled. ## Group Assignment Users that auth via OIDC, can automatically be associated with Groups defined in Kasm. To automatically assign groups: 1. In the OpenID Authentication configuration, ensure the **Groups Attribute** is defined to match the corresponding group attribute of the IDP. 2. Navigate to the Access Management -> Groups tab in the admin navigation bar. 3. Using the arrow menu select **Edit** of the desired group. 4. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 5. Select the OpenID IDP for example "OpenID - test_oidc" for the **SSO Provider**. 6. Enter the group name used in the identity provider for the OpenID Group Name field, either preceded by a forward slash (e.g. `/sales`) if the OIDC Provider has Full Group Path set to On, or without a preceding forward slash (e.g. `sales`) if Full Group Path is set to Off. ## OpenID Attribute Mapping Additional OpenID attributes can be passed with the login redirect. Administrators can optionally map those attribute values to fields on the Kasm user. See the documentation for your OpenID provider for a listing of attributes. These can be configured by editing an existing OpenID Authentication configuration, if creating a new configuration you will need to submit and edit to add them. The following Kasm User fields can be populated with values from OpenID attributes. - First Name - Last Name - Phone - Organization - Notes - City - State - Country - Email - Custom Attribute 1 - Custom Attribute 2 - Custom Attribute 3 Kasm can log all OpenID attributes present in the login event, this is helpful for determining the attribute names. Add an OpenID Attribute Mapping with an attribute name of 'debug' and target any user field. The next time a user logs in, all OpenID attributes and values will be logged by Kasm. ## Single Logout Kasm supports the Single Logout (SLO) mechanisms defined by the OpenID Connect protocol. * Backchannel (server-to-server) SLO is enabled as long as the `OpenID Connect Issuer` value is configured * Enabling `Logout with OIDC Provider` will direct the user's browser to the OIDC provider's logout page once they have logged out of Kasm * Frontchannel (iframe-in-browser) logout requests are not honored unless `Enable OIDC SLO Frontchannel Endpoint` is checked Please see the example configurations for more information on SLO. ## Configuration Examples - [Github OpenID Setup](oidc/github.mdx) - [Google OpenID Setup](oidc/google.mdx) - [Keycloak OpenID Setup](oidc/keycloak.mdx) - [Microsoft (Public) OpenID Setup](oidc/microsoft.mdx) - [Microsoft (Internal) OpenID Setup](oidc/microsoft-internal.mdx) - [Auth0 OpenID Setup](oidc/auth0.mdx) --- ## Adfs # ## Active Directory Federation Services (ADFS) SAML Setup This guide walks through a basic setup for connecting Kasm to ADFS on Windows Server 2016 via SAML. Active Directory user accounts are assumed to have a populated email address attribute. ### ADFS Signing Certificate 1. From the ADFS Management console, expand **Service**, and select **Certificates**. 2. Right-Click the **Token-signing** certificate and select **View Certificate**. ![View Cerificate](/img/saml/adfs/view_certificate.png) 3. Select the **Details** tab, then click **Copy to File**. ![Copy Certificate](/img/saml/adfs/copy_certificate.png) 4. In the **Certificate Export Wizard**, click **Next**. ![Export Certificate](/img/saml/adfs/certificate_export_wizard.png) 5. Select **Base-64 encoded X.509 (CER)** . Click **Next**. 6. Select a desired output file and click **Next**. 7. Click **Finish**. 8. Open the certificate in your preferred text editor. This data will be used in the creation of the Kasm SAML configuration in the next section. ![Certificate Contents](/img/saml/adfs/cert_data.png) ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration**. 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Edit the auto-generated **Entity ID** value to remove the query argument in the URL. (e.g [https://kasm.server/api/metadata/?id=123](https://kasm.server/api/metadata/?id=123) => [https://kasm.server/api/metadata/](https://kasm.server/api/metadata/) ) 5. Update the form with the following entries. | **Setting** | **Value** | | --- | --- | | ADFS | *Checked* | | Debug | *Checked* | | Digest Algorithm | http://www.w3.org/2001/04/xmlenc#sha256 | | Enabled | *Checked* | | Group Member Attribute | `http://schemas.xmlsoap.org/claims/Group` | | Identity Provider: Entity Id | `http:///adfs/services/trust` | | Identity Provider: Single Logout Service: | `https:///adfs/ls/?wa=wsignout1.0` | | Identity Provider: Single Sign On Service | `https:///adfs/ls/` | | Identity Provider: X509 Certificate | *Certificate data from the previous section* | | Name | ADFS | | NameID Attribute | emailAddress | | Signature Algorithm | http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 | | Want Attribute Statement | *Checked* | | Want Assertion Signed | *Checked* | | Want Name ID | *Checked* | ![Kasm SAML Configurations](/img/saml/adfs/kasm_saml_configurations.webp) 6. Click **Save** to save the changes. 7. Click the **Edit** icon to re-open to SAML configuration. Leave this page open and continue to the next steps. ### ADFS Party Trust 1. Log into the ADFS Management Console. 2. Right-Click **Relying Party Trusts** and select **Add Relying Party Trust**. The wizard will open. 3. Select **Claims aware** then click **Start**. ![Claims Aware](/img/saml/adfs/claims_aware.png) 4. Select **Enter data about the relying party manually** and click **Next**. ![Relaying Party Manually](/img/saml/adfs/manual.png) 5. Enter a **Display Name** and select **Next** e.g (Kasm ADFS). ![Display Name](/img/saml/adfs/display_name.png) 6. Click **Next** to accept the defaults for the **Configure Certificate** step. ![Configure Certificate](/img/saml/adfs/encrypt_claims.png) 7. Select **Enable support for the SAML 2.0 WebSSO Protocol**. Enter the **Single Sign On Server** URL from the **Service Provider** section of the KASM SAML configuration page started in the previous section. Click **Next**. ![Enable SSO](/img/saml/adfs/enable_sso.png) 8. In the **Relay party trust identifier**, enter the **Entity ID** from the Service Provider section from the Kasm SAML configuration page started in the previous section. Click **Add**, then Click **Next**. ![Add Service Provider](/img/saml/adfs/trust_providers.png) 9. Select **Permit Everyone**, then click **Next**. ![Permit Access](/img/saml/adfs/access_control_policy.png) 10. No changes are needed for the **Ready to Add Trust** section. Click **Next**. 11. At the **Finish** screen, Uncheck **Configure claims issuance policy for this application**, then click **Close**. 12. Right click the new trust (e.g Kasm ADFS) and select **Properties**. ![ADFS Properties](/img/saml/adfs/trust_properties.png) 13. Select the **Endpoints** tab, then click **Add SAML**. 14. Select **SAML Logout** as the **Endpoint type** and select **POST** as the **Binding**. 15. Enter **https://\/adfs/ls/?wa=wsignout1.0** in the **Trusted URL**. Click **OK**, then **OK** again. ![Logout Configuration](/img/saml/adfs/saml_logout.png) ### ADFS Edit Claim Issuance Policy 1. From the ADFS management console, select **Relying Party Trusts**, right click trust previously configured (.e.g Kasm ADFS) and select **Edit Claim Issuance Policy**. ![Edit Issuance Policy](/img/saml/adfs/edit_issuance_policy.png) 2. Click **Add Rule**. ![Modify Issuance Policy](/img/saml/adfs/issuance_policy.png) 3. In the **Claim rule template** field, select **Send LDAP Attributes as Claims**. Click **Next**. ![Select Template](/img/saml/adfs/select_template.png) 4. Enter a name in **Claim rule name**, then select **Active Directory** in the **Attribute store** drop down. 5. Select **E-Mail-Addresses** as the **LDAP Attribute**. Select **E-Mail-Address** as the **Outgoing Claim Type**. 6. In another entry, select **Is-Member-Of-DL** in **LDAP Attribute** and select **Group** in the **Outgoing Claim Type**. Click **Finish**. ![Email Claim](/img/saml/adfs/email_claim.png) 6. Create another rule to expose the email address as the NameID. Click **Add Rule**. 7. Select **Transform an Incoming Claim** from the **Claim rule template** dropdown. Click **Next**. ![Claim Rule Template](/img/saml/adfs/transform_claim.png) 08. Enter a name in **Claim rule name**. 09. Select **E-Mail Address** for **Incoming claim type**. 10. Select **Name ID** for **Outgoing claim type**. 11. Select **Email** for **Outgoing name ID format** and click **Finish**. ![Save Email Claim Rule](/img/saml/adfs/transform_email_claim.png) 12. Back in the **Edit Claim Issuance Policy** window, click **OK** ![Edit Issuance Policy](/img/saml/adfs/finish_issuance_policy.png) ### Verifying Access 1. Navigate to the Kasm UI Login screen. An "ADFS" button is visible representing the SAML config. 2. Click **ADFS** ![Kasm Login](/img/saml/adfs/kasm_login.webp) 3. The user is navigated to the ADFS login portal. Enter the username/password of the desired user. ![ADFS Login](/img/saml/adfs/adfs_login.png) 4. The user is redirected and logged into Kasm. 5. From the Kasm UI select Logout. The user is logged out and redirected to the ADFS logout page. ![ADFS Logout](/img/saml/adfs/adfs_logout.png) ### ADFS Group Mapping In the previous configuration ADFS was configured to pass along the user's Active Directory group membership in the SAML assertions. Administrators can leverage this to automatically map users to groups defined in Kasm based off their group membership in Active Directory. 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups** then click **Add Group**. 3. Enter a **Name** and **Priority**. 4. Save the new group by clicking **Save**. ![New Group](/img/groups/new_group.webp) 5. On the groups screen, using the arrow menu select **Edit** on the group that was just created. 6. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 7. Select the SAML IDP that was created above "SAML - ADFS" for the **SSO Provider**. 8. Enter the group DN in **Group Attributes** (e.g CN=MyGroup,OU=MyOrg,DC=kasm,DC=core). 9. Click **Submit**. ![SAML SSO Group Mapping](/img/saml/adfs/saml_group.webp) 7. Login via SAML as a user that is a member of the group. Notice the users is automatically placed in the Kasm group. --- ## Azure ## Azure Active Directory SAML Setup ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration** 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Check **Enable** and enter a **Display Name**. e.g (Azure AD) 5. Enter `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups` in **Group Member Attribute** 6. Enter `emailAddress` in **NameID Attribute** ![Kasm SAML Configurations](/img/saml/azure/kasm_saml_configurations.webp) 5. Leave this page open and continue to the next steps. ### Add a new application in Azure 1. Navigate to **Azure Active Directory** in the Portal. ![Azure Portal](/img/saml/azure/portal.png) 2. Under the **Manage** section of the menu, select **Enterprise applications**. ![Enterprise Applications](/img/saml/azure/enterprise_apps.png) 3. Click the **New Application** button and select **Non-Gallery application**. Provide a name. e.g (**Kasm**) and click **Add** ![New Applications](/img/saml/azure/create_application.png) ### Basic SAML Configurations 1. Select **Single Sign-On** under the **Manage** Menu. 2. Select **SAML**. 3. Select **Edit** next to the **Basic SAML Configuration** ![SAML Single Sign-On](/img/saml/azure/single_sign_on.png) 4. Copy the **Service Provider** entries from the Kasm SAML Configurations started in the previous section into the Basic SAML configurations and click **Save** , and close the section. | **Kasm Property Name** | **Azure Property Name** | | --- | --- | | Entity ID | Identifier (Entity ID) | | Single Sign On Service | Reply URL (Assertion Consumer Service URL) | | Single Logout Service | Logout URL | | Relay State | Relay State | ![Basic SAML Configurations](/img/saml/azure/basic_saml_configurations.png) ### User Attributes and Claims 1. Select **Single Sign-On** under the **Manage** Menu. 2. Select **SAML**. 3. Select **Edit** next to the **User Attributes and Claims** 4. Click **Add a Group to Claim** ![Add a Group to Claim](/img/saml/azure/add_group_to_claims.png) 5. Select **Security Groups**, leave the **Source Attributes** as **Group ID** and click **Save** then close the section. ![Group Claims](/img/saml/azure/group_claims.png) ### SAML Signing Certificate 1. Select **Single Sign-On** under the **Manage** Menu. 2. Select **SAML**. 3. Click **Download** next to **Certificate (Base64)** in the **SAML Signing Certificate** section . Save this file for later 4. Select **Edit** next to the **SAML Signing Certificate** 5. Change the **Singing Algorithm** to **SHA-1** and click **Save**. Close the section. ![Singing Certificate](/img/saml/azure/saml_singing_certificate.png) 6. Open the Base64 certificate that was downloaded in the earlier step in a text editor. Copy the contents into the **X509 Certificate** setting in the **Identity Provider** section of the Kasm configuration ![X509 Certificate](/img/saml/azure/x509_certificate.webp) ### Set Up Kasm 1. Select **Single Sign-On** under the **Manage** Menu. 2. Select **SAML**. 3. Review *Section 4* , **Set Up Kasm**. Copy the properties into the **Identity Provider** options in the Kasm Configuration. | **Kasm Property Name** | **Azure Property Name** | | --- | --- | | Single Sign On Service / SAML 2.0 Endpoint | Login URL | | Entity ID | Azure AD Identifier | | Single Logout Service / SLO Endpoint | Logout URL | ![Identity Provider](/img/saml/azure/identity_provider.webp) 4. In the **Advanced Settings** of check **Want Assertion Signed** and click **Submit** ### Mapping Users You must assign users or groups to the Azure Kasm application. This will provide users access to login. Azure will then pass all user group memberships during login so that Kasm can determine Authorization (e.g mapping AD groups to Kasm groups) In this example, a **Kasm Users** and **Kasm Admin** groups were defined. 1. Navigate to **Azure Active Directory** in the Portal. 2. Under the Manage section of the menu, select **Enterprise applications**. 3. Search for **Kasm** and select it. 4. Click **Users and Groups** under the **Manage** menu. 5. Click **Add Users** and add the desired users and group assignments. 6. Inspect the desired groups and note the **Object ID**. This will be used to map to Kasm groups. ![Group Assignments](/img/saml/azure/group_assignments.png) 07. Log into the Kasm UI as an administrator. 08. Select **Access Management** -> **Groups**, then using the arrow menu click **Edit** next to the **Administrators** Group. 09. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 10. Select "SAML - Azure AD" as the **SSO Provider** and enter the **Object Id** for the desired Azure AD Security group previously configured into the **Group Attributes** field. ![Add SSO Mapping](/img/saml/azure/update_group.webp) ### Testing Access 1. Log out of the Kasm UI if already logged in. 2. Navigate to the Kasm UI login page. ![Kasm Login](/img/saml/azure/kasm_login.webp) 3. Click Azure AD to initiate the SAML SSO process. ![Azure Login](/img/saml/azure/azure_login.png) ### Known Issues #### SLO Error AADSTS75005 Azure AD may present the following error when a user logs out the application: ```Bash AADSTS75005: The request is not a valid SAML 2.0 protocol message. ``` In some Azure AD deployments, Microsoft will generate a SLO URL similar to `https://login.microsoftonline.com//saml2` This endpoint requires an encoding that is not currently supported by Kasm. The workaround is to utilize the older federated SLO endpoint `https://login.microsoftonline.com/common/wsfederation?wa=wsignout1.0` for the **Single Logout Service/SLO Endpoint** in the Kasm SAML Configuration. --- ## F5 APM ## F5 BIG-IP Access Policy Manager (APM) SAML Setup This guide walks through a basic setup for connecting Kasm to F5 BIG-IP Access Policy Manager (APM) SAML via SAML using Active Diretory as a backend. Active Directory user accounts are assumed to have a populated email address attribute. Also an LDAP Service account should be created in Active Directory already. ### Prerequisites Before starting the configuration, F5 BIG-IP should be enabled with Local Traffic (LTM) and Access Policy Manager (APM) feature. ### Architecture Here is the architecture for this deployment. ![F5 BIG-IP APM and Kasm Architecture](/img/saml/f5apm/f5apm_architecture.png) ### Signing Certificate 1. From the F5 BIG-IP console, select **System**, select **Certificate Management**, select **Traffic Certificate Management**, and select **SSL Certificate List**. 2. Click **Create...**. 3. Enter Certificate settings: | **Setting** | **Value** | | --- | --- | | Name | *Enter friendly name for identification* | | Issuer | Self | | Common Name | *Enter the hostname for the SAML Identity Provider, e.g. auth.internal.kasm* | | Division/Organization/Locality/State or Province/Country | *Enter the relevant details as appropriate* | | Lifetime | *Enter appropriate lifetime according to organization policy* | | Subject Alternative Name | *Enter as* `DNS:` | ![Signing Certificate](/img/saml/f5apm/f5apm_signingcert.png) 4. Click **Finished**. 5. Click on the newly created signing certificate. Click **Export**, and then copy the **Certificate Text**. This data will be used in the creation of the Kasm SAML configuration in the next section. ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration**. 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Update the form with the following entries. | **Setting** | **Value** | | --- | --- | | **Service Provider** | ---| | Enabled | Yes | | Display Name | *Enter friendly name for F5 SAML IdP*| | Host Name | *Enter Kasm Workspaces host name* | | Default | Unchecked | | Auto Login | Unchecked | | Group Member Attribute | *Leave empty*| | NameID Attribute | emailAddress | | Debug | Checked *Remark: Leave checked for more debug messages. Can be unchecked if confirmed everything is working.* | | **Identity Provider** | ---| | Entity Id | `http:///idp` | | Single Sign On Service | `https:///saml/idp/profile/redirectorpost/sso` | | Single Logout Service: | `https:///saml/idp/profile/redirect/sls` | | X509 Certificate | *Certificate data from the previous section* | | **Advanced Settings** | ---| | Want Attribute Statement | Checked | | Send Requested Authn Context | Checked | | Want Assertion Signed | Checked | | Want Name ID | Checked | | Signature Algorithm | http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 | | Digest Algorithm | http://www.w3.org/2001/04/xmlenc#sha256 | ![Kasm SAML Configurations](/img/saml/f5apm/f5apm_kasmsamlconfig.webp) 6. Click **Save** to save the changes. 7. Click the **Edit** icon to re-open to SAML configuration. Leave this page open and continue to the next steps. ### Upload or Confirm F5 iApp Guided Configurations package 1. From the F5 BIG-IP console, select **iApps** and select **Package Management LX**. Confirm *f5-iappsix-access-framework* and *f5-iappsix-access-saml-idp* exists. 2. If the package does not exist, download *Access and Advanced WAF Guided Configuration* packages under *Guided Configuration* product line in *BIG-IP* Group from MyF5 page. Go back to the **Package Management LX** console, click **Import...**, select the package and click **Upload**. Repeat the upload for the next package. 3. Confirm the *f5-iappsix-access-framework* and *f5-iappsix-access-saml-idp* packages are installed. ![F5 iApps Guided Configurations Packages](/img/saml/f5apm/f5apm_f5packages.webp) ### Import TLS certificate for SAML Identity Provider 1. From the F5 BIG-IP console, select **System**, select **Certificate Management**, select **Traffic Certificate Management**, and select **SSL Certificate List**. 2. Import TLS certificate key in PEM format. * Click **Import**. * Select **Import Type** as **Key**. * Click **Choose File...**. Select certificate key file. * Click **Import**. 3. Import TLS certificate in PEM format. * Click **Import**. * Select **Import Type** as **Certificate**. * Click **Choose File...**. Select certificate file. * Click **Import**. 4. Ensure the TLS certificate key and certificate are properly imported. 5. Select **Local Traffic**, select **Profiles**, select **SSL**, and select **Client**. * Click **Create...**. * Update the form with the following entries. For rows where **Custom** is enabled, remember to click the checkbox on the right hand side. | **Setting** | **Value** | **Custom** | | --- | --- | --- | | Name | *Enter friendly name for the Client SSL Profile* | *Not Applicable* | | Certificate Key Chain | *Click Add. Select the TLS certificate imported in last section for the certificate. Remember this is not the signing certificate. Select the TLS certificate key.* | Yes | * Click **Finished**. ### F5 Guided Configuration 1. From the F5 BIG-IP console, select **Access** and then select **Guided Configuration**. 2. Click **Federation**. 3. Click **SAML Identity Provider for Applications**. 4. Click **Next** in the page of *Configuration Example*. 5. Update the **Identity Provider Properties** form with the following entries. | **Setting** | **Value** | | --- | --- | | Configuration Name | *Enter friendly name for the configuration* | | Entity Id | `http:///idp` | | Scheme | https | | Host Name | `` | | Assertion Properties \\ Signing Key | *Select the IdP signing certificate key previously imported* | | Assertion Properties \\ Signing Certificate | *Select the IdP signing certificate previously imported* | Click **Save & Next**. 6. Update the **Virtual Server Properties** form with the following entries. | **Setting** | **Value** | | --- | --- | | Destination Address | *Enter F5 SAML IdP Virtual Server IP address* | | Service Port | 443 \/ HTTPS | | Enable Redirect Port | Checked | | Redirect Port | 80 \/ HTTP | | Client SSL Profile | *Select **Use Existing** \/ Add previously created Client SSL Profile* | Click **Save & Next**. 7. Update the **Authentication Properties** form with the following entries. | **Setting** | **Value** | | --- | --- | | Choose Authentication Server Type | Active Directory | | Choose New Authentication Server | Create New | | Authentication Server Properties \\ Domain Name | *Enter Active Directory domain name* | | Server Connection | Direct | | Domain Controller | *Enter Domain Controller IP address* | | Admin Name | *Enter the service account for authenticating users in Active Directory using LDAP* | | Admin Password | *Enter the password for the above service account* | | Verify Admin Password | *Enter the password for the above service account again* | Click **Save & Next**. 8. Click **Save & Next** on the **Multi Factor Authentication** form. 9. Click **Add Application** on the **Configured Application List** form. 10. Update the **Authentication Properties** form with the following entries. | **Setting** | **Value** | | --- | --- | | Select method to configure your application | Custom | | Application Name | *Enter friendly application name* | | IdP Initiated SSO | No | | Create New or pick existing SP Connector | Create New | | Service Provider Name | *Enter friendly Service Provider Name* | | Entity ID | *Copy Entity ID from Kasm administration panel under **Access Management** -> **Authentication** -> **SAML**. It should look like* `https:///api/metadata/?id=` | | Assertion Consumer Services | *Select* **Default** *on Index 0. Copy Single Sign On Service from Kasm administration panel under* **Access Management** -> **Authentication** -> **SAML** *to Location URL. It should look like* `https:///api/acs/?id=` *Keep Binding to POST.*| Click **Save**. 11. Click on the newly created application. Click on **Show Advanced Setting** to modify properties previously hidden. 12. Select **Yes** on **Does SaaS application require SAML attributes?** 13. Update the **Authentication Properties** form with the following entries. | **Setting** | **Value** | | --- | --- | | SAML Attributes \\ Attribute Name | NameID | | SAML Attributes \\ Attribute Value | emailAddress | | Single Logout Service Settings \\ Single Logout Request URL | *Copy Single Logout Service from Kasm administration panel under* **Access Management** -> **Authentication** -> **SAML** *to Location URL. It should look like* `https:///api/slo/?id=` | | Single Logout Service Settings \\ Single Logout Response URL | *Copy Single Logout Service from Kasm administration panel under* **Access Management** -> **Authentication** -> **SAML** *to Location URL. It should look like* `https:///api/slo/?id=` | | Single Logout Service Settings \\ Single Logout Binding | POST | Click **Save**. 14. Click **Save & Next** on the next three screens, including **Endpoint Checks Properties**, **Customization Properties** and **Session Management Properties**. 15. Click **Deploy**. 16. Click **Finish**. Confirm the application has a **Deployed** status. 17. In the Kasm Workspaces login screen, there will be a new button for login via F5 APM. Click to test the new SAML authentication method. ### Configuration Video Tutorial This video walks through configuring F5 APM SAML Identity Provider as discussed above. --- ## Gsuite ## Google Workspace SAML Setup ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration**. 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Check **Enable**, enter the **Hostname** of the Kasm Workspaces URL (e.g `kasm.example.com`) and enter a **Display Name**. e.g (Login with Google). 5. Update the following Settings: | **Setting** | **Value** | | --- | --- | | Group Member Attribute | groups | | NameID Attribute | emailAddress | | Want Attribute Statement | Unchecked | | Want Assertions Signed | Unchecked | | Want Messages Signed | Checked | | Want Name ID | Checked | | Signature Algorithm | rsa-sha256 | | Digest Algorithm | sha256 | 6. Leave this page open and continue to the next steps. ### Add a new application in Google Workspace 1. Open the **Google Admin** Console, Expand **Apps**, then Select **Web and mobile apps**. ![Portal Navigation](/img/saml/gsuite/portal.png) 2. Select **Add app**, then click **Add custom SAML app**. ![SAML Apps](/img/saml/gsuite/saml_apps.png) 3. Enter an App name (e.g Kasm Workspaces) then select **Continue**. ![Add Applications](/img/saml/gsuite/app_name.png) 4. Copy the Google IdP entries to the **Identity Provider** section of the Kasm SAML Configurations started in the previous section. Then click **Continue**. | **Kasm Property Name** | **Google Workspace Property Name** | | --- | --- | | Entity ID | Entity ID | | Single Sign On Service | SSO URL | | X509 Certificate | Certificate | ![Google IdP Information](/img/saml/gsuite/g_idp.png) 5. Copy the Kasm SAML configurations from the **Service Provider** section into the **Service Provider Details** section. | **Kasm Property Name** | **Google Workspace Property Name** | | --- | --- | | Entity ID | Entity ID | | Single Sign On Service | ACS URL | | `https:///#/staticlogin` e.g `https://kasm.example.com/#/staticlogin` | Start URL | ![Service Provider Details](/img/saml/gsuite/service_provider_details.png) 6. Ensure the following settings are configured in the Google Workspace **Service Provider Details** . Select **Continue**. | **Setting** | **Value** | | --- | --- | | Signed Response | Checked | | Name ID | Basic Information / Primary Email | | Name ID Format | EMAIL | 7. If desired, select Google groups to pass to Kasm in the SAML assertion. Ensure the **App attribute** is set to `groups` to match the **Group Membership Attribute** previously configured in the Kasm SAML settings. In this example, a previously created security group `KasmAdmins` is selected. When complete, select **Finish**. ![Group Mempership mapping](/img/saml/gsuite/group_membership.png) 10. Review the final Kasm SAML Configuration form. Click **Sumbit** to save. ![Google SAML Config](/img/saml/gsuite/final_kasm_config.webp) ### Enabling Access for Users Once the Kasm SAML app is configured , access must be granted to Google users. 1. From the **Google Admin** Admin Console Expand **Apps**, then Select **Web and mobile Apps**, then select **Kasm Workspaces** 2. Click **User Access** ![Edit Service](/img/saml/gsuite/edit_service.png) 3. Select **ON for everyone** or for the desired Organizational Units or Groups, then click **Save** ![Giving App Access](/img/saml/gsuite/access.png) ## Group Mappings In the previous steps, the Google Workspace SAML configuration was configured to pass the `KasmAdmin` security group in the SAML assertion. The following example will demonstrate how to associate the Google group with a Kasm Group. 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups** then select **Edit** next to the **Administrators Group**. 3. In the **SSO Group Mappings** section, select **Add SSO Mapping**. 4. Select **SAML-Login with Google** in the *SSO Provider** section. 5. Enter `KasmAdmins` in the **Group Attribute** section. ![SSO Group Mapping](/img/saml/gsuite/saml_group.webp) ### Testing Access 1. Log out of the Kasm UI if already logged in. 2. Navigate to the Kasm UI login page. ![Kasm Login](/img/saml/gsuite/kasm_login.webp) 3. Click **Login with Google** to initiate the SAML SSO process. ![Google Login](/img/saml/gsuite/google_login.png) 4. After logging in, you should be redirected to the Kasm UI Dashboard. If the user was a member of the `KasmAdmins` Google group, they should now be a member of the `Administrators` group within Kasm. 5. From another browser, login to Google. Click the Google Apps icon in the top right corner. Scroll down and click **Kasm**. You should be logged into the Kasm UI Dashboard. ![Kasm App in Google Apps](/img/saml/gsuite/google_app.png) --- ## Keycloak(Saml) ## Keycloak SAML Setup ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration** 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Check **Enable** and enter a **Display Name**. e.g (Keycloak) 5. Enter the **Hostname** for the Workspaces deployment (e.g my.kasm.server). 6. Check **Default**. 7. Enter `Role` in **Group Member Attribute**. 8. Enter `username` in **NameID Attribute**. ![Kasm SAML Configurations](/img/saml/keycloak/kasm_saml_configuration.webp) 09. Check **Debug**. **Disable this setting after testing is complete**. 10. Leave this page open and continue to the next steps. ### Realm SAML Settings 1. Navigate to the Keycloak Admin Portal. Select the desired Realm (e.g `master`) then select Realm Settings. 2. Click on **SAML 2.0 Identity Provider Metadata**. ![Realm Settings](/img/saml/keycloak/realm_settings.png) 3. Copy the following items from the XML document to the **Identity Provider** section of the SAML configuration in Workspaces. | **Keycloak Property** | **Kasm Property Name** | | --- | --- | | entityID | Entity ID | | ds:X509Certificate | X509 Certificate | | md:SingleLogoutService..HTTP-POST | Single Logout Service/SLO Endpoint | | md:SingleSignOnService..HTTP-POST | Single Sign On Service/SAML 2.0 Endpoint | ![SAML XML](/img/saml/keycloak/keycloak_xml.png) 4. In the **Advanced Settings** of the Workspaces SAML configuration, ensure **Want Attribute Statement**, **Want Assertions Signed**, and **Want Name ID** are enabled. 5. In the **Advanced Settings** of the Workspaces SAML configuration, set **Signature Algorithm** to **rsa-sha256**. 6. Click **Save**. ![Identity Provider](/img/saml/keycloak/kasm_idp_configs.webp) 7. Select **Edit** next to the new Saml config as these settings will need to be referenced in th following sections. ### Add a new client in Keycloak 1. Navigate to the Keycloak Admin Portal. Select the desired Realm (e.g `master`) then select Clients. ![Keycloak Portal](/img/saml/keycloak/clients.png) 2. In the Clients window select **Create Client**. 3. In the **Client type** select **SAML** 4. In the **Client ID** enter a short name (e.g `kasm`) - Note: we will modify this in the next section to work around a keycloak bug. 5. Enter a value for the **Name** field (e.g Kasm Workspaces). 6. Select **Next**. ![Add Client](/img/saml/keycloak/add_client.png) 7. Update the **Home URL** with the URL of the Workspaces deployment (e.g `https://my.kasm.server`). 8. Update **Valid Redirect URLs** with a wildcard entry for the Workspaces deployment (e.g `https://my.kasm.server/*` 9. Select **Save**. ![Add Client](/img/saml/keycloak/add_client2.png) ### Client Configurations Update the client details configuration 1. In the Client Details page, select the **Settings** tab. 2. In the **Client ID** field, enter the value found in the **Entity ID** from the **Service Provider** sections in the Workspaces SAML configuration form. 3. In the **Master SAML Processing URL** enter the value found in the **Single Sign On Service** from the **Service Provider** sections in the Workspaces SAML configuration form. 4. Ensure **Name ID format** is `username`. 5. Ensure **Force name ID format** is set to **On**. 6. Ensure **Sign Assertions** is set to **On**. 7. Click **Save** ![Client Settings](/img/saml/keycloak/client_configs.png) 8. Select the **Keys** tab. 9. Set **Client signature required** to **Off** ![Keys](/img/saml/keycloak/client_signature.png) 10. Select the **Advanced** Tab. 11. In the **Logout Service POST Binding URL** enter the value found in the **Single Logout Service** from the **Service Provider** sections in the Workspaces SAML configuration form. 12. Click **Save** ![Advanced](/img/saml/keycloak/client_advanced.png) ### Adjust Single Role Attribute in Keycloak 1. Navigate to the Keycloak Admin Portal. Select the desired Realm (e.g `master`) then select **Client Scopes**. ![Keycloak Portal](/img/saml/keycloak/client_scopes.png) 2. Select **role_list** (saml). 3. Select the **Mappers** tab. 4. Select **role list**. 5. Set **Single Role Attribute** to **On**, then click Save. ![Role List](/img/saml/keycloak/role_list.png) ### Testing Access 1. Log out of the Kasm UI if already logged in. 2. Navigate to the Kasm UI login page. ![Kasm Login](/img/saml/keycloak/kasm_login.webp) 3. Click **Keycloak** to initiate the SAML SSO process. ![Keycloak Login](/img/saml/keycloak/keycloak_login.png) ### Mapping Roles During the SAML authentication process , Keycloak will send a list of the user's roles. These can be mapped to Kasm Groups. 1. Navigate to the Keycloak Admin Portal. Select the desired Realm (e.g `master`) then select **Realm Roles**. ![Keycloak Portal](/img/saml/keycloak/roles.png) 2. Select **Create Role**. 3. Name the role **kasm_admins** then click **Save**. ![Create Role](/img/saml/keycloak/create_role.png) 4. Select **Users** from the Keycloak menu, then click the username for the desired user. ![User Selection](/img/saml/keycloak/user_selection.png) 05. Select the **Role Mappings** tab, then select **Assign role** 06. Select **kasm_admins** from the **Available Roles** then click **Assign**. 07. Log into the Kasm UI as an administrator. 08. Select **Access Management** -> **Groups**, then click **Add Group**. 09. Name the Group **Keycloak Kasm Admins** and give it a priority (e.g 10). 10. Save the new group by clicking **Save**. ![Create Group](/img/saml/keycloak/create_group.webp) 11. On the **Groups** screen, using the arrow menu select **Edit** on the group that was just created. 12. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 13. Select the SAML IDP that was created above "SAML - Keycloak" for the **SSO Provider**. 14. Enter **kasm_admins** as the **Group Attributes** then click **Submit**. ![Add SSO Group Mapping](/img/saml/keycloak/create_sso_group_mapping.webp) 15. Log out of Kasm, and back in via SAML as the previously assigned user. The user should now be mapped to the **Keycloak Kasm Admins** a group. --- ## Okta ## Okta SAML Setup Follow the steps in the Okta application [setup](https://help.okta.com/oie/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm). Some of the Okta SAML settings fields displayed blow require information from the Kasm SAML configuration page. ![Okta SAML Settings](/img/saml/saml_okta_settings.webp) Go To Kasm's SAML configuration - Select Add Configuration Fill out the Okta Configuration form from the Kasm Information: > - Copy the "Single Sign on Service" from the Kasm configuration page to the "Single sign-on URL" field in Okta > - Copy "Entity ID" from the Kasm configuration page to the "Audience URI (SP Entity ID)" field in Okta > - Change Name ID format to EmailAddress > - Optionally advanced settings can be set here and the Single Logout Service could be configured Kasm SAML currently requires attributes to be returned in the SAML response unless security option wantAttributeStatement is false > - Add the setting below to ensure that Okta sends the username attribute in the SAML response. ![Okta SAML Attributes](/img/saml/saml_okta_attributes.webp) Okta can be configured to send over group membership information to Kasm in order for Kasm to assign groups based on Okta groups. In the example below Okta will send over all groups the user is a part of that start with "kasm" via the "samlGroup" attribute in the SAML Response. The Kasm "Group Member Attribute" setting must be configured to match this Okta setting. - Add the setting below if you wish Okta to send group information to Kasm ![Okta Group Settings](/img/saml/saml_okta_group_settings.webp) Select next and add an internal app. Once created navigate to the the Sign On configuration page in Okta and click on "View SAML Setup Instructions" on the right side of the page. Copy the following fields from this Okta page into the corresponding fields of the Kasm Saml Configuration page. - Copy the "Identity Provider Single Sign-On URL" from Okta to the "Single Sign On Service/SAML 2.0 Endpoint" in the Kasm Identity Provider configuration - Copy the "Identity Provider Issuer" in Okta to the "Entity ID" in the Kasm Identity Provider configuration - Copy the "X.509 Certificate" in Okta to the "X509 Certificate" in the Kasm Identity Provider configuration Then in Okta assign a user to the application in the Okta Configuration. In Kasm Select the "Test SSO" button at the bottom of the configuration form to perform a test of the SSO configuration. Users should now be able to select Okta as an authentication method in the sign-on page. --- ## Onelogin ## OneLogin SAML Setup In the Administration panel of OneLogin: - Select add app - Select SAML Test Connector (IdP w/attr) - Select Save - Select the Configuration tab ![Configure OneLogin](/img/saml/onelogin_config.png) Open Kasm as an administrator. - Go to Access Management -> Authentication -> SAML in Kasm's navigation bar - Click "Add Configuration" - Copy Entity ID to OneLogin's Audience field - Copy Single Sign On Service to OneLogin's Recipient Field. - Copy Single Sign on Service to OneLogin's ACS (Consumer) URL - Enter .\* in ACS validator (this should be updated with regex for the ACS URL later once login is setup) - Optionally copy Single Logout Service to Single Logout URL - Select Save on the OneLogin configuration page Go to the SSO tab on OneLogin's page ![SSO Settings OneLogin](/img/saml/onelogin_sso.png) - Copy the Issuer URL to the Identity Provider Entity ID field on the bottom of the Kasm SAML configuration form - Copy the SAML 2.0 Endpoint URL to the Identity Provider Single Sign field on the bottom of the Kasm SAML configuration form - Optionally add the SLO endpoint single logout service to the Single Logout Field - Select the SSO, then select View Details of the X.509 certificate on the OneLogin page - Copy the certificate into the X509 certificate text area in Kasm - Select Save on the Kasm Configuration In OneLogin select the Access tab and select the default roles for users. Go back to the Kasm Saml configuration and select Test SSO. This will launch the login with the OneLogin portal. If the test is successful the Kasm will be logged in under the username for the OneLogin email provided. If the test was successful it will have logged out the Admin. Logout and log back in as an administrator. If the login is not working you may select the debug checkbox in the saml configuration the response will contain the specific saml error If the login works properly enable the configuration with the enabled checkbox under service Provider This will enable the login to be seen by the users --- ## Pingone ## PingOne SAML Setup ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration** 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Check **Enable** and enter a **Display Name**. e.g (PingOne) 5. Enter `memberOf` in **Group Member Attribute** 6. Enter `emailAddress` in **NameID Attribute** ![Kasm SAML Configurations](/img/saml/pingone/kasm_saml_configurations.webp) 7. Leave this page open and continue to the next steps. ### Create a new SAML Application in PingOne 01. In the PingOne Admin portal, click **Applications** -> **My Applications** -> **Add Application** -> **New SAML Application** ![Add SAML Application](/img/saml/pingone/add_application.png) 02. Give the application a Name, Description , Category and optionally an icon. Click **Continue to Next Step** ![New SAML Application](/img/saml/pingone/new_application.png) 03. Copy the **Service Provider** entries from the Kasm SAML Configurations started in the previous section into the Basic SAML configurations and click. | **Kasm Property Name** | **PingOne Property Name** | | --- | --- | | Entity ID | Entity ID | | Single Sign On Service | Assertion Consumer Service (ACS) | | Single Logout Service | `` (e.g https://kasm.server) | | Relay State | Application URL | 04. Select **Redirect** for **Single Logout Binding Type** 05. Select **RSA_SHA1** for **Signing Algorithm** 06. Select **Continue to Next Step** 07. At the **SSO Attribute Mapping** page click **Continue to Next Step** 08. At the **Group Access** page enabled the groups desired. In this example we will add both the built in **Domain Administrators@directory** and **Users@directory** groups. ![Group Access Selections](/img/saml/pingone/group_access.png) 09. Select **Continue to Next Step**. The **Review Setup** page is shown. ![Review Setup](/img/saml/pingone/review.png) 10. Click **Download** next to **Signing Certificate**. Open this file with a text editor. This will be used as the **Singing Certificate** in the next section. 11. Click **Download** next to **SAML Metadata**. Open the file with a text editor. 1. Identify the **Location** for the `md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` property. This will be used as the **Single Logout Service** property in the next section. 2. Identify the **Location** for the `md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` property. This will be used as the **Single Sign On Service** property in the next section. ![Group Access Selections](/img/saml/pingone/metadata.png) ### Complete SAML configuration in Kasm 1. Back in the Kasm UI SAML configuration page update the **Identity Provider** selections | **Kasm Property Name** | **Azure Property Name** | | --- | --- | | Entity ID | Issuer | | Single Sign On Service | Single Sign On Service | | Single Logout Service / SLO Endpoint | Single Logout Service | | X509 Certificate | Signing Certificate | 2. In the **Advanced Settings** of check **Want Assertion Signed** and click **Save** ![Group Access Selections](/img/saml/pingone/kasm_saml_configurations_2.webp) ### Mapping Users PingOne is not set up to pass along the user's group membership during the SAML assertion. These groups can be mapped to groups within the Kasm Application. In the previous step we gave application login permissions to both the **Domain Administrators@directory** and **Users@directory** groups in PingOne. The following steps will now map the PingOne **Domain Administrators@directory** group to the **Administrators** group in Kasm. 1. In the PingOne Admin portal, click **Users** -> **User Groups** 2. Inspect the **Domain Administrators@directory** group. ![PingOne User Groups](/img/saml/pingone/user_groups.png) 3. Log into the Kasm UI as an administrator. 4. Select **Access Management** -> **Groups**, then using the arrow menu click **Edit** next to the **Administrators** Group 5. Navigate to the **SSO Group Mappings** tab and select **Add SSO Mapping**. 6. Select the SAML IDP that was created above "SAML - PingOne" for the **SSO Provider**. 7. Enter **Domain Administrators@directory** into the **Group Attributes** field. ![Add SSO Group Mapping](/img/saml/pingone/group_settings.webp) ### Testing Access 1. Log out of the Kasm UI if already logged in. 2. Navigate to the Kasm UI login page. ![Kasm Login](/img/saml/pingone/kasm_login.webp) 3. Click PingOne to initiate the SAML SSO process. ![PingOne Login](/img/saml/pingone/pingone_login.png) 4. Login as a member of the **Domain Administrators@directory** group. --- ## RequestedAuthnContext # ## RequestedAuthnContext In previous releases of Kasm, the `RequestedAuthnContext` was required, which was problematic as some configurations with certain IdPs will not work properly when Kasm requires this value. An example of this issue is documented on [Microsoft.com](https://docs.microsoft.com/en-us/troubleshoot/azure/active-directory/error-code-aadsts75011-auth-method-mismatch) This is no longer the case and is now configurable in the SAML form. --- ## Keycloak(3) ## VMware Workspace ONE SAML Setup ### Create a new SAML configuration in Kasm 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Authentication** -> **SAML** -> **Add Configuration** 3. The **SAML 2.0 Configuration** page will auto-generate the **Entity ID**, **Single Sign On Service**, **Single Logout Server**, and **Relay State** values. 4. Check **Enable** and enter a **Display Name**. e.g (Workspace One) 5. Update the following Settings | **Setting** | **Value** | | --- | --- | | Group Member Attribute | groupNames | | NameID Attribute | emailAddress | | Want Attribute Statement | Unchecked | | Want Message Signed | Checked | | Want Name ID | Checked | 6. Leave this page open and continue to the next steps. ### Add a new SaaS Application 1. Open the **Workspace One Access** Admin Console and select the **Catalog** tab, then select **New**. ![Workspace One Access Portal](/img/saml/workspaceone/access.png) 2. In the **New SaaS Application** dialogue, enter a **Name** (e.g Kasm) and optionally a **Description** and **Icon**. Select **Next**. ![New SaaS Application Definition](/img/saml/workspaceone/definition.png) 3. Select **SAML 2.0** as the **Authentication Type** and select **Manual** for the **Configuration**. ![Authentication Type](/img/saml/workspaceone/auth_type.png) 4. Copy the following values from the Kasm SAML Configurations started in the previous section into the **New SaaS Application form**. | **Workspace One Property Name** | **Kasm Property Name** | | --- | --- | | Single Sign-On URL | Single Sign On Service | | Recipient URL | Single Sign On Service | | Application ID | Entity ID | | Relay State URL | Relay State | ![SAML URL Configuration](/img/saml/workspaceone/saml_urls.png) 5. Select **Email Address** as the **Username Format**. ![Username Format](/img/saml/workspaceone/username_format.png) 6. Click **Advanced Properties**. Scroll down to the **Custom Attribute Mapping** section. Add an entry with the following information then click **Next** | **Attribute** | **Value** | | --- | --- | | Name | groupNames | | Format | Basic | | Namespace | `` | | Value | `${groupNames}` | ![Group Names](/img/saml/workspaceone/group_names.png) 7. Select a desired **Access Policy**. In this example we will use the **default_access_policy_set**. Select **Next**. ![Access Policies](/img/saml/workspaceone/access_policy.png) 8. Review the configuration then select **Save & Assign**. ![Review Configuration](/img/saml/workspaceone/review.png) 9. In the **Assign** dialogue, type in the desired user or group. In this example the **ALL USERS** group is used. Select **Save** ![Assign Users/Groups](/img/saml/workspaceone/assign.png) 10. From the **Catalog** tab of the **Workspace ONE Access** panel, select **Settings**. ![Settings](/img/saml/workspaceone/settings.png) 11. Select **SAML Metadata**. Copy the contents of the **Signing Certificate** into **X509 Certificate** field under **Identity Provider** in the Kasm SAML Configurations started in the prior section. ![Signing Certificate](/img/saml/workspaceone/signing_cert.png) ![Configuring Signing Certificate](/img/saml/workspaceone/x509.png) 12. Back in the **Settings** dialogue, click **Identity Provider (IdP) metatdata**. ![Certificate](/img/saml/workspaceone/signing_cert.png) 13. An XML metatdata file will be shown. Copy the highlighted sections into **Identity Provider** fields in the Kasm SAML Configurations started in the prior section. Once complete click **Submit** | **Workspace One Property Name** | **Kasm Property Name** | | --- | --- | | entityID | Entity ID | | SingleSignOnService | Single Sign On Service/SAML 2.0 Endpoint | | SingleLogoutService | Single Logout Service/SLO Endpoint | ![Metadata](/img/saml/workspaceone/metadata.png) ![SAML Configuration](/img/saml/workspaceone/identity_provider.webp) ## Testing Access 1. Log out of the Kasm UI if already logged in. 2. Navigate to the Kasm UI login page. ![Kasm Login](/img/saml/workspaceone/kasm_login.webp) 3. Click **Workspace One** to initiate the SAML SSO process. ![VMware Login](/img/saml/workspaceone/vmware_login.png) 4. After logging in, you should be redirected to the Kasm UI Dashboard 5. From another browser, login to Workspace ONE Access. **Kasm** should be displayed as an App. You may click the link to automatically open and log in to Kasm ![Workspace One Access](/img/saml/workspaceone/workspace_one_access.png) ### Group Mappings In the prior steps, Workspace One was configured to pass along the group names the user is a member of in the SAML assertion. This can be used to automatically map users into Groups within the Kasm application. The following assumes a group is created in Workspace named **Accounting** 1. Log into the Kasm UI as an administrator. 2. Select **Access Management** -> **Groups**, the select **Create New Group** 3. Give the Group a **Name** (Does not need to match the Workspace ONE Group Name) and **Priority** 4. Click **Save** to create the new group. ![Create Group](/img/saml/workspaceone/create_group.webp) 5. Select **Access Management** -> **Groups**, then using the arrrow menu click **Edit** next to the group just created. 6. Navigate to the **SSO Group Mapppings** tab and select **Add SSO Mapping**. 7. Select the SAML IDP that was created above e.g. "SAML - Workspace One" for the **SSO Provider**. 8. Enter the Workspace ONE Group Name in the **Group Attributes** field. Click **Submit** ![Add SSO Group Mapping](/img/saml/workspaceone/saml_groups.webp) The next time a user of the **Accounting** group logs in they will automatically become a member of this Kasm Group. --- ## SAML 2.0 Authentication Configuration in Kasm # SAML 2.0 Authentication Kasm offers SAML configurations for authorization through SAML 2.0 Identity Providers. This gives users a single sign on experience and improves security. ## Configuration Saml configuration can be found under the Authentication tab in the Admin Navigation Bar. ### Service Provider > We automatically generate the Service Provider Entity ID, single login url and single logout URL when you submit a > configuration as this is based on the hostname of your server. - **Enabled** - This checkbox will enable this configuration and determines wether it will be seen by the users as an option in the login page. - **Display Name** - This is the name shown to the users in a login button on the login page. e.g. 'OneLogin', 'Okta' - **Host Name** - The URL hostname (e.g kasm.example.com) of the deployment. This SAML config will only function when the deployment is accessed via this URL host name. This allows for a single deployment to service multiple tenants who may need different SAML configurations. If **Default** is defined, this config will apply regardless of the host name. - **Entity ID** - This is the URL that identifies the Service Provider. It may be called a Provider Issuer or something similar. The URL is automatically created by Kasm for this configurations sign on. - **Single Sign On Service** - This is the URL used for the response from the Idp to login. The URL is automatically created by Kasm to connect to the specific configuration. - **Single Logout Service** - This is the URL provided for the logout of the user. It may be provided by the IDP but is not required - **Relay State** - The Relay state must be set to [https://hostname/#/sso](https://hostname/#/sso) - **Default** - Used in conjunction with **Host Name**. When checked this config will apply regardless of what Host name the user is accessing the server with. - **Auto Login** - This setting will automatically launch this saml configuration from the default login page. Only one configuration should be set to auto login. If this is set the normal login page may still be accessed at /#/staticlogin - **Group Member Attribute** - This setting maps the attribute from the Idp to the Kasm group. The group must be enabled for kasm and given the name under the individual group edit. - **NameID** - This attribute is used as the identifier for the user. The Idp may specify it is set to "emailAddress" or something similar but it may also be blank. - **ADFS** - if using Active Directory Federation Services select this checkbox - **x509 Certificate** - This is an Optional Certificate that can be provided for signature verification of the SP - **Private Key** - This will be generated along with the optional x509 certificate above - **Debug** - This will enable the response to show the specific saml error that is occuring. It is useful during setup of the configuration. ### Identity Provider - **Entity ID \*Required** - This is the URL provided by the IDP that identifies the provider. It may be called a Provider Issuer or something similar. This URL must be configured for the Login to work properly. - **SingleSignOnService/SAML 2.0 Endpoint \*Required** - This is the URL provided by the IDP used for the login. This URL must be configured for the Login to work properly. - **SingleLogoutService/SLO Endpoint** - This is the URL provided for the logout of the user. It may be provided by the IDP but is not required - **x509 Certificate** - This is the certificate used to verify the signature of the application and it is required. - **Attributes** - One attribute must be provided by the IDP. It should be a unique identifier like username or email ## Advanced Settings These options can be configured to meet the security requirements needed. - **Want Attribute Statement** - Indicates a requirement for the AttributeStatement element - **Send Requested Authn Context** - Send the optional RequestedAuthnContext element in the SAML request. Certain IDPs will not work properly when this field is sent in the request. - **Name Id Encrypted** - Indicates that the nameID of the \ sent by this SP will be encrypted. - **Authn Requests Signed** - Indicates whether the \ messages sent by this SP will be signed.(Metadata of the SP will offer this info) - **Logout Request Signed** - Indicates whether the \ messages sent by this SP will be signed - **Logout Response Signed** - Indicates whether the \ messages sent by this SP will be signed. - **Want Messages Signed** - Indicates a requirement for the \, \ and \ elements received by this SP to be signed. - **Want Assertions Signed** - Indicates a requirement for the \ elements received by this SP to be signed.(Metadata of the SP will offer this info) - **Want Assertions Encrypted** - Indicates a requirement for the \ elements received by this SP to be encrypted. - **Want Name Id** - Indicates a requirement for the NameID element on the SAMLResponse received by this SP to be present. - **Want Name Id Encrypted** - Indicates a requirement for the NameID received by this SP to be encrypted. - **Signature Algorithm** - Algorithm that the toolkit will use on signing process. - **Digest Algorithm** - Algorithm that the toolkit will use on digest process. ## SAML Setup For general SAML configuration: - Copy the Service Provider Entity ID, Single Sign On, (optionally) Single Logout Service to the Identity Provider. if the single logout service field is left blank then there will be no logout redirection on users logout. - The Identity Provider must also be given the Relay State provided - a NameID attribute must be set to return the specific attribute of the user. (e.g. 'emailAddress', 'transient') A default of Unspecified is used when not present. The Identity Provider should then return these same settings to be put under the Identity Provider section in the configuration settings. - The metadata button should return the Service Provider information. Some of the specific IDP setups below may help in setting up SAML as they are sometimes similar A non redirecting login page is at [https://hostname/#/staticlogin](https://hostname/#/staticlogin) when auto login is enabled. ## Group Assignment Groups for SAML users are automatically assigned if group has a SSO Group Mapping for this saml IDP and SAML group name. This will allow automatic provisioning of groups to SAML users but will not unassign non-SAML groups. To automatically assign groups to saml users: - Navigate to the Access Management -> Groups tab in the admin navigation bar - Select edit for the desired group using the arrow - Select the SSO Group Mappings tab and select Add SSO Mapping - Select the SAML provider to be mapped to this Kasm group - There are two options for specifying with SAML users to assign to this Kasm group - Check the Assign All Users checkbox to assign all users from this SAML IDP to this Kasm group irrespective the users IDP groups - Leave Assign All Users unchecked and enter the group name the IDP has for this group, either preceded by a forward slash (e.g. `/sales_group`) if the IDP has Full Group Path set to On, or without a preceding forward slash (e.g. `sales_group`) if Full Group Path is set to Off ![Add SSO Group Mapping](/img/groups/add_sso_group_mapping_config.webp) - Navigate to the SAML configuration - Change the Group Member Attribute to the corresponding group attribute of the IDP ## SAML Attribute Mapping Additional SAML attributes can be passed with the SAML assertion. Administrators can optionally map those attribute values to fields on the Kasm user. See the documentation for your SAML Identity Provider (IdP) for a listing of attributes and how you can pass them to the Service Provider (SP) in the SAML assertion. The following Kasm User fields can be populated with values from SAML attributes. - First Name - Last Name - Phone - Organization - Notes - City - State - Country - Email - Custom Attribute 1 - Custom Attribute 2 - Custom Attribute 3 ![SAML Attribute Mapping](/img/saml/saml_attribute_mapping.webp) Kasm can log all SAML attributes in the assertions during login, this is helpful for determining the attribute names. Add a SAML Attribute Mapping with an attribute name of 'debug' and target any user field. The next time a user logs in, all SAML attributes and values will be logged by Kasm. ## Known Issues - [requestedAuthnContext](saml/requestedAuthnContext.mdx) ## Configuration Examples - [Active Directory Federation Services (ADFS) SAML Setup](saml/adfs.mdx) - [Azure Active Directory SAML Setup](saml/azure.mdx) - [Google Workspace SAML Setup](saml/gsuite.mdx) - [Group Mappings](saml/gsuite.mdx#group-mappings) - [Keycloak SAML Setup](saml/keycloak.mdx) - [Okta SAML Setup](saml/okta.mdx) - [OneLogin SAML Setup](saml/onelogin.mdx) - [PingOne SAML Setup](saml/pingone.mdx) - [VMware Workspace ONE SAML Setup](saml/workspaceone.mdx) - [F5 APM SAML Setup](saml/f5apm.mdx) - [Testing Access](saml/workspaceone.mdx#testing-access) --- ## Two-Factor Authentication (2FA) Setup # Two Factor Authentication Two Factor Authentication requires the user provide an additional piece of evidence beyond their standard password, to gain access to the system. Kasm implements a Time-based One-Time Password (TOTP) algorithm that can be used with popular apps such as Google's Authenticator. Physical tokens and WebAuthn devices (e.g. YubiKeys) can also be used. A user can be required to enroll a second authentication factor upon their next login by [the admin configuring the "require_2fa" group setting](groups.mdx). Alternatively, users may also self-enroll a Two Factor device through [the User Profile Page](../../../tutorials/user-guide/profile.mdx) when [the "allow_2fa_self_enrollment" group setting](groups.mdx) is enabled. ## Require Two Factor Authentication An Admin may require that all members of a group enroll a two factor device upon their next login. - Navigate to the Access Management -> Groups tab in the Administrators Sidebar and select Edit from the arrow menu for the group - Select Add Settings from the Settings tab - Select the "require_2fa" setting and select True to add to all of the users in the group ![Require Two Factor Authentication Group Setting](/img/two_factor/auth_enable.webp) WebAuthn and TOTP can be disabled individually using the "allow_webauthn_2fa" and "allow_totp_2fa" [group settings](./groups.mdx#group-settings). ## Self Enrollment A user may self enroll a two factor in their user settings page when the "allow_2fa_self_enrollment" setting is enabled. Navigate to the user profile settings on your Kasm deployment by logging into your Kasm Workspaces deployment, and clicking on the user icon at the top right. ![Edit Profile](/img/open_in_extension/profile.webp) Scroll down to select "Two Factor" and then select "Add Second Authentication Factor" ![Add Two Factor](/img/two_factor/profile_two_factor.webp) ## Two Factor Setup When a user logs in the first time with "require_2fa" enabled, or they self-enroll, they will be presented with a setup page where they can select the following methods to register a new second factor: - [Soft TOTP Token (Google Authenticator)](two-factor.mdx#user-authenticator-app-setup) - [Hard TOTP Token](two-factor.mdx#physical-totp-token-setup) - [WebAuthn Device (YubiKey, TouchID, FaceID)](two-factor.mdx#webauthn-authentication) ![Two Factor Setup](/img/two_factor/2fa_setup.webp) ## User Authenticator App Setup The user will be asked to add the authentication code to their Authenticator App on the first log on after two factor was enabled. Once the username and password have been verified, a QR code and secret are provided for easy implementation in Google's Authenticator - The User will select the plus icon in Authenticator and select Scan barcode to use their phone's camera to add the secret or Manual Entry to enter the secret manually ![TOTP Setup](/img/two_factor/auth_setup.webp) - User must enter one time password provided in the Authenticator App to log in ![Auth Code](/img/two_factor/auth_code.webp) Download the Apps: [Apple App Store](https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8) [Google Play Store](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en_US?) ### Reset Single-User Authentication The user can reset the authentication code in the reset password section. - Navigate to the profile tab in the Sidebar and select "Reset Password" - Enter current password and a new password - Check the "Reset Two Factor Authenticator" checkbox and then click Submit ![Auth Reset](/img/two_factor/auth_reset.webp) The administrator can reset the user's Two Factor TOTP Token or WebAuthn Credential. - Navigate to the Access Management -> Users tab in the Administrators Sidebar and select edit for the user from the arrow menu - Check the "Reset Two Factor TOTP Token" or "Reset Two Factor WebAuthn Credential" checkbox and then click Save ![Auth Reset Admin](/img/two_factor/auth_user_reset.webp) ## Physical TOTP Token Setup Kasm Workspaces supports using physical tokens that meet the TOTP specification defined in RFC 6238. The tokens must use a 30 second token interval and use SHA1. Physical tokens purchased must come with a seed file, which is a password encrypted zip file containing a list of serial numbers with the associated base32 secret for each token. ![Physical Tokens List](/img/two_factor/physical_tokens.webp) ### Import Physical Tokens Physical tokens will come with an encrypted zip file containing a list of serial numbers and associated secrets. In the administrator panel, go to Authenticate, Physical Tokens, and click the Import button. Provide the file and password associated with the file and click upload. ![Import Token Zip](/img/two_factor/import_physical_tokens.webp) Physical TOTP vendors will provide the seed file with your order. The file must be a password protected zip file. The vendor will provide the password for the zip file. The zip file will contain a text file with a comma separated list of tokens. The first value is the token serial number, which matches the serial number on the back of the token. The second value in each row is the secret, which is a base32 encoded string. The following is an example of what the raw uncompressed seed file would look like. ``` 1234567891234,JNQXG3JANFZSA5DIMUQGEZLTOQQHG33G 1234567891235,OR3WC4TFEBSXMZLSEBRXEZLBORSWICQG ``` ### Assigning Tokens #### Administrator Assigned Tokens can be assigned and unassigned by the administrator by clicking arrow menu icon next to a token and selecting assign or unassign. #### User Self Register If an administrator does not explicitly assign a token to a user, the user can input the serial number on login to self register the token. A user will only be able to self-register a token if they are required to login with two factor authentication and they don't currently have a token assigned. Under those conditions, the user will be prompted to setup a token on login. The user will need to select the "I have a physical hardware device instead" link, which will then display the following dialog where they can enter the serial number located on the back of the physical token. ![User Token Setup](/img/two_factor/token_setup.webp) ### Deleting Tokens Tokens can either be deleted individually or the administrator can delete all tokens that were imported together as part of the same seed file by clicking the Delete Seed Series button on the Physical Tokens view. Deleting a token will make it unusable to the currently assigned user. ## Token Time Drift TOTP requires the physical token or the user's phone to have nearly the same time as the server authenticating the user. This means that your Kasm backend servers need to have proper time synchronization for TOTP to work. Physical tokens utilize inexpensive crystal oscillation based timing hardware, which will drift over time. See your manufacturer's documentation for details. Generally speaking, crystal oscillation based hardware will drift upwards of 2 minutes every year. By default, Kasm allows for one 1 minute of drift forward or backward, from the server's time. A token is valid for 30 seconds, providing an overall allowed effective drift of 1 minute and 30 seconds by default. You may override the default by modifying the `Token Drift` [Server Settings](../../../reference/settings.mdx). ## WebAuthn Authentication WebAuthn Authentication allows for users to use a supported WebAuthn device, such as a Yubikey, TouchID, or FaceID as a second factor to login to Kasm. Upon selecting "WebAuthn Device" during the Two Factor registration process the user will be presented with a dialogue to use a passkey, the user may select whatever device is desired. On their next login they will be prompted to use the WebAuthn device as a second factor. ![WebAuthn Setup](/img/two_factor/create_passkey.webp) WebAuthn only functions when the user's browser trusts the connection to Kasm Workspaces. This can be acheived by setting up the deployment with a valid [Custom Certificate](../../networking/replace-certificates.mdx) or deploying behind a [Reverse Proxy](../../networking/reverse-proxy.mdx) that has a valid server certificate. --- ## User Management: Adding & Configuring Users # Users Users must first be added to the server and then added to a group to manage their permissions. User permissions can be set by updating the group settings found [here.](groups.mdx#group-settings). By default Anonymous users are hidden, if you wish to see them, click on the dropdown next to Add User and pick between, Hide Anonymous, Show Anonymous and Only Anonymous. ## Create User - Select **Access Management > Users** from the navigation menu. - Select **Add User** from the top right of the **Users** table. ![Creating a new user](/img/users/create_user.webp) - Fill out Users information with User properties below. ## User Properties | Name | Description | | --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | User Name | Username for login | | Password | Password for login | | First Name | User's first name | | Last Name | User's last name | | Realm | SSO that the user belongs to (local, LDAP, SAML, OIDC) | | Notes | Notes about user | | Locked | Lock account | | Disabled | The account is disabled. The user cannot login or authenticate until re-enabled by an administrator. | | Reset Two Factor Authentication Secret | Reset the 2FA secret. The users will be required to re-initialize the 2FA upon next login. | | Force Password Reset on Login | Force the user to change their password on the next login. This setting applies only to local accounts. | | Organization | Organization Name | | Last Session | Last login time | | Phone | Phone number | | City | City | | State | State | | Country | Country | | Email | Email address | | Custom Attribute 1 | Attribute to be used for custom purposes. | | Custom Attribute 2 | Attribute to be used for custom purposes. | | Custom Attribute 3 | Attribute to be used for custom purposes. | | Encryption Key | An encryption key optionally used in Storage Mappings to encrypt and obfuscate files at rest. A key is automatically generated for each user but can be replaced if desired. See [Custom Storage Provider Setup](../../data-storage/storage-mappings/custom.mdx) | | Encryption Salt | An encryption salt optionally used in Storage Mappings to encrypt and obfuscate files at rest. A key is automatically generated for each user but can be replaced if desired. See [Custom Storage Provider Setup](../../data-storage/storage-mappings/custom.mdx) | ## Add User to Group - Select **Access Management > Groups** from navigational menu. - Select **Edit** from the arrow menu of the group you want to add the user. - Select the **Users** Tab. - Select **Add User** from Users in Groups table. ![Users in Group](/img/users/add_user_group.webp) - Select the user you wish to add from dropdown menu and click **Submit**. ![Adding a user to a group](/img/users/add_user.webp) ## User Settings Users have the ability to change settings by visiting their profile. - Auto Launch Session. Automatically launch a session when the user logs in. Kasm Workspaces will use the configured **Default Workspace Image**. - Chat Sound Effects. Enable Sound effects for chats during shared sessions. - Default Workspace Image. The Default Kasm Image to use. This is the Image that is used for the **/go** URL, clicking the **Launch Now** menu item, and for **Auto Launch Session**. This item overrides the corresponding group setting if defined. - Show Tips During Session. By default the user is shown a Tip that describes how to find and use the control panel. This tip can be suppressed by setting this item to false. - Toggle Control Panel. Open and close the control panel within a Kasm session by pressing the *Ctrl* key twice. - Theme. Select the Kasm Workspaces app theme, there is also an *auto* setting that will use the OS setting of the user's local computer. ![User Settings](/img/users/user_settings.JPG) ## User Permissions The users permissions tab gives a breakdown of the resultant permissions a user has based on the groups they are a part of. If you want to give specific permissions you will need to create a group with those permissions and add the user to that group. In order to change the permissions: - Select **Access Management > Groups** from navigational menu. - Select **Edit** from the arrow menu of the group you want to modify the permissions of (or create a group). - Select the **Permissions** Tab. - Click the **Add Permissions** button. A full list of the options available is [here.](groups.mdx#group-permissions) ![User Permissions](/img/users/user_permissions.webp) ## User File Mappings File Mappings allow the administrator to manage files to be mapped to the inside of a user's container based Workspace session. File Mappings can be defined on a User, Group, and/or Workspace. See the primary documentation on [File mappings](../../workspaces-sessions/file-mappings.mdx) for more details. User defined File Mappings can only be defined by the administrator. ![File Mappings Table](/img/images/file_mappings.webp) The following is an example File Mapping of a Chrome Managed Policy to define bookmarks in Chrome. ![File Mapping Definition](/img/images/file_mapping.png) ## Bulk Import Users can be created in bulk through the "Import Users" button on the User administration page. The Developer API also exposes the [`/api/public/batch_create_user`](../../../reference/developer-api.mdx#batch-create-users) endpoint for programmatic use. ### CSV Formatting ### User CSV Schema The CSV file for User bulk imports recognizes the following columns. Optional columns may be omitted if they are not needed for any record. The descriptions from the "User Properties" section above apply to these fields, except where noted. | Column Header | Required | Default | User Property | Notes | | --- | --- | --- | --- | --- | | username | Yes | | User Name | | | password | No | See note | Password | If omitted or `null`, the server will generate a random default password for the User. Whitespace will be honored for this value. | | realm | No | `"local"` | Realm | | | sso_config_id | Conditionally | `null` | | This is the ID (UUID) of the SSO configuration in the Kasm database. Required for OIDC and SAML realms. | | first_name | No | `null` | First Name | | | last_name | No | `null` | Last Name | | | notes | No | `null` | Notes | | | lock_account | No | `false` | Locked | | | disable_account | No | `false` | Disabled | | | force_password_reset | No | `false` | Force Password Reset on Login | | | organization | No | `null` | Organization | | | phone_number | No | `null` | Phone | | | city | No | `null` | City | | | state | No | `null` | State | | | country | No | `null` | Country | | | email | No | `null` | Email | | | custom_attribute_1 | No | `null` | Custom Attribute 1 | | | custom_attribute_2 | No | `null` | Custom Attribute 2 | | | custom_attribute_3 | No | `null` | Custom Attribute 3 | | | encryption_key | No | `null` | Encryption Key | Whitespace will be honored for this value. | | encryption_salt | No | `null` | Encryption Salt | Whitespace will be honored for this value. | | group_... | No | `null` | | The file may contain any number of "group_*" columns, e.g. "group_1", "group_2", etc. Each should contain the name of an existing Kasm User Group that the user will join. Groups that all users join by default, such as the "All Users" system group, do not need to be listed. | Below is an example of a valid User CSV file. It contains all columns, including several groups. It would generate three users: 1. A local user. Their password is automatically generated, but required to be changed upon login. They are a member of 3 additional specified groups. 2. A user that exists in an OIDC SSO solution. They are a member of 1 additional specified group. 3. A user that exists in the LDAP system configured for use with the Kasm deployment. They are a member of no additional groups. ```csv username,realm,password,sso_config_id,email,last_name,first_name,organization,phone_number,city,state,country,encryption_key,encryption_salt,lock_account,disable_account,force_password_reset,notes,custom_attribute_1,custom_attribute_2,custom_attribute_3,group_1,group_2,group_3 jane.smith@ourorg.local,local,,,localuser1@ourorg.local,Smith,Jane,Our Organization,+12345678900,London,,UK,,,false,false,true,,,,,Other Admin Group,Finance,Data Managers alice@ourorg,oidc,,00001111-2222-3333-4444-555566667777,alice@ourorg.local,,Alice,,,,,,,,,,,,,,,Other Admin Group,, bob,ldap,,88889999aaaabbbbccccddddeeeeffff,,,,,,,,,,,,,,,,,,,, ``` --- ## Web Filtering Configuration # Web Filtering Administrators can limit access to websites by defining **Web Filter Policies**. Once a policy is created it can be assigned to any number of groups via [Group Setting](users-groups-mgmt/groups.mdx#group-settings) or directly to [Workspaces](../workspaces-sessions/container-workspace/workspaces.mdx) . Policies set on the Workspaces take priority over those assigned to Groups. ![Denied Request](/img/web_filtering/denied.png) ## Configuration ![Filter Policy](/img/web_filtering/policy.webp) ![Filter Policy Advanced](/img/web_filtering/policy2.webp) Use of the **Categorization** requires a license. Kasm Workspaces must also have live internet access to communicate with the categorization service. Please contact your Kasm Technologies representative for details. | **Property** | **Description** | | --- | --- | | Name | A name for the policy | | Description | A description for the policy | | Deny By Default | If checked, all requests will be **denied** unless the domain is added to the **Domain Whitelist**, or the category of the domain is set to **allow**. If unchecked, all requests will be **allowed** unless the domain is added to the **Domain Blacklist**, or the category of the domain is set to **deny**. | | Domain Blacklist | A list of domains to reject. Enter one domain per line. Sub-domains are automatically matched unless explicitly defined elsewhere. | | Domain Whitelist | A list of domains to allow. Enter one domain per line. In the event of a conflict, the blacklist takes priority. Sub-domains are automatically matched unless explicitly defined elsewehere. | | Enable Safe Search | When enabled, *Safe Search* for popular search engines will enforced using the **Safe Search Patterns**. Google, Bing, Yandex, DuckDuckGo, and Yahoo are supported by default. | | Enable Categorization | If checked, requested domains will be checked against Kasm's url categorization service. Each category can be set to **Allow**, **Deny**, or **Inherit**. Inherited categories will utilize the **Deny By Default** setting. Domains specified in the **Domain Whitelist** or **Domain Blacklist** take priority over categorization. | | URL Categories | Administrators can choose to **Allow**, **Deny** or **Inherit** the default rule for each category. If **Inherit** is selected, the category will be allowed/denied based on the **Deny By Default** setting | | Disable Logging | When enabled, no access related logs will be produced. | | Safe Search Patterns | A data structure containing the URL rewrite rules used to apply **Safe Search**. | | SSL Bypass Domains | Web Filtering uses SSL inspection technology to enforce policy. In some cases, this technology will not be compatible with a website. Administrators can enter a list of domains that will bypass this inspection to restore functionality. Enter one domain per line. To match all subdomains domains, prefix a period before the domain `.google.com` | | SSL Bypass IPs | Web Filtering uses SSL inspection technology to enforce policy. In some cases, this technology will not be compatible with a website. Administrators can enter a list of IPs that will bypass this inspection to restore functionality. Enter an IP or CIDR notation one per line. | ## URL Categorization Caching When URL categorization is enabled, categorization data is queried via the **Web Filter Update URL** categorization service defined in the global settings. For performance reason, these results are cached in the local Kasm deployment for a configurable period of time. The two settings that govern the expiration of these records are: - **Web Filter Default Category Expiration (Hours)** - URL categorization results will be cached for the specified time, defined in hours. This setting applies to domains that have a category other than Uncategorized. - **Web Filter Uncategorized Expiration (Hours)** - URL categorization results will be cached for the specified time, defined in hours. This setting only applies to domains that are currently categorized as Uncategorized. Any session that is launched after the expiration time, will have fresh categorization results fetched from the **Web Filter Update URL**. --- ## General Server Issues(Troubleshooting) - **Compatible Docker Version** > Ensure the system is running compatible versions of `docker` and `docker compose`. See > [System Requirements](../../explanations/system-requirements.mdx) for more details. - **Cloud Security Groups** > If the security group rule in the AWS / Azure / OCI console that allows https into the Web App restricts connections by IP address > (the source IP is not "0.0.0.0/0"), then an additional rule must be added to allow the server to connect to itself. > > This is done by creating an additional rule to the security group allowing https connections from the same security group. ![Security Group Example](/img/troubleshooting/requesting_kasm/ip_allowlist_example.jpg) ## Linux Server Workspaces - **No audio in Linux (xrdp) sessions** > No sound is heard in a session, and `pactl list sinks short` shows only a dummy `auto_null` sink. On Ubuntu 24.04 and later, the `pulseaudio-module-xrdp` package no longer exists, and xrdp audio support has moved to PipeWire (`pipewire-module-xrdp`). If the session is still running the legacy PulseAudio daemon, the PipeWire xrdp sink never loads and audio falls back to `auto_null`. Switch the session to PipeWire: > > ```bash > sudo apt-get install -y pipewire pipewire-pulse wireplumber pipewire-audio alsa-utils > sudo apt-get remove -y pulseaudio > sudo systemctl --global enable pipewire.socket pipewire-pulse.socket wireplumber.service > ``` > > Disconnect and reconnect the session so that a fresh user session starts under PipeWire, then verify with `pactl info` (which should report `PulseAudio (on PipeWire ...)`) and `pactl list sinks short` (which should show an xrdp sink rather than `auto_null`). Apply this fix in the golden image, or in a session-start or autoscale provisioning script, so that it persists across newly provisioned sessions. - **Web browser missing or "Input/output error" in a session** > Clicking the browser icon does nothing, or it returns an `Input/output error`; in some images the browser is not installed by default. Do not rely on the browser being present in the base image. Install it from the autoscale provisioning script or a session-start script instead. On Ubuntu 24.04, the snap-packaged Firefox frequently fails under xrdp, so prefer a `.deb` browser such as Chromium, Chrome, or Firefox from the Mozilla PPA. A stale `~/thinclient_drives` FUSE mount left over from a previous xrdp session can also cause an `Input/output error`; clear it with `fusermount -u ~/thinclient_drives`, or disable drive redirection in `/etc/xrdp/sesman.ini` or `xrdp.ini` if it is not needed. - **Active Directory domain-join failures on auto-scaled VMs** > Newly auto-scaled VMs fail to join the domain. SSH into the affected VM that was created by autoscale and review the provisioning log at `/var/log/kasm_install.log` (for example, `sudo less /var/log/kasm_install.log`). The most common cause is that the required ports are not open between the VM and the domain controllers, such as DNS (53), Kerberos (88, 464), LDAP (389, 636), SMB (445), and the Global Catalog (3268). Verify your cloud security lists or NSGs (for example, OCI security lists) and any host firewall rules. When using autoscale to join VMs to Active Directory, also review the [Linux VM startup script README](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/blob/develop/linux_vms/README.md) for the required configuration. --- ## Gpu Issues # GPUs - **Agents table shows 0 GPUs** > The first image below is the Agents list. The GPUs column should show the number of GPUs available on that agent. The second > image is of the top of the View Agent panel. If the GPU(s) was detected, this view will show details about the GPU. Finally, > the third image below is the GPU Info details shown on the Agent View Panel. > > Kasm uses multiple methods to gather information about GPUs. If the GPU Info json contains some, but not all information about > your GPUs and the agent is not reporting any GPUs, ensure that the Nvidia Docker toolkit is installed and you restarted the > docker daemon. Run the command `sudo docker system info | grep Runtimes` and check that `nvidia` is listed. > To enable GPU support on an agent, the Nvidia GPU acceleration driver must be installed on the agent. Reference the [GPU installation guide](../../tutorials/install/gpu.mdx) for more information. ![Agents List](/img/gpus/agent_no_gpus.png) ![Agent Details](/img/gpus/agent_details.png) ![Agent GPU Info](/img/gpus/agent_gpu_info.png) - **No resources are available** : When users attempt to provision a workspace they get the following error message. ![No Resources Error](/img/gpus/no_resources_error.png) ![Logs indicating source of issue](/img/gpus/no_resources_logs.png) - **nvidia-smi errors** : The nvidia-smi tool should automatically be available inside the container. Before troubleshooting anything with Workspaces, ensure nvidia-smi works on the host directly. Next, ensure that you can manually run a container on the host with the nvidia runtime set and successfully run the nvidia-smi command from within the container. If you are able to run nvidia-smi from the host directly and when manually running a container, then open a support issue with Kasm. - **Session With Black Screen** : When running a session with an NVIDIA GPU enabled, the session may only render a black screen. Viewing the container logs of the sessions may show the following error `libEGL warning: egl: failed to create dri2 screen`. Add the following entry to the [docker-run-config](./gpu-issues.mdx) of the Workspace. ```json { "environment": { "NVIDIA_DRIVER_CAPABILITIES": "all" } } ``` --- ## Troubleshooting Kasm Workspaces on Kubernetes # Troubleshooting Kasm on Kubernetes Recommendations and resources useful when troubleshooting a Kasm Kubernetes deployment. --- ## Confirm All Pods are Running ```bash kubectl get pods -n {NAMESPACE} ``` All application pods should have a `Running` status. Completed job pods (such as `db-upgrade` or `pre-upgrade-backup`) should show `Completed`. If any pod shows `Pending`, `CrashLoopBackOff`, `Error`, or `ImagePullBackOff`, proceed to the next section to investigate further. --- ## Check Error with Specific Pod If a pod is not in a healthy state, inspect it with: ```bash kubectl describe pod {POD_NAME} -n {NAMESPACE} ``` Check the `Events` section at the bottom of the output for error messages. To view the pod logs: ```bash kubectl logs {POD_NAME} -n {NAMESPACE} ``` If the pod has multiple containers, specify the container: ```bash kubectl logs {POD_NAME} -n {NAMESPACE} -c {CONTAINER_NAME} ``` If the pod has already crashed, retrieve logs from the previous instance: ```bash kubectl logs {POD_NAME} -n {NAMESPACE} --previous ``` If a pod is stuck in `Init` state, check the init container logs: ```bash kubectl logs {POD_NAME} -n {NAMESPACE} -c {INIT_CONTAINER_NAME} ``` To list the init containers for a pod: ```bash kubectl describe pod {POD_NAME} -n {NAMESPACE} | grep -A5 "Init Containers:" ``` --- ## Make Sure Your Ingress is Provisioned and Has an Address ```bash kubectl get ingress -n {NAMESPACE} ``` The `ADDRESS` column should contain an IP address or hostname. If it is empty, your ingress controller may not be running or your cloud provider's load balancer has not finished provisioning. To investigate further: ```bash kubectl describe ingress {INGRESS_NAME} -n {NAMESPACE} ``` Check the `Events` section for any errors related to the ingress controller. --- ## Make Sure Your Certificate is Ready (cert-manager) ```bash kubectl get certificate -n {NAMESPACE} ``` The `READY` column should show `True`. If it shows `False`, pods that depend on the TLS secret may remain in a `Pending` or `ContainerCreating` state until the certificate is issued. Inspect the certificate for more detail: ```bash kubectl describe certificate {CERTIFICATE_NAME} -n {NAMESPACE} ``` Check the `Events` and `Status.Conditions` sections for error messages. You can also check the cert-manager logs directly for more detail: ```bash kubectl logs -n cert-manager -l app=cert-manager ``` --- ## Investigate PVC / PV Issues If a pod is stuck in `Pending` due to an unbound volume, check the status of all PersistentVolumeClaims in the namespace: ```bash kubectl get pvc -n {NAMESPACE} ``` All PVCs should show a `Bound` status. If a PVC shows `Pending`, it means Kubernetes has not been able to provision the underlying storage. Inspect the PVC for more detail: ```bash kubectl describe pvc {PVC_NAME} -n {NAMESPACE} ``` Check the `Events` section for errors such as no matching `StorageClass`, insufficient capacity, or a missing provisioner. If your cluster requires a specific storage class, ensure `storageClassName` is set correctly in your values or template files. :::note When using the built-in PostgreSQL database, the Kasm Helm chart creates a PersistentVolumeClaim that requires a default StorageClass (or an explicit `storageClassName` in your values). A missing or misconfigured StorageClass is a common cause of the database pod remaining in `Pending` state. ::: To list available storage classes in your cluster: ```bash kubectl get storageclass ``` --- ## Find Container Image Versions When troubleshooting, it is often useful to confirm the exact container image and version running in each pod: ```bash kubectl get pods -n {NAMESPACE} \ -o=custom-columns="NAME:.metadata.name,IMAGE:.spec.containers[*].image,IMAGE_ID:.status.containerStatuses[*].imageID" ``` This shows the image tag and the full image ID (including digest), which is helpful for verifying that the correct version is deployed. --- ## Run Commands Inside a Container To inspect configuration or debug issues inside a running pod, use `kubectl exec`. For example, to view the Kasm API application configuration: ```bash kubectl exec {POD_NAME} -n {NAMESPACE} -- cat /opt/kasm/current/conf/app/api/api.app.config.yaml ``` If the pod has multiple containers, specify the container with `-c`: ```bash kubectl exec {POD_NAME} -n {NAMESPACE} -c {CONTAINER_NAME} -- cat /opt/kasm/current/conf/app/api/api.app.config.yaml ``` You can also open an interactive shell for more in-depth debugging: ```bash kubectl exec -it {POD_NAME} -n {NAMESPACE} -- /bin/bash ``` --- ## General Kasm Troubleshooting For issues not specific to Kubernetes, see the [Kasm Troubleshooting guides](../troubleshooting). --- ## Reverse Proxies If running Kasm behind a reverse proxy such as NGINX, please consult the [Reverse Proxy Guide](../networking/reverse-proxy.mdx) The reverse proxy used, must support WebSockets, and the Zone configuration must also be updated accordingly. If users can access the Kasm Workspaces UI, but cannot connect to a session, then run through the [advanced connection troubleshooting](../workspaces-sessions/container-workspace/advanced-connection-troubleshooting.mdx) steps. If users are not able to access the Kasm Workspaces UI at all, the first step would be to ensure that Kasm Workspaces is accessible directly, without going through the reverse proxy. Next, ensure that from your reverse proxy you can `curl` Kasm Workspaces. ```bash curl -k https://:/api/__healthcheck {"ok": true} ``` Replace `` with the IP address of one of your Kasm WebApp servers and `` with the port that Kasm Workspaces is listening on, by default that is 443. Repeat this test for all WebApp servers and on all reverse proxies you have in front of Kasm Workspaces. If you are able to access Kasm Workspaces directly and you are able to curl Kasm Workspaces from the reverse proxy, but you still cannot load the UI at all when navigating to the domain-name or IP address of the reverse proxy, then consult the documentation of your reverse proxy. If you are using the [RDP local client workspace option](../workspaces-sessions/container-workspace/workspaces.mdx#servers), make sure the [**Restrict RDP Client IP Address**](../infra-autoscale/deployment-zones.mdx#defining-zone-configurations) setting is disabled in Infrastructure / Zones. If it isn't may not be able to connect, as the IP stored with the request will differ due to the connection being over a reverse proxy. If this is the case it will be reported in the Error Logs with a message such as "Invalid Request. Wrong client IP." ### RDP Session Disconnects Reverse proxies and load balancers have settings that will timeout requests after a failing to get a response from the upstream server in a period of time. This can result in Kasm desktop/app sessions disconnecting if the user is not actively using the session. Container based sessions send a keep-alive every 5 seconds, therefore, most container based sessions will be unaffected. This issue primarily affects sessions brokered by the Kasm RDP HTTPS Gateway. By default, RDP does not send a keep-alive, therefore, RDP connections being proxied can get disconnected if the user is inactive for a time longer than reverse proxies in the path allow. Kasm NGINX servers use a `proxy_send_timeout` and `proxy_read_timeout` value of 3600 seconds, or 1 hour. The default setting for both is 60 seconds for NGINX. RDP does support sending keep-alives, with a [registry setting](https://admx.help/?Category=Windows_10_2016&Policy=Microsoft.Policies.TerminalServer::TS_KEEP_ALIVE). Either all proxies in the path need to set a non-default `proxy_send_timeout` and `proxy_read_timeout` that is long enough to allow for normal inactivity during an RDP Session, or keep-alives needs to be enabled using the registry setting. The `proxy_send_timeout` and `proxy_read_timeout` are NGINX directives, if you are not using NGINX in front of Kasm, you will need to consult the documentation for the reverse proxy or load balancer you are using. Each vendor has different defaults and different terminology. For example, the Azure Application Gateway has a very short default value of 20 seconds for its `request time-out` setting. --- ## Server Tokens This article explains how to recognize service disruptions caused by auth token desync between Kasm components, as well as how to fix potential issues in a deployed system. ## Background Starting with version 1.18 of Kasm, a new token refresh workflow has been introduced to enhance security and simplify maintenance. Under normal conditions tokens automatically refresh without user intervention; however, some scenarios might prevent components from refreshing their tokens in time—such as extended maintenance windows or infrastructure powered down when not in use. Kasm settings include a grace period option that allows a limited time after token expiration for exchanging it with a new token. During this leeway period the expired token cannot authorize service calls; it can only be exchanged for a new token. When a token expires the client can re-establish trust with the Admin API by providing the same registration token used during the initial deployment. In a non-Kubernetes environment this registration token should be placed in a file named `registration_token.txt` which is automatically deleted after use. In contrast, in a Kubernetes deployment the registration token can be set as an environment variable from a Secret which allows the service to be fully self-healing. The following flowchart illustrates the component logic when refreshing a token. ![Client token refresh workflow](/img/troubleshooting/server_tokens/client_token_refresh_workflow.jpg) Note that in the case where the client does not have an existing token at all, the service will need to be redeployed as if it is a new component. ## Recognizing authentication token issues Administrators can determine whether Kasm services have lost authentication with the Admin API by looking either at the [Kasm administrative logs](../../reference/settings.mdx#logging) or by examining console output from the component in question. Some messages you might see when a component has an expired token include `The JWT token has expired` and `Expired JWT utilized on register_component`. The following screenshot shows a message indicating the RDP Proxy component of a single server installation has lost authentication: ![Admin logs with expired token](/img/troubleshooting/server_tokens/expired_token_logs.jpg) The following console output comes from that same RDP Proxy which was turned off long enough to miss the token refresh window: ```bash Jul 23 18:47:04 INFO (7/7) -- ReDemPtion 12.0.11 starting Jul 23 18:47:04 INFO (7/7) -- create_ip_dual_stack_server: binding socket 4 on [::]:3389 Jul 23 18:47:04 INFO (7/7) -- create_server: listening on socket 4 Jul 23 18:47:04 INFO (7/7) -- Reading font file /usr/local/share/rdpproxy/dejavu_14.rbf2 Jul 23 18:47:04 INFO (7/7) -- Font: version: 1 name: 'DejaVuSans,NotoSansCJK-Regular' size: 14 style: 1 max_ascent: 14 max_descent: 4 nbglyph: 59914 unicode_max = 195102 total_data: 1138296 2025-07-23 18:47:05,188 [INFO] __main__.handler: Refreshing auth token which expires 2025-07-23 18:45:47 2025-07-23 18:47:05,188 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 18:47:05,226 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 18:47:05,274 [ERROR] __main__.handler: Error from Kasm server for api: https://proxy:443/api/admin/refresh_token status: 403 error: No response 2025-07-23 18:47:05,275 [ERROR] __main__.handler: Failed to refresh auth token 2025-07-23 18:47:05,276 [INFO] __main__.handler: Registering rdp-gateway with configuration: {'target_component': {'type': 'connection_proxy', 'connection_proxy_type': 'RDP-GATEWAY', 'server_address': 'proxy', 'server_port': 443, 'zone_name': 'default', 'proxy_port': 3389, 'status': 'running', 'id': 'd7c9927661a948a692634a96cc323811'}, 'token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb25uZWN0aW9uX3Byb3h5X2lkIjoiZDdjOTkyNzYtNjFhOS00OGE2LTkyNjMtNGE5NmNjMzIzODExIiwiZXhwIjoxNzUzMjk2Mzc3LCJhdXRob3JpemF0aW9ucyI6WzkwXX0.oy9VFBn5ObL2POWD9oC4td5e09hLpsqTqnfR72GaxgOJV0-hmU-ftr4Mxk_Q3vSfWgvg6BVUM_y0raDkhGWYMwoZUwYDhVSgPgvwgXIwucaspLSwlsTT2FJjKQCZknv_MqO9Rk9iobksUWJJAuUWrDRlU8lMQbN_W3SZcc_n8szUMnFGBsgJXfADy0SlEtL9Cuni1tT5n3hh9Cr1zhwnW1ygIfaZuRKODz8wLy0Ev_a93Jm15Ryk2s6dUZwqM3u8RJOMrYKtLmQgcsljMQFmf4DEjMr3x96xk1dHYW975_A8JzgsMqaX6G3aU-vNr51T0BnPBQ8IL5zHqVCBouuGrQ'} 2025-07-23 18:47:05,277 [INFO] __main__.handler: Attempt 1 /10 attempts 2025-07-23 18:47:05,277 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 18:47:05,309 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 18:47:05,344 [ERROR] __main__.handler: Error from Kasm server for api: https://proxy:443/api/admin/register_component status: 200 error: The JWT token has expired. 2025-07-23 18:47:05,344 [WARNING] __main__.handler: Failed to register component on attempt: 1 2025-07-23 18:47:08,345 [INFO] __main__.handler: Attempt 2 /10 attempts 2025-07-23 18:47:08,346 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 18:47:08,377 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 18:47:08,418 [ERROR] __main__.handler: Error from Kasm server for api: https://proxy:443/api/admin/register_component status: 200 error: The JWT token has expired. 2025-07-23 18:47:08,420 [WARNING] __main__.handler: Failed to register component on attempt: 2 2025-07-23 18:47:08,420 [INFO] __main__.handler: Attempt 3 /10 attempts 2025-07-23 18:47:08,421 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 18:47:08,457 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 18:47:08,492 [ERROR] __main__.handler: Error from Kasm server for api: https://proxy:443/api/admin/register_component status: 200 error: The JWT token has expired. ``` ## Recovering a component When a component has an expired token it can be re-registered by placing a text file named `registration_token.txt` into the appropriate directory with contents of the current [Component Registration Token](../../reference/settings.mdx#authentication). Here is an example of what the text file should contain (trailing newlines are automatically ignored and should not cause issues): ``` MjAyNzk0MmUtZjQzMS00NDZlLWFkODMtOGU2OWVmMzk3MGQx ``` Each component uses a different named file to store configuration, but the `registration_token.txt` file MUST have that exact name, and then be placed alongside the correct config file. The following list shows standard config file paths for each component on the host machine (mounted into the service containers based on a standard single-server installation): * Agent: `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` * Guac: `/opt/kasm/current/conf/app/guac/kasmguac.app.config.yaml` * RDP Gateway: `/opt/kasm/current/conf/app/rdp_gateway/passthrough.app.config.yaml` * RDP HTTPS Gateway: `/opt/kasm/current/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml` * Windows Server: `C:\Program Files\Kasm\config.yaml` * Linux Server: `/etc/kasm-desktop-service/config.yaml` In this configuration, you would recover the RDP Gateway by creating the registration token file at `/opt/kasm/current/conf/app/rdp_gateway/registration_token.txt`. The service does not need to be restarted, as it should automatically detect this new file when it makes another attempt to refresh the expired token (typically within 30 seconds, based upon the default configured heartbeat interval). When the token is successfully refreshed, you will see the following output: ```bash 2025-07-23 20:09:26,773 [INFO] __main__.handler: Refreshing auth token which expires 2025-07-23 18:45:47 2025-07-23 20:09:26,774 [DEBUG] __main__.handler: Loaded registration token from /usr/local/etc/rdpproxy/conf/registration_token.txt 2025-07-23 20:09:26,775 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 20:09:26,809 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 20:09:26,886 [INFO] __main__.handler: New auth token expires 2025-07-23 20:11:27 2025-07-23 20:09:26,890 [DEBUG] __main__.handler: Saved configuration changes. 2025-07-23 20:09:26,891 [INFO] __main__.handler: Successfully removed registration token file at /usr/local/etc/rdpproxy/conf/registration_token.txt 2025-07-23 20:09:26,892 [INFO] __main__.handler: Registering rdp-gateway with configuration: {'target_component': {'type': 'connection_proxy', 'connection_proxy_type': 'RDP-GATEWAY', 'server_address': 'proxy', 'server_port': 443, 'zone_name': 'default', 'proxy_port': 3389, 'status': 'running', 'id': 'd7c9927661a948a692634a96cc323811'}, 'token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb25uZWN0aW9uX3Byb3h5X2lkIjoiZDdjOTkyNzYtNjFhOS00OGE2LTkyNjMtNGE5NmNjMzIzODExIiwiZXhwIjoxNzUzMzAxNDg2LCJhdXRob3JpemF0aW9ucyI6WzkwXX0.ZSflAx1_8At2DnJYtbHcClu2CUI4QveJK3h_zzwSIFyGT51BfB7WGiRqDVv_VBkcI4xGd9IHVCUJ4_SCoBIDGMlvjbpxfF7Em7immwqhRxIlyAyhHpjZpMNthLf-OuQJjgebzXjMA3hYlCNOUWK5PWRcR159UYJPVTzVCTTWBfm_QxoFejkgRXHXAYXHQEMBaXjFmBtTK3Hr0LDlkjJ_axKrraRWwyyhOTmmWcpIiiD06TYkDT3HB0UDbz21QEOG0Fw71L3HPb5VZYr4VYnW-Fhswr4pJ3VbILsPpmeOjyHuF1ReNpp35b1qW_vTQxYqggc4bH-zOqiG3W24hTgwTg'} 2025-07-23 20:09:26,892 [INFO] __main__.handler: Attempt 1 /10 attempts 2025-07-23 20:09:26,893 [INFO] __main__.handler: Current list of API servers (['proxy', 'dev-kasm']) 2025-07-23 20:09:26,923 [DEBUG] __main__.handler: Health check return: {'ok': True} 2025-07-23 20:09:27,006 [DEBUG] __main__.handler: Saved configuration changes. 2025-07-23 20:09:27,007 [INFO] __main__.handler: Component registration successful ``` The following lines (from the above snippet) show that the component utilized our registration token and then cleaned up automatically: ```bash ... 2025-07-23 20:09:26,774 [DEBUG] __main__.handler: Loaded registration token from /usr/local/etc/rdpproxy/conf/registration_token.txt ... 2025-07-23 20:09:26,891 [INFO] __main__.handler: Successfully removed registration token file at /usr/local/etc/rdpproxy/conf/registration_token.txt ``` Windows and Linux desktop agents may not automatically recover after creating the `registration_token.txt` file, so you may need to manually restart the service. --- ## Kasm Workspaces: Support Bundle # Support Bundle The Support Bundle page in Kasm Workspaces is used to generate a diagnostic archive that can be downloaded and shared for troubleshooting. The page includes bundle generation controls, a jobs table, lifecycle state tracking, and download handling for both small and large bundle files. ## What the Support Bundle page does Administrators can use the Support Bundle page to: - Generate a new support bundle. - Review existing support bundle jobs. - Track whether a bundle is queued, running, completed, or deleted. - Download completed bundles. - Delete bundles that are no longer needed. ![Support Bundle Generation](/img/troubleshooting/support_bundle/support_bundle_generate.webp) ## Generating a support bundle When creating a support bundle, the UI exposes three time-based options: - **Timeout**: How long the job should spend collecting data before it stops. - **Expiration**: How long the completed archive should remain available for download. These values are stored in minutes in the backend, while the UI allows entering them in minutes, hours, or days where appropriate. The contents of the support bundle will be stored in a password protected AES256 encrypted zip file. You may need to use a utility such as 7zip to decrypt the support bundle. The password for a support bundle is exposed as a copy action on the assocated support bundle element in the UI. The password will only become available once the system has finished processing the support bundle and it transitions to the **Completed** state. ## Job lifecycle Support bundle jobs can move through the following states: - **Queued**: The job has been requested but processing has not started yet. - **Running**: Collection or processing has started but the bundle is not complete. - **Completed**: The archive is ready to download. - **Deleted**: The bundle has been removed and is no longer available. The jobs table also tracks progress and expiration to make it clear whether a bundle is still active or available. ## Download behavior Completed bundles can be downloaded directly from the jobs table. Kasm chooses the safest download path based on browser capabilities and the size of the bundle returned by the API. - Small downloads can use the browser fallback download flow. - Large downloads are expected to stream directly to disk when supported by the browser. ## Large Downloads The Support Bundle page checks the `Content-Length` header returned by the download API before deciding which download path to use. - Downloads smaller than 1 GB can use the browser fallback download path. - Downloads 1 GB or larger require a secure browser context and support for the `showSaveFilePicker()` API. - If those requirements are not available, Kasm shows a warning instead of starting a large in-memory download. ### Requirements for large downloads To download large support bundles safely, the browser must provide both of the following: - A secure context, typically HTTPS. - Support for the `showSaveFilePicker()` API so the file can be streamed directly to disk. ![Support Bundle Download](/img/troubleshooting/support_bundle/support_bundle_download.webp) ### Expected user experience When the browser supports streamed downloads: 1. Select **Download** for a completed support bundle. 2. Choose a destination file in the browser save dialog. 3. The browser writes the archive directly to disk instead of buffering the entire file in memory. When the browser does not support streamed downloads and the archive is 1 GB or larger: 1. Select **Download** for a completed support bundle. 2. Kasm shows a warning notification explaining that a secure context and `showSaveFilePicker()` support are required. 3. Retry the download from a supported browser or environment. Large support bundle files should not be downloaded through a browser fallback path that buffers the full archive in memory. That approach can fail or degrade the browser for multi-gigabyte files. ## Troubleshooting If the large download warning is shown unexpectedly: - Confirm the site is loaded over HTTPS. - Check for a secure context. - Type `window.isSecureContext` in the browser console. - Check whether `window.showSaveFilePicker` is available. - Type `typeof window.showSaveFilePicker === "function"` in the browser console. - Some browsers, like Brave, have the functionality but disable it by default. Check your browser's documentation to see if the feature is available and how to enable it. - Retry in a browser that supports the File System Access API. ![Support Bundle](/img/troubleshooting/support_bundle/secure_context.webp) --- ## Kasm Workspaces: Configuration File Location Changes (v1.17.0+) Starting in Kasm Workspaces 1.17.0, the following configuration files have changed locations. | Old Location | New Location | | ------------ | ------------ | | `/opt/kasm/current/conf/app/agent.app.config.yaml` | `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` | | `/opt/kasm/current/conf/app/api.app.config.yaml` | `/opt/kasm/current/conf/app/api/api.app.config.yaml` | | `/opt/kasm/current/conf/app/kasmguac.app.config.yaml` | `/opt/kasm/current/conf/app/guac/kasmguac.app.config.yaml` | | `/opt/kasm/current/conf/app/passthrough.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_gateway/passthrough.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpproxy.ini` | `/opt/kasm/current/conf/app/rdp_gateway/rdpproxy.ini` | | `/opt/kasm/current/conf/app/rdp_https_gateway.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpgw.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdpgw.yaml` | --- ## Upgrade Legacy Helm Deployment to 1.1181.0 If you are using the legacy `kasm-single-zone` chart, follow the steps below to upgrade your Kasm Helm deployment to 1.1181.0. :::note You must upgrade to `1.1181.0` first before you can further upgrade to `1.1190.0`. ::: ### At a Glance: Upgrade Steps 1. [Backup your Kasm database](#1-backup-your-database-and-secrets) 2. [Update StatefulSet PVC Retention Policy](#2-update-statefulset-pvc-retention-policy) 3. [Delete your old Kasm Helm release](#3-delete-the-old-kasm-helm-release) 4. [Download the 1.1181.0 Helm Chart](#4-download-the-111810-helm-chart) 5. [Configure Helm Chart Values for Upgrade](#5-configure-helm-chart-values-for-upgrade) 6. [Install the 1.1181.0 release](#6-install-the-111810-release) 7. [Verify and log in](#7-verify-and-log-in) --- ### 1. Backup Your Database and Secrets - Deploy the [DB backup job template](https://raw.githubusercontent.com/kasmtech/kasm-helm/refs/heads/release/1.1190.0/examples/db-backup.yaml) to your Kasm namespace: ```bash kubectl apply -f db-backup.yaml -n {NAMESPACE} kubectl logs backup- -n {NAMESPACE} --follow ``` - **Sample output:** ``` kasm-old-db-backup-container Creating DB Backup... -rwxr-xr-x. 1 kasm kasm 1.8M Jul 23 18:26 /data/kasm-db-dump/kasm_dump.tar ``` - Backup secrets and store output securely: ```bash kubectl -n {NAMESPACE} get secrets/kasm-secrets --template='{{ range $key, $value := .data }}{{ printf "%s: %s\n" $key ($value | base64decode) }}{{ end }}' ``` - **Sample output:** ``` admin-password: xxx db-password: xxx manager-token: xxx redis-password: xxx service-token: xxx user-password: xxx ``` --- ### 2. Update StatefulSet PVC Retention Policy This ensures your Persistent Volumes are preserved when the Helm release is deleted. ```bash helm upgrade --no-hooks {RELEASE_NAME} {old-chart-path} -n {NAMESPACE} --reuse-values --set kasmApp.servicesToDeploy.db.persistentVolumeClaimRetentionPolicy.enabled=true --set kasmApp.servicesToDeploy.db.persistentVolumeClaimRetentionPolicy.whenDeleted=Retain ``` Replace the placeholders: 1. `{RELEASE_NAME}`: The name of your Kasm Helm release. Run `helm list -n {NAMESPACE}` if you are unsure. 2. `{NAMESPACE}`: The Kubernetes namespace where your Kasm deployment is running. 3. `{old-chart-path}`: The file path to your existing chart directory (for example: `/home/user/kasm-helm/kasm-single-zone`). Verify the retention policy has been updated: ```bash kubectl -n {NAMESPACE} get statefulset kasm-db-statefulset -o yaml | grep whenDeleted ``` Expected output (if you don't see this, the retention policy isn't applied correctly): ``` whenDeleted: Retain ``` --- ### 3. Delete the Old Kasm Helm Release :::warning This step will remove your Kasm deployment. However, because you updated the StatefulSet PVC retention policy in Step 2, your database and persistent volumes will be preserved. ::: ```bash helm uninstall {RELEASE_NAME} -n {NAMESPACE} --no-hooks ``` --- ### 4. Download the 1.1181.0 Helm Chart ```bash git clone https://github.com/kasmtech/kasm-helm.git cd kasm-helm git checkout release/1.18.1 ``` --- ### 5. Configure Helm Chart Values for Upgrade Refer to the [chart documentation](https://github.com/kasmtech/kasm-helm/tree/release/1.18.1/charts/kasm) to configure your `my-values.yaml` override file. For example: ```yaml publicAddr: "kasm.contoso.com" certificate: secretName: kasm-ingress-cert proxyService: type: ClusterIP ingress: enabled: true ``` Then add the following `dbManagement` section: ```yaml dbManagement: initialize: false upgrade: enable: true ``` :::note Leave other `dbManagement.upgrade` values as default unless you customised your PVC or DB backup file name. ::: --- ### 6. Install the 1.1181.0 Release ```bash helm install {RELEASE_NAME} ./charts/kasm -n {NAMESPACE} -f my-values.yaml ``` Notes: 1. The `{NAMESPACE}` must be the same namespace where your old chart and backup job was deployed. 2. Ensure you have already updated your `my-values.yaml` (see Step 5) before running the install. --- ### 7. Verify and Log In - Wait several minutes for all services to come online. - Access your Kasm environment using the `publicAddr` value you set. - For admin and user credentials, see the helm note via: ```bash helm get notes {RELEASE_NAME} -n {NAMESPACE} ``` --- ## Upgrade to 1.1190.0 To further upgrade to 1.1190.0, follow the [Upgrade Existing Helm Deployment](./upgrade_new_chart). --- ## Upgrade Troubleshooting See [Kubernetes Troubleshooting](../../troubleshooting/kubernetes) for assistance. --- ## Upgrade Existing Helm Deployment If you are using the `kasm` chart, follow the steps below to upgrade your Kasm Helm deployment. :::warning If you are currently on the legacy `kasm-single-zone` chart, you must first follow the steps in [Upgrade Legacy Helm Deployment](./upgrade_legacy_chart) to upgrade to the `kasm` chart at version `1.1181.0` before proceeding with this guide. ::: --- ## Upgrade Paths This guide covers the following upgrade paths: 1. **Older version → 1.1181.0** — Follow the [legacy upgrade guide](./upgrade_legacy_chart) to upgrade from the old `kasm-single-zone` chart to the `kasm` chart at version `1.1181.0`. 2. **1.1181.0 → 1.1190.0** — Follow the steps in this guide. 3. **`develop` branch → 1.1190.0** — If you installed the Helm chart from the `develop` branch (between the 1.18.1 and 1.19.0 releases), follow the same 1.1181.0 → 1.1190.0 steps in this guide. --- ## Upgrade from 1.1181.0 to 1.1190.0 ### At a Glance 1. [Retrieve your current values](#1-retrieve-your-current-values) 2. [Review field changes and migrate your values](#2-review-field-changes-and-migrate-your-values) 3. [Run the Helm upgrade](#3-run-the-helm-upgrade) 4. [Upgrade standalone PostgreSQL (if applicable)](#4-upgrade-standalone-postgresql-if-applicable) 5. [Verify the upgrade](#5-verify-the-upgrade) 6. [Kasm log in](#6-kasm-log-in) --- ### 1. Retrieve Your Current Values Before upgrading, export your current Helm values so you can migrate them to the new chart format. - **If you deployed using a custom `my-values.yaml`**, retrieve it with: ```bash helm get values {RELEASE_NAME} -n {NAMESPACE} ``` Replace the placeholders: - `{RELEASE_NAME}`: Your Kasm Helm release name. Run `helm list -n {NAMESPACE}` if you are unsure. - `{NAMESPACE}`: The namespace where your Kasm deployment is running. - **If you edited `values.yaml` directly**, you will need to diff your changes against the `1.1181.0` defaults to identify what you customised. Follow these steps: 1. Download the `1.1181.0` default values: ```bash curl -o default-values.yaml https://raw.githubusercontent.com/kasmtech/kasm-helm/release/1.18.1/charts/kasm/values.yaml ``` 2. Export your currently deployed values: ```bash helm -n {NAMESPACE} get values {RELEASE_NAME} --all -o yaml > current-values.yaml ``` 3. Compare the two files to identify your customisations. The recommended tool is [`dyff`](https://github.com/homeport/dyff#installation): ```bash dyff between default-values.yaml current-values.yaml ``` Apply the same customisations to the new `1.1190.0` `values.yaml`, taking into account the field changes described in [Step 2](#2-review-field-changes-and-migrate-your-values). --- ### 2. Review Field Changes and Migrate Your Values Version `1.1190.0` introduces several renamed, removed, and restructured fields. Review the tables below and update your `my-values.yaml` accordingly before running the upgrade. #### Fields Renamed | Old field (1.1181.0) | New field (1.1190.0) | Notes | |---|---|---| | `imagePullSecrets.server` + `imagePullSecrets.type` | `imagePullSecrets.registry` | Both old fields are merged into a single `registry` field | | `kasmZones[].upstream_auth_addr` | `kasmZones[].proxyAddress` | Renamed to better reflect its purpose | | `annotations` | `extraAnnotations` | The nested annotation sub-keys (`configMap`, `cron`, `deployment`, etc.) have moved under `extraAnnotations`; a new simple `annotations: {}` top-level key is now used for chart-wide annotations | #### Fields Removed | Removed field | Action required | |---|---| | `imagePullSecrets.type` | Merged into `imagePullSecrets.registry` — see above | | `imagePullSecrets.server` | Merged into `imagePullSecrets.registry` — see above | | `dbManagement.upgrade.oldDbBackupPvc` | Removed; no longer used. Remove from your values. | | `annotations.certSecret` (previously `extraAnnotations.certSecret`) | Use `certificate.certManager.annotations` instead | | `extraLabels.certSecret` | Use `certificate.certManager.labels` instead | #### Fields with Behaviour Changes | Field | Change | |---|---| | `database.hostname` | Previously used as the DB service name. Now empty by default and **only used when `database.standalone: true`**. Remove this value from your custom values if you are not using a standalone DB. | :::note Many new fields and features have been added in `1.1190.0`. Refer to the [chart documentation](https://github.com/kasmtech/kasm-helm/tree/release/1.1190.0/charts/kasm-helm) for the full list of available configuration options. ::: #### Configure Values for the DB Upgrade The upgrade chart will automatically back up your existing database, apply the schema migration, and upgrade Kasm. To enable this, add the following to your `my-values.yaml`: ```yaml dbManagement: initialize: false upgrade: enable: true oldDbHostname: "" backupStorageClass: "" oldDbSecretsName: "" oldDbBackupFileName: kasm_dump.tar ``` Replace the placeholders: 1. `oldDbSecretsName`: Leave empty (`""`) in nearly all cases — the chart will auto-resolve to `{RELEASE_NAME}-secrets`, which is the standard secret name created by 1.1181.0+ deployments. Only set this if you manually renamed the Kasm secrets object before upgrading; if so, the value MUST exactly match the in-cluster secret name. To check the current name, run: ```bash kubectl -n {NAMESPACE} get secret | grep secrets ``` 2. `oldDbHostname`: The database hostname from your previous Helm release. Only required if your old deployment used a non-default DB hostname (i.e. not `database.hostname=kasm-db`). Leave empty (`""`) if using a standalone DB, or if you did not change `database.hostname` from its default value of `kasm-db` in your previous deployment. If you are unsure, you can check your DB service name by running: ```bash kubectl -n {NAMESPACE} get service ``` 3. `backupStorageClass`: The storage class used to create the PersistentVolume for the backup PVC. Leave empty (`""`) to use the cluster default. 4. `oldDbBackupFileName`: Leave as `kasm_dump.tar`. --- ### 3. Run the Helm Upgrade Once your `my-values.yaml` is ready, run the upgrade: #### OCI Registry (Recommended) ```bash helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 --namespace {NAMESPACE} -f my-values.yaml ``` #### Classic Helm Repository ```bash helm repo add kasm https://helm.kasm.com helm repo update helm upgrade {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 --namespace {NAMESPACE} -f my-values.yaml ``` :::note Make sure you are using the same `{RELEASE_NAME}` as your previous installation. ::: This will: 1. Back up the existing database 2. Apply the schema migration 3. Upgrade the Kasm deployment You can monitor the backup job with: ```bash kubectl logs -n {NAMESPACE} -l app.kubernetes.io/component=pre-upgrade-backup ``` Expected backup job pod output when the backup completes successfully: ``` Starting backup to /data/kasm-db-dump/kasm_dump.tar Backup complete ``` --- ### 4. Upgrade Standalone PostgreSQL (if applicable) :::warning Only follow this section if you are using a standalone PostgreSQL database. If you are using the included database, skip to [Step 5](#5-verify-the-upgrade). ::: :::warning Do NOT upgrade your database until the backup job has finished. ::: 1. Run the Helm upgrade command from Step 4. 2. Wait until the `pre-upgrade-backup` job completes and all new pods are in the `Init` state: ```bash kubectl get pods -n {NAMESPACE} ``` 3. Once the backup is confirmed complete, upgrade your standalone PostgreSQL instance from version 14 to version 16. 4. The `db-upgrade` job will wait for PostgreSQL 16 to be detected before proceeding. You can monitor this with: ```bash kubectl -n {NAMESPACE} logs -l app.kubernetes.io/component=db-upgrade -c db-major-version-is-ready ``` You will see output like the following while it waits, then a confirmation once the upgrade is detected: ``` PostgreSQL 14.x detected (need 16.x) ... waiting ... PostgreSQL 14.x detected (need 16.x) ... waiting DB not reachable yet... waiting ... DB not reachable yet... waiting PostgreSQL 16.x detected (server_version_num=160012) ``` --- ### 5. Verify the Upgrade ```bash kubectl get pods -n {NAMESPACE} ``` Confirm all pods have a `Running` status (job pods should show `Completed`), then log in to the Kasm web interface to verify the upgrade completed successfully. ### 6. Kasm Log In - Add your ingress address to your DNS - Access your Kasm environment using the `publicAddr` value you set. - For admin and user credentials, see the helm note via: ```bash helm get notes {RELEASE_NAME} -n {NAMESPACE} ``` --- ## Rollback and Troubleshooting ### Failure during backup If the upgrade fails during the backup stage, roll back and clean up the incomplete jobs before retrying: ```bash helm rollback {RELEASE_NAME} -n {NAMESPACE} kubectl -n {NAMESPACE} delete jobs {RELEASE_NAME}-db-upgrade {RELEASE_NAME}-pre-upgrade-backup ``` After resolving the underlying issue, re-run the upgrade from [Step 3](#3-run-the-helm-upgrade). For additional troubleshooting assistance, see [Kubernetes Troubleshooting](../../troubleshooting/kubernetes). --- ## Upgrading Kasm Workspaces on Kubernetes # Upgrading Kasm on Kubernetes This guide walks you through safely **upgrading your Kasm deployment on Kubernetes**. --- ## Upgrade Scenarios | Scenario | Use This Section | |---|---| | Upgrade legacy `kasm-single-zone` chart 1.17.0 → 1.1181.0 | [Upgrade Legacy Helm Deployment to 1.1181.0](./upgrade_legacy_chart) | | Upgrade `kasm` chart 1.1181.0 → 1.1190.0 | [Upgrade Existing Helm Deployment](./upgrade_new_chart) | | Installed from `develop` branch (between 1.18.1 and 1.19.0) | [Upgrade Existing Helm Deployment](./upgrade_new_chart) | ### Assumptions - You have admin access to your Kubernetes cluster - `kubectl` and `helm` are installed and configured - You have backup and restore permissions --- ## Determine Your Current Chart Version To determine which Kasm Helm chart you are currently using, run the following command: ```bash helm list -n {NAMESPACE} ``` Interpret the output as follows: - **Legacy chart** (`kasm-single-zone`): The output contains: ```text NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION kasm kasm 1 xxx deployed kasm-single-zone-1.17.0-develop 1.17.0 ``` - **New chart** (`kasm`): The output contains: ```text NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION kasm kasm 1 xxx deployed kasm-1.1181.0 1.18.1 ``` --- ## Upgrade Troubleshooting See [Kubernetes Troubleshooting](../../troubleshooting/kubernetes) for assistance. --- ## Kasm Workspaces Multi-Server Upgrade Guide # Multi Server Upgrade For long-running systems: this release requires a minimum Docker version of v25.0.5. If necessary prior to Kasm upgrade, please upgrade Docker following their instructions for your distribution. A detailed explanation and instructions are available in [the Kasm support article](https://kasmweb.atlassian.net/servicedesk/customer/kb/view/418611248). When running any upgrade please ensure there are no active Kasm Workspaces sessions running. On large deployments this will likely require a maintenance window. While not required, making a backup using a VM snapshot or other method of the servers in the installation is recommended as a precaution to provide a recovery point if something goes wrong. Starting in 1.19.0, the default installation uses rolling images to deliver ongoing security fixes and updates. For static images with manual update control, pass in the `-f or --use-static-images` arguments during the installation or upgrade process. ```Bash sudo bash kasm_release/install.sh -f or sudo bash kasm_release/upgrade.sh -f ``` Refer to Rolling Image Management for more information about rolling images. | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] | :::caution Starting in Kasm Workspaces 1.17.0, the following configuration files changed locations. | Old location | New location | | ------------ | ------------ | | `/opt/kasm/current/conf/app/agent.app.config.yaml` | `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` | | `/opt/kasm/current/conf/app/api.app.config.yaml` | `/opt/kasm/current/conf/app/api/api.app.config.yaml` | | `/opt/kasm/current/conf/app/kasmguac.app.config.yaml` | `/opt/kasm/current/conf/app/guac/kasmguac.app.config.yaml` | | `/opt/kasm/current/conf/app/passthrough.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_gateway/passthrough.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpproxy.ini` | `/opt/kasm/current/conf/app/rdp_gateway/rdpproxy.ini` | | `/opt/kasm/current/conf/app/rdp_https_gateway.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpgw.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdpgw.yaml` | ::: ## Manually Please read through the entire process before getting started. Issues can be reported on the [Kasm Workspaces Issues Page](https://github.com/kasmtech/workspaces-issues/issues) **Component Registration Token** The **Component Registration Token** is used during the upgrade process to register new components that were not present on earlier versions of Kasm Workspaces. Login to the Workspaces UI as an administrator. Retrieve the value of **Component Registration Token** from the Global Settings. :::warning The Kasm Workspaces [[release]] upgrade optionally installs a new set of [default desktop and application images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx). Ensure 50 GB of free space is available on the Kasm server (or Agent role server for multi-server installations) before upgrading if you select the options to seed new images. ::: - Stop all Kasm Services on all Servers ```Bash sudo /opt/kasm/bin/stop ``` ### Upgrade Database Server Role Create a Database Backup - Ensure Kasm services are stopped on all hosts. Database corruption can occur if Kasm services are still connected to the database when it goes down. If the database is a standalone remote database refer here for backup instructions. [Backing up the PostgreSQL Server](../../tutorials/install/remote-database.mdx#backing-up-the-postgresql-server). ```Bash sudo /opt/kasm/bin/stop ``` - Execute the database backup utility If there is an existing `/opt/kasm/backups` directory, the permissions on this directory have changed in 1.18.0. Please run: ```bash sudo chown -R 70:70 /opt/kasm/backups ``` If the directory does not already exist, create the directory then adjust the permissions by running: ```bash sudo mkdir -p /opt/kasm/backups/ sudo chown -R 70:70 /opt/kasm/backups ``` ```bash sudo bash /opt/kasm/[[previous_release]]/bin/utils/db_backup -f /opt/kasm/backups/kasm_db_backup.tar -p /opt/kasm/[[previous_release]]/ ``` - Verify the presence and location of the database backup ```Bash sudo ls -al /opt/kasm/backups/kasm_db_backup.tar ``` - Remove the kasm_redis container ```Bash sudo docker container rm kasm_redis ``` - Download and extract the new installation media ```bash cd /tmp/ \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz ``` When performing an offline upgrade please ensure that versions of docker and docker compose that meet the updated system requirements have been downloaded and installed see [System Requirements](../../explanations/system-requirements.mdx) for details. - Get the existing database password for use in the subsequent commands. ```bash sudo grep " password" /opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml ``` **Perform a clean install** Perform a clean install of the Database Role Services If the database is a standalone remote database refer here for clean install instructions. [Initializing PostgreSQL Server](../../tutorials/install/remote-database.mdx#initializing-postgresql-server). - Install kasm from the release media downloaded in the prior steps. - When performing an offline update add these flags `--offline-workspaces --offline-service ` ```Bash sudo bash kasm_release/install.sh -S db -D -Q ``` ### Restore and upgrade the database Restore and update the database from the prior version - Ensure all Kasm services are stopped on all hosts If the database is a standalone remote database refer here for restoration instructions. [Restoring the PostgreSQL server from a backup](../../tutorials/install/remote-database.mdx#restoring-the-postgresql-server-from-a-backup). ```Bash sudo systemctl stop kasm ``` - Execute the database restore command ```bash sudo /opt/kasm/[[release]]/bin/utils/db_restore -f /opt/kasm/backups/kasm_db_backup.tar -p /opt/kasm/[[release]]/ ``` - Perform an upgrade of the database schema If the database is a standalone remote database refer here for upgrade instructions. [Standalone Remote Database](../../tutorials/install/remote-database.mdx). ```bash sudo /opt/kasm/[[release]]/bin/utils/db_upgrade -p /opt/kasm/[[release]] ``` - **Advanced**: Review the contents of the existing configs to ensure any custom docker settings are migrated to the new configuration. ```bash diff /opt/kasm/[[previous_release]]/docker/docker-compose.yaml /opt/kasm/[[release]]/docker/docker-compose.yaml ``` - (Optional) Install the Kasm [[release]] default images for the platform - With Kasm Workspaces 1.13.0 and newer the Kasm team recommends using the Workspaces Registry to install Workspaces rather than seeding the images during the installation. - Seeding workspaces is still needed when doing an offline Kasm installation as the official Kasm Workspaces Registry will be unavailable. - If doing an offline upgrade first extract the default image seed data from the workspace images tar. For x86 (amd64) platforms: ```bash tar xf --strip-components=1 -C /opt/kasm/[[release]]/conf/database/seed_data/ workspace_images/default_images_amd64.yaml ``` For ARM (arm64) platforms: ```bash tar xf --strip-components=1 -C /opt/kasm/[[release]]/conf/database/seed_data/ workspace_images/default_images_arm64.yaml ``` For x86 (amd64) platforms: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init -s /opt/kasm/[[release]]/conf/database/seed_data/default_images_amd64.yaml ``` For ARM (arm64) platforms: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init -s /opt/kasm/[[release]]/conf/database/seed_data/default_images_arm64.yaml ``` - Start the Kasm services ```Bash sudo systemctl start kasm ``` ### Upgrade Web App Server Role - Stop existing Kasm Services ```Bash sudo /opt/kasm/bin/stop ``` - Remove the kasm_share container ```Bash sudo docker container rm kasm_share ``` - Download and extract the new installation media ```Bash cd /tmp/ \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_*-latest.tar.gz ``` When performing an offline upgrade please ensure that versions of docker and docker compose that meet the updated system requirements have been downloaded and installed see [System Requirements](../../explanations/system-requirements.mdx) for details. - Install kasm from the release media downloaded in the prior steps. - When performing an offline update add this flag `--offline-service ` ```Bash sudo bash kasm_release/install.sh -S app -D -q -Q ``` - Copy **manager_id** and **server_hostname** from the old configuration into the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.server.server_hostname = load("/opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml").server.server_hostname' /opt/kasm/[[release]]/conf/app/api/api.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.manager.manager_id = load("/opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml").manager.manager_id' /opt/kasm/[[release]]/conf/app/api/api.app.config.yaml ``` - **Advanced**: Review the contents of the existing configs to ensure any custom docker settings are migrated to the new configuration. ```bash diff /opt/kasm/[[previous_release]]/docker/docker-compose.yaml /opt/kasm/[[release]]/docker/docker-compose.yaml ``` - Start the Kasm services ```Bash sudo systemctl start kasm ``` ### Upgrade Agent Server Role - Ensure all Kasm services are stopped ```Bash sudo /opt/kasm/bin/stop ``` - Get the existing manager token for use in the subsequent commands. ```bash sudo grep "token" /opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml ``` When performing an offline upgrade please ensure that versions of docker and docker compose that meet the updated system requirements have been downloaded and installed see [System Requirements](../../explanations/system-requirements.mdx) for details. - Install kasm. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -S agent -D -p -m -M ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -S agent -D -p -m -M ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -S agent -D -p -m -M --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -S agent -D -p -m -M --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -S agent -D -p -m -M --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -S agent -D -p -m -M --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz ``` - Copy the server_id and the public_hostname properties from the old agent to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.agent.server_id = load("/opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml").agent.server_id' /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.agent.public_hostname = load("/opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml").agent.public_hostname' /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml ``` - Copy the auto-generated nginx configs for any sessions that may exist on the Agent ```bash sudo cp /opt/kasm/[[previous_release]]/conf/nginx/containers.d/* /opt/kasm/[[release]]/conf/nginx/containers.d/ ``` - **Advanced**: Review the contents of the existing configs to ensure any custom docker settings are migrated to the new configuration. ```bash diff /opt/kasm/[[previous_release]]/docker/docker-compose.yaml /opt/kasm/[[release]]/docker/docker-compose.yaml diff /opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml ``` - Start the Kasm services ```Bash sudo systemctl start kasm ``` - Verify the Agent Service is properly checking into the Manager Service. Log into the UI as an Administrator. Select **Agents** and verify the Agent is listed with a **Last Reported** time of less than 1 minute. If the agent has not checked in, it likely can’t resolve or connect to \[AGENT_HOSTNAME\]:443 . Inspect the logs for details. ```bash sudo tail -f /opt/kasm/current/log/agent.log ``` ### (Optional) Install the Connection Proxy (Guac/rdp-gateway) Role(s) The Connection Proxy role is new in Workspaces 1.12.0. This service is used to connect to VM/Hardware running RDP, VNC, or SSH. If these capabilities are not needed, this role does not need to be installed. Login to the Workspaces UI as an administrator. Retrieve the value of **Component Registration Token** from the Global Settings. - Download and extract the new installation media ```bash cd /tmp/ \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_*-latest.tar.gz ``` - Install the Connection Proxy role from the release media downloaded in the prior steps. - When performing an offline update add these flags `--offline-workspaces --offline-service ` - Replace `` below with the **Component Registration Token** ```Bash sudo bash kasm_release/install.sh --role guac --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] -D ``` - Copy the id and the token properties from the old connection_proxy to the new - The *token* field of *kasmguac.app.config.yaml* has been renamed to *auth_token* in the Kasm Workspaces 1.13.0 release ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.kasmguac.id = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").kasmguac.id' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.public_jwt_cert = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").api.public_jwt_cert' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i 'del(.kasmguac.registration_token)' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml ``` - Copy the id and the auth_token properties from the old rdp_gateway to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/rdp_gateway/passthrough.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.id = load("/opt/kasm/[[previous_release]]/conf/app/rdp_gateway/passthrough.app.config.yaml").rdp-gateway.id' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml ``` - Copy the id and the auth_token properties from the old rdp_https_gateway to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.id = load("/opt/kasm/[[previous_release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml").rdp-gateway.id' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml ``` In Kasm Workspaces version 1.16.0 The Kasm RDP Gateway service was added, when upgrading from any Kasm Workspaces `version <= 1.15.0` to any Kasm Workspaces `version >= 1.16.0` please perform the below steps to register the new services: - Set the registration_token for the rdp_gateway using the **Component Registration Token** retrieved from the UI earlier. - Replace `` below with the **Component Registration Token** ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.registration_token = ""' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml ``` - Set the registration_token for the rdp_https_gateway using the **Component Registration Token** retrieved from the UI earlier. - Replace `` below with the **Component Registration Token** ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.registration_token = ""' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml ``` ```Bash sudo systemctl start kasm ``` ## Upgrade Script Since Kasm Workspaces version 1.11.0 an upgrade script is included with the installation package under kasm_release/upgrade.sh. Before starting the upgrade process please ensure that the Web App servers are stopped. If left running there is a chance for database corruption on the Webb App servers ```sudo sudo /opt/kasm/bin/stop ``` The upgrade script can be found in the installation package under kasm_release/upgrade.sh. These instructions assume there are 3 servers with the app, db, and agent roles. Login to the db server and execute: ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role db ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role db ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role db --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role db --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role db --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role db --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` Login to the agent server and execute: ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role agent ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role agent ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role agent --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role agent --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role agent --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role agent --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz ``` Login to the Web App server and execute: ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role app ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role app ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role app --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role app --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role app --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role app --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` Login to the connection proxy server and execute: The **Component Registration Token** can be obtained by viewing its field in the Kasm Workspaces Deployment's [Global Server Settings](../../reference/settings.mdx#authentication) ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role guac --registration-token [COMPONENT_REGISTRATION_TOKEN] --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` Login to the dedicated proxy server and execute: In this example we assume the proxy domain is proxy.example.com and the Web App hosting the API server is located at workspaces.example.com. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role proxy --api-hostname workspaces.kasmweb.com ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role proxy --api-hostname workspaces.kasmweb.com ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role proxy --api-hostname workspaces.kasmweb.com --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role proxy --api-hostname workspaces.kasmweb.com --offline-service /tmp/{{ amd_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --role proxy --api-hostname workspaces.kasmweb.com --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --role proxy --api-hostname workspaces.kasmweb.com --offline-service /tmp/{{ arm_service_images_url.split('/') | last }} ``` Here are the available helper flags for the upgrade.sh script: | Flag | Description | |:-------------------------------------|:----------------------------------------------------------------------------| | `-h` or `--help` | Display this help menu | | `-L` or `--proxy-port` | Default Proxy Listening Port | | `-s` or `--offline-service` | Path to the tar.gz service images offline installer | | `-x` or `--offline-network-plugin` | Path to the tar.gz plugin images offline installer | | `-S` or `--role` | Role to Upgrade: `[app|db|agent|remote_db|guac|proxy]` | | `-p` or `--public-hostname` | Agent/Component `` used to register with deployment. | | `-g` or `--database-master-user` | Database master username required for remote DB | | `-G` or `--database-master-password` | Database master password required for remote DB | | `-q` or `--db-hostname` | Database Hostname needed when upgrading agent and pulling images | | `-T` or `--db-port` | Database port needed when upgrading agent and pulling images (default 5432) | | `-Q` or `--db-password` | Database Password needed when upgrading agent and pulling images | | `-b` or `--no-check-disk` | Do not check disk space | | `-n` or `--api-hostname` | Set API server hostname | | `-A` or `--enable-lossless` | Enable lossless streaming option (1.12 and above) | | `-O` or `--use-rolling-images` | Use rolling Service images (deprecated) | | `-f` or `--use-static-images` | Use static Service images (1.19 and above) | | `-k` or `--registration-token` | Register a component with an existing deployment. | | `--skip-egress` | Do not install egress network plugin or dependencies | | `--ignore-dep-failures` | Continue installation even if optional dependencies fail to install | | `--offline-logger-plugin` | Path to the tar.gz logger plugin offline installer | | `--enable-epel` | Enable EPEL repo to install packages not in default RHEL repos | ### Automatic Upgrade Troubleshooting The upgrade.sh script creates a log file as it runs, this file is removed upon completion of a successful upgrade. However, if something does go wrong the logfile will be available from the directory the upgrade.sh script was executed from in the format `kasm_upgrade_${TIMESTAMP}.log`. This file will be important for diagnosing the error that caused the upgrade to fail and will be requested when submitting a support ticket with Kasm Technologies. # Update Custom Workspaces Each release, the Kasm Technologies team updates the default workspaces with new features and security updates. Old workspaces should be removed as they may not be compatible with new Kasm features. :::note Kasm Workspaces 1.13.0 and newer use a Workspaces Registry to install new Workspaces after an upgrade. When the administrator logs into Kasm Workspaces for the first time after the upgrade, Kasm offers to add the default Workspaces Registry if it is not already configured. Workspaces from prior releases may contain incompatible features and are not guaranteed to work. Kasm recommends that the administrator use the registry to add the latest compatible Workspaces for the installed version. ::: Kasm recommends rebuilding any custom Workspaces using the appropriately tagged Docker image (e.g : kasmweb/core-ubuntu-jammy:[[release]] ) see creating custom Kasm images for more information. See [Default and Custom Docker Images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx) for details. For existing Workspaces officially supported by Kasm, it is possible to edit the Workspace configuration and change the tag to the new version of Kasm Workspaces, this will preserve configuration and group settings that may already have been added. It will take a few minutes for the Kasm Agent to download the new Workspace during which time it will be unavailable. --- ## Kasm Workspaces: Single Server Upgrade Guide # Single Server Upgrade For long-running systems: this release requires a minimum Docker version of v25.0.5. If necessary prior to Kasm upgrade, please upgrade Docker following their instructions for your distribution. A detailed explanation and instructions are available in [the Kasm support article](https://kasmweb.atlassian.net/servicedesk/customer/kb/view/418611248). When running any upgrade please ensure there are no active Kasm Workspaces sessions running. On large deployments this will likely require a maintenance window. While not required, making a backup using a VM snapshot or other method of the server is recommended as a precaution to provide a recovery point if something goes wrong. Starting in 1.19.0, the default installation uses rolling images to deliver ongoing security fixes and updates. For static images with manual update control, pass in the `-f or --use-static-images` arguments during the installation or upgrade process. ```Bash sudo bash kasm_release/install.sh -f or sudo bash kasm_release/upgrade.sh -f ``` Refer to Rolling Image Management for more information about rolling images. | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] | :::caution Starting in Kasm Workspaces 1.17.0, the following configuration files changed locations. | Old location | New location | | ------------ | ------------ | | `/opt/kasm/current/conf/app/agent.app.config.yaml` | `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` | | `/opt/kasm/current/conf/app/api.app.config.yaml` | `/opt/kasm/current/conf/app/api/api.app.config.yaml` | | `/opt/kasm/current/conf/app/kasmguac.app.config.yaml` | `/opt/kasm/current/conf/app/guac/kasmguac.app.config.yaml` | | `/opt/kasm/current/conf/app/passthrough.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_gateway/passthrough.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpproxy.ini` | `/opt/kasm/current/conf/app/rdp_gateway/rdpproxy.ini` | | `/opt/kasm/current/conf/app/rdp_https_gateway.app.config.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml` | | `/opt/kasm/current/conf/app/rdpgw.yaml` | `/opt/kasm/current/conf/app/rdp_https_gateway/rdpgw.yaml` | ::: ## Automated Upgrade The automated upgrade script can be used to upgrade a previous installation to [[release]] . Administrators have several options to choose from when running the automated upgrade script: | Flag | Description | |:-------------------------------------|:----------------------------------------------------------------------------| | `-h` or `--help` | Display this help menu | | `-L` or `--proxy-port` | Default Proxy Listening Port | | `-s` or `--offline-service` | Path to the tar.gz service images offline installer | | `-x` or `--offline-network-plugin` | Path to the tar.gz plugin images offline installer | | `-S` or `--role` | Role to Upgrade: `[app|db|agent|remote_db|guac|proxy]` | | `-p` or `--public-hostname` | Agent/Component `` used to register with deployment. | | `-g` or `--database-master-user` | Database master username required for remote DB | | `-G` or `--database-master-password` | Database master password required for remote DB | | `-q` or `--db-hostname` | Database Hostname needed when upgrading agent and pulling images | | `-T` or `--db-port` | Database port needed when upgrading agent and pulling images (default 5432) | | `-Q` or `--db-password` | Database Password needed when upgrading agent and pulling images | | `-b` or `--no-check-disk` | Do not check disk space | | `-n` or `--api-hostname` | Set API server hostname | | `-A` or `--enable-lossless` | Enable lossless streaming option (1.12 and above) | | `-O` or `--use-rolling-images` | Use rolling Service images (deprecated) | | `-f` or `--use-static-images` | Use static Service images (1.19 and above) | | `-k` or `--registration-token` | Register a component with an existing deployment. | | `--skip-egress` | Do not install egress network plugin or dependencies | | `--ignore-dep-failures` | Continue installation even if optional dependencies fail to install | | `--offline-logger-plugin` | Path to the tar.gz logger plugin offline installer | | `--enable-epel` | Enable EPEL repo to install packages not in default RHEL repos | In this example `--proxy-port` is used. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --proxy-port 443 ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --proxy-port 443 ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --proxy-port 443 --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --proxy-port 443 --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/upgrade.sh --proxy-port 443 --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/upgrade.sh --use-static-images --proxy-port 443 --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz ``` ### Automatic Upgrade Troubleshooting The upgrade.sh script creates a log file as it runs, this file is removed upon completion of a successful upgrade. However, if something does go wrong the logfile will be available from the directory the upgrade.sh script was executed from in the format `kasm_upgrade_${TIMESTAMP}.log`. This file will be important for diagnosing the error that caused the upgrade to fail and will be requested when submitting a support ticket with Kasm Technologies. ## Manual Upgrade Kasm Tech recommends installing a separate instance of the application, migrating the data and performing a cutover of the application. Please read through the entire process before getting started. :::warning The Kasm Workspaces [[release]] upgrade optionally installs a new set of [default desktop and application images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx). Ensure 50 GB of free space is available on the Kasm server (or Agent role server for multi-server installations) before upgrading if you select the options to seed new images. ::: **Component Registration Token** The **Component Registration Token** is used during the upgrade process to register new components that were not present on earlier versions of Kasm Workspaces. Login to the Workspaces UI as an administrator. Retrieve the value of **Component Registration Token** from the Global Settings. **Create a Database Backup** Backup the existing Kasm database. This can be saved for later recovery, but will also be used to migrate existing data to the latest version. - Stop existing Kasm Services ```Bash sudo /opt/kasm/bin/stop ``` - Execute the database backup utility If there is an existing `/opt/kasm/backups` directory, the permissions on this directory have changed in 1.18.0. Please run: ```bash sudo chown -R 70:70 /opt/kasm/backups ``` If the directory does not already exist, create the directory then adjust the permissions by running: ```bash sudo mkdir -p /opt/kasm/backups/ sudo chown -R 70:70 /opt/kasm/backups ``` ```bash sudo bash /opt/kasm/[[previous_release]]/bin/utils/db_backup -f /opt/kasm/backups/kasm_db_backup.tar -p /opt/kasm/[[previous_release]]/ ``` - Verify the presence and location of the database backup ```Bash sudo ls -al /opt/kasm/backups/kasm_db_backup.tar ``` - Remove kasm_share and kasm_redis containers ```Bash sudo docker container rm kasm_share sudo docker container rm kasm_redis ``` When performing an offline upgrade please ensure that versions of docker and docker compose that meet the updated system requirements have been downloaded and installed see [System Requirements](../../explanations/system-requirements.mdx) for details. - Get the existing database password for use in the subsequent commands. ```bash sudo grep " password" /opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml ``` - Get the existing manager token for use in the subsequent commands. ```bash sudo grep "token" /opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml ``` ______________________________________________________________________ **Perform a clean install** ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -D -Q -M ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -D -Q -M ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -D -Q -M --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -D -Q -M --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh -D -Q -M --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images -D -Q -M --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz ``` **Modify Configs** - Copy the **server_id** and the **public_hostname** properties from the old agent to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.agent.server_id = load("/opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml").agent.server_id' /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.agent.public_hostname = load("/opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml").agent.public_hostname' /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml ``` - Copy **manager_id** and **server_hostname** from the old configuration into the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.server.server_hostname = load("/opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml").server.server_hostname' /opt/kasm/[[release]]/conf/app/api/api.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.manager.manager_id = load("/opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml").manager.manager_id' /opt/kasm/[[release]]/conf/app/api/api.app.config.yaml ``` - Copy the auto-generated nginx configs for any sessions that may exist on the Agent ```bash sudo cp /opt/kasm/[[previous_release]]/conf/nginx/containers.d/* /opt/kasm/[[release]]/conf/nginx/containers.d/ ``` - Copy the id and the token properties from the old connection_proxy to the new - The *token* field of *kasmguac.app.config.yaml* has been renamed to *auth_token* in the Kasm Workspaces 1.13.0 release ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.kasmguac.id = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").kasmguac.id' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.public_jwt_cert = load("/opt/kasm/[[previous_release]]/conf/app/guac/kasmguac.app.config.yaml").api.public_jwt_cert' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i 'del(.kasmguac.registration_token)' /opt/kasm/[[release]]/conf/app/guac/kasmguac.app.config.yaml ``` - Copy the id and the auth_token properties from the old rdp_gateway to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/rdp_gateway/passthrough.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.id = load("/opt/kasm/[[previous_release]]/conf/app/rdp_gateway/passthrough.app.config.yaml").rdp-gateway.id' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml ``` - Copy the id and the auth_token properties from the old rdp_https_gateway to the new ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.api.auth_token = load("/opt/kasm/[[previous_release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml").api.auth_token' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.id = load("/opt/kasm/[[previous_release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml").rdp-gateway.id' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml ``` In Kasm Workspaces version 1.16.0 The Kasm RDP Gateway service was added, when upgrading from any Kasm Workspaces `version <= 1.15.0` to any Kasm Workspaces `version >= 1.16.0` please perform the below steps to register the new services: - Set the registration_token for the rdp_gateway using the **Component Registration Token** retrieved from the UI earlier. - Replace `` below with the **Component Registration Token** ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.registration_token = ""' /opt/kasm/[[release]]/conf/app/rdp_gateway/passthrough.app.config.yaml ``` - Set the registration_token for the rdp_https_gateway using the **Component Registration Token** retrieved from the UI earlier. - Replace `` below with the **Component Registration Token** ```bash sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.rdp-gateway.registration_token = ""' /opt/kasm/[[release]]/conf/app/rdp_https_gateway/rdp_https_gateway.app.config.yaml ``` ______________________________________________________________________ **Restoring the Database.** Restore and update the database from the prior version - Ensure all Kasm services are stopped ```Bash sudo systemctl stop kasm ``` - Execute the database restore command ```bash sudo /opt/kasm/[[release]]/bin/utils/db_restore -f /opt/kasm/backups/kasm_db_backup.tar -p /opt/kasm/[[release]] ``` - Perform an upgrade of the database schema ```bash sudo /opt/kasm/[[release]]/bin/utils/db_upgrade -p /opt/kasm/[[release]] ``` - (Optional) Install the Kasm [[release]] default images for the platform - With Kasm Workspaces 1.13.0 and newer the Kasm team recommends using the Workspaces Registry to install Workspaces rather than seeding the images during the installation. - Seeding workspaces is still needed when doing an offline Kasm installation as the official Kasm Workspaces Registry will be unavailable. - If doing an offline upgrade first extract the default image seed data from the workspace images tar. For x86 (amd64) platforms: ```bash tar xf --strip-components=1 -C /opt/kasm/[[release]]/conf/database/seed_data/ workspace_images/default_images_amd64.yaml ``` For ARM (arm64) platforms: ```bash tar xf --strip-components=1 -C /opt/kasm/[[release]]/conf/database/seed_data/ workspace_images/default_images_arm64.yaml ``` For x86 (amd64) platforms: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init -s /opt/kasm/[[release]]/conf/database/seed_data/default_images_amd64.yaml ``` For ARM (arm64) platforms: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init -s /opt/kasm/[[release]]/conf/database/seed_data/default_images_arm64.yaml ``` - Start the Kasm services ```Bash sudo systemctl start kasm ``` ______________________________________________________________________ **Add Connection Proxy Settings to Database** When upgrading from a `version <= 1.11.0` to `>= 1.12.0` add connection proxy settings to the database: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init -s /opt/kasm/[[release]]/conf/database/seed_data/default_connection_proxies.yaml ``` - Start the Kasm services ```Bash sudo systemctl start kasm ``` # Update Custom Workspaces Each release, the Kasm Technologies team updates the default workspaces with new features and security updates. Old workspaces should be removed as they may not be compatible with new Kasm features. :::note Kasm Workspaces 1.13.0 and newer use a Workspaces Registry to install new Workspaces after an upgrade. When the administrator logs into Kasm Workspaces for the first time after the upgrade, Kasm offers to add the default Workspaces Registry if it is not already configured. Workspaces from prior releases may contain incompatible features and are not guaranteed to work. Kasm recommends that the administrator use the registry to add the latest compatible Workspaces for the installed version. ::: Kasm recommends rebuilding any custom Workspaces using the appropriately tagged Docker image (e.g : kasmweb/core-ubuntu-jammy:[[release]] ) see creating custom Kasm images for more information. See [Default and Custom Docker Images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx) for details. For existing Workspaces officially supported by Kasm, it is possible to edit the Workspace configuration and change the tag to the new version of Kasm Workspaces, this will preserve configuration and group settings that may already have been added. It will take a few minutes for the Kasm Agent to download the new Workspace during which time it will be unavailable. --- ## Configuring Workspace Banners # Banners This feature provides an overt banner on workspaces to enable administrators to make it easy for users to identity "where they are" or "what workspace" they are in and to also give administrators the ability to enforce things like classification banners. We have tried to make it as flexible as possible and allow administrators to define how they want the banners to look, as well as whether to display text at the top, bottom or both (if the border size of the top or bottom are greater than 0 then text will be displayed). ![Session Banners](/img/banners/session-banner.webp) To use a banner, you need to create one first, this can be done from Settings / Banners. ![Banners List](/img/banners/banners.webp) Creating or editing a banner opens up a visual editor so you can get an idea of how it will look. ![Editing a Banner](/img/banners/banner-edit.webp) The boxes around the outside allow you to set the border width exactly for each side. If the top or bottom borders are greater than 0 then the text from the text section will be displayed in these areas. If the left and right sides are greater than 0 then it will just display a border for those. ## Border | Property | Description | | --- | --- | | Name | The name of the banner, this is used when selecting a banner on workspaces and group settings | | Border Color | This opens a color picker to select the border color, hex values can be entered by clicking on the arrows next to the RGB value. | | Text Color | This opens a color picker to select the text color, hex values can be entered by clicking on the arrows next to the RGB value. | | Font Size | The size of the text in pixels | | Font Weight | An integer for the html font weight, valid values are 100 through 900 in 100 increments, where 100 is the thinnest and 900 the thickest. | ## Text ![Banner Text](/img/banners/banner-text.webp) This is the text to display in the top (and/or bottom) border. There are some built in variables that are displayed under the textarea, clicking on one will insert it onto the end of the current text. | Property | Description | | --- | --- | | `{user_id}` | This is the currently logged in users unique UUID. | | `{username}` | This is the currently logged in users username. | | `{image_name}` | This is the workspace's display name. **Chromium** for example. | | `{image_id}` | The workspace's UUID | | `{kasm_id}` | This is the UUID that identifies the specific session. | | `{egress_provider_name}` | This is the name of the egress provider being used in the session (if any) for example, **PureVPN** | | `{egress_gateway_name}` | This is the name of the specific gateway being used (if any), for example **US-ATLANTA-16158** | | `{egress_gateway_country}` | This is the name of the country egress is being routed through, it's usually the country's 2 character code, such as **US** or **CA** but is whatever is set in the country field for the gateway. | | `{egress_gateway_city}` | This is the name of the city egress is being routed through, such as **New York** | | `{zone_name}` | The name of the zone being used, for example **default**. | ## Settings | Property | Description | | --- | --- | | Allow close | This allows end users to close the banner. Closing the banner is remembered for the life of the session. | | Allow edit | This Allows an end user to change what information is displayed in the banner by clicking on the text. There is also an option to reset it back to the default, the text they choose is also remembered for the life of the session. | ## Group setting Banners can be added to groups by adding a group setting. To do this go to the group you want to add a banner to (or create one), then go to Settings and click on the Add Settings button. Enter **session_banner** into the setting name and select the name of the banner you wish to apply. ![Group Setting](/img/banners/banner-group-setting.webp) ## Workspace setting Workspace settings take precedence over group settings. The option is under the **Other Options** category and by default is set to **Inherit** this means if there is a banner set on a group it will be applied, if not it won't. The other available options are **Force Disabled** which will ensure a banner isn't displayed, or selecting a specific banner from the options. ![Group Setting](/img/banners/banner-workspace.webp) --- ## Advanced Connection Troubleshooting # Connectivity Troubleshooting When deploying Kasm at scale in enterprise type settings, with advanced L7 firewalls, proxies, and other security devices in the path, there is no end to the possible combinations of configurations and devices at play. Therefore, an advanced guide is needed to assist engineers in finding potential problems within their environment that may be keeping Kasm from working properly. When troubleshooting this issue, always test by creating new sessions after making changes. Resuming a session may not have the changes applied. This section assumes that users are able to get to the Kasm Workspaces application and login. Users are able to create a session and Kasm does provision a container or VM session for the user. The user would typically see the following connecting screen which may loop, the screenshot below is shown with Chrome Developer Tools open. ![Session hangs at requesting Kasm](/img/troubleshooting/advanced_connectivity/requesting_kasm_devtools.webp) ### Browser Extensions As a first step, open a new Incognito Window, ensure no other Incognito Windows are open before opening a new one. This will ensure that browser extensions are disabled. It will also ensure [cookie collisions](#cookie-conflict) do not occur. Ensure to use the Incognito Window for all further testing as you progress through the following sections. If the problem goes away immediately when using an Incognito Window, try a normal window but disable all browser extensions. Enable them one at a time until the issue appears again. If you cannot load a session with all browser extensions disabled, but you can load a session in an Incognito Window, then it is likely a cookie issue. Follow the troubleshooting steps in the [Validating Session Cookies](#validate-session-cookies), [Cookie Conflict](#cookie-conflict), and [Cookie Transit](#cookie-transit) sections. ### Validate Session Port Here is an expanded view of the above example with the Url field extended. In this below example, the port going to the KasmVNC session is on 8443 while the Kasm Web application seems to be on port 443. This is likely a misconfiguration. Many organizations will configure Kasm Workspaces to run on a high port number internally, but then proxy to the internet on port 443. This is very common in the DoD and Federal sector where DISA STIGs disallow the use of privileged low port numbers on internal servers. ![Session hangs at requesting Kasm](/img/troubleshooting/advanced_connectivity/devtools_wrong_port.webp) What typically occurs is that Kasm Workspaces is installed internally on a high port number. When accessing Kasm directly on the high port number, it works fine. When accessing Kasm externally through a proxy on port 443, Kasm sessions fail to load. The setting that applies here is the [Zone](../../infra-autoscale/deployment-zones.mdx#configuring-deployment-zones) proxy port setting. This port setting is relative to the client. So if Kasm has been configured to internally be running on 8443, but it is proxied by an F5, for example, on port 443, the Zone setting `Proxy Port` should be set to port 443. After changing the setting, you will need to destroy any existing sessions. Newly created sessions will pick up the new port change. ### Validate Session Cookies While standard API calls use tokens in the JSON body of the request, requests to KasmVNC use two cookies that authorize the connection. The cookies are validated at each hop in the path to the users container. KasmVNC itself does not check the cookies, instead, the last NGINX server in the path injects a HTTP Authorization header with a unique token. The client never has access to or knowledge of this token. Further sections will walk through validating this process, this section will focus on ensuring the cookies are present and confirming they are making it all the way to the last hop. ![Session hangs at requesting Kasm](/img/troubleshooting/advanced_connectivity/devtools_cookies_present.webp) Using the above screenshot as an example, find the request to load vnc.html and select the request. On the Cookies sub tab for the request, ensure the checkbox `show filtered out request cookies` is unchecked. The username and session_token cookies are the ones that are required by Kasm. Ensure there is only one of each. If the username or session_token cookie is missing, check the `show filtered out request cookies` to see if the cookie is there but being blocked by your browser. See the sub section [Browser Blocking Cookies](advanced-connection-troubleshooting.mdx#browser-blocking-cookies) for troubleshooting this issue. If there are multiple usernames or multiple session_token cookies, see the [Cookie Conflict](advanced-connection-troubleshooting.mdx#cookie-conflict) section. If both cookies are present and there is only one of each, continue on to the [Cookie Transit](advanced-connection-troubleshooting.mdx#cookie-transit) subsection. #### Cookie Conflict If you have Kasm Workspaces deployed with a subdomain on your company's primary domain name, such as kasm.apps.acme.com, you may see a very long list of cookies. This is because your company may have hundreds of other websites under the apps.acme.com domain name and these applications may be configured [insecurely](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#security) by allowing their cookies to be sent to all applications under acme.com. This can cause many issues, the first issue is that app.acme.com may have a username or session_token cookie as well, causing overlapping cookies. To fix this, the offending application(s) needs to be identified. Ensure the domain field of cookies for the offending application is made more specific so that they are not applied to all hostnames under the same domain. Another issue that can occur is that other applications on your domain may not be following the [specification](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes) for cookies. Kasm Technologies has identified multiple instances where other applications on a corporate domain are both inappropriately setting the domain field on the cookie and setting cookies with invalid characters in the name. Unfortunately browsers have sided with being more amendable to servers not meeting the specifications and as a result these invalid cookies are sent to all web applications on the corporate domain. Not all web servers will be as willing to handle invalid cookies as some browsers. The Kasm API service will stop processing cookies on a request once an invalid cookie is hit. Fortunately, as of Kasm Workspaces 1.14.0, Kasm blocks all cookies at the NGINX container, which do not match any of the names of cookies that Kasm sets. As stated earlier, KasmVNC does not utilize cookies, but the NGINX proxy sitting in front of user containers uses the cookies to authorize the incoming request and places a session token in a header for KasmVNC. While KasmVNC does not use cookies, it is limited in the total length of any header, to include the cookies header. As of Kasm Workspaces 1.14.0, the cookies header is modified by NGINX. All cookies that are not relevant to KasmVNC are dropped. In conclusion, if you see a lot of cookies being sent, ensure you are on Kasm Workspaces 1.14.0, this will fix most issues, but it will not fix cookie conflicts. If you see multiple cookies with the name username or session_token, follow the above guidance. #### Browser Blocking Cookies Browsers can block cookies for a number of reasons. Browser extensions and security software can block cookies for any number of reasons. A good place to start would be the Console tab within DevTools. If the browser itself is blocking the cookies, it will usually list the reason. Common reasons for the browser itself to block the cookie would include [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) security mechanisms. If Console tab output indicates CORS issues, ensure you are on the latest release of Kasm Workspaces. Kasm Workspaces 1.14.0 included better handing of CORS issues for common architectures. CORS issues can come into play when Kasm Workspaces is setup with multiple Zones, with each zone in a different region. Each zone will have a different domain name. When a user navigates to the main site, such as kasm.acme.com, all requests go to the primary region's API servers. When a user creates a session, the iframe for KasmVNC or RDP session will go to the region specific hostname, such as us-east.kasm.acme.com. It is important that all zone domain names are sub domains of the primary site, otherwise you will run into CORS issues. Do not, for example, make the primary application domain kasm.acme.com and a zone domain us-east.acme.com. Ensure that zone domain names are sub domains of the primary Kasm Workspaces domain name. #### Cookie Transit After you have confirmed that the required cookies are present and being sent by the browser, it is time to confirm the cookies are making it all the way to Kasm. Enterprises with complex architectures may have multiple security or proxy devices in the path, which can interfere with the transmission of cookies and other HTTP headers. The following guidance assumes you have a multi-server deployment. If you are on a single server deployment, you may skip some parts that are not applicable. We need to trace the request at each hop to ensure the cookie is received at all hops. First create a session and do not destroy it. Go to the admin page in Kasm and navigate to the sessions panel. Find your session and make note of which agent the session is on. We will need to tail logs on all API servers and the agent server that your session is on. Load balancers will typically spread requests across all WebApp servers making troubleshooting more difficult. For the purposes of this demonstration, I have configured my front-end load balancer to send all requests to a single Kasm API (WebApp) server, however, you could also just repeat these steps on all API servers and tail the logs on all of them at once. SSH to the each API server and Agent and modify the NGINX configuration. ```yml # Modify the NGINX logging to include the session token sudo sed -i "s#cookie_username\",'#cookie_username\",'\n '\"cookie_session_token\": \"\$cookie_session_token\",'#" /opt/kasm/current/conf/nginx/logging.conf # Reload nginx sudo docker exec -it kasm_proxy nginx -s reload # You may get warnings in the output depending on your configuration, ensure no errors are present # Tail the NGINX logs to find requests to load vnc.html. # You can filter further by piping the results to another grep and looking for your username. sudo tail -f /opt/kasm/current/log/nginx/access_json.log | grep -P 'request":"GET \S+?vnc\.html' ``` Here is an example log. ```json {"upstream_response_length": "6318","body_bytes_sent": "6318","server_addr": "172.18.0.9","server_port": "443","request_method": "GET","http_referer": "https://139.243.62.99/","http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","http_x_forwarded_for": "","http_x_header": "","nginx_version": "1.25.1","server_protocol": "HTTP/1.1","request":"GET /desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/vnc.html?video_quality=2&enable_webp=false&idle_disconnect=20&password=&autoconnect=1&path=desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/websockify&cursor=true&resize=remote&clipboard_up=true&clipboard_down=true&clipboard_seamless=true&toggle_control_panel=null HTTP/1.1","request_length": "1336","request_time": "0.025","upstream_response_time": "0.021","request_host":"139.243.62.99","server_name": "ubuntu-base","remote_addr": "119.15.5.44","realip_remote_addr": "119.15.5.44","http_status": "200","time_local":"17/Nov/2023:15:03:26 +0000","time_iso8601":"2023-11-17T15:03:26+00:00","msec":"1700233406.024","upstream_addr": "172.18.0.9:443","upstream_connect_time": "0.001","upstream_response_time": "0.021","upstream_status": "200","uri": "/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/vnc.html","query_string": "video_quality=2&enable_webp=false&idle_disconnect=20&password=&autoconnect=1&path=desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/websockify&cursor=true&resize=remote&clipboard_up=true&clipboard_down=true&clipboard_seamless=true&toggle_control_panel=null","remote_user": "","cookie_username": "\"matt@kasm.local\"","cookie_session_token": "b5175662-a9ad-41e0-b3b3-69f3cc4fa5bd","upstream_header_time": "0.020"} ``` Ensure that the `cookie_username` and `cookie_session_token` fields are in the JSON and contain valid values. The following is an example log where the cookie values are not present. When the cookies are not present or otherwise not valid, you will notice that there is no upstream_status, this is because NGINX never proxied the request, because the request authorization failed. ```json {"upstream_response_length": "","body_bytes_sent": "177","server_addr": "172.18.0.9","server_port": "443","request_method": "GET","http_referer": "https://139.243.62.99/","http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","http_x_forwarded_for": "","http_x_header": "","nginx_version": "1.25.1","server_protocol": "HTTP/1.1","request":"GET /desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/vnc.html?video_quality=2&enable_webp=false&idle_disconnect=20&password=&autoconnect=1&path=desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/websockify&cursor=true&resize=remote&clipboard_up=true&clipboard_down=true&clipboard_seamless=true&toggle_control_panel=null HTTP/1.1","request_length": "870","request_time": "0.003","upstream_response_time": "","request_host":"139.243.62.99","server_name": "ubuntu-base","remote_addr": "119.15.5.44","realip_remote_addr": "119.15.5.44","http_status": "403","time_local":"17/Nov/2023:15:09:37 +0000","time_iso8601":"2023-11-17T15:09:37+00:00","msec":"1700233777.141","upstream_addr": "","upstream_connect_time": "","upstream_response_time": "","upstream_status": "","uri": "/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/vnc.html","query_string": "video_quality=2&enable_webp=false&idle_disconnect=20&password=&autoconnect=1&path=desktop/3f712ec4-c6c5-49c9-a74b-eb3ba2939eab/vnc/websockify&cursor=true&resize=remote&clipboard_up=true&clipboard_down=true&clipboard_seamless=true&toggle_control_panel=null","remote_user": "","cookie_username": "","cookie_session_token": "","upstream_header_time": ""} ``` Ensure this test passes on all API servers and the agent server the session's container is on. If the session_token or username values are empty in the logs of any API server, then something between the user's browser and the Kasm WebApp server, not including the WebApp server itself, is interfering. This can include the user's own systems as security software installed on the client's system can intercept communications, either in transit or as a browser extension. Devices between the client and the Kasm WebApp server can also interfere with HTTP headers, such as the cookie header. Inspect the logs of any security or proxy devices in the network path to ensure the cookies are not being blocked. If possible, output the cookies within the logs of each device, as we did for NGINX, to see if each device in the path is receiving the logs. If you saw the request come into the API server, and the cookies were present with valid values, but the request was denied with a 403 in the `http_status` field, then proceed to the [Validate Session Authorization](advanced-connection-troubleshooting.mdx#validate-session-authorization) section. Also proceed to the Validate Session Authorization section if you saw the request come in at the Agent server but it returned any status code other than a 200 series. If you saw the request come into the API server, and the cookies were present with valid values, but the request returned a 502 or 504, there is likely a connectivity issue to the agent. Use curl to check the health of each agent from each of the API servers. ```bash curl -k https://:443/agent/__healthcheck {"ok": true} ``` If all the API servers can talk to the agent, then proceed to the [Validate Session Authorization](advanced-connection-troubleshooting.mdx#validate-session-authorization) section. ### Validate Session Authorization When a user's request travels to their session container, it traverses a WebApp server's nginx container, it then travels to the agent server that the container is on and traverses an nginx container and finally the user's container. On both servers, the NGINX container makes an API call to the kasm_api container. For the WebApp server this kasm_api container resides on the same server as nginx and in the same docker network. The WebApp server's NGINX container makes a call to /api/kasm_connect to retrieve the details of where to forward the request. In a distributed architecture, the agent can be anywhere and be privately addressed. The client does not have the IP address or hostname of the agent, nor does the user's HTTP request contain this information. NGINX calls the kasm_connect API to retrieve the required information. Run the following command to check that the API container is getting the request and that it returns a 202 status code. ```bash sudo docker logs -f --tail 10 kasm_api 2>&1 | grep /api/kasm_connect 2023-11-17 18:31:01,529 [INFO] cherrypy.access.140087972390848: 172.18.0.9 - - [17/Nov/2023:18:31:01] "GET /api/kasm_connect/ HTTP/1.0" 202 - "https://kasm.example.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" ``` In the above example the /api/kasm_connect API call was received and a status code 202 was returned, indicating it should have been successful. Ensure that the target agent is reachable from each API server. NGINX receives the same IP/hostname that is shown in the Kasm Admin UI under Infrastructure -> Docker Agents. So ensure you use the address listed there in the curl example below to ensure the API server can reach the agent in question. ```bash curl -k https://:443/agent/__healthcheck {"ok": true} ``` The Agent server will send API calls to the Kasm WebApp server to authorize the incoming request. This can sometimes cause issues in complex environments. First, check your deployments configuration, go to the Kasm Admin UI and navigate to Infrastructure, Zones, and edit the applicable Zone. In the Zone settings is the `Upstream Auth Address`. For a multi-server deployment the default value is `$request_host$` which is a Kasm variable that gets replaced at runtime with the hostname of the incoming request. Lets walk through the following example. Client --> Load Balancer (kasm.example.com) --> Layer 7 Firewall --> Kasm WebApp Servers --> Agent A client connects to Kasm at https://kasm.example.com, the load balancer then forwards that to one of 4 Kasm WebApp servers, which then forward that request to the agent that the user's container is on. When the agent receives the request, it needs to authorize the request. With default Zone settings on a multi-server deployment, it will send that API call to https://kasm.example.com/api/internal_auth. This is a ok default behavior that works for many deployments, however, in this example the domain name kasm.example.com does not point directly to the WebApp servers, it is for a public load balancer that is in a DMZ some where else in the enterprise. The Kasm agents may not have access to send API calls there, or the calls might be subject to a forward proxy with SSL inspection. To validate whether your agent can access the API servers through this default setting, run the following command. ```yml # success curl -k https://kasm.example.com/api/__healthcheck {"ok": true} # name resolution fails curl -k https://kasm.example.com/api/__healthcheck curl: (6) Could not resolve host: kasm.example.com # invalid host curl -k https://kasm.example.com/api/__healthcheck curl: (7) Failed to connect to 10.0.0.251 port 443 after 3074 ms: No route to host ``` If you do not get the json response shown in the first example above, then your agent likely can't access the WebApp server through the same domain name that your clients access kasm through. A better way to architect this for enterprise grade deployments is to use an internal load balancer with a hostname. Change the [Zone](../../infra-autoscale/deployment-zones.mdx) Upstream Auth Address to the hostname of the internal load balancer. Ensure your can curl the API health check through the internal load balancer from the agents. Another approach is to use an internal DNS name that points to all 4 WebApp servers and change the Zone's Upstream Auth Address to point to that internal hostname. After changing this setting, you will need to delete any created sessions. Any newly created sessions will have the new setting. Finally, it is good to ensure that an API server actually received the internal_auth API request and what it did with the request. Run the below command on each WebApp server to inspect the API container logs for internal_auth requests. ```bash sudo docker logs -f kasm_api 2>&1 | grep internal_auth 2023-11-15 18:43:18,076 [INFO] cherrypy.access.140168522947744: 172.18.0.9 - - [15/Nov/2023:18:43:18] "GET /api/internal_auth/ HTTP/1.1" 202 - "https://kasm.example.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" ``` The above example log shows a 202 response, indicating the request was not only received, wit was authorized. ### WebSockets The actual stream of the desktop session goes through a websocket connection, and websocket connections are handled differently and may be blocked or otherwise disrupted by security software installed on the client system or by security devices in the path from the client to the Kasm WebApp servers. First, make sure that the client is sending the request for the websocket connection in the first place. Open up DevTools in the browser, go to the Network tab, and then attempt to connect to a session. Click the WS filter, shown in the below screenshot, to get just the websocket connections and look for the `websockify` request. ![DevTools WebSocket](/img/troubleshooting/advanced_connectivity/devtools_websocket.webp) Also check the console tab in DevTools and ensure you don't see errors. ![Session hangs at requesting Kasm](/img/troubleshooting/requesting_kasm/websocket_error.png) Next, determine if the websockify request is making it all the way to the target agent. The easiest way to quickly determine if the websocket connection is making it all the way down to the agent is to run the following command on the agent. ```bash sudo docker logs -f kasm_proxy 2>&1 | grep '/websockify ' | grep -v -P '(internal_auth|kasm_connect)' 123.123.123.123 - - [15/Nov/2023:18:50:20 +0000] "GET /desktop/72248a05-922d-4518-b92f-7a9d1ea529eb/vnc/websockify HTTP/1.1" 101 3104787 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" "-" ``` In the above example, the request was received and the response code was 101, which is what should happen. If you see this request come in on the agent, then this means the websocket has traversed all the way through the stack to the agent. In this case proceed to the next section. If you do not see any output from the above command on the Agent, then something in your stack, prior to Kasm is interfering with the websocket connection. ### KasmVNC Troubleshooting If you have verified all the above steps the next step is to troubleshoot KasmVNC. First, enable debug logging on the user container. 1. In the Kasm Admin UI, navigate to Workspaces -> Workspaces 2. Find the target Workspace in the list and click the Edit button. 3. Scroll down to the Docker Run Config Override field and paste in the following. `{ "environment": { "KASM_DEBUG": 1 } }` 4. Launch a new session Now SSH to the agent that the session was provisioned on and run the following command to get a shell inside the container. ```yml # Get a list of running containers and identify your session container, the name of the container contains your partial username and session ID. sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 125348fe9990 kasmweb/core-ubuntu-jammy-private:feature_KASM-5078_multi-monitor "/dockerstartup/kasm…" 3 minutes ago Up 3 minutes 4901/tcp, 5901/tcp, 6901/tcp mattkasm.loc_4f8ada7f # Get a shell inside of the container sudo docker exec -it 125348fe9990 /bin/bash default:~$ # Tail the KasmVNC logs default:~$ tail -f .vnc/125348fe9990\:1.log ``` With the tail of the logs running, try to connect to the session. You will see a bunch of normal HTTP requests that are loading the static page resources such as vnc.html, javascript, stylesheets, etc. They will look like the following: ```bash 2023-11-17 14:51:07,525 [DEBUG] websocket 141: BasicAuth matched 2023-11-17 14:51:07,525 [INFO] websocket 141: /websockify request failed websocket checks, not a GET request, or missing Upgrade header 2023-11-17 14:51:07,525 [DEBUG] websocket 141: Invalid WS request, maybe a HTTP one 2023-11-17 14:51:07,525 [DEBUG] websocket 141: Requested file '/app/sounds/bell.oga' 2023-11-17 14:51:07,525 [INFO] websocket 141: 172.18.0.9 71.62.47.171 kasm_user "GET /app/sounds/bell.oga HTTP/1.1" 200 8701 2023-11-17 14:51:07,525 [DEBUG] websocket 141: No connection after handshake 2023-11-17 14:51:07,525 [DEBUG] websocket 141: handler exit ``` The first field is the date and time. After the time is a comma, followed by a number, that number is a HTTP request ID. Group each request by ID, so that you have all logs for a specific request. In the above example, all the logs were produced for the request for /app/sounds/bell.oga. The above log of "/websockify request failed websocket checks, not a GET request, or missing Upgrade header" is misleading. This is not, in and of itself an issue. It merely means that the incoming request was not a websocket request. In the beginning, KasmVNC only had a websocket server and it did not handle other types of web requests. The message is only relevant if the requested file was /websockify. If you saw the message "/websockify request failed websocket checks, not a GET request, or missing Upgrade header" for the /websockify file, then this means that KasmVNC was unable to identify the request as a valid websocket connection. Below is an example of what you should see for the websocket connection. Note the message "using protocol HyBi/IETF 6455 13" indicating that KasmVNC was able to correctly identify the exact Websocket specification being used by the browser. ```bash 2023-11-17 14:51:07,526 [DEBUG] websocket 142: using SSL socket 2023-11-17 14:51:07,526 [DEBUG] websocket 142: X-Forwarded-For ip '71.62.47.171' 2023-11-17 14:51:07,529 [DEBUG] websocket 142: BasicAuth matched 2023-11-17 14:51:07,529 [DEBUG] websocket 142: using protocol HyBi/IETF 6455 13 2023-11-17 14:51:07,529 [DEBUG] websocket 142: connecting to VNC target 2023-11-17 14:51:07,529 [DEBUG] XserverDesktop: new client, sock 32 ``` In some cases KasmVNC could have a bug. In the recent past, KasmVNC would crash due to large cookies or if the websocket connection was not exactly to the spec. These issues have since been corrected, however, there is no end to the combination of devices and services out there that sit between users and Kasm. In some cases these security devices or services manipulate the HTTP requests in a way that brings them out of compliance with the specification. This can cause improper handling by KasmVNC. The following is an exmaple of what a crash would look like in the KasmVNC logs. ```bash (EE) (EE) Backtrace: (EE) 0: /usr/bin/Xvnc (xorg_backtrace+0x4d) [0x5e48dd] (EE) 1: /usr/bin/Xvnc (0x400000+0x1e8259) [0x5e8259] (EE) 2: /lib/x86_64-linux-gnu/libpthread.so.0 (0x7f5a57ef6000+0x12980) [0x7f5a57f08980] (EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (epoll_wait+0x57) [0x7f5a552eca47] (EE) 4: /usr/bin/Xvnc (ospoll_wait+0x37) [0x5e8d07] (EE) 5: /usr/bin/Xvnc (WaitForSomething+0x1c3) [0x5e2813] (EE) 6: /usr/bin/Xvnc (Dispatch+0xa7) [0x597007] (EE) 7: /usr/bin/Xvnc (dix_main+0x36e) [0x59b1fe] (EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xe7) [0x7f5a551ecbf7] (EE) 9: /usr/bin/Xvnc (_start+0x2a) [0x46048a] (EE) (EE) Received signal 11 sent by process 17182, uid 0 (EE) Fatal server error: (EE) Caught signal 11 (Segmentation fault). Server aborting (EE) ``` KasmVNC will be restarted automatically by the container's entrypoint script, so you may see this repeat. Copy the backtrace output and provide it to Kasm support, along with the output of the following command. ```bash sudo docker exec -it 125348fe9990 Xvnc -version Xvnc KasmVNC 1.2.0.e4a5004f4b89b9da78c9b5f5aee59c08c662ccec - built Oct 31 2023 11:22:56 Copyright (C) 1999-2018 KasmVNC Team and many others (see README.me) See http://kasmweb.com for information on KasmVNC. Underlying X server release 12008000, The X.Org Foundation ``` With the above information we should be able to symbolize the backtrace and potentially find out what the issue is. ## Server Configuration Issues The following sub sections cover configuration issues on individual servers. These issues would be at the host OS level, so not with Kasm itself, but with the configuration of the host operating system or dependencies therein. ### Confirm Local Connectivity Sometimes in troubleshooting, if individual Kasm service containers are started, stopped, or restarted, the Kasm proxy container may lose the local hostname resolution of the other containers. First, lets stop and start the Kasm services to ensure hostname resolution is refreshed and that all containers were started in the proper order. ```bash sudo systemctl restart kasm ``` Next lets confirm that all services are up, running, and healthy. The following output shows that all services are up, running, and healthy. This is from a single server deployment. ```bash sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 401963ee87a0 kasmweb/proxy:[[release]] "/docker-entrypoint.…" 6 days ago Up 6 days 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp kasm_proxy 0eb604899140 kasmweb/agent:[[release]] "/bin/sh -c '/usr/bi…" 6 days ago Up 6 days (healthy) 4444/tcp kasm_agent 140660c3c201 kasmweb/manager:[[release]] "/bin/sh -c '/usr/bi…" 6 days ago Up 6 days (healthy) 8181/tcp kasm_manager 1ed22b860c6b kasmweb/kasm-guac:[[release]] "/dockerentrypoint.sh" 6 days ago Up 6 days (healthy) kasm_guac 109bf1f9fa3d kasmweb/rdp-https-gateway:[[release]] "/opt/rdpgw/rdpgw" 6 days ago Up 6 days (healthy) 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp kasm_rdp_https_gateway dfffa127e9c5 kasmweb/rdp-gateway:[[release]] "/start.sh" 6 days ago Up 6 days (healthy) 0.0.0.0:3389->3389/tcp, :::3389->3389/tcp kasm_rdp_gateway 5759e5692a85 kasmweb/api:[[release]] "/bin/sh -c 'python3…" 6 days ago Up 6 days 8080/tcp kasm_api 670da792ed27 postgres:14-alpine "docker-entrypoint.s…" 7 days ago Up 7 days (healthy) 5432/tcp kasm_db ``` For a WebApp server on a multi-server deployment, the output should look like the following. ```bash sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 401963ee87a0 kasmweb/proxy:[[release]] "/docker-entrypoint.…" 6 days ago Up 6 days 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp kasm_proxy 140660c3c201 kasmweb/manager:[[release]] "/bin/sh -c '/usr/bi…" 6 days ago Up 6 days (healthy) 8181/tcp kasm_manager 5759e5692a85 kasmweb/api:[[release]] "/bin/sh -c 'python3…" 6 days ago Up 6 days 8080/tcp kasm_api ``` For an Agent server on a multi-server deployment, the output should look like the following. ```bash sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 401963ee87a0 kasmweb/proxy:[[release]] "/docker-entrypoint.…" 6 days ago Up 6 days 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp kasm_proxy 0eb604899140 kasmweb/agent:[[release]] "/bin/sh -c '/usr/bi…" 6 days ago Up 6 days (healthy) 4444/tcp kasm_agent ``` Make note of the port number in the output of the kasm_proxy container. From the above examples you can see `0.0.0.0:443->443/tcp`, which indicates that the host's port 443 is mapped to the container's port 443. This indicates that kasm was installed on port 443, ensure this matches your expectation. Next, ensure that there is a program listening on the target port. ```bash ss -ltn State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* LISTEN 0 511 127.0.0.1:35521 0.0.0.0:* LISTEN 0 511 0.0.0.0:9001 0.0.0.0:* LISTEN 0 4096 [::]:111 [::]:* LISTEN 0 128 [::]:22 [::]:* LISTEN 0 4096 [::]:443 [::]:* ``` The above output shows that my server is listening on port 443 on both ipv4 and ipv6. Next, get the local IP address of the user facing network interface. ```bash ubuntu@roles-matt:~$ ip add 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens3: mtu 9000 qdisc pfifo_fast state UP group default qlen 1000 link/ether 02:00:17:0f:8c:19 brd ff:ff:ff:ff:ff:ff altname enp0s3 inet 10.0.0.106/24 metric 100 brd 10.0.0.255 scope global ens3 valid_lft forever preferred_lft forever inet6 fe80::17ff:fe0f:8c19/64 scope link valid_lft forever preferred_lft forever ``` Ignore loopback interfaces, docker0, bridge interfaces, and any other interfaces without an IP address. In the example above we can see the IP address is 10.0.0.106. Curl the IP address using HTTPS on the expected port number. ```yml # Correct Output curl -k https://10.0.0.106:443/api/__healthcheck {"ok": true} # Failure curl -k https://10.0.0.106:443/api/__healthcheck curl: (7) Failed to connect to 10.0.0.106 port 443 after 0 ms: Connection refused ``` If that command either hung or immediately returned a `Connection refused` message as shown above in the failure case, then your local system likely has a firewall running, see the next section. ### Host Based Firewalls Host based firewalls such as McAfee HBSS and even the Linux default UFW can interfere with communications. Docker manages iptables rules and other firewalls and security products either apply additional rules or actually use iptables as well. This can result in corrupt iptables rules. If you have UFW installed, run the following to allow https on port 443. See the UFW documentation on how to make this rule permanent, add alternative ports, or for additional usage instructions. ```bash sudo ufw status sudo ufw allow https ``` The following commands will completely clear IP tables rules and any NAT rules. **This may break your system, ensure you know what you are doing** ```yml # shut down kasm sudo systemctl stop kasm # Accept all traffic first to avoid ssh lockdown via iptables firewall rules # iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT # Flush All Iptables Chains/Firewall rules # iptables -F # Delete all Iptables Chains # iptables -X # Flush all counters too # iptables -Z # Flush and delete all nat and mangle # iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -t raw -F iptables -t raw -X # Restarting docker will regenerate the iptables rules that docker needs sudo systemctl restart docker # Bring Kasm back up sudo systemctl start kasm ``` If the above fixes your issues, it may only be temporary. You may have security or configuration management software installed on your server that eventually re-apply the offending rules. Please consult the documentation of your offending software for remediation. --- ## Chrome Managed Policies Configuration # Chrome Managed Policies Kasm administrators may wish to have certain configurations be automatically set when launching new instances of Google Chrome in a Kasm Workspace. This guide will cover two different methods of achieving this. The first is to use the File Mapping feature to manage files in the Admin UI, that will be mapped to the inside of user containers. The second method is to create a custom Workspace Docker Image. See [Chrome Policies](https://chromeenterprise.google/policies/) for full documentation on what can be managed in Chrome via managed policies. ## Video Tutorial This video walks through Chrome Managed Policies with Kasm Workspaces. ## File Mappings Administrators can add File Mappings to a [User](../../security/users-groups-mgmt/users.mdx), [Group](../../security/users-groups-mgmt/groups.mdx), or [Workspace](workspaces.mdx) definition. File Mappings define file content and where that content will be placed in a container based session. The following examples show how to add a File Mappings to a Workspace definition to manage Chrome Managed Policies. ### Managed Bookmarks To build bookmarks into the image's bookmarks bar we will make use of the "ManagedBookmarks" Chrome Policy. 1. Using the following example, create a managed policy for Managed Bookmarks. ```json { "BookmarkBarEnabled": true, "ManagedBookmarks":[ { "toplevel_name":"Managed Bookmarks" }, { "name":"Google", "url":"google.com" }, { "name":"Youtube", "url":"youtube.com" }, { "name":"Chrome links", "children":[ { "name":"Chromium", "url":"chromium.org" }, { "name":"Chromium Developers", "url":"dev.chromium.org" } ] } ] } ``` 2. From the Admin panel in Kasm Workspaces, navigate to Workspaces and Edit the desired Workspace definition. 3. Scroll down to the bottom of the Edit Workspace page and click **Add File Mapping**. Provide the file mapping a name and description. 4. Set the destination to `/etc/opt/chrome/policies/managed/bookmarks.json` and copy in your policy json into the Content section. Click Add. The next Workspace launched will have the file `/etc/opt/chrome/policies/managed/bookmarks.json` created with the content you defined. ### Managed Extensions To build extensions into the image we make use of the "ExtensionSettings" Chrome Policy. 1. Find a chrome extension you want to add to an image, in this case we will use "UBlock Origin" from the Chrome Web Store, making a note of the URL. ``` https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en ``` 2. Use the following example to create your Managed Policy to specify extensions to install. ```json { "ExtensionSettings": { "*": { "installation_mode": "blocked" }, "cjpalhdlnbpafiamejdnhcphjbkeiagm": { "installation_mode": "force_installed", "update_url": "https://clients2.google.com/service/update2/crx", "toolbar_pin" : "force_pinned" } } } ``` 2. From the Admin panel in Kasm Workspaces, navigate to Workspaces and Edit the desired Workspace definition. 3. Navigate to the **File Mapping** tab and click **Add File Mapping**. Provide the file mapping a name and description. 4. Set the destination to `/etc/opt/chrome/policies/managed/extensions.json` and copy in your policy json into the Content section. Click Save. ### Google Chrome Enterprise Google Chrome Enterprise is a business-focused version of the familiar Chrome browser, designed to provide organizations with enhanced security, centralized management, and tools to boost productivity. The most compelling benefits include robust security features like Safe Browse and comprehensive administrative controls that allow IT to manage browser settings, policies, and updates across the entire organization. This combination helps ensure a secure and efficient web browsing experience for users while simplifying IT management. Kasm Workspaces allows Google Chrome Enterprise customers to enroll their Chrome workspaces into the Google Chrome Enterprise ecosystem. This allows IT administrators to extend their enterprise browser policies to otherwise non-managed or BYOD devices. It also enables organizations to offer contractors and third-parties a *zero-installation* Enterprise Browser experience. 1. Obtain an enrollment token by following the instructions [here](https://support.google.com/chrome/a/answer/9301891). *You must have a Chrome Enterprise subscription with Google*. 2. In the Workspace you want to enroll into Chrome Enterprise, click on the **File Mapping** section and create a new file mapping. - Set **Type** field to **Text** - Set **Name** and **Description** fields to `Chrome Enrollment Token` - Set **Destination Path** field to `/etc/opt/chrome/policies/enrollment/CloudManagementEnrollmentToken` - Ensure **Executable** and **Writeable** options are disabled - Paste your enrollment token (e.g `f1a2b3c4-d5e6-f7a8-1234-5b6c7d8e9f0a`) into the body area to the right (*It is important to do this without any other characters such as whitespaces or line-breaks.*) - Click **Save**. 3. By default, if enrollment fails (for example if the enrollment token is invalid or revoked), Chrome will start in an unmanaged state. If you would like to prevent Chrome from starting without a valid enrollment token add another file mapping: - Set **Type** field to **Text** - Set **Name** and **Description** fields to `Force Chrome Enrollment` - Set **Destination Path** field to `/etc/opt/chrome/policies/enrollment/CloudManagementEnrollmentOptions` - Ensure **Executable** and **Writeable** options are disabled - Paste `Mandatory` into the body area to the right (*It is important to do this without any other characters such as whitespaces or line-breaks.*) - Click **Save**. Due to Kasm Workspaces being a containerized platform, all Chrome browsers on a single agent will share the same "device ID" for enrollment. This does not impact the enforcing of any Chrome Enterprise policies but may restrict device-level tracking. User tracking, through Google Workspace user accounts will remain unaffected. ## Custom Image Another method for managing Chrome Managed Policies is to create a custom Docker image that incorporates all customizations. As an example we will be editing the [Kasm Chrome Dockerfile](https://github.com/kasmtech/workspaces-images/blob/develop/dockerfile-kasm-chrome), but any Desktop Dockerfile that installs Chrome can be used. For instructions on how to build a Kasm image please see the [Building Image Documentation.](customization/building-images.mdx) ### Managed Bookmarks To build bookmarks into the image's bookmarks bar we will make use of the "ManagedBookmarks" Chrome Policy. 1. Create a file called 'bookmarks.json' with the following contents: ```json { "BookmarkBarEnabled": true, "ManagedBookmarks":[ { "toplevel_name":"Managed Bookmarks" }, { "name":"Google", "url":"google.com" }, { "name":"Youtube", "url":"youtube.com" }, { "name":"Chrome links", "children":[ { "name":"Chromium", "url":"chromium.org" }, { "name":"Chromium Developers", "url":"dev.chromium.org" } ] } ] } ``` 2. Edit the following line just before the "End Customizations" line in the 'dockerfile-kasm-chrome' file. ``` COPY ./bookmarks.json /etc/opt/chrome/policies/managed/bookmarks.json ``` 3. Build the image using the instructions from the [Building Images Documentation.](customization/building-images.mdx) ### Managed Extensions To build extensions into the image we make use of the "ExtensionSettings" Chrome Policy. 1. Find a chrome extension you want to add to an image, in this case we will use "UBlock Origin" from the Chrome Web Store, making a note of the URL. ``` https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en ``` 2. Create a file called 'extensions.json' with the following contents, note the Extension ID is copied from the Chrome Web Store URL. ```json { "ExtensionSettings": { "*": { "installation_mode": "blocked" }, "cjpalhdlnbpafiamejdnhcphjbkeiagm": { "installation_mode": "force_installed", "update_url": "https://clients2.google.com/service/update2/crx", "toolbar_pin" : "force_pinned" } } } ``` 3. Edit the following line just before the "End Customizations" line in the 'dockerfile-kasm-chrome' file. ``` COPY ./extensions.json /etc/opt/chrome/policies/managed/extensions.json ``` 4. Build the image using the instructions from the [Building Images Documentation.](customization/building-images.mdx) # Firefox Managed Policies Kasm administrators may wish to have certain configurations be automatically set when launching new instances of Mozilla Firefox in a Kasm Workspace. This guide will cover two different methods of achieving this. The first is to use the File Mapping feature to manage files in the Admin UI, that will be mapped to the inside of user containers. The second method is to create a custom Workspace Docker Image. See [Firefox Policy Templates](https://mozilla.github.io/policy-templates/) for full documentation on what can managed in Firefox from managed policies. ## File Mappings Administrators can add File Mappings to a [User](../../security/users-groups-mgmt/users.mdx), [Group](../../security/users-groups-mgmt/groups.mdx) , or [Workspace](workspaces.mdx) definition. File Mappings define file content and where that content will be placed in a container based session. The following examples show how to add a File Mappings to a Workspace definition to manage Firefox Managed Policies. ### Managed Bookmarks To build bookmarks into the image's bookmarks bar we will make use of the "ManagedBookmarks" Firefox Policy. 1. Using the following example, create a managed policy for Managed Bookmarks. ```json { "policies": { "DisplayBookmarksToolbar": "always", "ManagedBookmarks": [ { "toplevel_name": "My managed bookmarks folder" }, { "url": "example.com", "name": "Example" }, { "name": "Mozilla links", "children": [ { "url": "https://mozilla.org", "name": "Mozilla.org" }, { "url": "https://support.mozilla.org/", "name": "SUMO" } ] } ] } } ``` 2. From the Admin panel in Kasm Workspaces, navigate to Workspaces and Edit the desired Workspace definition. 3. Scroll down to the bottom of the Edit Workspace page and click **Add File Mapping**. Provide the file mapping a name and description. 4. Set the destination to `/etc/firefox/policies/policies.json` and copy in your policy json into the Content section. Click Add. The next Workspace launched will have the file `/etc/firefox/policies/policies.json` created with the content you defined. ### Managed Extensions To build extensions into the image we make use of the "ExtensionSettings" Firefox Policy. 1. Find a firefox extension you want to add to an image, in this case we will use "UBlock Origin" from the [Firefox Browser Add-ons Store](https://addons.mozilla.org/en-US/firefox/extensions/), making a note of the URL. ``` https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/ ``` 2. Firefox requires a specific extension ID for each add-on. Obtain the extension ID by manually installing the extension in Firefox, then go to "about:support". You will see a list of all installed extensions in the Add-ons section. Copy the extension ID for your add-on. 3. Use the following example to create your Managed Policy to specify extensions to install. In this example the extension ID is `uBlock0@raymondhill.net`. Replace the extension ID in the example below with your copied extention ID. Notice that the field "install_url" has been modified to remove the extension version (eg: `-1.57.2`). For our example the original copied download url was `https://addons.mozilla.org/firefox/downloads/file/4261710/ublock_origin-1.57.2.xpi`. Removing the download version works for most of the download urls as a method for downloading the latest version of the add-on for installation. The download urls for extensions can be obtained by selecting an extension from [Firefox Add-ons Extensions](https://addons.mozilla.org/en-US/firefox/extensions/) directory, then copying the url from the `Download File` link on an extension's page. ```json { "policies": { "ExtensionSettings": { "*": { "installation_mode": "blocked", "allowed_types": ["extension"] }, "uBlock0@raymondhill.net": { "installation_mode": "force_installed", "install_url": "https://addons.mozilla.org/firefox/downloads/file/4261710/ublock_origin.xpi" } } } } ``` 4. From the Admin panel in Kasm Workspaces, navigate to Workspaces and Edit the desired Workspace definition. 5. Navigate to the **File Mapping** tab and click **Add File Mapping**. Provide the file mapping a name and description. 6. Set the destination to `/etc/firefox/policies/policies.json` and copy in your policy json into the Content section. Click Save. ## Custom Image Another method for managing Firefox Managed Policies is to create a custom Docker image that incorporates all customizations. As an example we will be editing the [Kasm Firefox Dockerfile](https://github.com/kasmtech/workspaces-images/blob/develop/dockerfile-kasm-firefox), but any Desktop Dockerfile that installs Firefox can be used. For instructions on how to build a Kasm image please see the [Building Images Documentation](customization/building-images.mdx) ### Managed Bookmarks To build bookmarks into the image's bookmarks bar we will make use of the "ManagedBookmarks" Firefox Policy. 1. Create a file called 'policies.json' with the following contents: ```json { "policies": { "DisplayBookmarksToolbar": "always", "ManagedBookmarks": [ { "toplevel_name": "My managed bookmarks folder" }, { "url": "example.com", "name": "Example" }, { "name": "Mozilla links", "children": [ { "url": "https://mozilla.org", "name": "Mozilla.org" }, { "url": "https://support.mozilla.org/", "name": "SUMO" } ] } ] } } ``` 2. Edit the following line just before the "End Customizations" line in the 'dockerfile-kasm-firefox' file. ``` COPY ./policies.json /etc/firefox/policies/policies.json ``` 3. Build the image using the instructions from the [Building Images Documentation](customization/building-images.mdx) ### Managed Extensions To build extensions into the image we make use of the "ExtensionSettings" Chrome Policy. 1. Find a firefox extension you want to add to an image, in this case we will use "UBlock Origin" from the [Firefox Browser Add-ons Store](https://addons.mozilla.org/en-US/firefox/extensions/). ``` https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/ ``` 2. Firefox requires a specific extension ID for each add-on. Obtain the extension ID by manually installing the extension in Firefox, then go to "about:support". You will see a list of all installed extensions in the Add-ons section. Copy the extension ID for your add-on. 3. Create a file called 'policies.json' with the following contents. In this example the extension ID is `uBlock0@raymondhill.net`. Replace the extension ID in the example below with your copied extention ID. Notice that the field "install_url" has been modified to remove the extension version (eg: `-1.57.2`). For our example the original copied download url was `https://addons.mozilla.org/firefox/downloads/file/4261710/ublock_origin-1.57.2.xpi`. Removing the download version works for most of the download urls as a method for downloading the latest version of the add-on for installation. The download urls for extensions can be obtained by selecting an extension from [Firefox Add-ons Extensions](https://addons.mozilla.org/en-US/firefox/extensions/) directory, then copying the url from the `Download File` link on an extension's page. ```json { "policies": { "ExtensionSettings": { "*": { "installation_mode": "blocked", "allowed_types": ["extension"] }, "uBlock0@raymondhill.net": { "installation_mode": "force_installed", "install_url": "https://addons.mozilla.org/firefox/downloads/file/4261710/ublock_origin.xpi" } } } } ``` 4. Edit the following line just before the "End Customizations" line in the 'dockerfile-kasm-firefox' file. ``` COPY ./policies.json /etc/firefox/policies/policies.json ``` 5. Build the image using the instructions from the [Building Images Documentation](customization/building-images.mdx). --- ## Default Docker Images: Complete List # Default Docker Images Kasm Technologies maintains and publishes several default Docker images. The **rolling** editions are automatically built and pushed regularly with the latest software updates and security patches. The Kasm installation will regularly pull the updated Docker images and start using them for newly created sessions. The following are the Kasm Technologies maintained Docker images. Source code for the Docker images is available on [GitHub](https://github.com/kasmtech/workspaces-images). | **Docker Image** | **Dockerhub Path** | **DockerHub** | **AMD64** | **ARM64** | **GPU** | |---|---|---|---|---|---| | | kasmweb/almalinux-8-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/almalinux-8-desktop) | **X** | **X** | | | | kasmweb/almalinux-9-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/almalinux-9-desktop) | **X** | **X** | | | | kasmweb/alpine-319-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/alpine-319-desktop) | **X** | **X** | | | | kasmweb/alpine-320-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/alpine-320-desktop) | **X** | **X** | | | | kasmweb/alpine-321-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/alpine-321-desktop) | **X** | **X** | | | | kasmweb/atom:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/atom) | **X** | | | | | kasmweb/audacity:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/audacity) | **X** | **X** | | | | kasmweb/blender:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/blender) | **X** | | **X** | | | kasmweb/brave:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/brave) | **X** | **X** | **X** | | | kasmweb/chrome:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/chrome) | **X** | | **X** | | | kasmweb/chromium:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/chromium) | **X** | **X** | **X** | | | kasmweb/cyberbro:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/cyberbro) | **X** | **X** | | | | kasmweb/debian-bookworm-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/debian-bookworm-desktop) | **X** | **X** | | | | kasmweb/debian-bullseye-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/debian-bullseye-desktop) | **X** | **X** | | | | kasmweb/debian-trixie-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/debian-trixie-desktop) | **X** | **X** | | | | kasmweb/deluge:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/deluge) | **X** | **X** | | | | kasmweb/discord:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/discord) | **X** | | | | | kasmweb/doom:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/doom) | **X** | **X** | | | | kasmweb/edge:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/edge) | **X** | | **X** | | | kasmweb/fedora-39-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/fedora-39-desktop) | **X** | **X** | | | | kasmweb/fedora-40-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/fedora-40-desktop) | **X** | **X** | | | | kasmweb/fedora-41-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/fedora-41-desktop) | **X** | **X** | | | | kasmweb/filezilla:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/filezilla) | **X** | **X** | | | | kasmweb/firefox:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/firefox) | **X** | **X** | **X** | | | kasmweb/forensic-osint:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/forensic-osint) | **X** | | **X** | | | kasmweb/gimp:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/gimp) | **X** | **X** | | | | kasmweb/hunchly:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/hunchly) | **X** | **X** | | | | kasmweb/inkscape:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/inkscape) | **X** | **X** | | | | kasmweb/insomnia:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/insomnia) | **X** | | | | | kasmweb/java-dev:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/java-dev) | **X** | **X** | | | | kasmweb/kali-rolling-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/kali-rolling-desktop) | **X** | **X** | | | | kasmweb/kasmos-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/kasmos-desktop) | **X** | **X** | | | | kasmweb/libre-office:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/libre-office) | **X** | **X** | | | | kasmweb/maltego:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/maltego) | **X** | **X** | **X** | | | kasmweb/minetest:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/minetest) | **X** | **X** | **X** | | | kasmweb/nessus:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/nessus) | **X** | **X** | | | | kasmweb/obsidian:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/obsidian) | **X** | **X** | | | | kasmweb/only-office:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/only-office) | **X** | | | | | kasmweb/opensuse-15-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/opensuse-15-desktop) | **X** | **X** | | | | kasmweb/oracle-8-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/oracle-8-desktop) | **X** | **X** | | | | kasmweb/oracle-9-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/oracle-9-desktop) | **X** | **X** | | | | kasmweb/parrotos-6-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/parrotos-6-desktop) | **X** | **X** | | | | kasmweb/pinta:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/pinta) | **X** | **X** | | | | kasmweb/postman:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/postman) | **X** | | | | | kasmweb/qbittorrent:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/qbittorrent) | **X** | **X** | | | | kasmweb/redroid:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/redroid) | **X** | **X** | | | | kasmweb/remmina:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/remmina) | **X** | **X** | | | | kasmweb/remnux-noble-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/remnux-noble-desktop) | **X** | | | | | kasmweb/retroarch:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/retroarch) | **X** | **X** | **X** | | | kasmweb/rhel-9-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/rhel-9-desktop) | **X** | **X** | | | | kasmweb/rockylinux-8-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/rockylinux-8-desktop) | **X** | **X** | | | | kasmweb/rockylinux-9-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/rockylinux-9-desktop) | **X** | **X** | | | | kasmweb/signal:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/signal) | **X** | | | | | kasmweb/slack:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/slack) | **X** | | | | | kasmweb/spiderfoot:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/spiderfoot) | **X** | **X** | | | | kasmweb/steam:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/steam) | **X** | | | | | kasmweb/sublime-text:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/sublime-text) | **X** | **X** | | | | kasmweb/super-tux-kart:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/super-tux-kart) | **X** | **X** | | | | kasmweb/telegram:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/telegram) | **X** | **X** | | | | kasmweb/terminal:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/terminal) | **X** | **X** | | | | kasmweb/thunderbird:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/thunderbird) | **X** | **X** | | | | kasmweb/tor-browser:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/tor-browser) | **X** | **X** | | | | kasmweb/tracelabs:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/tracelabs) | **X** | **X** | | | | kasmweb/ubuntu-jammy-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-desktop) | **X** | **X** | **X** | | | kasmweb/ubuntu-jammy-desktop-vpn:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-desktop-vpn) | **X** | **X** | **X** | | | kasmweb/ubuntu-jammy-dind:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind) | **X** | **X** | **X** | | | kasmweb/ubuntu-jammy-dind-rootless:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind-rootless) | **X** | **X** | **X** | | | kasmweb/ubuntu-noble-desktop:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-desktop) | **X** | **X** | **X** | | | kasmweb/ubuntu-noble-dind:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-dind) | **X** | **X** | **X** | | | kasmweb/ubuntu-noble-dind-rootless:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-dind-rootless) | **X** | **X** | **X** | | | kasmweb/unityhub:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/unityhub) | **X** | **X** | | | | kasmweb/vivaldi:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/vivaldi) | **X** | **X** | **X** | | | kasmweb/vlc:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/vlc) | **X** | **X** | | | | kasmweb/vs-code:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/vs-code) | **X** | **X** | | | | kasmweb/zoom:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/zoom) | **X** | | | ## Core Docker Images The core docker images contain the minimum set of software/configurations to allow the container to operate within the Kasm Workspaces platform. All subsequent Docker images are based from one of these. Source code for the Docker images is available on [GitHub](https://github.com/kasmtech/workspaces-core-images). | **Docker Image** | **Dockerhub Path** | **DockerHub** | **AMD64** | **ARM64** | **GPU** | |---|---|---|---|---|---| | | kasmweb/core-almalinux-8:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-almalinux-8) | **X** | **X** | | | | kasmweb/core-almalinux-9:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-almalinux-9) | **X** | **X** | | | | kasmweb/core-alpine-321:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-alpine-321) | **X** | **X** | | | | kasmweb/core-alpine-322:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-alpine-322) | **X** | **X** | | | | kasmweb/core-alpine-323:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-alpine-323) | **X** | **X** | | | | kasmweb/core-cuda-jammy:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-cuda-jammy) | **X** | | **X** | | | kasmweb/core-debian-bullseye:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-debian-bullseye) | **X** | **X** | | | | kasmweb/core-debian-bookworm:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-debian-bookworm) | **X** | **X** | | | | kasmweb/core-debian-trixie:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-debian-trixie) | **X** | **X** | | | | kasmweb/core-fedora-42:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-fedora-42) | **X** | **X** | | | | kasmweb/core-fedora-43:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-fedora-43) | **X** | **X** | | | | kasmweb/core-kali-rolling:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-kali-rolling) | **X** | **X** | | | | kasmweb/core-kasmos:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-kasmos) | **X** | **X** | | | | kasmweb/core-opensuse-15:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-opensuse-15) | **X** | **X** | | | | kasmweb/core-oracle-8:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-oracle-8) | **X** | **X** | | | | kasmweb/core-oracle-9:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-oracle-9) | **X** | **X** | | | | kasmweb/core-parrotos-7:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-parrotos-7) | **X** | **X** | | | | kasmweb/core-rhel-9:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-rhel-9) | **X** | **X** | | | | kasmweb/core-rockylinux-8:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-rockylinux-8) | **X** | **X** | | | | kasmweb/core-rockylinux-9:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-rockylinux-9) | **X** | **X** | | | | kasmweb/core-ubuntu-jammy:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-ubuntu-jammy) | **X** | **X** | **X** | | | kasmweb/core-ubuntu-noble:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/core-ubuntu-noble) | **X** | **X** | **X** | ## AI Docker Images The AI docker images contain specialized environments for artificial intelligence, machine learning, and AI-powered tools. These images support GPU acceleration where required and include pre-configured frameworks and tools. Source code for the Docker images is available on [GitHub](https://github.com/kasmtech/workspace-ai-images). | **Docker Image** | **Image Path** | **DockerHub** | **AMD64** | **ARM64** | **GPU** | |---|---|---|---|---|---| | | kasmweb/ubuntu-jammy-desktop-ai-dev:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-desktop-ai-dev) | **X** | **X** | | | | kasmweb/ubuntu-noble-anythingllm:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-anythingllm) | **X** | | | | | kasmweb/claude-code:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/claude-code) | **X** | **X** | | | | kasmweb/codex-cli:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/codex-cli) | **X** | **X** | | | | kasmweb/cursor:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/cursor) | **X** | **X** | | | | kasmweb/ubuntu-noble-easydiffusion:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-easydiffusion) | **X** | | **X** | | | kasmweb/gemini-cli:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/gemini-cli) | **X** | **X** | | | | kasmweb/ubuntu-jammy-nvidia:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-jammy-nvidia) | **X** | | **X** | | | kasmweb/ubuntu-noble-nvidia:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-nvidia) | **X** | | **X** | | | kasmweb/ubuntu-noble-nvidia-pytorch:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-nvidia-pytorch) | **X** | | **X** | | | kasmweb/ubuntu-noble-nvidia-tensorflow:[[release]] | [DockerHub](https://hub.docker.com/r/kasmweb/ubuntu-noble-nvidia-tensorflow) | **X** | | **X** | ## Rolling Docker Images Kasm Technologies also publishes two **rolling** editions of the Default Docker images that are automatically built and published nightly with the latest software and patches. Administrators may choose to use these Docker images to have up-to-date end-user sessions. **rolling-daily** images are built daily and **rolling-weekly** images are built once a week. Daily images should be used for when using the most up to date images with the latest security fixes is critical, and the weekly images may be used when bandwidth constraints or other limitations require a less aggressive update schedule. If Workspaces is configured to use the rolling Docker images it is recommended to enable **Automatically Prune Images** on the Agent(s). This will reclaim diskpace that would otherwise be taken up by the old docker images once the new ones are pulled. See [Agent Settings](../../infra-autoscale/docker-agent.mdx) for more details. ## Custom Docker Images A powerful component of Kasm Workspaces is the ability for administrators to create their own Docker images with the software and configurations they desire. Please see the [Building Custom Docker Images](customization/building-images.mdx) and [Creating Docker Image Maintenance Processes](image-maintenance.mdx) guides for details. --- ## Building Custom Docker Images for Kasm Workspaces # Building Custom Images The ability to create custom [workspaces ](../../../../reference/glossary.mdx#workspace) is a powerful feature of the Kasm framework. Administrators may choose to maintain and automatically deploy always up-to-date Images to the Kasm deployment with no user downtime. See [Image Maintenance Process](../image-maintenance.mdx) for more details. While the build process in this guide is the preferred method for creating robust, sustainable and highly automated images, administrators may also wish to experiment with the [create-image-from-session](../../sessions/sessions.mdx#create-image-from-session) feature, which provides a quick and convenient way to capture the state of an active session if manual configuration is desired. Administrators will create Docker Images that import from an existing [Default or Core Docker Image](../custom-images.mdx) published by the Kasm Technologies team. The **Core** Docker images contain the minimal set of configurations that is necessary for the Docker images to work within the platform. The `kasmweb/core-ubuntu-jammy` image is the preferred core image and is based on Ubuntu 22.04 LTS. Generally speaking most programs that can be installed on Ubuntu can be installed inside this image. The exception are programs that come delivered as containers themselves such as [Snaps](https://snapcraft.io) and some [FlatPaks](https://flatpak.org/). Administrators will need working knowledge of Docker and scripting to add custom software and configurations to the Docker images. A Git repository with several example Dockerfiles that demonstrate how to build full desktop or single application images is available on [GitHub](https://github.com/kasmtech/workspaces-images). In this guide we will walk through the basic steps for creating a custom Image. These steps can be conducted on the server with the Kasm [agent ](../../../../reference/glossary.mdx#agent) installed. The Kasm team publishes new editions of the core image at every release cycle. The Kasm team also maintains rolling updates for all published images, we would recommend basing custom images against a rolling tag on a scheduled build so that the custom image will get regular program and security updates. Be sure to build your image based on the appropriate tag for your deployed Kasm version for example kasmweb/core-ubuntu-jammy:[[release]]-rolling-daily or kasmweb/core-ubuntu-jammy:[[release]]-rolling-weekly ```bash FROM kasmweb/core-ubuntu-jammy:[[release]] ``` It is also possible to base a custom Image on any of the default Images published. See [Default Docker Images](../custom-images.mdx) for a list. ## Basic Build If performing a build directly on the Kasm Workspaces server or Agent, disable **Automatically Prune Images** for the applicable Agent. See [Agent Settings](../../../infra-autoscale/docker-agent.mdx) for more details. 1. Below is the baseline `Dockerfile` used to create a custom Kasm Image. There is a pre-defined sections where customizations are to be added. The statements before and after this section should not be modified. In this example a single customization is added: an file named **hello.txt** is created on the desktop. Create a file named `Dockerfile` with the following contents. ```yml FROM kasmweb/core-ubuntu-jammy:[[release]] USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### RUN touch $HOME/Desktop/hello.txt ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 2. Build the Image. ```bash sudo docker build -t sublime-text:example -f Dockerfile . ``` 3. Log into the Kasm UI as an administrator and register a new Workspace by selecting the **Workspaces** panel and clicking on **Add Workspace** (It is also possible using the arrow menu to clone the configuration of an existing workspace) Kasm Workspaces does not assume the tag `latest` as many other docker tools do. This is because docker images from older versions my not be compatible with newer versions, and reduces the benefit of a `latest` tag. The Kasm team recommends using a tag that reflects the version of the core image being used as a base. Kasm workspaces expects an explicit tag be specified in the Workspace configuration for *Docker Image*. 4. When finished editing details of the workspace click **Save** to create the new workspace. ![Register New Image](/img/building_images/image_registration.webp) 5. From the Kasm Dashboard click Sublime Text Image. ![New Image Available](/img/building_images/new_image.webp) 6. There will be a new pop up in the UI that has a **LAUNCH SESSION** button, click it to launch the Kasm session. ![Launch Session](/img/building_images/launch_image.webp) 7. A new session is created with the **hello.txt** file we created. ![Running the custom Image](/img/building_images/hello.png) ## Installing Software 1. Now it's time to do something more useful. We will update the `Dockerfile` to actually install Sublime Text. Update the `Dockerfile` with the following contents. ```yml FROM kasmweb/core-ubuntu-jammy:[[release]] USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### RUN wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | apt-key add - \\ && apt-get update \\ && apt-get install -y apt-transport-https \\ && echo "deb https://download.sublimetext.com/ apt/stable/" | tee /etc/apt/sources.list.d/sublime-text.list \\ && apt-get update \\ && apt-get install sublime-text \\ && cp /usr/share/applications/sublime_text.desktop $HOME/Desktop/ \\ && chmod +x $HOME/Desktop/sublime_text.desktop \\ && chown 1000:1000 $HOME/Desktop/sublime_text.desktop ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` Creating desktop icons is a common need. This example highlights how applications , when installed often place a `.desktop` file in `/usr/share/applications`. This file can often be copied without modification to the desktop `$HOME/Desktop/`. It is important to mark the file as executable and ensure the ownership is changed to user and group `1000` **Reference:** - [https://www.sublimetext.com3/linux_repositories.html](https://www.sublimetext.com/docs/3/linux_repositories.html) 2. Rebuild the Image and create a new session and verify Sublime Text is installed and an icon is present on the desktop. ![Sublime Text is Installed](/img/building_images/sublime_1.png) ## Custom Startup 1. Next we will utilize the `custom_startup.sh` interface point to launch Sublime text when the session starts. Create the script and mark it executable. This script will run in the standard user (`1000`) context when the session starts. Utilize the built-in command `/usr/bin/desktop_ready` to ensure Sublime Text starts after the Kasm desktop environment. Update the `Dockerfile` with the following contents. ```yml FROM kasmweb/core-ubuntu-jammy:[[release]] USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### RUN wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | apt-key add - \\ && apt-get update \\ && apt-get install -y apt-transport-https \\ && echo "deb https://download.sublimetext.com/ apt/stable/" | tee /etc/apt/sources.list.d/sublime-text.list \\ && apt-get update \\ && apt-get install sublime-text \\ && cp /usr/share/applications/sublime_text.desktop $HOME/Desktop/ \\ && chmod +x $HOME/Desktop/sublime_text.desktop \\ && chown 1000:1000 $HOME/Desktop/sublime_text.desktop RUN echo "/usr/bin/desktop_ready && /opt/sublime_text/sublime_text &" > $STARTUPDIR/custom_startup.sh \\ && chmod +x $STARTUPDIR/custom_startup.sh ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 2. Rebuild the Image and create a new session. Sublime Text should start automatically. ![Sublime Text Started Automatically](/img/building_images/sublime_2.png) ## Desktop Background 1. The background can be changed by overwriting the `/usr/share/backgrounds/bg_default.png` file. Update the `Dockerfile` with the following contents. ```yml FROM kasmweb/core-ubuntu-jammy:[[release]] USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### RUN wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | apt-key add - \\ && apt-get update \\ && apt-get install -y apt-transport-https \\ && echo "deb https://download.sublimetext.com/ apt/stable/" | tee /etc/apt/sources.list.d/sublime-text.list \\ && apt-get update \\ && apt-get install sublime-text \\ && cp /usr/share/applications/sublime_text.desktop $HOME/Desktop/ \\ && chmod +x $HOME/Desktop/sublime_text.desktop \\ && chown 1000:1000 $HOME/Desktop/sublime_text.desktop RUN echo "/usr/bin/desktop_ready && /opt/sublime_text/sublime_text &" > $STARTUPDIR/custom_startup.sh \\ && chmod +x $STARTUPDIR/custom_startup.sh RUN wget https://cdn.hipwallpaper.com/i/92/9/0Ts6mr.png -O /usr/share/backgrounds/bg_default.png ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 2. Rebuild the image and create a new session. Sublime Text should start automatically. ![Custom Desktop Background](/img/building_images/background.png) ## Single App Workspace You can also configure a container-based workspace to launch in single-application mode using XFCE. When a Single App workspace is launched, it opens a specific application (for example, Firefox) automatically on session start and only that app is usable. The traditional desktop interface is disabled, preventing users from interacting with panels, menus, or launching additional applications. This is made possible with some XFCE configurations. We already have some popular applications available as Single App Workspaces in our [official Workspaces registry](https://registry.kasmweb.com/1.1/). Some examples include: Firefox, Chrome, Brave, Slack, Telegram, Zoom, etc. 1. Start by writing a Custom Dockerfile for your Single App Workspace. We recommend you use the `kasmweb/core-ubuntu-jammy` image as the base image when creating a Single App workspace. If you use a different image, you would have to manually load the image with the Single App XFCE config files available on our [Github repo](https://github.com/kasmtech/workspaces-core-images/tree/develop/src/ubuntu/xfce/.config/xfce4/xfconf/single-application-xfce-perchannel-xml) ```yml FROM kasmweb/core-ubuntu-jammy:[[release]]-rolling-weekly USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 2. Set the Single App XFCE config files as your default XFCE config and remove the `xfce4-panel` ```yml FROM kasmweb/core-ubuntu-jammy:[[release]]-rolling-weekly USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### ## --> Update the desktop environment to be optimized for a single application RUN cp $HOME/.config/xfce4/xfconf/single-application-xfce-perchannel-xml/* $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/ ## --> Optionally, set a background image RUN cp /usr/share/backgrounds/bg_kasm.png /usr/share/backgrounds/bg_default.png ## --> Remove the xfce4-panel RUN apt-get remove -y xfce4-panel ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` 3. Write installation logic as a bash script to install the custom app of your choice. As an example, let’s say you want to install Discord, You can write an installation bash script like this which installs Discord and name it `install_discord.sh` (Another example [here](https://gitlab.com/kasm-technologies/internal/workspaces-images/-/blob/develop/src/ubuntu/install/chromium/install_chromium.sh?ref_type=heads)): ```bash #!/usr/bin/env bash set -ex # Install Discord from deb apt-get update curl -L -o discord.deb "https://discord.com/api/download?platform=linux&format=deb" apt-get install -y ./discord.deb rm discord.deb # Default config values mkdir -p $HOME/.config/discord/ echo '{"SKIP_HOST_UPDATE": true}' > $HOME/.config/discord/settings.json # Desktop file setup sed -i "s@Exec=/usr/share/discord/Discord@Exec=/usr/share/discord/Discord --no-sandbox@g" /usr/share/applications/discord.desktop cp /usr/share/applications/discord.desktop $HOME/Desktop/ chmod +x $HOME/Desktop/discord.desktop # Cleanup if [ -z ${SKIP_CLEAN+x} ]; then apt-get autoclean rm -rf \ /var/lib/apt/lists/* \ /var/tmp/* \ /tmp/* fi # Cleanup for app layer chown -R 1000:0 $HOME find /usr/share/ -name "icon-theme.cache" -exec rm -f {} \; ``` 4. Also, write a `custom_startup.sh` script that automatically launches your custom application on workspace startup (Another Example [here](https://gitlab.com/kasm-technologies/internal/workspaces-images/-/blob/develop/src/ubuntu/install/chromium/custom_startup.sh?ref_type=heads)): ```bash #!/usr/bin/env bash set -ex START_COMMAND="/usr/share/discord/Discord" PGREP="Discord" export MAXIMIZE="true" export MAXIMIZE_NAME="Discord" MAXIMIZE_SCRIPT=$STARTUPDIR/maximize_window.sh DEFAULT_ARGS="--no-sandbox" ARGS=${APP_ARGS:-$DEFAULT_ARGS} options=$(getopt -o gau: -l go,assign,url: -n "$0" -- "$@") || exit eval set -- "$options" while [[ $1 != -- ]]; do case $1 in -g|--go) GO='true'; shift 1;; -a|--assign) ASSIGN='true'; shift 1;; -u|--url) OPT_URL=$2; shift 2;; *) echo "bad option: $1" >&2; exit 1;; esac done shift # Process non-option arguments. for arg; do echo "arg! $arg" done FORCE=$2 kasm_exec() { if [ -n "$OPT_URL" ] ; then URL=$OPT_URL elif [ -n "$1" ] ; then URL=$1 fi # Since we are execing into a container that already has the browser running from startup, # when we don't have a URL to open we want to do nothing. Otherwise a second browser instance would open. if [ -n "$URL" ] ; then /usr/bin/filter_ready /usr/bin/desktop_ready bash ${MAXIMIZE_SCRIPT} & $START_COMMAND $ARGS $OPT_URL else echo "No URL specified for exec command. Doing nothing." fi } kasm_startup() { if [ -n "$KASM_URL" ] ; then URL=$KASM_URL elif [ -z "$URL" ] ; then URL=$LAUNCH_URL fi if [ -z "$DISABLE_CUSTOM_STARTUP" ] || [ -n "$FORCE" ] ; then echo "Entering process startup loop" set +x while true do if ! pgrep -x $PGREP > /dev/null then /usr/bin/filter_ready /usr/bin/desktop_ready set +e bash ${MAXIMIZE_SCRIPT} & $START_COMMAND $ARGS $URL & set -e fi sleep 1 done set -x fi } if [ -n "$GO" ] || [ -n "$ASSIGN" ] ; then kasm_exec else kasm_startup fi ``` Notice that in the `custom_startup.sh` script above, the `START_COMMAND` contains the command that needs to be executed to start the application. Similarly, `PGREP` contains the name of the application process (it can be a partial name of the process) so that the startup script can automatically check and re-open the application if it crashes or is closed by the user. Similarly, you can set `MAXIMIZE` to true if you want your application to be automatically maximized. This requires that you also configure the `MAXIMIZE_WINDOW` name to match the window name of your application. 5. Copy both the install script and custom startup script to your image ```yml FROM kasmweb/core-ubuntu-jammy:[[release]]-rolling-weekly USER root ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup ENV INST_SCRIPTS $STARTUPDIR/install WORKDIR $HOME ######### Customize Container Here ########### ## Update the desktop environment to be optimized for a single application RUN cp $HOME/.config/xfce4/xfconf/single-application-xfce-perchannel-xml/* $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/ ## Optionally, set a background image RUN cp /usr/share/backgrounds/bg_kasm.png /usr/share/backgrounds/bg_default.png ## Remove the xfce4-panel RUN apt-get remove -y xfce4-panel ## --> Copy installation script COPY ./install_discord.sh $INST_SCRIPTS/discord/ ## --> Run installation script RUN bash $INST_SCRIPTS/discord/install_discord.sh && rm -rf $INST_SCRIPTS/discord/ ## --> Copy custom_startup.sh script to the startup directory inside the image COPY ./custom_startup.sh $STARTUPDIR/custom_startup.sh ## --> Make it executable RUN chmod +x $STARTUPDIR/custom_startup.sh ## --> Set permissions RUN chmod 755 $STARTUPDIR/custom_startup.sh ######### End Customizations ########### RUN chown 1000:0 $HOME RUN $STARTUPDIR/set_user_permission.sh $HOME ENV HOME /home/kasm-user WORKDIR $HOME RUN mkdir -p $HOME && chown -R 1000:0 $HOME USER 1000 ``` The script `$STARTUPDIR/custom_startup.sh` will be automatically executed on the workspace startup, thus launching the application. 6. Build the Image ```bash sudo docker build -t my_custom_singleapp_image -f Dockerfile . ``` ## Push to Registry To simplify Image management, it is recommended to utilize a docker container registry. This example will utilize a container registry that is provided by GitLab. 1. Login to the docker container registry. You will be prompted for a username and password. GitLab provides the ability to create [Personal Access Tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) with permissions that are limited to read and/or write permissions to the registry. ```bash sudo docker login registry.gitlab.com ``` 2. Build the image, using the registry location as part of the image name. ```bash sudo docker build -t registry.gitlab.com/my-company/my-project/sublime-text:example -f Dockerfile . ``` 3. Push the image to the registry ```bash sudo docker push registry.gitlab.com/my-company/my-project/sublime-text:example ``` 4. Register the image in Kasm by creating a new Workspace pointing to the docker image. Enter the gitlab username in the **Docker Registry Username** field and the Gitlab password or access token under the **Docker Registry Password** field ![Using a Docker Container Registry](/img/building_images/registry_image.webp) ## Custom Launch Forms It is also possible for administrators to present custom forms to users when a workspace is launched. This may be helpful when creating more advanced turnkey solutions for a given workspace. In the following example, a form element is presented to get an authentication key for a Tailscale VPN connection. The workspace container will then use this key to establish the connection. ![Launch Config Form](/img/launch_config/launch_config_example_dash-1.png) See [Workspace Launch Forms](../workspace-launch-form.mdx#launch_form) for more details. ## Understanding `kasm-default-profile` In the Dockerfile template used above, the pre-customization steps set the `HOME` environment variable to `/home/kasm-default-profile`. ```bash ENV HOME /home/kasm-default-profile ``` Then in the post-customizations steps, the `HOME` directory is set to `/home/kasm-user` which eventually is the profile directory used when the container starts. ```bash ENV HOME /home/kasm-user ``` This process is done to support the [Persistent Profiles](../../../data-storage/persistent-profiles.mdx) feature. When a container is not using persistent profiles or the first time a user creates a session when persistent profiles is enabled, the `/home/kasm-user` directory will be empty. When the container starts, if the path `/home/kasm-user` is empty, it will copy the default profile from `/home/kasm-default-profile` to `/home/kasm-user`. If persistent profiles are enabled, the `/home/kasm-user` directory will not be empty for the user's next session. The copy script resides within the Core images and can be adjusted if necessary. It is visible in the [workspaces-core-images Github Repo](https://github.com/kasmtech/workspaces-core-images/blob/develop/src/common/startup_scripts/kasm_default_profile.sh) ## General Docker Images Kasm Workspaces is intended primarily for UI streaming containers, however, Workspaces can also orchestrate containers using any image. Images that are not based on one of the Kasm maintained [core images](https://github.com/kasmtech/workspaces-core-images) will be incompatible with some features. - Web Filtering - URL Categorization - Connecting to container through the UI By default, Workspaces applies a restart policy to containers of 'unless-stopped', which means the container is automatically restarted unless it is manually stopped. This may or may not be desired. To launch containers that perform a task and exit, the default restart policy must be overridden. Workspaces will also run every container as USER 1000 unless overridden. In the Workspaces Admin UI, navigate to Workspaces, edit the desired Workspace and in the **Docker Run Config Override (JSON)** field, set the restart policy to 'on-failure' and optionally the container user as shown here ```Json {"restart_policy":{"Name":"on-failure","MaximumRetryCount":5}, "user": "root"} ``` With this policy applied, when a user creates an instance of this image, it will be automatically removed when the container is finished running. ## Routing Image traffic through a VPN In order to route an image's traffic through a sidecar VPN container please checkout [VPN Sidecar Containers](../../../networking/vpn-sidecar.mdx). --- ## Force Install Custom Chrome Extensions in Kasm Workspaces # Custom Chrome Extensions Administrators may need to force install custom chrome extensions automatically when launching a new instance of a workspace. This guide will cover how to achieve this with [File Mapping](../../file-mappings.mdx). ## Video Tutorial This video will walk you through installing a custom unsigned chrome extension on your workspace. ## Installing Custom Chrome Extensions on your Workspace 1\. Zip your extension's source code directory. Make sure you zip the directory and not the source files. ![Zip source code files with zip command](/img/custom_chrome_extensions/zip_source_files.png) 2\. In your Kasm dashboard, go to "Admin" -> "Workspaces" -> "Edit" -> "File Mapping" -> "Add File Mapping" Set the type to "File Upload" and give it an appropriate name and description. Set the "Destination Path" to something like `/tmp/extension/your-extension.zip` Set both Writable and Executable to Disabled and save the changes. ![Workspace-level file mapping settings](/img/custom_chrome_extensions/file_mapping.png) File Mapping can be set at both the workspace level and at the group level. 3\. In your Workspace's Docker Run Config Override, use the following config (make sure to replace it with your extension's name and path): ```json { "hostname": "kasm", "environment": { "APP_ARGS": "--load-extension=/tmp/extension/your-extension" } } ``` ![Docker run config override](/img/custom_chrome_extensions/run_config.png) Chrome removed --load-extension in Chrome 137 It still works on Chromium and it works for now with --disable-features=DisableLoadExtensionCommandLineSwitch but that will go away in a future version of Chrome. ```json { "hostname": "kasm", "environment": { "APP_ARGS": "--disable-features=DisableLoadExtensionCommandLineSwitch --load-extension=/tmp/extension/your-extension" } } ``` ![Docker exec config](/img/custom_chrome_extensions/exec_config_disable.png) 4\. In your Workspace's Docker Exec Config, use the following config (make sure to replace it with your extension's name and path): ```json { "first_launch": { "user": "root", "cmd": "bash -c 'unzip /tmp/extension/simple-chrome-extension-master.zip -d /tmp/extension/'" } } ``` ![Docker exec config](/img/custom_chrome_extensions/exec_config.png) Your workspace will now have the custom extension loaded to Google Chrome. ![Custom chrome extension in action](/img/custom_chrome_extensions/extension.png) --- ## Docker in Kasm: Rootless vs. Root Setup # Using Docker in a Kasm Desktop Developers may wish to run Docker inside a Kasm Desktop, allowing them to use the disposable container to run and develop Docker containers from their browser. ## Choosing Rootless or Root Docker Workspaces There are two options for running Docker in Kasm. ### Rootless The recommended, more secure method is to use rootless Docker image: [https://hub.docker.com/r/kasmweb/ubuntu-focal-dind-rootless](https://hub.docker.com/r/kasmweb/ubuntu-focal-dind-rootless), [https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind-rootless](https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind-rootless), or [https://hub.docker.com/r/kasmweb/ubuntu-noble-dind-rootless](https://hub.docker.com/r/kasmweb/ubuntu-noble-dind-rootless). The Docker Daemon does not run as root, which mitigates the impact of using `--privileged`. However, the rootless container prevents users from exposing ports with a number lower than 1024 and is also limited to the vfs storage driver regardless of what the underlying host supports leading to some IO overhead and lower performance vs Root. ### Root Running the daemon as root in the Kasm Workspace is insecure, and is only recommended for development deployments. However it removes some of the limitations of the rootless Workspace. It can be found on dockerhub: [https://hub.docker.com/r/kasmweb/ubuntu-focal-dind](https://hub.docker.com/r/kasmweb/ubuntu-focal-dind), [https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind](https://hub.docker.com/r/kasmweb/ubuntu-jammy-dind), or [https://hub.docker.com/r/kasmweb/ubuntu-noble-dind](https://hub.docker.com/r/kasmweb/ubuntu-noble-dind). Use of Docker inside of a Kasm Desktop requires the Desktop to be launched with "Privileged" permissions, running the daemon as root [makes it trivial for a user to run commands as root on the host machine](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/). ## Workspace Configuration - Log into your Kasm Workspaces deployment as an administrator and navigate to Workspaces -> Workspaces and click "Add Workspace" - Configure the Workspace with the following settings: | Field | Value | | :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Docker Image | ``kasmweb/ubuntu-focal-dind:[[release]]`` or ``kasmweb/ubuntu-focal-dind-rootless:[[release]]`` or ``kasmweb/ubuntu-jammy-dind:[[release]]`` or ``kasmweb/ubuntu-jammy-dind-rootless:[[release]]`` or ``kasmweb/ubuntu-noble-dind:[[release]]`` or ``kasmweb/ubuntu-noble-dind-rootless:[[release]]`` | | Description | Docker in a Kasm Desktop | | Friendly Name | Docker | | Cores | 1 | | Memory | 1768 | | Enabled | True | | Docker Registry | https://index.docker.io/v1/ | | Docker Run Config | ``{"privileged":true}`` | - Once the Workspace is created you can launch it by clicking on the "Docker" Workspace from the User Dashboard. ## Storage and performance When running Docker in Docker the default storage driver will be [fuse-overlayfs](https://github.com/containers/fuse-overlayfs) if the storage for the isolated Docker daemon is contained within a Docker volume. To leverage host supported filesystem drivers like [overlay2](https://docs.docker.com/storage/storagedriver/overlayfs-driver/) you can mount the Docker storage directory to the host filesystem: | Image Type | Docker Storage Path | | :--------- | :--------------------------------- | | Rootless | /home/kasm-user/.local/share/docker | | Root | /var/lib/docker | If leveraging [Persistent Profiles](../../data-storage/persistent-profiles.mdx) with a Rootless image this will happen automatically as the home directory for the user will be mounted out of the ephemeral container volume You can check what storage driver the container is running with: ``` docker system info | grep "Storage Driver" --- ## Embedding Kasm in an Iframe # Embedding in an Iframe Kasm Workspaces can be embedded in an iframe. This guide will walk through setting up a single server Kasm instance embedded in a simple iframe. We'll assume a Kasm instance at 10.10.0.10 with the hostname kasm.example.com and a Nginx server hosting the iframe webpage located at 10.10.0.11 with hostname app.example.com. ## Cookies There are two cookies that have to be set during the Kasm authentication request, the username cookie and token cookie when connecting to a running Kasm session. When that session is running inside an iframe those cookies will be blocked by default. ### Using Sibling Domains The best way to handle cookie management between Kasm in the iframe and the parent page is to have the parent page and Kasm be sibling domains (domains that are at the same level with respect to the parent domain) such as: - app.example.com (For the application that will have the iframe containing kasm) - kasm.example.com (For Kasm itself) Configure your webserver (in this example Nginx) to host your website on the new domain name for example app.example.com. Use the hostname for your Kasm instance for this guide, we will use kasm.example.com for this guide. ### Using Sub-Domains You can also use subdomains for cookie management. Such as: - app.example.com (For the application that will have the iframe containing kasm) - kasm.app.example.com (For Kasm itself) This should work for all browsers. However, if there is more than one level separating the two domains, some browsers most notably Safari will not work, for instance: - example.com (For the application that will have the iframe containing kasm) - kasm.app.example.com (For Kasm itself) This is likely to break since Kasm is two levels down from the domain hosting the iframe. ## Example Webpage With Kasm in Iframe Let's start with a simple HTML page that hosts an iframe pointing to Kasm. ```html

Embedded Kasm

``` After saving this HTML file into the root of the webserver (Nginx) and browsing to it, you should see the login page to the Kasm instance. You can log in and browse the instance, but if you try to launch a Workspaces image the connection to the session will fail, and you will be returned to the Workspaces dashboard. This is because Kasm is unable to set the username and token cookies after authentication. We will solve this issue in the next step. Go to Settings / Global and scroll down to the **Kasm Auth Domain**. Here you need to set it to the parent domain, in this example `example.com`, so that the response cookies received back are valid for both the parent page and Kasm. If you don't see the Kasm login screen it could be because you are using self-signed certs for your Kasm instance and will need to accept the cert in your browser by browsing directly to the instance and accepting the certificates before using the iframe. We strongly recommend using valid trusted certificates for all Kasm deployments Now if you browse to the test page you will see the Kasm instance rendered in the iframe, be able to log in, and launch a Kasm session. ## Iframe Permissions Now that the connection goes through when launching a Kasm session you will notice that several things are not working as expected. For instance the microphone may be inaccessible, and Kasm's seamless clipboard experience may not function as expected. This is because the iframe must explicitly be granted the permissions needed for this functionality. Several things must be added to the allow attribute for the iframe: - autoplay - This allows the audio from a Kasm session to start playing without any interaction from the user. Without this permission the user must interact with the iframe before audio will play. - microphone - Without this the browser will not allow Kasm within the iframe to request the microphone permission so microphone capability will be unusable. - camera - Allows Kasm to request access to the users camera/webcam. - clipboard-read - Allows Kasm to read text from the client clipboard. - clipboard-write - Allows Kasm to write text to the client clipboard. - window-management - Allows Kasm to know about the state of your monitors, how many there are and where they are placed. This makes utilising the multi monitor options much more streamlined. - self - Allows the previous permissions to be passed to iframes within the iframe its set on. This matters because the Kasm session connection is an iframe within the Kasm Web App. - https://kasm.example.com ```html

Embedded Kasm

``` Now when browsing to the site and using Kasm in an iframe you will have the full set of capabilities for your Kasm session. --- ## Gamepad Pass-Through for Sessions # Gamepad Pass-through Workspaces supports passing through up to 4 gamepads into the Kasm sessions. Participants in shared sessions may also pass through gamepads. ## Configuration To enable this feature: 1. Set the `allow_kasm_gamepad` [Group Setting](../../security/users-groups-mgmt/groups.mdx) to `true` prior to launching the session. 2. Launch a Kasm session. The `kasmweb/ubuntu-focal-desktop` and `kasmweb/ubuntu-jammy-desktop` images have several gamepad testing utilities included that may help with troubleshooting. The `:develop` tag or versioned tags >= to `:1.12.0` may be used. - Use `jstest-gtk` to test the `udev` interface. - Use `gamepadtool` to test the `sdl2` interface. Available on amd64 images only. 3. Open the control panel on the left side of the session, and select **Gamepads**. 4. Press any button on the connected Bluetooth or USB gamepad(s). If the browser detects the gamepad(s), an entry will be listed for each device. A dropdown will be visible next to each device representing the virtual device port/index ( 0 - 3 ) mapped within the session. These can be changed as desired. Gamepads may not be visible if they are in use by another program, browser, or tab. It may be necessary to close those programs then re-open the current browser. It may be helpful to verify the gamepads can be seen using other [browser-based gamepad testing utilities](https://greggman.github.io/html5-gamepad-test) ## More Details This feature works by connecting to the local USB or Bluetooth gamepads via the browser's GamepadAPI, then passing the gamepad events (button presses) into virtual devices mapped inside the container. The virtual gamepads should be accessible by programs within the session container supporting `udev` or `sdl2` interfaces. A default `sld2` mapping environment variable is defined within the Workspaces Images and may be overridden if desired either by creating a [Custom Image](customization/building-images.mdx), or by updating the variable via [Docker Run Config](workspaces.mdx). ``` SDL_GAMECONTROLLERCONFIG="030000005e040000be02000014010000,XInput Controller,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b16,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7" ``` The virtual gamepad devices are exposed inside the sessions using Xbox controller attributes and use a standard mapping in line with the [GamepadAPI Standard Mapping Spec](https://www.w3.org/TR/gamepad/#dfn-standard-gamepad). ## Known Issues - Chromium based browsers running inside the Kasm sessions will only pick up a single gamepad running on port/index 3. - L2 and R2 triggers are mapped as buttons that support being pressed/not pressed instead of an analog axis. - Rumble/Haptic feedback is not supported. - The feature is not supported on Docker in Docker (DinD) installs including TrueNAS and Unraid integrations. - The feature is not supported on older linux distros/kernels. Please refer to [Kasm Documentation](../../../explanations/system-requirements.mdx) for current supported operating systems. --- ## Image Maintenance: Builds, Testing & Deploy # Image Maintenance Administrators may wish to create and maintain a library of Kasm [workspaces ](../../../reference/glossary.mdx#workspace) with custom software and configurations. They may also wish to ensure Images are always up to date with the latest software patches for improved security and reliability with no user downtime. In this situation, it is recommended for administrators to create a DevOps process for automatically building, testing and publishing custom Images to their Kasm deployment. ## Process Overview The following diagram highlights general steps that may be used to orchestrate an Image maintenance process. - **Build** : Create a repository inside a Version Control System (VCS) (e.g GitLab, BitBucket) to host the custom image Dockerfiles. Utilize automated CI/CD toolchains such as pipelines built into the VCS or standalone tools such as Jenkins to automatically build images based on a schedule. See [Building Custom Images](customization/building-images.mdx) for more details in image creation. **References:** - [GitLab Pipelines](https://docs.gitlab.com/ee/ci/pipelines/) - [BitBucket Pipelines](https://bitbucket.org/product/features/pipelines) - [Jenkins Pipelines](https://www.jenkins.io/doc/book/pipeline/) - **Push** : Utilize the CI/CD toolchain to push the images to a docker container registry. This can be a public registry such as DockerHub, or private registry such those provided by GitLab, AWS, Digital Ocean, etc. The registry must be accessible by all Kasm [agents ](../../../reference/glossary.mdx#agent) in order for them to automatically pull the Images. When defining the Workspaces inside the Kasm UI, utilize the custom docker image name, registry , and if needed a username and password/access token needed to authenticate to the private registry. Consider the naming convention of the docker image tags. It may be beneficial to push an image with multiple tags such as one that represents something unique such as the current date/time `myimage:11302020` and another that represents a moving target such as `myimage:latest` . Consider the [Pull Behavior](#pull-behavior) and how that will impact the desired process. **References:** - [Docker Registry](https://docs.docker.com/registry/) - [GitLab Container Registry](https://docs.gitlab.com/ee/user/packages/container_registry/) - [Digital Ocean Container Registry](https://www.digitalocean.com/products/container-registry/) - [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/) - [Google Cloud Artifact Registry](https://cloud.google.com/artifact-registrydocker) - **Test** : Create a new Workspace and set the Docker image name, Docker Registry, and the Docker Registry Username and Password if authentication is used. Within a few minutes the Agents will pull down the Images from the defined registry. [Assign the Image](../../security/users-groups-mgmt/groups.mdx) to a testing group, and verify the desired functionality.
- **Deploy** : When ready, update the user-facing Images to use the verified docker image name and tag. The next time the user creates a session, the new Image will be used. ## Pull Behavior Kasm [agents ](../../../reference/glossary.mdx#agent) check-in with the Kasm [web app ](../../../reference/glossary.mdx#web-application) service every 30 seconds and will inform the Agent about which Images are defined in the system. If the Agent does not have currently have the Image it will immediately issue a `docker pull`. The default maximum number of image pulls is `2`, and is configurable in section below [Changing MAX Concurrent Docker Pulls](#changing-max-concurrent-docker-pulls). Separately, the Agent will also issue a pull every hour for those images even if they are present on the system in order to fetch an updated version if available. In either case, a pull only occurs if a **Docker Registry** is defined on the Workspace. Some registries such as DockerHub have implemented [Pull Rate Limiting](https://docs.docker.com/docker-hub/download-rate-limit/). Administrators should authenticate to the registry to raise those limits by utilizing the **Docker Registry Username** and **Docker Registry Password** options when registering an image. For the **Google Cloud Artifact Registry** or **Google Cloud Container Registry** a JSON [Service Account Key](https://cloud.google.com/artifact-registrydocker/authentication#json-key) must be entered in the **Docker Registry Password** field and the **Docker Registry Username** must be set to **_json_key**. For the **Google Cloud Artifact Registry** a base64-encoded key can be used instead, with the **Docker Registry Username** of **_json_key_base64**. ## Changing MAX Concurrent Docker Pulls By default, each Kasm Agent will only pull a maximum number of `2` docker images at a time. However, for users running Kasm in environments with more available resources you may want to increase this to satisfy your needs. Changing the MAX Concurrent Docker Pulls involves restarting the Kasm Agent service(s) and will result in an interruption in service. **Login to each server with the agent role and complete the following steps:** Stop the Agent Services ```Bash sudo systemctl stop kasm ``` Replace the value of `max_concurrent_docker_pulls` in the agent config with the new value. ```Bash sudo vi /opt/kasm/current/conf/app/agent/agent.app.config.yaml ``` Start the Agent Services ```Bash sudo systemctl start kasm ``` If you tail the logs of the agent, after 30 seconds, and if you have multiple images pending will see notifications of images now being pulled. ```Bash sudo docker logs -f kasm_agent --- ## IME Support: Input Method Editor Setup # Enable Input Method Editor (IME) Input Method Editor (IME) allows for a user to input characters not represented on a standard QWERTY keyboard. ![IME Inputt Animation](/img/ime/kasm_ime.gif) When IME is enabled Kasm is able to detect what and utilize IME in the Kasm Workspace. There are two ways to enable IME mode in a Kasm session. ## Client-side Open the control panel on the left side of the Kasm Desktop Session using the three dots, select Configure, then enable IME Input Mode. ![Enable IME](/img/ime/ime_settings.webp) ## Server-side There is a group setting *kasm_ime_mode_default_on* that when set to *true* will automatically enable IME mode for any user in the group when they start a Kasm session. For more information see [group settings](../../security/users-groups-mgmt/groups.mdx) ![Group Setting](/img/ime/ime_group_setting.png) Your operating system's IME should now be visible when you type in your session. ![IME in Sublime](/img/ime/ime_example.png) ![IME in Notepad](/img/ime/ime_example_windows.png) --- ## KasmVNC: Applying Data Loss Prevention (DLP) Policies # Applying KasmVNC DLP Policies KasmVNC DLP settings allow for defining rate limits for the clipboard and keyboard input, visible regions, watermarking and more. This guide walks shows examples of DLP configurations and then walks through managing KasmVNC configurations using the [File Mapping](../file-mappings.mdx) feature. ## KasmVNC Configuration The KasmVNC configuration file located at `/etc/kasmvnc/kasmvnc.yaml`, has a lot of configuration options, to include data loss prevention (DLP) settings. For a full reference of the KasmVNC YAML configuration, see the [KasmVNC Docs](https://kasm.com/kasmvnc/docs/latest/configuration.html). It is not necessary for your custom configuration file to specify default settings, this minimizes the size of your custom configurations. You may use [File Mappings](../file-mappings.mdx) to manage the kasmvnc.yaml file and any referenced images for the watermark. This ensures that a custom image is not needed in order to enable watermarking or other custom KasmVNC configurations. The following example will enable an image based watermark and a visible region that blocks clicks in the non-visible region of the screen. ```yaml network: ssl: pem_certificate: ${HOME}/.vnc/self.pem pem_key: ${HOME}/.vnc/self.pem udp: public_ip: 127.0.0.1 data_loss_prevention: visible_region: top: 10 left: 10 right: -40 bottom: -40 concealed_region: allow_click_down: false allow_click_release: false watermark: image: /etc/kasmvnc/kasm.png tint: 20,20,255,60 repeat_spacing: 50 ``` The following example defines a water mark with repeating text, where the text includes the Kasm Workspaces username, user ID, and a timestamp. The text is repeated over the entire display(s) with 50 pixels of padding. For the Kasm username to be available, the `expose_user_environment_vars` [Group Setting](../../security/users-groups-mgmt/groups.mdx#group-settings) must be enabled. ```yaml network: ssl: pem_certificate: ${HOME}/.vnc/self.pem pem_key: ${HOME}/.vnc/self.pem udp: public_ip: 127.0.0.1 data_loss_prevention: watermark: repeat_spacing: 50 tint: 200,200,235,60 text: template: "Kasm Workspaces User ${KASM_USER} (${KASM_ID}) at %F %H:%M" font: auto font_size: 24 timezone_name: Asia/Taipei ``` RedHat, AlmaLinux, Rocky Linux, Fedora, and Oracle operating systems may require an empty line at the end of the yaml configuration file as shown in the example above. ## Applying a KasmVNC Configuration To apply your own custom KasmVNC configuration to Workspace sessions, use the [File Mapping](../file-mappings.mdx) feature. [File Mappings](../file-mappings.mdx) allow you to directly edit files with in the Kasm Workspaces Admin UI and have them mapped into user sessions. File Mappings can be defined on a Workspace, Group, or User, allowing you flexibility in determining which KasmVNC configuration is applied for different use cases. Your custom KasmVNC YAML configuration file should be mapped to the location `/etc/kasmvnc/kasmvnc.yaml`. The following is an example of a File Mapping definition for a KasmVNC Configuration that defines a DLP policy to enforce a visible region within the screen and a watermark. The network portion of the configuration shown is required, as those settings override KasmVNC defaults which are required for it to operate within Kasm Workspaces. A file mapping also needs to be defined for the image to be used as the watermark. Per the yaml configuration above, the image should be mapped to `/etc/kasmvnc/kasm.png`, however, you may change this, as long as what is defined in the yaml configuration at data_loss_prevention.watermark.image is the location defined in the file mapping. The following screenshot shows the DLP policy in action, where the defined visible region starts 10 pixels from the top and 10 pixels from the left and ends 40 pixels from the right and 40 pixels from the bottom. The defined watermark is applied across the entire screen in a repeating pattern with 50 pixels between each image. --- ## Lossless Encoding for High-Quality Streaming # Lossless encoding Kasm Workspaces allows an optional true Lossless mode to be enabled using an installation flag. Before enabling and using this mode, it is important to understand the bandwidth/compute requirements especially in shared environments. Lossless encoding can and will consume all available bandwidth available to a client and is designed to be run on local networks. This means under even moderate motion and activity at 60 frames per second any resolution 1920x1080 and up will likely consume an entire gigabit connection. Bandwidth consumed depends heavily on the client's capabilities, however, most quad core x86_64 CPUs produced after 2014 should be capable of decoding at a sustained 1000mbps. In this document we will be reviewing how to enable and use this mode along with brief technical notes on how this was implemented to function in any modern web browser. ## Enabling Lossless Lossless encoding is disabled by default and enabling it has consequences that can break certain configurations or integrations between Kasm and other systems. Lossless requires [Cross-origin isolation](https://developer.chrome.com/docs/extensions/develop/concepts/cross-origin-isolation), which blocks requests on the page to all external sites. Enabling Cross-origin isolation may break certain configurations such as [branding](../../administration/branding.mdx) or referencing external images for Workspace thumbnails. If you have integrated Kasm Workspaces with other systems, enabling Cross-origin isolation will need to be thoroughly tested with your environment. During installation or upgrade of Kasm Workspaces 1.12.0 or newer you can pass the flag `--enable-lossless`: ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz sudo bash kasm_release/install.sh --enable-lossless ``` ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz sudo bash kasm_release/upgrade.sh --enable-lossless ``` During installation this will set the apropriate headers needed by Lossless mode and the software will detect the presence of these headers unlocking quality level 5 Lossless for all clients connecting to this Kasm Workspaces deployment. ## Using Lossless Enabling lossless is pretty straightforward once enabled by the installation. After connecting to a Workspaces session, navigate to Streaming Quality in the sidebar and move the quality slider all the way to the right (Quality level 5 Lossless). If this option is unavailable re-check your installation/upgrade settings and ensure `--enable-lossless` was passed. ![Lossless Setting](/img/lossless/setting-lossless.webp) With lossless enabled you should be able to play videos/games at near 60fps with very little latency. While Lossless mode will function on any modern web browser the best experience will be had on [Chromium](https://www.chromium.org/) based browsers. ## Technical Background ![Lossless Workflow](/img/lossless/qoi-flow.png) Lossless encoding uses [The Quite OK Image Format](https://qoiformat.org/) which is a very fast to encode and decode lossless image format. While it is a great image format for delivering truly lossless image compression it has no native support in any modern web browser. Without native image decoding support it is necessary to pass the VNC rect images to worker threads to be decoded into raw image data that can be painted to the canvas presented to the end user. The server side headers are needed to enable [SharedArrayBuffer](https://developer.chrome.com/blog/enabling-shared-array-buffer/) support, specifically known as [Cross-origin isolation](https://developer.chrome.com/docs/extensions/develop/concepts/cross-origin-isolation). This enables a high speed in memory methodology to pass the huge amounts data back and forth from the workers to the main browser javascript thread for rendering. These headers specifically in NGINX format: ```bash add_header 'Cross-Origin-Embedder-Policy' 'require-corp'; add_header 'Cross-Origin-Opener-Policy' 'same-origin'; add_header 'Cross-Origin-Resource-Policy' 'same-site'; ``` Because this is all happening manually leveraging WebAssembly and pure CPU decoding the overhead is significant in comparison with decoding native browser formats like JPEG and WebP. For comparative image delivery it is at least double CPU usage and 10x the bandwidth of near lossless JPEG as native image formats can leverage GPU and worker threads baked into the browser for rendering DOM elements. The main advantages of using this form of lossless compression are we are no longer bound by a single thread and the image is truly lossless. When leveraging workers this means we can achieve a higher framerate versus native browser decoding at the expense of bandwidth and CPU overhead. As with anything lossless it is impossible to convey the quality and experience in a video or technical document, it is something that needs to be experienced. --- ## No Resources Available This error has several possible causes, the most common ones are covered below. Before proceeding with troubleshooting this video provides an overview on resource allocation within Kasm Workspaces: ### Checking That the Agents Are Online It's possible the admin has created enough docker agents, but not all of them are enabled. In the admin UI select `Infrastructure` and then select `Docker Agents`, this will display a table of all agents registered with the system. There is a column in the table that displays if the agent is enabled or not. If agents are listed as disabled that should be enabled that may be the reason for the No Resources Available error. Enable the agents and try again after a few minutes. The table below shows both an enabled and a disabled agent. > > Agents that are disabled will not download new images until re-enabled. After enabling an agent that agent > might require some time to download the latest images. > If all the agents that are supposed to be enabled are enabled, then it may be a communication problem. The table on the Docker Agents page in the admin UI also displays a column for the last time the agent reported in to Kasm Workspaces. The heartbeat interval of an agent is configurable in the agent config (in milliseconds) `/opt/kasm/current/conf/app/agent/agent.app.config.yaml`, on each agent server. The default is 30 seconds. In the screenshot below you can see one agent that has not reported for more than 3 days. The first thing to verify if you have an agent that is not reporting in to Kasm Workspaces is to verify that the agent is powered on and that the Kasm agent container is running on the agent. After verifying that the agent is powered on, ssh into the agent and from the command line run `sudo docker ps` to verify the Kasm agent docker container is running. Here you can see that both the `kasm_agent` and `kasm_proxy` containers are up and healthy. If either container is not running, you can restart the Kasm service by running `sudo systemctl restart kasm`. After running this command, verify that the containers have started properly and show a healthy status by running `sudo docker ps` again. Once the containers are running and healthy, try launching your Workspace again. If the agent is powered on and the `kasm_agent` and `kasm_proxy` containers are running then it is likely a communication problem between the agent and the manager/webapp server. A quick diagnostic that can be run is a simple curl between the agent and the manager. SSH into the agent and exec into the agent container. `sudo docker exec -it kasm_agent bash`, then run `curl -v -k https:///manager_api/__healthcheck` filling in the proper manager IP into the URL. If your output looks like below then you have working basic connectivity between the agent and manager, otherwise it will be necessary to troubleshoot what is causing the disruption in communication. ```bash root@04721c171946:/src/provision_agent# curl -v -k https:///manager_api/__healthcheck * Trying :443... * TCP_NODELAY set * Connected to () port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=US; ST=VA; L=None; O=None; OU=DoFu; CN=dev-deployment; emailAddress=none@none.none * start date: Jan 5 17:44:03 2023 GMT * expire date: Jan 4 17:44:03 2028 GMT * issuer: C=US; ST=VA; L=None; O=None; OU=DoFu; CN=dev-deployment; emailAddress=none@none.none * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET /manager_api/__healthcheck HTTP/1.1 > Host: > User-Agent: curl/7.68.0 > Accept: */* > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx < Date: Tue, 31 Jan 2023 18:03:34 GMT < Content-Type: application/json; charset=UTF-8 < Content-Length: 12 < Connection: keep-alive < Etag: "9463df0cbfa20eb19a5b7d1fa0b99cf9a0cbf56f" < Strict-Transport-Security: max-age=63072000 < * Connection #0 to host left intact {"ok": true} ``` - Here are a few items to verify when experiencing communication issues. - Misconfigured cloud provider firewall. - Misconfigured firewall on the agent. - Misconfigured firewall on the webapp servers. - Misconfigured DNS. ### Not enough Free Resources If all the agents are enabled, and you are still seeing the No Resources Available error then it might be that none of the available agents have enough free resources to provision the Workspace container. [CPUs, memory and GPUs](no-resources-available.mdx) are specified when the workspace is defined, there must be a Kasm agent that has at least that number of CPUs, memory, and GPUs available in order to start the Workspace. If there is not an agent that has the required resources free there are three options for increasing available resources. - Override the agents to simulate additional resources. - There are two sets of resources an agent has, the actual physical resources assigned to the agent and the resources the administrator specifies Kasm Workspaces should consider the agent has, this is called [overriding](../../troubleshooting/reverse-proxies.mdx). The documentation link has more information on what overriding is and how to use it. - Even with overridding resources docker cannot start a container that requires more resources than the agent/host has physically available. - Add additional resources to the agent VMs. - If your agents are virtual machines and not bare metal hardware then it is possible to add additional resources to the individual VMs that the agents are installed upon. After modifying the VM assigned resources restart the VM. When the Kasm agent starts it should automatically pick up the increased resources that are available. If you have any [overrides](../../troubleshooting/reverse-proxies.mdx) configured on that agent make sure to update those overrides to reflect the new available resources for the agent. - Add additional agents - If you have already added [resource overrides](../../troubleshooting/reverse-proxies.mdx) to your agents and increased the number of physical resources available to the agent VMs then the next best option is to create additional VMs and install/configure these VMs as additional Kasm agents. Reference the [multi server installation docs](../../../tutorials/install/multi-server-install.mdx) for details. - Kasm Workspaces has the ability to dynamically create additional agents to satisfy demand. See the [Autoscale documentation](sigtrap.mdx) for more details. It is also possible to adjust the resources that a Workspace [requires](no-resources-available.mdx), however lowering the resources assigned to a Workspace container will have performance implications for users. All of these options give Kasm administrators a great deal of flexibility in how they architect and design their Kasm Workspaces solution to ensure that there are enough resources available for their users. It's important to take into account not just the nominal usage case, but also the maximum expected usage scenario in both users and sessions to ensure adequate resources are available. Kasm provides a [deployment and sizing guide](../../../explanations/sizing-operations.mdx) that can help with deciding on the best Kasm architecture. ### The Agent Doesn't Have the Image Requested After an image is added to Kasm Workspaces each agent needs to download that image. The time it takes to download the image will depend on the available bandwidth and the size of the image. It is also possible that there is an error preventing the agents from download the image, like a typographical error in the name of the image. To determine whether that is the case review the logs for errors similar to this: In this case by looking at the error message we can see that `kasmweb/ubuntu-focal-esktop` is misspelled and is missing the `d` in `desktop`. The agent will be unable to pull this image since it doesn't exist and that results in the No Resources Available error. In the case that the Workspace definition is valid you should see two messages from the Kasm agent, one for pulling the image, and one for when the image has successfully pulled. if the Successfully pulled image message is not present and there is no error log present then likely the reason for the No Resources Available error is that the agent has not yet finished pulling the image, wait for the agent to successfully pull the image to resolve the No Resources Available error. An additional way to verify if the image is present on the Kasm agents is to ssh to each agent and run `sudo docker image ls | grep ubuntu` substituting `ubuntu` for the image name that you are looking for. Another problem that can happen with a Workspace is if the image specified in the Workspace configuration is of a different architecture than the agent it is trying to run on. --- ## Running Kasm as Root: Configuration # Running Workspaces as Root By default Kasm containers run as a non privileged user with a UID of 1000. This user can launch programs and perform typical workloads, but cannot install new programs using the system package manager. In order to install packages the package manager must be run as root, this document shows the methods for using sudo or the docker run config to run commands as root. Packages installed in a running container do not persist when the container is destroyed. To have a package be permanently installed an Admin must build it into a custom Workspace, for more details see the [Custom Images Guide](customization/building-images.mdx). Running a container as root is not recommended, as it removes one layer of security for preventing a user from breaking out of the container and gaining access to the host system. There are two main methods of running programs inside the container as root: - Altering the **Docker Run Config** to run the whole container as root. - Using **sudo** run individual commands as root. ## YouTube tutorial ## Running whole container as root Running the container as root is the easiest, as it only requires altering the docker run config, but it comes with some limitations. - If the desktop session refuses to start and enters looping screen of "Creating secure connection" you may have to disable pulse audio. - Some programs, like Mozilla Firefox will refuse to start as root. Enter the **Kasm Workspaces Admin UI**, select **Workspaces** -> **Workspaces** . Edit the Workspace you want to run as root or create a new Workspace. Modify the **Docker Run Config Override** field to include `"user":"root"`. For example: ```json { "hostname":"kasm", "user":"root" } ``` Test launching the Workspace. Running `whoami` should display "root". If the Workspace fails to launch and instead cycles through a "Creating Workspace" and a black screen, then edit **Docker Run Config Override** to disable pulseaudio. The resulting field should look like the following example: ```json { "hostname":"kasm", "user":"root", "environment" : {"START_PULSEAUDIO" : "0"} } ``` If the Workspace launches and `whoami` shows "root" that means the config change is successful and all commands are being run as root. ## Installing and Configuring sudo via Docker Exec Enter the **Kasm Workspaces Admin UI**, select **Workspaces** -> **Workspaces**. Edit the Workspace you want to run as root or create a new Workspace. Modify the [Docker Exec Config](workspaces.mdx#docker-exec-config) field to include the following example of installing sudo and configuring sudo to not require a password. ```json { "first_launch":{ "user":"root", "cmd":"bash -c '/usr/bin/desktop_ready && apt-get update && apt-get install -y sudo && echo \"kasm-user ALL=(ALL) NOPASSWD: ALL\" >> /etc/sudoers'" } } ``` Test launching the Workspace. It may take a few moments for sudo to be installed and configured. After which, it may be used from a terminal. This workflow requires the Kasm session have access to the ubuntu repositories. This script may be modified to work on other distros. ## Building a Workspace with sudo If desired, sudo can be built directly into a custom image. This only goes over the specific configuration required to get the sudo command working, for detailed instructions on building custom images, please see the [Custom Images Guide](customization/building-images.mdx). Follow the Custom Images guide to create a custom Workspace, adding the following to the section of the Dockerfile marked "###Customize Container Here###" . ```bash RUN apt-get update \ && apt-get install -y sudo \ && echo 'kasm-user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers \ && rm -rf /var/lib/apt/list/* ``` When testing the Workspace `sudo whoami` should show "root". Commands can now be run as root by prepending them with `sudo`. kspace `sudo whoami` should show "root". Commands can now be run as root by prepending them with `sudo`. kspace `sudo whoami` should show "root". Commands can now be run as root by prepending them with `sudo`. rkspace `sudo whoami` should show "root". Commands can now be run as root by prepending them with `sudo`. --- ## Sigtrap # SIGTRAP Browser Crash If a Chromium based browser inside the workspace session crashes with a SIGTRAP error, it may be an indication that browser has exhausted the `/dev/shm` shared memory segment allotted to the container. This is more likely to occur if the browser is running a large number of tabs and/or resource intensive pages. ![Browser crashing with SIGTRAP error](/img/troubleshooting/sigtrap/error.png) To reduce the likelihood of this error occurring, the administrator can increase the size of `/dev/shm` for the container by adding a custom value via [docker-run-config](../../troubleshooting/gpu-issues.mdx) on an individual Workspace, or at the Group level. The example below changes the size to `4g` (4 gigabytes). If not defined, the default is `512m` (512 megabytes). ```bash { "shm_size" : "4g" } ``` --- ## Sysbox Runtime for Enhanced Security # Sysbox Runtime The default docker container runtime is "runc". [Sysbox](https://github.com/nestybox/sysbox) is an open-source and free container runtime, originally developed by Nestybox, to function as a drop-in replacement container runtime. Sysbox provides improved container isolation and support of VM workloads. Kasm has the option of using Sysbox to allow Workspaces to run as root or with sudo privileges without comprimising the security of the Kasm Agent server. Using Sysbox with Kasm also provides the ability for Workspaces to run system-level software that is not normally possible in a containerized environment, such as systemd, buildx, and Docker. If a Kasm user needs the ability to install software in a Workspace or use sudo (or root access), Sysbox is a recommended method to keep the Kasm Agent secure against container breakout. Please note that [limitations](#limitations-of-kasm-with-sysbox) apply. The following Kasm Workspaces core images, and all variants built on top of those images, support a systemd init methodology: | Container | Source Code | |---|---| | [kasmweb/core-almalinux-8:[[release]]](https://hub.docker.com/r/kasmweb/core-almalinux-8) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-almalinux-9:[[release]]](https://hub.docker.com/r/kasmweb/core-almalinux-9) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-debian-bullseye:[[release]]](https://hub.docker.com/r/kasmweb/core-debian-bullseye) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | | [kasmweb/core-debian-bookworm:[[release]]](https://hub.docker.com/r/kasmweb/core-debian-bookworm) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | | [kasmweb/core-kali-rolling:[[release]]](https://hub.docker.com/r/kasmweb/core-kali-rolling) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | | [kasmweb/core-opensuse-15:[[release]]](https://hub.docker.com/r/kasmweb/core-opensuse-15) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-suse) | | [kasmweb/core-oracle-8:[[release]]](https://hub.docker.com/r/kasmweb/core-oracle-8) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-oracle-9:[[release]]](https://hub.docker.com/r/kasmweb/core-oracle-9) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-parrotos-6:[[release]]](https://hub.docker.com/r/kasmweb/core-parrotos-6) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | | [kasmweb/core-rockylinux-8:[[release]]](https://hub.docker.com/r/kasmweb/core-rockylinux-8) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-rockylinux-9:[[release]]](https://hub.docker.com/r/kasmweb/core-rockylinux-9) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core-oracle) | | [kasmweb/core-ubuntu-focal:[[release]]](https://hub.docker.com/r/kasmweb/core-ubuntu-focal) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | | [kasmweb/core-ubuntu-jammy:[[release]]](https://hub.docker.com/r/kasmweb/core-ubuntu-jammy) | [Dockerfile](https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core) | This allows any container based off of these core images to be run with the [Sysbox Runtime](https://github.com/nestybox/sysbox) and init with [systemd](https://www.freedesktop.org/wiki/Software/systemd/). When using Sysbox, containers behave much closer to Virtual Machines and allow users in a shared environment to run at root level in their Workspaces with a lower risk of escaping isolation. For additional security enhancements of using Sysbox with your Workspaces check out the [Sysbox User Guide: Security](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/security.md). When using the Sysbox Runtime for a Kasm Workspaces session it may take longer for the Workspaces to be ready as compared to launching with native Docker init. This is due to the general overhead of using shiftfs along with a full systemd init chain needing to be run before the KasmVNC service is finally started. ### Limitations of Kasm with Sysbox These features are incompatible with Sysbox: - Persistent profiles - NVIDIA GPU support within Kasm Workspaces - Limited Storage mapping or Volume mapping support. No support between Workspaces using Sysbox and Workspaces not using Sysbox (see [Using Storage Mapping with Sysbox](#using-storage-mapping-with-sysbox) for more information on this) ## Installing Sysbox Before getting started see the list of supported host operating systems [here](https://github.com/nestybox/sysbox/blob/master/docs/distro-compat.md#supported-linux-distros), and the official installation guide [here](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-package.md). The purpose of this guide is not to replace the existing Sysbox methodology just review our recommended setup for using the `sysbox-runc` runtime. Currently we recommend using an [Ubuntu Jammy](https://releases.ubuntu.com/jammy/) host running the 6.5 LTS kernel as this will have `shiftfs` integrated with the kernel. If you have a Linux kernel version between 5.15 and 6.3, refer to the [Install shiftfs](#install-shiftfs) steps below. The *minimum* compatible Linux kernel for Sysbox is 5.15. To ensure the necessary Kasm dependencies are installed correctly it is recommended to download and extract the Kasm installer. Once done, navigate to the `kasm_release` directory and run the `install_dependencies.sh` script. This will install all Kasm prerequisites including Docker, after which you can [Install Sysbox](#install-sysbox-runtime). ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release_[[release]].tar.gz sudo bash kasm_release/install_dependencies.sh ``` ### Install Sysbox Runtime As mentioned previously this step should be performed after Docker is installed but before Kasm Workspaces is installed. Sysbox can be installed on top of a machine with an active Kasm Workspaces deployment, but we cannot guarantee containers will not be removed or deleted. ```bash sudo apt-get install jq wget wget -O sysbox.deb https://github.com/nestybox/sysbox/releases/download/v0.6.7/sysbox-ce_0.6.7.linux_amd64.deb sudo apt-get install ./sysbox.deb ``` To get the most updated Sysbox download link and for other architectures, please refer to the official [Sysbox GitHub releases page](https://github.com/nestybox/sysbox/releases). Post installation confirm the Docker daemon was configured correctly: ```bash cat /etc/docker/daemon.json ``` ```json { "runtimes": { "sysbox-runc": { "path": "/usr/bin/sysbox-runc" } }, "bip": "172.20.0.1/16", "default-address-pools": [ { "base": "172.25.0.0/16", "size": 24 } ] } ``` ## Configuring Workspaces to use Sysbox Runtime Any Workspace that you would like to leverage the Sysbox Runtime on will need their runtime set to use systemd for init. This can be achieved with the following `Docker Run Config Override (JSON)`: ```json { "runtime": "sysbox-runc", "entrypoint": [ "/sbin/init" ], "user": 0 } ``` This setting can be Workspace specific under `Admin > Workspaces > Edit > Docker Run Config Override (JSON)` or set at a group level with `Access Management > Groups > Edit > Settings tab > Add Setting > run_config`. When using the Sysbox Runtime the Workspace will lose the ability to leverage an NVIDIA GPU using the [NVIDIA Container Runtime](https://developer.nvidia.com/nvidia-container-runtime). DRI3 using open source drivers will still function in a Sysbox Workspace, for more information on that please see the [DRI3 documentation](../../../tutorials/install/manual-intel-amd.mdx). ### Enable sudo for users Now that Sysbox is installed and the Workspace is using it as the designated runtime, it is time to allow sudo for the workspace. Within the Kasm Workspace configuration page, scroll down to the [Docker Exec Config](workspaces.mdx#docker-exec-config) block and add the below JSON block. This code will run as root when the Workspace first launches, then it will install sudo, and add the kasm-user to the sudoers group. To read more about configuring a Kasm Workspace for sudo using Docker Exec, check the [Installing and Configuring sudo via Docker Exec](running-as-root.mdx) docs. ```json { "first_launch":{ "user":"root", "cmd":"bash -c '/usr/bin/desktop_ready && apt-get update && apt-get install -y sudo && echo \"kasm-user ALL=(ALL) NOPASSWD: ALL\" >> /etc/sudoers'" } } ``` ## Using Storage Mapping with Sysbox When using a Storage Provider or Volume mapping configuration with Sysbox, attaching the same Storage Provider or Volume mapping to a non-Sysbox container **will** cause permission problems between Workspaces. The owner of the files and folders in a Sysbox container will be different than the owner of a non-Sysbox container. Read more below to understand why this happens and why it is important. Using Kasm's Storage Provider and/or Volume mapping with Sysbox introduces some differences in the way this feature normally works (for additional information on why, check out the [Sysbox Documentation](https://github.com/nestybox/sysbox?tab=readme-ov-file#how-it-works) as well as their documentation on [User Namespace ID Mapping](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/security.md#user-namespace-id-mapping)). When Kasm starts a Workspace container normally it runs the container as a user called `kasm-user` inside all of it's Workspaces (refer to our [Building Custom Images](customization/building-images.mdx) to see how we do this). This user has a UID (User ID) and GID (Group ID) of `1000`. When Kasm maps Storage or Volume drives to a Workspace the UID/GID of `1000` is used to grant permission to the files and folders in the shared drive. Because of this fact, most of Kasm's [Storage Mapping](../../data-storage/storage-mappings/index.mdx) documentation uses a config similar to the below JSON: ```json { "driver" : "rclone", "driver_opts" : { "type" : "s3", "s3-provider" : "AWS", "s3-env-auth" : "false", "s3-region" : "us-east-1", "uid" : "1000", "gid" : "1000", "allow_other" : "true" } } ``` In the above JSON field, the `"uid" : "1000"` and `"gid" : "1000"` values are used to set the permissions on all of the files and folders in the share to correspond with the `kasm-user` UID and GID so the Workspace user has permission to view and modify files and folders in the mapped volume. To understand how Sysbox changes things it is important to get a good handle on how it is remapping UID and GID values and what Kasm does with those for file and folder permissions. Sysbox changes permissions because it remaps the UID and GID values from the host to random, high values with no or very limited permissions on the host. Under the hood, the `sysbox-runc` runtime uses Docker's [User Namespaces](https://docs.docker.com/engine/security/userns-remap/) to handle this remapping. This allows apparent `root` level access inside the container, while associating all container processes to a random high UID/GID value on the host. To see what this looks like on a host you can `cat` the `/etc/passwd` file to see what users exist and to see their associated UID and GID values. ```bash $ cat /etc/passwd ... opc:x:1000:1000::/home/opc:/bin/sh ubuntu:x:1001:1001:Ubuntu:/home/ubuntu:/bin/bash kasm:x:1002:1002::/home/kasm:/bin/sh sysbox:x:1003:1003::/home/sysbox:/bin/false ... ``` On this host, there are 4 (four) users with login permssions and they have the UID values from 1000-1003 and GID values from 1000-1003. To see the Sysbox remapped UID/GID values you can `cat` the `/etc/subuid` and `/etc/subgid` files on your host after installing Sysbox. ```bash $ cat /etc/subuid opc:100000:65536 ubuntu:165536:65536 kasm:231072:65536 sysbox:296608:65536 ``` ```bash $ cat /etc/subgid opc:100000:65536 ubuntu:165536:65536 kasm:231072:65536 sysbox:296608:65536 ``` When using Sysbox CE, the only user responsible for running containers is the `sysbox` user. Thus, the only UID/GID values of importance in the `/etc/subuid` or `/etc/subgid` files are those associated with the `sysbox` user. In these files it is possible to see that Sysbox has remapped the user `sysbox` with a **host** UID of 1003 and **host** GID of 1003 to the random high UID of `296608` and random high GID of `296608` and has given it a total of `65536` additional UID and GID values for any other required users inside its containers. Thus, **from the host perspective**, when a container runs using the `sysbox-runc` runtime, all processes and file or folder permissions will be associated with the UID and GID of `296608` on this host (*this will likely be different on yours*). From the **container** perspective, however, the user is `root` with a UID and GID of `0`. Below we show running a container with the Sysbox runtime and get some information from it and from the host to demonstrate this process.
Check Sysbox Runtime
```yml ## Run a container using the `sysbox-runc` runtime ubuntu@kasm-agent:~$ docker run --runtime=sysbox-runc --name=sysbox-test --rm -d alpine tail -f /dev/null 2a70c22a9c3af66e3f4f76df3de9cf46dafed97ac7831953b0ebc3561eeeda91 ## Container view using uid_map ubuntu@kasm-agent:~$ docker exec sysbox-test cat /proc/self/uid_map 0 296608 65536 ## User info from within the container ubuntu@kasm-agent:~$ docker exec sysbox-test id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) ## Host process info of `tail` command running inside the container ubuntu@kasm-agent:~$ ps -fC "tail -f /dev/null" UID PID PPID C STIME TTY TIME CMD 296608 171532 171503 0 21:35 ? 00:00:00 tail -f /dev/null ``` Now that we know the UID and GID of the container `root` user is `296608` we must figure out what the UID and GID is of the `kasm-user` used inside of every Kasm Workspace container. Previously we said that the UID and GID of the `kasm-user` inside a Kasm Workspace is `1000`. So, to figure out how we need to modify the Storage or Volume mapping permissions values, we must take the Sysbox `root` UID of `296608` and add `1000` to it to get the **host** UID of the `kasm-user`. **Get kasm-user UID for Storage/Volume Mapping:** ```math 296608 + 1000 = 297608 ``` Aside from the kasm-user UID (1000), the values above are the ones the Sysbox service used for my deployment. **Yours will likely be different!** Now that we have the `kasm-user` UID and GID values we can update our Storage or Volume mapping values so that our file shares work appropriately with these users. ```json { "driver" : "rclone", "driver_opts" : { "type" : "s3", "s3-provider" : "AWS", "s3-env-auth" : "false", "s3-region" : "us-east-1", "uid" : "297608", "gid" : "297608", "allow_other" : "true" } } ``` ## Install shiftfs Application "[shiftfs](https://github.com/toby63/shiftfs-dkms)" is a kernel filesystem for the Linux kernel. It provides easier uid/gid-shifting for containers. Shiftfs is a dependency of Sysbox. Linux kernels 5.15.x and later have shiftfs preinstalled. ### Installing shiftfs While Kernels 5.15-6.3 in Ubuntu Jammy do support shiftfs it is best to install an up to date version for performance reasons. ```bash sudo apt-get update sudo apt-get install -y make dkms git wget git clone -b k5.16 https://github.com/toby63/shiftfs-dkms.git shiftfs-k516 cd shiftfs-k516/ ./update1 sudo make -f Makefile.dkms modinfo shiftfs ``` You should see output similar to: ``` filename: /lib/modules/5.15.0-1031-aws/updates/dkms/shiftfs.ko license: GPL v2 description: id shifting filesystem author: Christian Brauner author: Seth Forshee author: James Bottomley alias: fs-shiftfs ``` At this point shiftfs is ready, but best to reboot the machine before continuing `sudo reboot`. --- ## Web App Gateway: Securely Deliver Web Apps # Web App Gateway Kasm Workspaces can be used to serve web applications to end users through isolated browser containers. This may be helpful if the administrator wishes to provided external users access to the web app while utilizing the robust authentication, security and DLP protections of Workspaces. While most commonly this is used to provide access to internal web applications, any web app can be accessed in the same manner as long as the Kasm Workspaces deployment has network access to it. The following steps can be used to serve isolated Web App Workspaces: 1. [Configuring a browser-based workspace.](web-app-gateway.mdx#configuring-a-browser-based-workspace) 2. [(Optional) Kiosk and App Modes](web-app-gateway.mdx#optional-kiosk-and-app-modes) 3. [(Optional) Assign a Web Filter Policy](web-app-gateway.mdx#optional-assign-a-web-filter-policy) ## Configuring a browser-based workspace. 1. Log into the Kasm UI as an administrator. 2. Select **Workspaces** > **Workspaces**. 3. Select **Clone** next to one of the browser-based Workspaces from the arrow menu (e.g Chrome). ![Clone the Chrome Workspace](/img/isolated_web_apps/clone.webp) 4. Give the workspace a Friendly Name. In this case we will configure the workspace to open Wikipedia, so we will use that as the name. Changing the icon can also be a nice touch, but is optional. Often the website's favicon is a good choice (e.g `https://www.wikipedia.org/favicon.ico`) 5. In the Docker Run Config, replace the contents with the following entry which will define a `LAUNCH_URL` which will be used to automatically navigate the browser to the desired page (e.g `https://wikipedia.org`). Click Save. ```JSON { "environment": { "LAUNCH_URL": "https://wikipedia.org" } } ``` ![Run Config Normal](/img/isolated_web_apps/docker_run_config.webp) 6. Back at the launcher, the Workspace will be shown. ![Launcher in User Dashboard](/img/isolated_web_apps/launcher.png) 7. Launch the Workspace. The Chrome browser will launch inside the session and navigate directly to the desired webpage (e.g `https://wikipedia.org`) ![Workspace View Normal](/img/isolated_web_apps/standard_mode.png) ## (Optional) Kiosk and App Modes In the previous example, you will notice the "browser in browser" view, since the user is being presented the full Chrome browser inside the session container. You may wish to change this user experience and run the Chrome browser in **kiosk** mode. This feature and **app** mode (discussed later) are supported by all Chromium based browsers (e.g Chromium, Chrome, Brave, Vivaldi, Edge). Utilzing kiosk mode should be considered with care, as it may be confiusing for users who don't understand they are operating in a Kasm session. 1. Update the previously created Workspace. Update the `LAUNCH_URL` variable in the Docker Run Config to include `--kiosk`. ```JSON { "environment": { "LAUNCH_URL": "--kiosk https://wikipedia.org" } } ``` ![Run Config Kiosk](/img/isolated_web_apps/docker_run_config_kiosk.webp) 2. Launch a new instance of the Workspace from the launcher. Notice the Chrome browser navigation bar is no longer shown. ![Workspace View Kiosk](/img/isolated_web_apps/kiosk_mode.png) 3. Chrome also offers an **app** mode which is similar to kiosk mode, but adds a title bar. Update the `LAUNCH_URL` variable with `--app=`. ```JSON { "environment": { "LAUNCH_URL": "--app=https://wikipedia.org" } } ``` ![Run Config App Mode](/img/isolated_web_apps/docker_run_config_app.webp) ![Workspace View App Mode](/img/isolated_web_apps/app_mode.png) ## (Optional) Assign a Web Filter Policy Often, when creating web app based workspaces, its desirable to restrict the user to only access the specific site. To accomplish this, administrators may wish to create a Web Filter Policy that denies all sites by default, and only allows a small subset to be visited. Please see [Configuring a Web Filter Policy](../../security/web-filtering.mdx) for more details. It is important to note, that often websites load resources from additional domains. In the case of Wikipedia, it loads additional resources from `wikimedia.org`, so this domain will also need to be added to the Web Filter Policy. You will want to inspect the behavior of your site to ensure all needed domains are allowed for the site to fully function. ![Inspecting a web page for additional domains visited](/img/isolated_web_apps/web_filter_triage.png) ![Denying all sites by default except for a subset specificly utilized by Wikipedia](/img/isolated_web_apps/web_filter_policy.webp) Once defined, update the Workspace definition to utilize the Web Filter Policy. ![Workspace Setting for Web Filter](/img/isolated_web_apps/workspace_web_filter_policy.webp) Trying to access sites not approved by the policy, will result in an **Access Denied** page. ![Access Denied Page](/img/isolated_web_apps/access_denied.png) --- ## Webcam Pass-Through: Setup & Troubleshooting # Webcam Pass-through Workspaces supports passing a webcam feed directly into the Kasm sessions. ## Configuration To enable this feature: 1. Set the `allow_kasm_webcam` [Group Setting](../../security/users-groups-mgmt/groups.mdx) to `true` prior to launching the session. 2. Launch a Kasm session. 3. Open the control panel on the left side of the session, and select *Webcam*. Please note that you may be prompted to grant browser permissions to access the webcam. You can select the webcam device to be used and adjust its settings by navigating to Webcam Settings in the Control Panel ## More Details This feature works by connecting to the local webcam via the browser's Media Capture and Streams API. This process intercepts the video feed and directs it into a virtual webcam device mapped within the container. All programs within the session container that use the `/dev/video0` interface should be able to access this virtual webcam. ### Host Level Requirements To enable the webcam feature in Kasm, it is necessary to meet a critical host level requirement: the v4l2loopback kernel module must be installed and running on the host system. This kernel module facilitates the streaming of video content by creating multiple V4L2 loopback devices, making it possible for the video feed to be intercepted and redirected into a virtual webcam device mapped within the container. As part of the installation process, Kasm installs this kernel module on the following distributions: - Ubuntu 24.04 - Ubuntu 22.04 - Debian 10 - Debian 11 - Debian 12 However, this feature is not limited to the aforementioned distributions; it's supported on any distribution, provided the v4l2loopback kernel module is installed and active. If the module is already installed, its installation can be skipped using the `--skip-v4l2loopback` parameter. For distributions where Kasm does not pre-install this module, users will need to refer to their specific distribution's documentation or community resources for detailed installation instructions for the v4l2loopback module. In such a scenario, the module needs to be installed before the Kasm installation. ### Troubleshooting To check the status of the virtual webcam devices created by Kasm, you can consult the agent logs. These logs should provide you with a comprehensive rundown of the virtual devices, their respective statuses, and any operational anomalies that might have occurred. It's important to note that if there were pre-existing webcam devices on the host system, the Kasm installation will not create new virtual devices. This is because the v4l2loopback kernel module recognizes the existing devices and opts not to duplicate these within the system. If you don't observe any new devices after the Kasm installation, it's likely due to the presence of these pre-existing devices. #### Known issues ##### Kernel lacks videodev Many cloud hosting providers provide custom Linux kernels for all flavors of Linux they provide. In most cases these Kernels will pull out modules that are deemed superfluous for a Linux server and conventionally only used on a Linux desktop. One of these modules is **videodev** which is critical for webcam pass-through to function. The error will resemble: ``` modprobe: FATAL: Module videodev not found in directory /lib/modules/Kernel-Version ``` This can be resolved by installing the extra modules package for your distribution: * **Debian/Ubuntu** - `sudo apt-get install -y linux-modules-extra-$(uname -r)` * **RHEL based** - `sudo dnf install -y kernel-modules-extra` After installation confirm functionality by running: ``` sudo modprobe videodev ``` The command will have no output that means it is working. ##### UEFI Secure Boot If using dedicated hardware or [Azure Linux Virtual Machines](https://azure.microsoft.com/en-us/products/virtual-machines/linux) Secure Boot will need to be disabled in order for webcam pass-through to function. The error to indicate this behavior is: ``` modprobe: ERROR: could not insert 'v4l2loopback': Key was rejected by service ``` On dedicated hardware Secure Boot will need to be disabled in the bios On Azure Linux Virtual Machines Secure Boot will be enabled by default and will need to be disabled at launch time or modified on a running Virtual Machine (This will reboot the Virtual Machine). Navigate to Services -> Virtual machines -> Add -> Virtual machine -> Instance details -> Security type -> Configure security features -> uncheck **Enable secure boot**. ### Performance The overall system resource consumption in using Kasm, specifically in terms of CPU and memory usage, scales in relation to the number of sessions utilizing virtual webcam devices and the frame rate and quality settings chosen. As an example, a single session operating with default settings might utilize around 3% of the CPU's capacity. In contrast, if there are five concurrent sessions, this could potentially consume up to 20% of the CPU. However, bear in mind that these figures are estimations, and actual usage can vary based on numerous factors such as hardware specifications, other system loads, and specific application demands. Importantly, the frame rate selected by the user has a direct correlation with the utilization of internet bandwidth. Higher frame rates translate to a higher image transfer each second, which in turn demands more bandwidth. --- ## Workspace Issues # Advanced Workspace Troubleshooting There are times that a workspace can fail to load because it crashes shortly after launch. From the user’s perspective launching a workspace would seem to work correctly, but end in returning the user to the user dashboard. From the kasm administrators perspective you might see error logs referring to the container or workspace is “is restarting, wait until the container is running". To diagnose the root cause of this error you can enable the advanced feature "container logging" which will redirect all logs generated by the container to Kasm Workspaces. To use this feature: 1. Ensure that `enable_container_logging` in is set to True in the [Group Settings](../../security/users-groups-mgmt/groups/group-settings.mdx). 2. Launch a workspace. 3. View the container logs in the Kasm UI by filtering the `Host` field using the `Session ID`. Note that enabling this group setting will cause the container sessions to be logged for all sessions started by users in that group, and may impact performance due to the high number of log messages generated. --- ## Workspace Launch Forms for Custom Input # Workspace Launch Forms The Kasm Workspaces platform allows administrators and systems integrators the ability to present custom forms to end users when they launch a Workspaces session. The `Launch Config` property defined on the Workspace entry is the schema for the form to present to the user. Once defined, when a user chooses that Workspace from the launcher, the custom form will be rendered to the user to gather the input. The results of the configuration will be placed inside the Workspace session at a defined location. The administrator then can create startup scripts for that Workspaces that can process the information. This feature is available on Container based Workspaces and Server/Server Pool Workspaces if the [Kasm Desktop Service](../server-workspace/windows/kds-windows-service.mdx) is installed. ## Quick Example 1. The administrator defines the `Launch Config` on the Workspace The administrator defines the form element entries in the `launch_form` section. The `file_mapping` section determines where the system will write out the file inside the session so it can be consumed by the administrator's Workspace-specific initialization scripts. ```json { // highlight-next-line "file_mapping": { "destination": "/tmp/launch_selections.json" }, // highlight-next-line "launch_form": [ { "key": "tailscale_key", "label": "Tailscale Auth Key", "value": null, "allow_saving": true, "placeholder": "tskey-auth-xyz", "required": false, "help": "Authentication key used to establish the Tailscale connection", "input_type": "text", "options": [], "validator_regex": null, "validator_regex_description": null, "display_if": null } ] } ``` 2. The `Launch Config` form presented to the user. 3. Per the `file_mapping` section of the `Launch Config` a file is written to disk at `/tmp/launch_selections.json` within the session with the key/value pair of the user's selections. 4. The administrator configures a startup scirpt for the session to parse the user's selections from the file and do something within them. In this example, the command line tool `jq` is used to collect the desired value from the selections file ```yaml #!/usr/bin/env bash set -ex TAILSCALE_KEY="$(jq -r '.tailscale_key' /tmp/launch_selections.json)" tailscaled & tailscale up --authkey=${TAILSCALE_KEY} ``` ## Launch Config Schema The Launch Config JSON schema requires two top level keys: - `file_mapping`: Describes where the user's form selections will be writted to disk. This ultimately leverages the [File Mapping](../file-mappings.mdx) feature under the hood. - `launch_form`: Describes the form elements that should be presented to the user. ```json { // highlight-next-line "file_mapping": { "destination": "/tmp/launch_selections.json" }, // highlight-next-line "launch_form": [ { "key": "tailscale_key", "label": "Tailscale Auth Key", "value": null, "allow_saving": true, "placeholder": "tskey-auth-xyz", "required": false, "help": "Authentication key used to establish the Tailscale connection", "input_type": "text", "options": [], "validator_regex": null, "validator_regex_description": null, "display_if": null } ] } ``` ### file_mapping An object describing where the json file should be written within the Workspace session that contains the user's form selections. ```json { "file_mapping": { "destination": "/tmp/launch_selections.json", "is_readable": true, "is_writeable": false, "is_executable": false } } ``` **Properties** - **destination\* *string***: The file path where the user's launch selections should be written. This will be a json formatted file. Since this feature leverages File Mapping, [Windows Sessions](../file-mappings.mdx#windows-sessions) can leverage special environment variables when defining the path. - **is_readable *bool***: if `true` (default) the file will be readable. - **is_writeable *bool***: If `false` (default) the file will be mounted as a read-only filesystem - **is_executable *bool***: if `false` (default) the file will not be marked as executable. ### launch_form An array of objects (order implied) that describes individual form elements that should be presented to the users. This schema supports defining multiple element types, conditions on when to display certain elements, and input validation options. ```JSON { "launch_form": [ { "key": "vpn_service", "label": "VPN Service", "value": null, "allow_saving": true, "required": true, "placeholder": null, "help": "This is the vpn service", "input_type": "select", "options": [ { "value": "tailscale", "label": "TailScale" }, { "value": "openvpn", "label": "OpenVPN" } ], "validator_regex": null, "validator_regex_description": null, "display_if": null }, { "key": "tailscale_key", "label": "Tailscale Auth Key", "allow_saving": true, "value": null, "placeholder": "Auth Key", "required": false, "help": "The Auth key for tailscale", "input_type": "text", "options": [], "validator_regex": "[\\w\\-]{0,30}", "validator_regex_description": "Alphanumeric, including underscores and hyphens, Max 30 characters.", "display_if": [ { "key": "vpn_service", "value_regex": "tailscale" } ] } ] } ``` **Properties** - **key\* *string***: A unique name for the item. This value is not user facing. The key will be the same key used in the selection output. - **label\* *string***: A user-facing name for the item. - **value\* *string***: The default value to assign for the item. `null` should be used if no default is to be defined. - **allow_saving\* *bool***: When enabled, the end user will be presented the option to cache the selections for this item in their browser, so that they are remembered and pre-populated the next time the form is presented. The default is `false`. - **placeholder\* *string***: Placeholder text that is used inside the form element. This may be a hint to the user for the type of input expected. - **required\* *bool***: If `true`, this item must be filled in by the user before submission is allowed - **help\* *string***: This string will be displayed as a subtitle for the menu item. A short description of the item may be helpful for the end user - **input_type\* *string***: The type of input for this item. Acceptable value are `text`, `select`, `password`, `number`, `textarea`, `passwordtextarea`, `email` - **options\* *array of objects***: Used for `select` input_types. The array of objects (order implied) should each container a `value` and `label` key for the dropdown options to present to the user. If not applicable set this value as an empty array `[]` - **validator_regex\* *string***: A regular express to be used to validate the user's entry. Since this regex is embedded in JSON , quotes and slashes bust be escaped. - **validator_regex_description\* *string***: A description to present to the user if the input does not pass the regular expression validator. It should instruct the user what entries are valid. - **display_if\* *array of objects***: An array of objects that determines when to display this item. Each object should contain a `key` which should match the `key` for another item in this structure, and `value_regex` which runs a test against the `value` of the referenced key. If any of the conditions in this array matches, this item will be displayed to the user. Set this entry to `null` if not applicable --- ## Kasm Workspaces: Managing and Using Workspace Registries # Workspace Registry The Workspace Registry is a mechanism for allowing users to easily install workspaces. This can be from our own 1st party registry or from 3rd party registries. The intention was twofold. First to make it as simple as possible for users to add workspaces without needing to fill in lots of fields, and secondly to make it as simple as possible for anyone to create their own registries without us needing to be gatekeepers. ## Video Tutorial ## 1st Party Registry The 1st party registry comes pre-installed in Kasm Workspaces 1.13.0 or newer and makes it simple to install any of our workspaces that aren't already installed on your system. If you remove the 1st party registry and want it back at any point, our registry store front is located at [https://registry.kasmweb.com/](https://registry.kasmweb.com/) ## 3rd Party Registry 3rd Party repositories allow external developers to create their own workspaces that will work seamlessly with Kasm Workspaces. You should only install workspace registries from 3rd parties that you fully trust. Even then, always review what will execute inside the workspace before installing it. There are multiple ways arbitrary commands can be executed when using a 3rd-party workspace, and **not all of them are visible in the workspace configuration fields.** There are a couple of ways to inspect a workspace definition: 1. Click on a workspace tile and instead of clicking install, click on edit. 2. From the Registry page where you got the Workspace Registry Link, clicking on one of the workspaces takes you to a page that displays all the JSON for that workspace (you can also get to this by clicking the registry logo in the list on registries at the top of the page). Either of these 2 options allows you to see the workspace configuration that is being set. Pay particular attention to anything in the `Docker Run Config Override (JSON)` field (`run_config` in the workspace JSON) or the `Docker Exec Config (JSON)` field (`exec_config` in the workspace JSON) as these fields allow arbitrary commands to be run. If either of these fields are populated and you are unsure of what they are doing, ask the 3rd party to clarify before blindly installing. Even if both `run_config` and `exec_config` fields are empty, the container image itself may still contain malicious or unwanted behavior. A custom image may include: 1. Malicious Startup scripts baked into the image 2. Embedded binaries or background processes that are automatically configured to execute when a session starts Because this behavior is defined inside the image, it may not be visible from the workspace JSON alone. The only reliable way to fully understand what executes at session startup before launching the session, is to review the image’s source, such as the Dockerfile, build scripts, and startup logic. When in doubt, proceed with caution and only install images you fully trust. ## Installing Workspaces To install a workspace, click on the workspace you want to install then click on the install button that appears. If the registry has channels then you will be presented with a dropdown of the possible options, with the default pre-selected. If you want to see exactly what is being installed you can click on the edit button instead. Once you click on the install button, the estimated required space will be added to the size widget located at the top of the screen next to the list of stores. As workspaces finish installing the sizes will recalculate based on the actual size taken. The estimated size is the uncompressed size, and so should be a worst case scenario as any duplicate layers will lower the amount of space used up. The space remaining is based on the remaining space on every agent combined, however by default workspaces are installed on all available agents so potentially it could take up more space then expected. ## Configuration Warnings If a workspace has an orange border and an orange exclamation shield icon to the right of the name, this indicates that the workspace has been flagged as requiring review before installation. The reason for the workspace being flagged will be that it has defined a configuration that may provide elevated privileges or access. The warning doesn't mean that there is a problem with the workspace, just that you should review what it is doing prior to installation. For example, many of the linuxserver.io workspaces are flagged with a warning. By hovering over the exclamation you will receive a tooltip with more information. This tells you that if you click on the edit button instead of install, you should head to the `Docker Run Config Override (JSON)` section and look at the value of the **security_opt** property as that is what triggered the warning. In this case multiple properties are set. `user` is set, but it's set to 1000 so doesn't cause a flag. `entrypoint` is set but is on the list of ignored properties so also doesn't cause a flag. `security_opt` is not on the ignored list and so does cause a flag. We haven't included specific information for security_opt so it gets labeled with the generic `flag_property` identifier (that can be seen as the last item in the tooltip and is the link to this website so you can look up the meaning in the table below). In this specific case the workspace requires a minimum specific version of libseccomp to run, as a convenience the linuxserver.io workspaces are adding `"security_opt":["seccomp=unconfined"]` to ensure that users can just click install and get a functioning workspace. On the downside this does mean the workspace will run without the docker seccomp sandbox and will significantly reduce the amount of protection that Kasm Workspaces can provide. There may be multiple properties that caused a warning and they should all be listed in the tooltip. After the property that caused a flag there is a link to this website with a value to look up on the table below for more information. | Property | Description | | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | user_error | A user has been defined and it's not set to 1000. This often means the user has been set to root. Some workspaces may need to be run as root to function correctly so it's not necessarily a major cause for concern, you should just be more cautious and understand that the workspace has elevated privileges. | | privilege | This workspace is running in privileged mode which grants the workspace root capabilities to all devices on the host | | flag_property | This is a generic flag. What this means is the property that was flagged is not in the list of ignored or safe properties but we haven't added specific information on it yet. You should look up what the property does and if it's a cause for concern manually. | ## Updates Automatic updates are **on** by default with the official Kasm registry, and **off** for 3rd party registries. You can change this by clicking on the ellipsis button on a registry and ticking or unticking `Automatic Updates`. When automatic updates are on, the registry will be updated when you hit the registrly list page. Whether automatic updates are on or off there is a button to manually update the registry as well. Updating a registry will pull the latest available workspaces and any updated configuration but won't affect any currently installed workspaces. If a registry has channels, there will be a dropdown, clicking on the dropdown and making a selection will change the default channel to be used for all workspaces in that registry. This allows you to choose which is the most appropriate channel while still being able to override the choice on an individual workspace. ## Search and filter When on the registry page the same search and category options are available in the top right as when you are on the workspaces page. These allow you to search for specific workspaces or categories. When there is more than one registry installed the option to filter by registry will appear. Clicking on a registries name You can also click on the mini workspace icons under a registries name to just show that registries workspaces. Finally, once you are finished, you can click the **Clear Filters** button next to `Available Workspaces` to easily bring all the options back. ## Create your own workspace registry We have worked hard to try and make it as simple as possible for 3rd party developers to build and maintain their own Workspace Registries. With that goal in mind we have a [github template repository](https://github.com/kasmtech/workspaces_registry_template) which can be used as a basis for your own workspace registry. Full instructions on how to create a registry are included in the README there. ### Schema **Current version:** 1.1 | Property | Required | Description | | :------------------ | :------- | :---------------------------------------------------------------------------------------------- | | friendly_name | True | The name to show | | description | True | A short description of the workspace | | image_src | True | The name of the workspace icon used | | architecture | True | Json list containing either "amd64", "arm64" or both | | compatability | True | A list of dictionaries each containing version, image, uncompressed_size_in_mb, and available_tags. | | categories | False | Json list containing the categories the workspace belongs too. This should be limited to a max of 3. | | docker_registry | False | Which docker registry to use | | run_config | False | Any additional parameters to add to the run config | | exec_config | False | Any additional parameters to add to the exec config | | notes | False | Notes about running the workspace, such as if it requires libseccomp. | | cores | False | Specify the amount of cores to use for this workspace | | memory | False | Specify the amount of memory to use for this workspace | | gpu_count | False | Specify the amount of NVIDIA CUDA GPUs to use for this workspace | | cpu_allocation_method | False | What CPU allocation method to use for this workspace. Can be either "Inherit", "Quotas" or "Shares" | The compatibility property is an array of objects and needs a bit more explanation ```json "compatibility": [ { "version": "1.16.x", "image": "kasmweb/chromium:1.16.0-rolling-daily", "uncompressed_size_mb": 2643, "available_tags": [ "develop", "1.16.0", "1.16.0-rolling-weekly", "1.16.0-rolling-daily" ] } ] ``` * **version** - This is the version of kasm the entry is compatible with * **image** - The docker image. The tag is included for things like estimating the size and is used if there are no available_tags. * **uncompressed_size_mb** - Integer of the approximate size of the workspace when it’s uncompressed in MB. This doesn’t take into account layers. For example if an image is 2.46GB you would enter 2460 * **available_tags** - These values are what will determine the available "channels" on the front end. If you don't want/need channels, remove the available_tags section completely. You shouldn't mix and match though, if you specify available_tags for 1 workspace, it should be specified for all of them. That doesn't mean every workspace has to have all the same tags, if a workspace only has develop tags then it will only show when develop is the selected channel. ## Using workspace registries in Kasm The idea behind Workspace Registries was to try and make it as simple as possible to add and delete the registries. 1. Find a workspace registry. 1. Click the "Workspace Registry Link" button. 1. In Kasm click on the "Workspaces" navigation link. 1. Click on the "Workspace Registry" button. 1. Click on the "Add new" link at the top, and paste into the text box, then click the "Add" button. --- ## Workspace Administration & Configuration # Workspaces Kasm Workspaces allows administrators to define workspaces that users can use to access a desktop, a single application, or another webpage. There are four types of workspaces that can be defined in Kasm Workspaces. Those are: **Containers**, **Servers**, **Server Pools**, and **Links** ## Add / Edit Workspaces From the Workspaces menu you can edit existing Workspaces or add new Workspaces. Each Workspace has a number of properties, the following properties are common for each Workspace type. | **Name** | **Description** | | --- | --- | | Enabled | The Workspace is enabled for use. If unchecked the Workspace will not be available for users to provision. For Container-type Workspaces, Agents will not be given instructions to download disabled images. | | Workspace Type | The type of Workspace, options are Container, Server, Server Pool and Link. | | Friendly Name | Workspace name shown to user. | | Description | Description of Workspace. | | Thumbnail URL | (Optional) URL of Workspace icon. | | Include Labels | (Optional) When this setting is configured, sessions will only start on servers or agents that have at least one of the specified labels. | | Exclude Labels | (Optional) When this setting is configured, sessions will only start on servers or agents that do not have any of the specified labels. | | Enabled | The Workspace is enabled for use. If unchecked the Workspace will not be available for users to provision. For Container type Worksapaces Agents will not be given instructions to download Images that are disabled. | | Categories | (Optional) Define a list of categories the Workspace belongs to. These categories will be displayed on the Workspaces dashboard for uses to select. The first category listed is the one displayed for the Workspace when looking at a list of all Workspaces. | | Session Banner | **Inherit** will use any banners that are applied by a group setting. **Force disable** will override any group settings and not show a banner. Selecting a specific banner will override any group settings and display that banner for this workspace. [See Banners documentation.](../banners.mdx) | | Hide Workspace on Dashboard | Do not show the Workspace as available on the user dashboard. | | Notes | (Optional) A free form field used for taking notes about the Workspace. This is only displayed when editing or viewing a Workspace configuration. This is a great way to let other admins know about anything specific to this Workspace. | The Workspaces are by default added to the all users group. This behavior can be changed with the [Add Workspaces To Default Group](../../../reference/settings.mdx) server setting. ## Containers **Containers** are what have been traditionally referred to as images in the Kasm Workspaces ecosystem. These are Linux docker images that have applications installed, that are then provision by docker as containers and streamed to the user over KasmVNC. See [Images](custom-images.mdx) for more details on available default docker images and creating custom docker images. Attributes that are specific to **Container** type Workspaces are below: | **Name** | **Description** | | --- | --- | | Docker Image | The Docker Image and tag. | | Cores | Amount of CPU cores allocated per Workspace. | | Memory | Amount of Memory allocated per Workspace, in megabytes. | | GPU Count | When the session is created, the system will map in this many GPUs into the the container. See [Agent Settings](../../infra-autoscale/docker-agent.mdx#gpu-support). | | Uncompressed Image Size (MB) | The estimated size of a container image (in megabytes) when extracted to disk. When defined, the Agent can guard against pulling an image if it would result in filling the disk. More specifically, the volume where the Docker Root Directory resides (default: /var/lib/docker). By default the Agent will avoid pulling an image if it would result in the disk becoming over 90% full. The `disk_usage_limit` setting can be changed in the Agents config: `/opt/kasm/current/conf/app/agent/agent.app.config.yaml` | | CPU Allocation Method | Sets the CPU Allocation Method for the Workspace. Selecting **Inherit** will cause the Workspace to use the Global Setting **Default CPU Allocation Method**. See [CPU Allocation Method](../../../tutorials/remote-browser-isolation.mdx) for more details. | | Docker Registry | The docker registry to pull the docker images from For Docker Hub use https://index.docker.io/v1/ Leave this option blank if you intend to use local images built directly on the Agent server. | | Docker Registry Username | (Optional) Username. | | Docker Registry Password | (Optional) Password. | | Hash | (Optional) hash of docker image. | | Persistent Profile Path | (Optional) Absolute path of the location to store user's persistent profile or S3 URL. See [Persistent Profiles](../../data-storage/persistent-profiles.mdx) for more details. | | Enforce Workspace Persistent Profile | Enabling this option will ensure that persistent profiles for this workspace are always enabled. | | Volume Mappings | (Optional) Json data for [Volume Mappings](../../data-storage/volume-mapping.mdx). | | Docker Run Config Override | (Optional) Json data for specifying additional docker run arguments, see [Docker Run Config](workspaces.mdx#docker-run-config) for more info. | | Docker Exec Config | (Optional) Json data for specifying commands to be executed when a Workspace container is started or resumed. See the [Docker Exec Config](workspaces.mdx#docker-exec-config) for details. | | Launch Config | (Optional) Json data for specifying a custom form to present to the user when the workspace is launched. See [Workspace Launch Forms](workspace-launch-form.mdx) for more details. | | Web Filter Policy | Enables web filtering and sets the [Web Filter Policy](../../security/web-filtering.mdx) to be used. Policies can also be set via Group Settings. Policies assigned to Workspaces take priority over those defined via Group Settings. Selecting **Inherit** will instruct the system to use a policy if defined on a Group Setting. Selecting **Force Disabled** will instruct the system to not use a policy even if one is defined in a Group Setting. | | Allow Network Selection | When enabled, users will be presented with a dropdown of available docker networks when creating a session. The list of available networks can be limited if **Restrict Workspace to Docker Network** is configured. | | Restrict Workspace to Docker Network | (Optional) Instances of this Workspace will only be created on agent servers with this docker network. | | Restrict Workspace to Kasm Agent | (Optional) Instances of this Workspace will only be created on this agent server. | | Restrict Workspace to Deployment Zone | (Optional) Instances of this Workspace will only be created on Agents within the selected [Deployment Zone](../../../reference/glossary.mdx#deployment-zone). | | Session Time Limit | The amount of time (in seconds) before a session will automatically expire. A countdown timer will be displayed to the user. | | Direct Install URL | Workspaces and casting links can be installed as standalone PWA applications, this is the direct url that can be used for automatic installation via management systems such as Windows Group Policy and Chrome Managed Policies. | | Override Egress Gateways | When Enabled, the Egress Gateways mapped to this Workspace will be the only gateways available to select during launch. Users will also be required to launch this Workspace using an Egress Gateway if one there is one mapped. | ### Docker Exec Config The Docker Exec configurations allow administrators to configure custom commands to be executed when a user creates or resumes a Kasm. This JSON dictionary configuration accepts three top-level keys **first_launch**, **go**, and **assign**. - first_launch : This command is executed after the session is launched. - go : This command is executed when the user requests to create or resume a session via the /go url. If the session doesn't exist yet, and will be created for the first time, the **first_launch** command is used instead. If the user is assigned a [Staged Session](../sessions/session-staging.mdx) as part of the request, the **assign** command will be used. For resumed sessions, `KASM_URL` is only populated when the request includes the `kasm_url` query parameter. - assign : This command is executed when the user is assigned a [Staged Session](../sessions/session-staging.mdx) via direct request, the /go url, or via `request_kasm` api The following example demonstrates how to use the Docker Exec Config for the default **kasmweb/ubuntu-noble-desktop** Image for a seamless browser isolation configuration. See [Browser Isolation](../../../tutorials/remote-browser-isolation.mdx) for more details. ```JSON { "first_launch": { "cmd": "bash -c 'URL=\"${KASM_URL:-$LAUNCH_URL}\"; [ -n \"$URL\" ] && /usr/bin/filter_ready && /usr/bin/desktop_ready && google-chrome --new-window --start-maximized \"$URL\"'", "environment": { "LAUNCH_URL": "https://www.wikipedia.org" } }, "assign": { "cmd": "bash -c 'URL=\"${KASM_URL:-$LAUNCH_URL}\"; [ -n \"$URL\" ] && /usr/bin/filter_ready && /usr/bin/desktop_ready && google-chrome --new-window --start-maximized \"$URL\"'", "environment": { "LAUNCH_URL": "https://www.wikipedia.org" } }, "go": { "cmd": "bash -c 'URL=\"$KASM_URL\"; [ -n \"$URL\" ] && /usr/bin/filter_ready && /usr/bin/desktop_ready && google-chrome --new-window --start-maximized \"$URL\"'" } } ``` `KASM_URL` is only an environment variable. The image command or startup script must consume it for any URL to open. Browser images in the official registry already include this behavior. Desktop images require an explicit `exec_config` like the example above. ### Docker Run Config The Docker Run Config Override setting may be used by administrators to pass custom docker run options when the session container is created. Many items that can be invoked by the `docker run` commandline tool can be defined in the json structure mirroring the keyword arguments defined in the docker python API `Container.run` function. Detailed specs can be found in the [Docker SDK for Python Documentation](https://docker-py.readthedocs.io/en/stable/containers.html#docker.models.containers.ContainerCollection.run) #### Variable Substitution The following variables can be templated into the storage mapping `Default Target` and `Volume Config` properties to support additional use-cases. Note: Variable substitution is not compatible with [Session Staging](../sessions/session-staging.mdx). - `{username}` - The username of the user provisioning the session. e.g `user@kasm.local` - `{user_id}` - The user_id of the user provisioning the session . e.g `6c0535dc02eb49c4a556cae9816a585d` - `{image_id}` - The image ,aka workspace, id used for the session. eg. `9de4ea298f064e6999c5b9b164e2c04c` - `{custom_attribute_1}` - The custom attribute 1 value from the user. - `{custom_attribute_2}` - The custom attribute 2 value from the user. - `{custom_attribute_3}` - The custom attribute 3 value from the user. #### Examples **Setting environment variables.** ```JSON { "environment": { "FOO": "BAR", "BIN" : "BAZ", "CUSTOM_ATTRIBUTE_1": "{custom_attribute_1}" } } ``` **Setting the language and timezone.** Using the above environment variables syntax it's possible to set the language and timezone that the Kasm container will use. In Kasm Workspaces 1.14.0 many locales were added to the Kasm containerized workspaces in the official Workspaces Registry. See [Valid Timezones](../../../valid-timezones.mdx) and [Valid Locales](../../../valid-locales.mdx) ```JSON { "environment": { "LC_ALL": "fr_FR.UTF-8", "TZ" : "Europe/Paris" } } ``` **Setting Virtual Printer Name** Using the environment variables it's possible to set the name of virtual printer that the Kasm container will use. Please note that the name should not include any spaces. ```JSON { "environment": { "KASM_PRINTER_NAME": "Virtual-Printer" } } ``` **Setting the container hostname.** ```JSON { "hostname": "HOST-123" } ``` ```JSON { "hostname": "{user_id}" } ``` **Setting the user. see [Running as root](running-as-root.mdx) for more details** ```JSON { "user": "root" } ``` **Mapping in devices.** ```JSON { "devices": [ "/dev/input/event0:/dev/input/event0:rwm", "/dev/net/tun:/dev/net/tun:rwm" ] } ``` **Adjusting security options.** ```JSON { "security_opt": [ "seccomp=unconfined" ] } ``` **Adjusting the size of /dev/shm.** ```JSON { "shm_size" : "4g" } ``` **Running the container as privileged.** ```JSON { "privileged" : true } ``` **Adding / Removing Linux Kernel capabilities.** ```JSON { "cap_add" : ["SYS_ADMIN", "MKNOD"], "cap_drop" : ["SYS_RESOURCE"] } ``` **Adding Custom DNS Servers. See [Custom DNS Servers](../../networking/custom-dns-servers.mdx) for more info.** ```JSON { "dns": [ "208.67.220.220", "208.67.222.222" ] } ``` **Adding fixed hostname mappings to /etc/hosts.** ```JSON { "extra_hosts": { "testing1.example.com": "10.0.0.1", "testing2.example.com": "10.0.0.2", "testing3.example.com": "10.0.0.3" } } ``` **Adding custom labels.** ```JSON { "labels": { "kasm.username": "{username}", "kasm.user_id": "{user_id}" } } ``` ### GPU Hardware GPU hardware can be utilized for NVIDIA CUDA compute, graphics, and/or video acceleration and often times systems may have multiple GPUs with different capabilities. The settings in this section define what this image requires and/or prefers for each GPU feature. This feature uses the NVIDIA container runtime. ![File Mappings Table](/img/images/image_gpu_settings.webp) #### NVIDIA CUDA GPU Count This setting defines how many NVIDIA CUDA capable GPUs must be passed through to the resulting container. The container will only be provisioned on an agent that has at least this number of NVIDIA GPUs. #### Graphics Acceleration Method Preference This is the method that will be used to provide graphics acceleration to the desktop and applications. This is separate from the NVIDIA CUDA GPU, however, if a NVIDIA GPU is already passed through and one of the graphics methods is compatible, it will use the already passed through NVIDIA GPU for graphics as well. DRI3 is the preferred graphics acceleration method as it is natively supported by KasmVNC without using an external translation layer. DRI3 is supported by most Intel and AMD GPUs, but is not supported by NVIDIA. For NVIDIA GPUs you will need to use EGL (VirtualGL) or VULKAN (Zink). VirtualGL enables native OpenGL applications to run on a GPU using an EGL-based context in headless environments, while Zink provides a translation layer that implements OpenGL on top of Vulkan. Modern AMD and Intel GPUs generally support DRI3, EGL, and VULKAN. Enterprise grade NVIDIA GPUs may not support graphics at all, especially if they are configured to use MIG. The default MESA option refers to software based `llvmpipe` graphics. The selected list is ordered and the system will attempt to use each in the list in the order it is shown. If the image is set for DRI3, EGL, and MESA and the container ends of on an agent with only an NVIDIA GPU, it will end up using EGL. If no agents are available with a GPU, it will use MESA. #### Video Encoding Acceleration Method Preference This setting defines what should be used for video encoding. VAAPI is supported broadly by Intel and AMD GPUs, with varying support for different codecs, depending on the exact model. NVIDIA GPUs support NVENC, see NVIDIA documentation for details on what your model supports. Enterprise grade NVIDIA GPUs may not physically support NVENC. The SW option means software based encoding. If you remove SW from the selected list and there is no agent with a compatible GPU, the session will fail to get created. Therefore, in most circumstances you would include SW at the end of the list. #### GPU Selection When a workspace session is provisioned, the system evaluates the CUDA GPU Count, Preferred Graphics Mode list, and Preferred Video Encoding list configured on the image to determine which GPU or GPUs should be passed through to the container. An agent may have multiple GPUs with differing capabilities, and the selection process attempts to find the most efficient configuration, ideally satisfying CUDA, graphics, and video requirements with a single device. Selection of CUDA GPUs is prioritized and the load of sessions assigned to each GPU is evaluated, with new sessions round robin assigned to GPUs, selecting the GPU(s) with the fewest Kasm sessions assigned. Kasm may pass through a different GPU for CUDA, graphics, and video to satisfy the requirements and load balancing. For example, if you had configured 1 CUDA GPU Count and configured `DRI3` as the only graphics method, it would have no option but to assign one NVIDIA GPU and one AMD/Intel GPU to satisfy the requirement, as NVIDIA does not support `DRI3`. #### GPU Exclusions Administrators can exclude specific GPUs from CUDA, graphics, or video selection independently. An excluded GPU is skipped during candidate evaluation for that feature, allowing precise control over which physical devices are used for each workload type. Exclusions are configured in the Agent settings. #### GPU Limitations These are the known limitations as of Kasm Workspaces 1.19.0. * NVIDIA's beta driver R595 adds [support for DRI3](https://www.phoronix.com/news/NVIDIA-595.45.04-Linux-Beta). At this time Kasm Workspaces will not detect DRI3 on NVIDIA GPUs, even if using a driver with DRI3 support. Administrators can still manually pass through the GPU by setting the CUDA GPUs to 1 and then manually configure KasmVNC to use the DRI node and [enable hardware acceleration](https://docs.kasmvnc.com/docs/developer/gpu_acceleration#enabling-gpu-acceleration-in-kasmvnc). This has not been tested by Kasm Technologies at this time. * Kasm automatically detects which features are supported by each GPU on the system. For NVIDIA GPUs, the NVIDIA container runtime injects the appropriate user space libraries into the container we use to detect features, this ensures our container matches the host driver version. This generally makes NVIDIA GPUs reliably work in most scenarios. Intel and AMD GPUs on the other hand rely on the built in generic drivers available in the Debian apt repositories. Some newer GPUs from Intel and AMD that are not supported by these older drivers may not be fully supported. * Newer Intel Arc GPUs that require Intel's driver from their [PPA](https://dgpu-docs.intel.com/driver/client/overview.html) may not be detected by Kasm Workspaces. In our testing, Kasm Workspaces detected DRI3, Vulkan, and EGL support but was unable to detect support for VAAPI on newer Intel Arc cards. * KasmVNC can only be configured to use a single DRM device. There are two features of KasmVNC that need a DRM device, DRI3 for graphics acceleration and VAAPI for hardware accelerated video encoding. Kasm Workspaces attempts to pass in a single GPU to meet graphics and video acceleration needs, however, in some rare cases two GPUs may be selected to meet graphics and video acceleration settings on the workspaces image. * Late model Intel Arc GPUs will be detected as supporting DRI3, but not VAAPI. If there is another GPU on the system that supports VAAPI and the workspaces is configured to require VAAPI for video acceleration, Kasm will pass through both GPUs, however, since KasmVNC can only be configured to use a single DRM device, DRI3 graphics acceleration will function but video encoding acceleration will not function properly. There is potential that a custom Workspace image that includes the Intel driver from the Intel PPA could allow VAAPI to function properly, however, this has not been tested by Kasm Technologies at this time. #### Workspace Image GPU Support Not all Workspaces images support all GPU features that can be configured for a workspace. Enabling an unsupported feature can fail silently, meaning the workspace will successfully launch but the configured feature will not work. In other cases, enabling the feature will result in workspaces that fail to start. In some rare cases, the workspace will launch but applications may have issues. The following chart details the compatibility of each Workspaces Core image with each GPU feature. | **Image** | **DRI3** | **EGL** | **Vulkan** | **VAAPI** | **NVENC** | **CUDA** | | --- | :---: | :---: | :---: | :---: | :---: | :---: | | KasmOS | ✔ | ✗ | ✗ | ✔ | ✔ | ✔ | | Ubuntu Jammy | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | Ubuntu Noble | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | Debian Bullseye | ✔ | ✔ | ✗ | ✔ | - | ✔ | | Debian Bookworm | ✔ | ✔ | ✗ | ✔ | ✔ | ✔ | | Debian Trixie | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | Oracle 8 | ✔ | ✔ | ✗ | - | ✔ | ✔ | | Oracle 9 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Red Hat 9 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Rocky Linux 8 | ✔ | ✔ | ✗ | - | ✔ | ✔ | | Rocky Linux 9 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Alma Linux 8 | ✔ | ✔ | ✗ | - | ✔ | ✔ | | Alma Linux 9 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Open SUSE 16 | ✔ | ✔ | ✔ | - | - | ✔ | | Fedora 42 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Fedora 43 | ✔ | ✔ | ✔ | - | ✔ | ✔ | | Alpine 3.21 | ✔ | - | ✗ | ✔ | - | - | | Alpine 3.21 | ✔ | - | ✗ | ✔ | - | - | | Alpine 3.23 | ✔ | - | ✗ | ✔ | - | - | ✔ Feature works as expected.   ✗ Workspace will fail to launch if this feature is enabled.   ✗ Workspace may launch but be unstable or not work as expected.   **-** Workspace will launch but this feature will be inactive. ### File Mapping File Mappings allow the administrator to manage files to be mapped to the inside of a user's container based Workspace session. File Mappings can be defined on a User, Group, and/or Workspace. See the primary documentation on [File mappings](../file-mappings.mdx) for more details. File Mappings are only visible when editing an existing container based Workspace. To configure File mappings for a Workspace, Navigate to Workspaces, then select Edit next to desired container based workspace. ![File Mappings Table](/img/images/file_mappings.webp) The following is an example File Mapping of a Chrome Managed Policy to define bookmarks in Chrome. ![File Mapping Definition](/img/images/file_mapping.png) ## Links **Links** are a way to define another webpage that will be presented in the workspaces dashboard for users to access. This could be a company website like time sheet tracking or a ticketing system, or an external website such as Google Drive or microsoft OneDrive. Attributes that are specific to **Link** type Workspaces are below: | **Name** | **Description** | | --- | --- | | URL | The URL to direct the user to when clicking on this Workspace in the dashboard. | ## Servers **Servers** are workspaces intended to define a single physical or virtual server. This server can be connected to from Kasm Workspaces via KasmVNC, RDP, VNC, or SSH. Attributes that are specific to **Server** type Workspaces are below: | **Name** | **Description** | | --- | --- | | Server | Dropdown to select the defined Server entity to use for this Workspace. | | Session Time Limit | The amount of time (in seconds) before a session will automatically expire. A countdown timer will be displayed to the user. | | Launch Config | (Optional) Json data for specifying a custom form to present to the user when the workspace is launched. See [launch-config](workspace-launch-form.mdx) for more details. | | RDP Client Options | When the workspace definition targets a server with RDP connection type the administrator has the option of having the Workspace use *Web native client* for using Kasm's browser native connection to the RDP target or *RDP local client* to use the RDP thick client that is installed on the users client machine. Admins can allow the user to choose when they launch a session by setting this to *User Selectable*. | | Enable RemoteApp | Uses Microsoft RemoteApp to provide a user an application running remotely that appears to be running on the user's local system. | | RemoteApp Program Name/Path | The registered RemoteApp name in the format ` of the RemoteApp as registered in the backend system. Alternatively, the full path to the application executable can be provided if the server is configured to allow this, `C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe` for example. See the RemoteApp subsection below for more details. | | RemoteApp Arguments | (Optional) Arguments to be provided when executing the RemoteApp program. | ### Server Assignment Servers can be assigned to specific Users if they are part of a Server Pool that allows assignment. See the [Server Pool section](#user-server-assignment) below for more information. ### RemoteApp Microsoft's RemoteApp feature of Windows and Remote Desktop Services allows for users to run applications on remote systems, but make them appear as if they are running on their local system. Kasm supports RemoteApps as either WebNative and displayed within the user's browser or via RDP where the apps appear to be running as local applications. When the Workspace RDP Client Option is set to **Web native client** there is a current limitation that Kasm can only assign a single concurrent sesssion per user on each server. When selecting **RDP local client** as the RDP Client Option setting, there is no such limit. RemoteApps can be configured in Kasm by a RemoteApp name or by a fully qualified path to the application's executable, as covered in the following two sub-sections. For servers that are not part of an RDS deployment, whether AD joined or not, it is generally not required to register the RemoteApp or configure a group policy as shown below. Administrators can instead set the **RemoteApp Program Name/Path** value to the fully qualified path to the executable. RDS deployments will require a group policy to allow specifying an executable path or you will need to register the RemoteApp in RDS to reference it by name in the Kasm Workspaces settings. Administrators should install the [Kasm Desktop Service](../server-workspace/windows/kds-windows-service.mdx) when users will access RemoteApps using Kasm's web native client. The Kasm Desktop Service will ensure that when a user closes a web native session, the associated RemoteApp and Terminal Session on the Windows server will be closed. This is not required for RemoteApps where a RDP native client is used. When **Enable RemoteApp** is on and the **RemoteApp Program Name/Path** is a local executable path, the Kasm Desktop Service must be installed for web native client sessions. If the RemoteApp is published and referenced by name (for example `||Microsoft Edge`), the Desktop Service is not required. Without the service, sessions may fail with "Session closed." #### Registering a RemoteApp RemoteApps can be created in an RDS deployment and then referenced in Kasm Workspace settings by the RemoteApp name. See the Microsoft documentation for more details on publishing RemoteApps in RDS: [https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-create-collection](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-create-collection). Following these steps, you can configure a Workspace's **RemoteApp Program Name** to `||Microsoft Edge`, for example. Ensure the name is prepended with the two pipe characters. To register RemoteApps on servers that are not part of RDS, whether domain joined or not, follow these steps. This is not required if you prefer to provide the full path to the executable as covered in the next section. * Launch `regedit.exe` as an adminstrator * Naviate to `HKLM\Software\Microsoft\Windows NT\CurrentVersion\Terminal Server` * Create a new key `Applications` * Create a new key in Applications named after your application, such as `Microsoft Edge`. * Create the following values under your new key created in the previous step. The following is an example for Microsoft Edge. The **Name** and **Path** are required, the rest are optional registry entries: | Name | Type | Example | |-------------|---------|--------------------------------------------------------------| | Name | string | Microsoft Edge | | Path | string | C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe | | VPath | string | C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe | | RequiredCommandLine | dword | 00000001 | | IconPath | string | C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe | | IconIndex | dword | 00000000 | | ShowInTSWA | dword | 00000000 | Following these steps, you can configure a Workspace's **RemoteApp Program Name** to `||Microsoft Edge`. #### Configure RemoteApp Path Rather than registering a RemoteApp and specifying the name in the **RemoteApp Program Name/Path** field of the Workspace settings, administrators can specify the fully qualified path to the executable of the application on the remote system. For RDS deployments a group policy must be applied to the system that allows this. The Group/Local Policy is found under **Computer Configuration > Administrative Templates > Windows Components > Remote Desktop Services > Remote Desktop Session Host > Connections** called **Allow remote start of unlisted programs**. For standalone servers that are not part of an RDS deployment, it is not necessary to apply this change. ## Server Pools **Server Pools** are groups of **Servers** that are to be treated equally by Kasm Workspaces. These server instances don't need to be identical, but Kasm Workspaces will treat each server in a **Server Pool** as interchangeable. For instance, you may have a Server Pool that contains a Windows server with Microsoft Office installed and a Linux Ubuntu server with LibreOffice installed. When a user requests a server from this Server Pool, Kasm Workspaces will use whichever of the two servers is available. Attributes that are specific to **Server Pool** type Workspaces are below: | **Name** | **Description** | | --- | --- | | Pool | Dropdown to select the defined Server Pool entity to use for this Workspace. | | Session Time Limit | The amount of time (in seconds) before a session will automatically expire. A countdown timer will be displayed to the user. | | Launch Config | (Optional) Json data for specifying a custom form to present to the user when the workspace is launched. See [Workspace Launch Forms](workspace-launch-form.mdx) for more details. | ### User-Server Assignment Server Pools of the `Server` type support assignment of specific Users to specific Servers. Workspaces for pools with assignment enabled will create sessions only on Servers within the pool that are assigned to a given User. For example, if `User 1` is assigned only to `User1 Linux` in the Server Pool, then `User 1` will always receive a Session on `User1 Linux`. ![One Assigned Server](/img/sessions/server_pool_one.webp) If a User is assigned to more than one Server: * They may pick which server to use for the new session ![Select Assigned Server](/img/sessions/server_pool_specific.webp) * If they do not choose a server, then one will be selected based on Zone load distribution configurations ![Automatic Assigned Server](/img/sessions/server_pool_any.webp) If a User does not have an assigned Server but has the Workspace on their dashboard, then the Workspace will show with a warning. They will be instructed to contact an Administrator for support. ![No Assigned Server](/img/sessions/server_pool_none.png) #### Reverting to an Unassigned Pool If assignment is turned off for a Server Pool, all Servers in the pool are considered available for use by all Users that can access the Workspace. #### Additional Resources See the [User-Server Assignment page](../server-workspace/user-server-assignment.mdx) for more information. --- ## Kasm Workspaces: File Mapping for Workspace Customization # File Mappings File mappings allow the administrator to manage files to be mapped to the inside of a user's Workspace session. This can be used, for example, to [manage Chrome Policies](container-workspace/chrome-managed-policies.mdx). This reduces the need to create custom images. Text based files can be edited directly in the Kasm Admin UI. There is also the ability to upload arbitrary files, with a **file size limit of 5MB**. Arbitrary files that are scripts should have UNIX style line endings. File mappings can be applied to [Workspaces](container-workspace/workspaces.mdx), [Groups](../security/users-groups-mgmt/groups.mdx), and [Users](../security/users-groups-mgmt/users.mdx). When a user creates a session, the File Mappings are applied in the order of Workspace, Groups, and User defined File Mappings. Only the first File Mapping targeting the same destination will be added to the session. Subsequent File Mapping definitions targeting the same destination will be skipped and logged when a user creates a session. The Kasm Desktop Service must be installed on Windows systems for file mapping to work. File mappings defined at the Workspace level are applied on service start. When a user belongs to multiple Groups that define a File Mapping with the same destination, the group with the lowest priority value gets mapped into the user's container. The following is an example File Mapping of a Chrome Managed Policy to define bookmarks in Chrome. ## File Permissions and Ownership ### Container Sessions File Mapping definitions can be marked as Writable and Executable. By default, a file is owned by root and the container user does not have write permissions to the file. Marking the File Mapping as Writable changes the owner to the container user and provides write access to the file. Marking the File Mapping as Executable adds the executable permission to the file. Directories that do not already exist within the target path, will automatically be created and owned by root. For example, if you defined a writable File Mapping with a target location of `/data/bin/script.sh` and the location `/data/bin` did not already exist inside the container, the path `/data/bin` would get created with ownership belonging to root. The file, `script.sh` would be owned by the container user. The result is that the user would be able to edit the file `script.sh`, but would be unable to create new files within the containing directory. Permissions and ownership of existing paths will not be modified. Marking File Mappings as Writable is only supported when when the kasm_agent container is running as root. By default Kasm Workspaces runs the kasm_agent container as root, however, when [security hardening](../security/index.mdx) is applied to Kasm Workspaces the kasm_agent container runs as a non-root user. The kasm_agent will detect that it is not running as root and skip changing ownership for File Mappings marked as writable. ### Server Sessions In Windows and Linux Server based session, permissions and ownership are determined by the destination directory that the file is created in. Files placed in a user's [HOMEPATH](#windows-sessions), for example, are owned by the user. For this reason, the read-only and executable settings in the Kasm Admin UI for file mapping definitions are not affective on the server. A potential work around would be to use a bash [session start script](server-workspace/linux/linux-service.mdx#scripts) or PowerShell [session start script](server-workspace/windows/kds-windows-service.mdx#scripts) to customize advanced file permissions. ## User Home Profile ### Container Sessions A user's home profile for a containerized Workspace is located at `/home/kasm-user`. Many applications save configurations and other files in the user's home profile. For this reason, it is often advantageous to use File Mappings to manage files in the users home profile. There are, however, several things to be aware of when mapping files to a users home profile. Kasm containers use a default profile located at `/home/kasm-default-profile`, this directory contains the starting state for the container users home profile. If [Persistent Profiles](../data-storage/persistent-profiles.mdx) are enabled, different logic is used for the home directory. The following logic is followed on startup of a container. * Persistent Profiles are not configured. * Copy `/home/kasm-default-profile` to `/home/kasm-user` * Persistent Profiles are configured and enabled. * First time this user has started a session, no existing persistent profile for this user. * Copy `/home/kasm-default-profile` to `/home/kasm-user`. * Persistent profile already exists. * No action taken, `/home/kasm-user` is volume mapped into the container Due to the above logic, it is not possible to define File Mappings that target `/home/kasm-user`, since that directory is populated on container start. Instead, File Mappings should target `/home/kasm-default-profile`. When the container starts, the files mapped in at `/home/kasm-default-profile` will be copied to `/home/kasm-user`. If [Persistent Profiles](../data-storage/persistent-profiles.mdx) are enabled, users will not pickup changes to File Mappings. Users would either need to clear their persistent profile so that the profile is recreated or they would need to copy the specific files from `/home/kasm-default-profile` to `/home/kasm-user`. File mappings targeting a user's home profile on Windows or Linux VM session are only applied when the server is configured with User SSO enabled. This is because file mappings are applied per-user at the OS level. When User SSO is active, Kasm users are mapped to corresponding OS user accounts, allowing the service to correctly scope mappings to each user's profile. To enable this, set the **Connection Credential Type** to **SSO User Accounts** in the [server configuration](../infra-autoscale/servers.mdx#create-server), which sets `user_sso` to `true` in the Kasm Desktop Service configuration file. This value is automatically synchronized when the service checks in and does not require manual changes. If needed, `user_sso` can be manually overridden in the service configuration file after registration — see the [Linux service configuration](./server-workspace/linux/linux-service.mdx#configuration) and [Windows service configuration](./server-workspace/windows/kds-windows-service.mdx#configuration) for details. Without proper user isolation, file mappings may be applied incorrectly or insecurely across sessions. ### Windows Sessions Windows home profile is typically stored under `C:\Users\{username}`, however, the environmental variable `%HOMEPATH%` contains the actual path of the user. Environmental variables, to include `%HOMEPATH%` can be used in file mapping destination paths for Windows sessions. The [Kasm Desktop Service](server-workspace/windows/kds-windows-service.mdx) is required to be installed on the Windows server to support file mapping. File mappings mapped into a user's home profile path are automatically deleted on session termination. Only file mappings defined at the group and user levels can target a user's home profile. File mappings defined at the Workspace Image level are processed on the start of the Kasm Desktop Service and thus are processed with no associated user. The following example shows a file mapping that places a file on a user's Desktop on a Windows system. The above definition results in the file being placed on the user's desktop. ### Linux VM Sessions - Linux user profiles are typically stored under `/home/{username}`. However, environment variables such as `$HOME` or the shorthand `~` resolve dynamically to the active user’s home directory. These variables should be used when defining file mapping destination paths for Linux sessions. - The Kasm Desktop Service must be installed on the Linux VM server to support file mappings. File mappings that target a user’s home directory are applied within the context of the authenticated user session. - File mappings placed within a user’s home directory are automatically removed upon session termination. Only file mappings defined at the group and user levels can target a user’s home directory. - File mappings defined at the Workspace Image level are processed when the Kasm Desktop Service starts and are not associated with a specific user. ## Volume Mappings File Mappings can target locations inside a `Volume Mapping `. It should be noted, however, that mapping to directories that do not exist on a volume mapping will result in directories being created on the volume map that are owned by root. For example, consider a volume mapping of `/mnt/nfs_share/finance:/shares/finance`, where `/mnt/nfs_share/finance` was the location on the host and `/shares/finance` was the location inside the container and you created a File Mapping that targeted a destination of `/shares/finance/does_not_exist_on_share/policy.pdf`. The file, `policy.pdf` would never get saved on the host at `/mnt/nfs_share/finance`, because it is itself a mapping into the container. However, due to the behavior of Docker, the folder `/shares/finance/does_not_exist_on_share` would get created if it did not exist and it would be owned by root. This would result in the folder being created at `/mnt/nfs/share/finance/does_not_exist_on_share` on the host and/or the remote NFS share mounted to that location on the host. ## File Mapping Usage Examples Here are a few prepared examples of using the File Mapping feature. These examples will work with the User, Group, and Workspace iterations of the File Mapping feature. ### Mapping in a File to The User's Desktop This example will be a straightforward example of preparing a Syllabus to be mapped onto the desktop of an image. This eliminates the need to create a new image just to have the syllabus file available to students on container start. 1. Clone the Workspace to be used. Here the *Ubuntu Focal* workspace has been cloned and named *Ubuntu Focal Student Desktop*. After editing the name and description click *Submit*. 2. Click the arrow menu and select *Edit* and select the *File Mapping* tab and click *Add File Mapping*. 3. Fill in the details of the file to be mapped and click *Save*. 4. Now select the created Workspace from the Workspaces launcher. 5. The syllabus.pdf will be present on the Desktop. ### Using File Mapping to Install and Enable Sudo This example utilizes a feature in Kasm docker images to run a bash script as root after the container starts. This script is located in the image at `/dockerstartup/kasm_post_run_root.sh` and a custom version can be mapped in using the *File Mapping* feature. The script used in this example will install the sudo binary and add the kasm-user to the sudoers group. By using the file mapping feature, sudo can be added to any of the existing Kasm Workspaces without having to create a custom image. 1. Clone the Workspace to be used. Here the *Ubuntu Focal* workspace has been cloned and named *Ubuntu Focal Sudo Desktop*. After editing the name and description click *Submit*. 2. Click the arrow menu and select *Edit* and select the *File Mapping* tab and click *Add File Mapping*. 3. Fill in the details of the file to be mapped ensure to mark the file as executable and click *Save*. ```yml #!/usr/bin/env bash set -ex apt-get update apt-get install -y sudo echo "kasm-user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers notify-send "Script Complete" "sudo is now installed" ``` ![Sudo Install File Mapping Definition](/img/file_mapping/sudo_file_mapping.png) 4. Now select the created Workspace from the Workspaces launcher. ![Workspace Launcher Icon for Sudo Install](/img/file_mapping/ubuntu_focal_sudo_desktop_launcher.png) 5. Open the terminal and execute `sudo whoami` to observe that sudo is installed and working. ![Sudo Installed and Working on the Desktop](/img/file_mapping/sudo_on_desktop.png) ### Using File Mapping to Clone a Repo and Start VScode This example uses another script in the Kasm docker images that is the non-root user equivalent of the script used in the *Using File Mapping to Install and Enable Sudo* example. This script is located in the image at `/dockerstartup/kasm_post_run_user.sh` 1. Clone the Workspace to be used. Here the *Ubuntu Focal* workspace has been cloned and named *Ubuntu Focal VScode Desktop*. After editing the name and description click *Submit*. 2. Click the arrow menu and select *Edit* and select the *File Mapping* tab and click *Add File Mapping*. 3. Fill in the details of the file to be mapped ensure to mark the file as executable and click *Save*. ```yml #!/usr/bin/env bash set -ex /usr/bin/desktop_ready git clone https://github.com/kasmtech/KasmVNC /home/kasm-user/Desktop/KasmVNC/ code --no-sandbox -a /home/kasm-user/Desktop/KasmVNC/ -g /home/kasm-user/Desktop/KasmVNC/README.md ``` ![Repo Clone and Open VScode File Mapping Definition](/img/file_mapping/vscode_file_mapping.png) 4. Now select the created Workspace from the Workspaces launcher. ![Workspace Launcher Icon for Repo Clone and VScode](/img/file_mapping/ubuntu_focal_vscode_desktop_launcher.png) 5. When launching the Workspace, the KasmVNC repo will be cloned, and VScode will be opened with the KasmVNC readme. ![VScode Opened with KasmVNC repo loaded on the Desktop](/img/file_mapping/vscode_on_desktop.png) ### Using File Mapping to Change the Default Background of a Workspace This example replaces the default background of a workspace, for Ubuntu that is located at `/usr/share/backgrounds/bg_default.png`, it may be in a different location for other distros or Workspace images. 1. Clone the Workspace to be used. Here the *Ubuntu Focal* workspace has been cloned and named *Ubuntu Focal New Background Desktop*. After editing the name and description click *Submit*. 2. Click the arrow menu and select *Edit* and select the *File Mapping* tab and click *Add File Mapping*. 3. Fill in the details of the file to be mapped ensure to mark the file as executable and click *Save*. ![New Background File Mapping Definition](/img/file_mapping/new_background_file_mapping.png) 4. Now select the created Workspace from the Workspaces launcher. ![Workspace Launcher Icon with New Background](/img/file_mapping/ubuntu_focal_new_background_desktop_launcher.png) 5. When launching the Workspace observe the new background that was configured in the File Mapping. ![New Background in Session](/img/file_mapping/new_background_on_desktop.png) ### Using File Mapping to Apply a Custom KasmVNC Watermark This example replaces the default `/etc/kasmvnc/kasmvnc.yaml` configuration file in container-based workspaces. 1. Clone the Workspace to be used. Here the *Ubuntu Focal* workspace has been cloned and named *Ubuntu Focal Watermark*. After editing the name and description click *Submit*. 2. Click the arrow menu and select *Edit* and select the *File Mapping* tab and click *Add File Mapping*. 3. Fill in the details of the file to be mapped ensure to mark the file as executable and click *Save*. More details about found in the [Applying KasmVNC DLP Policies](container-workspace/kasmvnc-dlp-policies.mdx) ![New Background File Mapping Definition](/img/file_mapping/kasmvnc_file_mapping.png) ```yaml network: ssl: pem_certificate: ${HOME}/.vnc/self.pem pem_key: ${HOME}/.vnc/self.pem udp: public_ip: 127.0.0.1 data_loss_prevention: watermark: repeat_spacing: 50 tint: 0,255,0,80 text: template: "Kasm Workspaces User ${KASM_USER} (${KASM_ID}) at %F %H:%M" font: auto angle: 45 font_size: 24 timezone_name: Asia/Taipei ``` 5. When launching the Workspace observe the watermark that is applied. ![New Background in Session](/img/file_mapping/watermark_desktop.png) --- ## Progressive Web App (PWA) Setup in Kasm Workspaces # Progressive Web App (PWA) Kasm Workspaces installed as a Progressive Web App (PWA) allows users to use the Kasm Workspaces platform as a web-based application that behaves like a native desktop or mobile app, without requiring traditional installation. By leveraging modern browser capabilities, Kasm can be “installed” as a PWA, allowing users to launch remote workspaces (such as browsers, desktops, or applications) in a more seamless and app-like experience. This enhances the user experience by making applications feel more like locally installed software while preserving all the benefits of secure, centrally managed workspaces. ## Enable PWA Install In order to give users the option to install the per-workspace PWAs, the **control_panel.pwa_install_option** group setting must be enabled. Go to Access Management -> Groups -> Select the group and click edit -> Settings -> Add Setting -> Add the "control_panel.pwa_install_option" and set the value to "True". ![Set control_panel.pwa_install_option to True](/img/groups/add_pwa_group_setting.png) ### Prerequisite Requirements In order for workspaces to show as an installable PWA it must be served from a secure HTTPS connection and with trusted certificates. ## Customization ### Valid installed JSON manifest Kasm workspaces provides a working manifest, if you want to make changes for branding then you can swap out the icons found in the manifest. * `img/favicon.png` ### Icons In order for an icon to be used, it must be square with an exact 1:1 ratio. If the image type is an svg, then the svg should also specify height and width attributes in the source. If it isn't, the PWA can still be installed, it just won't use the image for the app icon. ![Icons must be square](/img/user_guide/svg_size.webp) ### Deploy PWAs using Active Directory GPO - [Deploy PWA GPO](pwa-gpo-deploy.mdx) --- ## Deploying Kasm Workspaces PWAs via Group Policy # Deploy PWAs with Group Policy In this guide, we will walk you through the detailed steps required to deploy one or more Progressive Web Apps (PWAs) using a Microsoft Group Policy Object (GPO) with Google Chrome and Microsoft Edge ADMX templates. By deploying the PWA centrally via Group Policy, organizations can ensure that users have quick and easy access to Kasm Workspaces directly from their desktop or start menu without requiring manual installations. ## Prerequisites - Kasm Workspaces 1.16 or later with trusted [SSL/TLS certificates](../../networking/replace-certificates.mdx) configured - Active Directory Domain Controllers with support for ADMX templates - Windows Server 2016 or later - Administrative access to Group Policy Management Console - Latest ADMX templates for Google Chrome or Microsoft Edge - Google Chrome ([Download Google Chrome templates](https://support.google.com/chrome/a/answer/187202)) - Microsoft Edge ([Download Microsoft Edge tetmplates](https://www.microsoft.com/edge/business/download)) ## Overview You can follow these four phases to deploy Kasm PWAs using Group Policy. 1. Prepare a JSON template for the Kasm PWA Group Policy Object. 2. Install ADMX templates for Google Chrome and Microsoft Edge. 3. Configure a browser-specific GPO. 4. Verify the deployment and troubleshoot common issues. ### Phase 1. Prepare JSON Template The Group Policy Object for PWA deployment only accepts JSON data in a single-line, concatenated format, stripping all whitespace and line breaks. 1. You can create your template using one of the two templates below. Copy and paste a template into a text editor. - Use this concatenated JSON template to add a single PWA: ```json [{"url":"https://www.contoso.com/maps","default_launch_container":"window","create_desktop_shortcut":true}] ``` - Use this concatenated JSON template to add multiple PWAs: ```json [{"url":"https://app.contoso.edu","default_launch_container":"window","create_desktop_shortcut":true},{"url":"https://app.contoso.edu/editor","default_launch_container":"window","create_desktop_shortcut":true},{"url":"https://app.contoso.edu/sheets","default_launch_container":"window","create_desktop_shortcut":true}] ``` 2. Log in to Kasm Workspaces with administrative credentials. 3. Navigate to **Workspaces > Workspaces**. 4. For each Workspace you want to deploy as a PWA: - Click the **Edit** (pencil icon) for the Workspace. - Locate and copy the **Direct Install URL**. - Paste the value into your JSON template, replacing the example URL. 5. Save your updated JSON template and keep the information available for the GPO configuration steps. ### Phase 2. Install ADMX Templates #### For Google Chrome: 1. Download Chrome Enterprise Bundle. ``` https://chromeenterprise.google/browser/download/ ``` 2. Extract `GoogleChromeEnterpriseBundle64.zip`. - Navigate to the extracted bundle and locate the `Configuration\admx` folder. - You will find two key folders: - admx: Contains the ADMX files - en-US: Contains language-specific ADML files (English in this example) - Copy `chrome.admx` to: ``` %systemroot%\PolicyDefinitions ``` - Copy `chrome.adml` to its corresponding language-specific folder: ``` %systemroot%\PolicyDefinitions\en-US ``` #### For Microsoft Edge: 1. Select and download the Edge Windows 64-bit Policy; the download link is located directly below the Download button. ``` https://www.microsoft.com/edge/business/download ``` 2. Extract `MicrosoftEdgePolicyTemplates.cab`. - Navigate to the extracted bundle and locate the `Windows\admx` folder. - You will find two key folders: - admx: Contains the ADMX files - en-US: Contains language-specific ADML files (English in this example) - Copy `msedge.admx` to: ``` %systemroot%\PolicyDefinitions ``` - Copy `msedge.adml` to its corresponding language-specific folder: ``` %systemroot%\PolicyDefinitions\en-US ``` ### Phase 3. Configure a Browser-Specific GPO #### Create a New GPO 1. Open Group Policy Management Console. ``` gpmc.msc ``` 2. Right-click on your desired Organizational Unit (OU) and select **Create a GPO in this domain, and Link it here...** 3. Name the new GPO, e.g., "Kasm Workspaces PWA Deployment". #### Configure List of Force-Installed Web Apps #### For Google Chrome: 1. Right click your newly created GPO and select **Edit**. 2. You can configure this setting in either of the locations below: - `Computer Configuration > Administrative Templates > Google Chrome` - `User Configuration > Administrative Templates > Google Chrome` Choose Computer Configuration to apply PWA settings universally on a specific set of devices, regardless of who is logged in. Choose User Configuration if you want the PWAs to follow a specific set of users across any device. Both configurations can work together, but if there’s a conflict between them, Computer Configuration typically takes precedence. Loopback Processing and policy filtering are the most common cases where User Configuration might override or replace Computer Configuration settings. 3. Locate and **Edit** the setting `Configure list of force-installed Web Apps` - Change the State to **Enabled** - Copy the single-line, concatenated JSON from **Phase 1. Prepare JSON Template**. - Paste JSON data into the `URLs for Web Apps to be silently installed` field. - Click **OK** to save changes. #### For Microsoft Edge: 1. Right click your newly created GPO and select **Edit**. 2. You can configure this setting in either of the locations below: - `Computer Configuration > Administrative Templates > Microsoft Edge` - `User Configuration > Administrative Templates > Microsoft Edge` Choose Computer Configuration to apply PWA settings universally on a specific set of devices, regardless of who is logged in. Choose User Configuration if you want the PWAs to follow a specific set of users across any device. Both configurations can work together, but if there’s a conflict between them, Computer Configuration typically takes precedence. Loopback Processing and policy filtering are the most common cases where User Configuration might override or replace Computer Configuration settings. 3. Locate and **Edit** the setting `Configure list of force-installed Web Apps` - Change the State to **Enabled** - Copy the single-line, concatenated JSON from **Phase 1. Prepare JSON Template**. - Paste JSON data into the `URLs for Web Apps to be silently installed` field. - Click **OK** to save changes. ### Phase 4. Verification and Troubleshooting Steps #### Update Group Policy on Client Machines 1. You can run the ` gpresult /R` command to review the Resultant Set of Policy (RSoP) information and determine whether or not the GPO you just created has been applied on a client machine. 2. Review **Applied Group Policy Objects** in both the Computer Settings and User Settings section. Your **Kasm Workspaces PWA Deployment** GPO should appear in the corresponding location that you used in **Phase 3. Configure a Browser-Specific GPO**. ```text COMPUTER SETTINGS ------------------ CN=Alpha,OU=Servers,DC=kasm,DC=local Last time Group Policy was applied: 10/25/2024 at 8:42:58 PM Group Policy was applied from: WindowsServer.kasm.local Group Policy slow link threshold: 500 kbps Domain Name: KASM Domain Type: Windows 2008 or later Applied Group Policy Objects ----------------------------- Kasm Workspaces PWA Deployment ... USER SETTINGS ------------------ CN=Alpha,OU=Servers,DC=kasm,DC=local Last time Group Policy was applied: 10/25/2024 at 8:42:58 PM Group Policy was applied from: WindowsServer.kasm.local Group Policy slow link threshold: 500 kbps Domain Name: KASM Domain Type: Windows 2008 or later Applied Group Policy Objects ----------------------------- Kasm Workspaces PWA Deployment ``` 3. If your Group Policy has not been applied yet, and immediate enforcement is needed, using `gpupdate /force` or rebooting the client machines will help expedite the process. #### Verify PWA Functionality #### For Google Chrome: 1. After the Group Policy is applied, open Chrome on a client machine. 2. Confirm that PWAs appear in the **Start Menu** and as **desktop shortcuts** if configured. 3. Navigate to `chrome://apps` and verify that the Kasm Workspaces PWAs are listed. 4. Launch each PWA. 5. Ensure each PWA opens in its own window as expected and provides access to Kasm Workspaces. #### For Microsoft Edge: 1. After the Group Policy is applied, open Edge on a client machine. 2. Confirm that PWAs appear in the **Start Menu** and as **desktop shortcuts** if configured. 3. Navigate to `edge//apps` and verify that the Kasm Workspaces PWAs are listed. 4. Launch each PWA. 5. Ensure each PWA opens in its own window as expected and provides access to Kasm Workspaces. ### Troubleshooting #### Common Issues 1. **PWAs Not Installing** - Verify GPO link and scope - Check policy application with: `gpresult /r` - Review Event Viewer for policy errors - Verify Direct Install URLs are correct and accessible 2. **Authentication Issues** - Verify SSL certificates - Check browser SSO configuration - Confirm Kasm server accessibility 3. **Performance Problems** - Review network connectivity - Check client system resources - Verify browser version compatibility - Monitor Kasm Workspace resource allocation ## Reference - [Google Chrome Enterprise Documentation](https://support.google.com/chrome/a/answer/187202) - [Microsoft Edge Enterprise Documentation](https://docs.microsoft.com/en-us/deployedge/microsoft-edge-policies) --- ## Auto Open Rdp File # Auto-Opening RDP files for each Client OS ## Windows Windows will query Group Policy to determine whether it should prompt the user for verification when opening an RDP connection. There are also configuration options for individual browsers that cause the browser to launch the RDP connection immediately after the RDP configuration file download completes. Kasm automatically generates a signed RDP file using the certificate and private key in [Server Settings](/reference/settings.mdx#default-vm-rdp-connection-settings). To avoid Windows warning that the Kasm RDP file is provided by an untrusted/unknown publisher, you must do the following: 1. Install either the certificate generated by Kasm or an applicable CA certificate on the client machine in the trusted certificate store. 2. Add the SHA1 thumbprint of the certificate as a trusted RDP publisher in Group Policy. To make things easier, Kasm provides a button to download the certificate and a button to copy the SHA1 thumbprint to your clipboard in order to add to your group policy. Navigate to this element in Kasm Workspaces by clicking "Settings > Global" in the left-hand menu, then scrolling down to the "Connections" section. ![RDP Public Signing Certificate](/img/windows/rdp_signing_cert.webp) ### Install the Certificate 1. Download the RDP certificate using the button shown above 2. Double-click the downloaded `.cer` file to open it 3. Click **Install Certificate...** 4. Select "Local Machine" (which requires Administrator privileges), or "Current User" 5. Select "Place all certificates in the following store" 6. Click **Browse** 7. Choose "Trusted Root Certification Authorities" 8. Click **OK** 9. Click **Next** 10. Click **Finish** 11. Wait for the import to finish, indicated by a pop-up with the message, "The import was successful." Alternatively, you can push the certificate to the trust store of a domain-joined machine using Group Policy: `Computer Configuration -> Windows Settings -> Security Settings -> Public Key Policies -> Trusted Root Certification Authorities` ### Add SHA1 Thumbprint as Trusted RDP Publisher Group Policy location: `Computer Configuration -> Administrative Templates -> Windows Components -> Remote Desktop Services -> Remote Desktop Connection Client -> Specify SHA1 thumbprints of certificates representing trusted .rdp publishers` ![Group Policy Location](/img/windows/rdp_waf_proxy/group_policy_editor.png) ![Setting the Trusted Publisher Certificate SHA1](/img/windows/rdp_waf_proxy/trusted_publisher_sha.png) To prevent a user from modifying a signed RDP file and then attempting to create a connection to the RDP target, there is another group policy setting that can be enabled: `Computer Configuration -> Administrative Templates -> Windows Components -> Remote Desktop Services -> Remote Desktop Connection Client -> Allow .rdp files from unknown publishers`. This GPO setting has the side effect of preventing a user from opening any RDP file not signed by a verified publisher, including those created by the user. ![Deny unknown publishers](/img/windows/rdp_waf_proxy/group_policy_disable_unknown_publishers.png) ### Google Chrome #### Option 1 The user right-clicks the rdp file in the download list and selects `Always open files of this type`. ![Always Open Files of this Type](/img/windows/rdp_waf_proxy/set_always_open.png) #### Option 2 The user or an administrator sets a registry entry. * Registry Key: `Software\Policies\Google\Chrome\AutoOpenFileTypes` * Registry Subkey: An index number * Registry Value: A file extension For example: `Software\Policies\Google\Chrome\AutoOpenFileTypes\1 = rdp`. ### Firefox When right-clicking the RDP file download, the option `Always Open Similar Files` sets Firefox to automatically open RDP files in the default client. ![Always Open Similar Files](/img/windows/rdp_waf_proxy/always_open_similar_files.png) ## ChromeOS The Chromebook (or other host running ChromeOS) must be joined to a Google Workspace Enterprise account. The administrator can set Chrome managed policies to ensure that Chrome will automatically open the RDP file upon download. You must install separate RDP client software on the ChromeOS host in order for the user to be able to make the RDP connection. Otherwise, these instructions will only result in the `.rdp` file being opened automatically by the text editor. ### Google Workspace configuration 1. Log into the Google Workspace account at `admin.google.com`. 2. Navigate to *Devices* -> *Chrome* -> *Settings*. ![ChromeOS device settings](/img/windows/rdp_waf_proxy/chromeos_device_settings.png) 3. Select the *User & browser settings* tab. 4. Scroll down to the *Content* section and select *Auto open downloaded files*. ![ChromeOS device content settings](/img/windows/rdp_waf_proxy/chromeos_device_content_settings.png) 5. Add *RDP* to the *Auto open file types*. The administrator can also restrict this setting to the URL of the Kasm deployment, e.g. `https://kasm.example.com/*`. ![ChromeOS Auto open downloaded files settings](/img/windows/rdp_waf_proxy/chromeos_auto_open_download_settings.png) ## MacOS On macOS the RDP connection is loaded as a URL rather than a downloadable file. An RDP client that supports the `rdp://` URL scheme (such as Microsoft Remote Desktop) must be installed. ### Google Chrome By default Chrome will show a confirmation dialog each time an `rdp://` URL is opened. To have Chrome automatically launch the RDP client without the dialog, set the `AutoLaunchProtocolsFromOrigins` policy. Replace `https://kasm.example.com` with your Kasm deployment URL: ```bash defaults write com.google.Chrome AutoLaunchProtocolsFromOrigins -array '{ protocol = rdp; allowed_origins = ("https://kasm.example.com"); }' ``` Chrome must be fully restarted (not just the tab) for the policy to take effect. You can verify the policy is active by navigating to chrome://policy in Chrome. ### Firefox Create the distribution directory and policies file at `/Applications/Firefox.app/Contents/Resources/distribution/policies.json`. The file must be owned by root. Replace `https://kasm.example.com` with your Kasm deployment URL: ```bash sudo mkdir -p "/Applications/Firefox.app/Contents/Resources/distribution" sudo tee "/Applications/Firefox.app/Contents/Resources/distribution/policies.json" << 'EOF' { "policies": { "AutoLaunchProtocolsFromOrigins": [ { "protocol": "rdp", "allowed_origins": [ "https://kasm.example.com" ] } ] } } EOF sudo chown -R root:wheel "/Applications/Firefox.app/Contents/Resources/distribution" ``` Firefox must be fully restarted for the policy to take effect. You can verify the policy is active by navigating to about:policies in Firefox. ### Safari Safari does not provide an enterprise policy or command-line setting to suppress the external protocol confirmation dialog. On the first `rdp://` URL launch Safari will prompt the user to allow the RDP client to open. For MDM-managed devices a configuration profile can be deployed to allowlist the `rdp://` URL scheme. --- ## Auto Scaled Servers # Auto Scaled Kasm Workspaces can auto-scale VMs in supported [Cloud Providers/Hypervisors](../../infra-autoscale/autoscale/vm-providers.mdx#vm-provider-configs). The [VM Provider](../../infra-autoscale/autoscale/vm-providers.mdx#vm-provider-configs) documentation provides a reference for the individual fields of each supported cloud provider/hypervisor. This document provides guidance for both Windows and Linux deployments, since each cloud environment has different idiosyncrasies. Servers auto-scaled by Kasm should be seen as individual servers connected to via RDP. Kasm Workspaces provides session handling and ensures users a distributed to the pool of servers. Kasm auto-scaling is not supported as a way to scale [RDS](windows/rds.mdx) deployments. AutoScaling is available in the Community and Enterprise editions only. ## Auto Scaling Pool Before you can create an auto-scaling configuration, you need to create a Pool that will be the target of the auto-scaling. A pool can have multiple auto-scaling configurations, allowing you to, for example, auto scale servers in Azure and AWS and have the VMs be part of the same pool that users will get assigned to. A more typical scenario, however, is to create one pool per Cloud environment, per region. To create a Pool, in the Admin Dashboard go to Infrastructure, Pools, and click the Add button on the Pool list. 1. Provide a Name 2. Select `Server` as the Type 3. Press Save ![Create Server Pool](/img/compute/create_server_pool.webp) ## Auto Scale Configuration Auto-Scale configurations have two parts, the AutoScale Details and the VM Provider Details. The AutoScale details are common to any cloud provider/hypervisor. To create an auto-scale configuration... 1. Navigate to Infrastructure->Pools 2. From the Pool list, click the arrow icon next to the desired pool and click Edit 3. Scroll to the bottom of the Pool Configuration page to the AutoScale Configuration list and click the Add button. ![Create Autoscaling Config](/img/compute/create_autoscale_server.webp) 4. Enter a Name 5. Check the Enabled box 6. Select the [Deployment Zone](../../infra-autoscale/deployment-zones.mdx), by default there is a single zone called `default`. 7. Select RDP as the connection type. 8. Enter the Connection Port, RDP uses port 3389 by default. 9. Enter an appropriate value for the username and password fields. See the authentication documentation for your OS: - [Windows Authentication](windows/authentication.mdx) - [Linux Authentication](linux/authentication.mdx) ### Windows-Specific Configuration 10. The connection info can be left empty, unless you are using [RemoteApp](windows/remote-apps.mdx). 11. If desired, enable the Create Active Directory Computer Record setting. See the [Join Active Directory](#join-active-directory) guide for more details. 12. Check the reusable box if you want VMs to be re-used after a user terminates their session. For privacy reasons, servers should only be reusable if single sign-on is configured. See the [Windows Authentication](./windows/authentication.mdx) documentation for guidance on SSO. ### Linux-Specific Configuration 10. The connection info can be left empty. 11. Check the reusable box if you want VMs to be re-used after a user terminates their session. For privacy reasons, servers should only be reusable if single sign-on is configured. See the [Linux Authentication](linux/authentication.mdx) documentation for guidance on SSO. ### Common Configuration 13. Set a desired **Minimum Available Sessions**, this is the number of available sessions you want at all times. For example, if each server could support up to 4 concurrent sessions and you set **Minimum Available Sessions** to 10, Kasm would ensure that across all servers there are at least 10 open sessions available. As soon as the number of available sessions drops below this number, additional VMs will be provisioned. 14. Set the **Max Simultaneous Sessions Per Server** to the desired limit. Kasm will ensure each server will only be assigned this maximum number of current user sessions. Multiple concurrent RDP sessions require a Windows operating system that supports this feature. Kasm will ensure each server is only assigned the maximum number of current user sessions specified. ## VM Provider Configuration The VM Provider Configuration settings are specific to the Cloud Service Provider or Hypervisor being used for autoscaling. Kasm Workspaces supports autoscaling across multiple Cloud Service Providers and Hypervisors. For a full list of supported providers and detailed setup instructions reference the [VM Provider Configs](../../infra-autoscale/autoscale/vm-providers.mdx#vm-provider-configs) documentation. - [Azure](../../infra-autoscale/autoscale/autoscale-providers/azure/azure-windows.mdx) - [AWS](../../infra-autoscale/autoscale/autoscale-providers/aws/aws-windows.mdx) ### VM Startup Scripts Each VM Provider has special caveats around how their startup scripts are handled, see [VM Provider Config](../../infra-autoscale/autoscale/vm-providers.mdx#vm-provider-configs) for details on your target environment. The startup script will have access to Kasm managed variables listed below. #### Windows Startup Scripts Windows startup scripts use PowerShell and can utilize the following variables: **Startup Script Variables (Windows)** | Variable Name | Description | | --------------------- | ---------------------------------------- | | ad_join_credential | If the auto-scale configuration is set to join the VM to an Active Directory domain, Kasm creates the AD record and sets a random password that can only be used for joining the VM to the domain. This can then be used in a Powershell startup script to complete the process of joining the system to the domain. | | checkin_jwt | JSON Web Token used to register components like the [Kasm Desktop Service](./windows/kds-windows-service.mdx). | | connection_username | If the auto-scale configuration is set to use a static username for Kasm user sessions, the username will be contained in this variable. | | connection_password | If the auto-scale configuration is set to use a static password for Kasm user sessions, this variable will contain the password. | | domain | If the auto-scale configuration is set to join the VM to an Active Directory domain, this variable will contain the name of the domain. | | server_id | The UUID created by Kasm for the new server which can be found in the Server's "Server Id" field within the Kasm UI. | | server_hostname | The server name generated by Kasm for the auto-scaled VM. This is also the name of the computer object added to Active Directory by Kasm when "Create Active Directory Computer Record" is enabled. | | upstream_auth_address | The resolvable hostname, IP, or FQDN of the KASM API server which can be found in the "Upstream Auth Address" of the Zone configuration in the Kasm UI. | #### Linux Startup Scripts Linux startup scripts use bash and can utilize the following variables: **Startup Script Variables (Linux)** | Variable Name | Description | | --------------------- | ---------------------------------------- | | connection_username | If the auto-scale configuration is set to use a static username for Kasm user sessions, the username will be contained in this variable. | | connection_password | If the auto-scale configuration is set to use a static password for Kasm user sessions, this variable will contain the password. | | ad_join_credential | If the auto-scale configuration is set to join the VM to an Active Directory domain, Kasm creates the AD record and sets a random password that can only be used for joining the VM to the domain. | | domain | If the auto-scale configuration is set to join the VM to an Active Directory domain, this variable will contain the name of the domain. | | upstream_auth_address | The resolvable hostname, IP, or FQDN of the KASM API server. | | checkin_jwt | The registration token (JWT) created by Kasm for the newly created server. | If your Linux script uses curly brackets, aside from Kasm variables, you must escape them by doubling them up. Example: ```bash configure_xyz() {{ echo "[INFO] ..." }} ``` ### Join Active Directory Auto-scaled servers can be configured to automatically join Active Directory. This is a two-step process which involves Kasm first creating a Computer Object in Active Directory within a specified AD container. When the Computer Object is created, a random single-use password is generated that can only be used to join the computer to the domain. The final step of joining the computer to the domain is facilitated through the startup script. :::info For a complete example see the [Domain Join](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/tree/release/[[release]]/windows_vms#domain-join) section in the Kasm Windows VM Startup Script Repository. ::: #### LDAP Configuration [[release]] For Kasm to create the Computer Object in Active Directory and generate the domain join credential, an [LDAP Configuration](../../security/users-groups-mgmt/ldap.mdx) must be defined. :::tip You can use the same LDAP configuration that is used to authenticate users or you can create a different LDAP configuration used specifically for joining and removing systems. If you use a separate LDAP configuration, leave it disabled so that it cannot be used for authentication purposes. ::: 1. Create an [LDAP Configuration](../../security/users-groups-mgmt/ldap.mdx) that will be used for user authentication to Kasm. 2. Create an LDAP Configuration that will be used to create computer objects in AD. The service account used by this LDAP configuration must have permissions to create and remove computers from the domain. 3. In the Auto-scale Configuration, select *SSO User Accounts* for the **Connection Credential Type**. 4. In the Auto-scale Configuration, enable **Add Active Directory Computer Record**. - In the **LDAP Config** select the LDAP configuration created in Step 2. - In the **Active Directory Computer OU DN**, enter the AD OU Distinguished Name.\ *Example:* `OU=Computers,DC=example,DC=local` - Enable **Recursively Cleanup Active Directory Computer Record** if you anticipate the Computer objects having child objects. This can prevent `notAllowedOnNonLeaf` errors when cleaning Azure VMs. - Click Next to save the auto-scale configuration. 5. The next page is the VM Provider configuration. Scroll down to the startup script. See the example in the [VM Startup Script](./auto-scaled-servers.mdx#vm-startup-scripts), which is a Powershell script that will add the VM to the domain specified by the LDAP configuration. Each VM Provider has different caveats for script formats and execution, see [VM Provider Config](../../infra-autoscale/autoscale/vm-providers.mdx#vm-provider-configs) for details on your target environment. ### FSLogix Container Profiles Auto-scaled Windows VMs can utilize FSLogix Profile Containers to maintain persistent user profiles across sessions, providing a consistent user experience as servers are dynamically created and assigned. When provided a profile storage location, Kasm's VM Startup Scripts will install the latest version of FSLogix and configure the VM to use FSLogix Profile Containers. To utilize FSLogix with Kasm Auto-Scale Startup Scripts: 1. Ensure that the [FSLogix prerequisites](./windows/persistent-profile.mdx#prerequisites) are met 2. Create a storage location (Azure Files or [SMB share](./windows/persistent-profile.mdx#create-a-smb-share)) 3. Provide the storage location as a argument to the startup script. For examples and additional configuration options see the [FSLogix section](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/tree/release/[[release]]/windows_vms#fslogix) of the **Kasm Windows VM Startup Script Repository**. ## Workspace To provide users access to the auto-scaled server pool, you must create a Workspaces. 1. Navigate to Worksapces -> Workspaces 2. Click the **Add Workspace** button at the top of the Workspaces list. 3. Select `Pool` from the **Workspace Type**. 4. Provide a **Friendly Name** and **Description**. 5. Check the Enable box. 6. In the **Pool** drop down, select the Pool you created earlier. 7. In the **RDP Client Options** dropdown, select one of: - *Web native client* to access the instance using Kasm's in browser access method. - *RDP local client* to access the instance using the client endpoint's RDP client software authenticated through the Kasm RDP gateway. 8. Click Save. You should now see the Workspaces on the user dashboard. --- ## Direct RDP Login in Kasm Workspaces # Direct RDP Login ## Overview Users typically interact with a Kasm Workspace by logging into the web UI and connecting to a session either in the browser, or by downloading an RDP file for thick client access. In some situations there may be limited or no access to a web browser, or normal web traffic may be restricted. In these cases, Kasm can be configured to allow an RDP client to connect directly to Kasm and authenticate user by their Kasm username and password. ## Configuration In order to enable direct RDP login, there are several configurations which must be present and there should be at least one valid RDP-enabled workspace. These instructions assumes we have a working Kasm install and an available RDP Windows or Linux target. ### Zone Configuration In this section we will configure the default Zone to allow direct RDP login. - Log in to Kasm as administrator. - Navigate to **Infrastructure** -> **Deployment Zones**, select the "default" zone record and select "Edit" ![List of zones](/img/direct_rdp_login/zone_list.webp) - Set "Kasm Authorization Domain" to the parent domain of the Web App and Agent servers, e.g., `kasm.example.com`. - Under the "Basic Details" section, find and enable the toggle labeled "Enable Direct RDP Login" - Click the "Save" button at the bottom of the page ![Zone configuration options](/img/direct_rdp_login/zone_config.webp) ### Group Settings In this section we will configure the "All Users" group to allow users to utilize direct RDP login. - Log in to Kasm as administrator. - Navigate to **Access Management** -> **Groups** - Select the "All Users" record and select "Edit", then select the "Settings" tab across the top of the page ![List of groups](/img/direct_rdp_login/group_list.webp) ![Group settings page](/img/direct_rdp_login/group_setting_list.webp) - Click on the "Add Settings" button, then use the "Setting Name" input box to find and add the `allow_login_kasm_rdp` setting with a value of "True" ![Configuring group settings](/img/direct_rdp_login/group_setting_config.webp) ### Target Workspace In this section we will configure a Workspace which allows RDP client connections. - Log in to Kasm as administrator. - Navigate to **Infrastructure** -> **Servers** -> **Server** - Click on the "Add Server" button and complete the form while paying special attention to the following settings - **Deployment Zone**: our selected zone must match the one configured earlier (in our case there is only one option) - **Connection Type**: must be RDP ![Server configuration](/img/direct_rdp_login/server_config.webp) - Once we have added our Server configuration, we then navigate to **Workspaces** --> **Workspaces** - Click on the "Add Workspace" button and complete the form, again ensuring some specific settings - **Workspace Type**: must be Server - **Server**: select our configured Server from the previous steps - **RDP Client Options**: this can be either "User Selectable" or "RDP local client" ![Workspace configuration](/img/direct_rdp_login/workspace_config.webp) ## Usage Now that we have Kasm set up to enable direct RDP login, we can initiate connections purely through RDP using our Kasm user credentials. Note that direct RDP login only supports username and password with no MFA support at this time (future updates may add more options). - Launch any RDP client (screenshots will be using Remmina from an Ubuntu desktop) - Enter our server hostname or IP address, e.g., `kasm.example.com` - Some clients allow for setting the username and password before connecting, but for this test we will leave all such options blank ![RDP client connection details](/img/direct_rdp_login/rdp_client_config.webp) - When prompted, enter your Kasm username and password ![Kasm RDP login page](/img/direct_rdp_login/rdp_login_filled.webp) - We are presented a list of available RDP workspaces which includes the Server we configured earlier ![Available workspaces list](/img/direct_rdp_login/rdp_workspace_list.webp) - Select our server using keyboard (up/down arrow and Enter) or mouse inputs (double click) - Verify we are placed into a full RDP session with the target Server ![Working RDP session](/img/direct_rdp_login/rdp_session.webp) ### Notes * As mentioned above, we can save our Kasm credentials in our RDP client for faster access but we must be aware of the security implications of storing these credentials since most clients will not encrypt them --- ## Kasm Workspaces: Server Enrollment Tokens # Server Enrollment Tokens Server Enrollment Tokens streamline the onboarding process for multiple servers by providing reusable tokens with pre-configured connection settings, credentials, zones, and access policies. This eliminates the need to manually configure each server individually during enrollment. ## Create Enrollment Token To create a new enrollment token, navigate to Infrastructure->Servers->Enrollment Tokens and click Add. Fill in the required information about the token configuration. | Property | Description | | :------- | :---------- | | Enabled | Whether this token is active and can be used for server enrollment. | | Friendly Name | A descriptive name for the enrollment token to help identify its purpose. | | Deployment Zone | Which deployment zone enrolled servers will be placed in. | | Server Pool | (Optional) Which pool enrolled servers will join. | | Max Uses | Maximum number of times this token can be used for enrollment. Must be greater than 0. | | Expiration Date | Date when the token expires and can no longer be used. Defaults to 48 hours in the future. | | Connection Port | Which port to connect to enrolled servers on. | | Connection Type | RDP connection type for servers. | | Connection Credential Type | Which type of credentials are used for enrolled servers. Options are Static Credentials, Dynamic User Accounts, SSO User Accounts, and Authenticate with Smartcard | | SSO Username Domain | This field applies when **Connection Credential** Type is set to `SSO User Accounts`. Use this field to modify the username. For example, in Kasm the username may be john.smith@acme.com, but the target system may expect john.smith@acme.local. A value of `localhost` strips the domain name from the username, i.e. `john.smith`. A value ending in `\` prepends this field to the username, i.e. `acme.local\john.smith`. All other values are appended to the username with @, i.e. `john.smith@acme.local`. | | Connection Username | The username to use to connect to enrolled servers. Only visible with Static Credentials **Connection Credential** Type. | | Connection Password | The password to use to connect to enrolled servers. Only visible with Static Credentials **Connection Credential** Type. | | Connection Info | (Optional) Additional connection info that needs to be passed to enrolled servers. For more information see the Connections section of the [global settings](../../../reference/settings.mdx) | | Max Simultaneous Sessions | The maximum amount of sessions that can connect to each enrolled server at a time. Must be greater than 0. For RDP servers with RemoteApps, admins may want to set this value higher than the `Max Simultaneous Users` setting to allow for multiple RemoteApps per user. | | Max Simultaneous Users | For RDP and SSH servers, the number of concurrently connected users per enrolled server. | ## Using Enrollment Tokens ### Server Enrollment Enrollment tokens can be used to enroll servers either manually through the Admin UI or programmatically via scripts. For detailed instructions on manual enrollment and automated scripting approaches for Windows servers, see the [Kasm Desktop Service](windows/kds-windows-service.mdx) section, and for Linux servers, see the [Kasm Desktop Service](linux/linux-service.mdx) section. Normally, the server hostname value is used to connect to the server however it cannot currently be templated and must be dynamically detected. In order to do so we attempt to connect to the server, first via the server's FQDN and if that fails we attempt to connect using the request IP address. If both attempts to establish connectivity to the server are unsuccessful, enrollment will fail. ### Enrolled Server Management Once servers are enrolled using tokens, they appear in the Infrastructure->Servers->Servers list and can be managed like any other server. The name of the server is derived from the template name plus the first 6 digits of the server ID. Enrolled servers display: - Which enrollment token was used - Enrollment timestamp - All standard server management options In order for enrolled servers to be accessible to users, a [Workspace](../container-workspace/workspaces.mdx) must be created and then add the Workspace to a [Group](../../security/users-groups-mgmt/groups.mdx). ## Token Management ### Viewing Token Usage Monitor enrollment token usage by navigating to Infrastructure->Servers->Server Enrollment Tokens. Each token displays: - Number of times used - Max uses - Expiration status ### Disabling Tokens To prevent further use of an enrollment token, navigate to Infrastructure->Servers->Server Enrollment Tokens and disable or delete the token. Existing enrolled servers remain unaffected. Treat enrollment tokens as sensitive credentials. Store tokens securely and rotate them regularly. Disabling or deleting a token does not affect servers that were previously enrolled using that token. ### Viewing Deleted Tokens Deleted enrollment tokens can still be viewed in the admin UI for debugging purposes. If you know the UUID of a deleted token, navigate to `https:///#/view_server_template/` to inspect its configuration details. --- ## Fixed Infrastructure: RDP, VNC, SSH, KasmVNC # Fixed Infrastructure - RDP/VNC/SSH/KasmVNC ## Overview Kasm Workspaces can be configured to connect to fixed remote endpoints that are using either the [Remote Desktop Protocol](https://en.wikipedia.org/wiki/Remote_Desktop_Protocol) or [KasmVNC](https://github.com/kasmtech/KasmVNC). This document will be going over the steps needed to configure these endpoints and present them to users on the Workspaces dashboard. ## Remote Desktop Protocol - RDP In this example an RDP endpoint is an external Windows server with RDP enabled that is always online and waiting for an external connection. This server is not managed by Kasm Workspaces in any way, Kasm Workspaces is simply providing a web based methodology of connecting to it. In order to add the server, first create a server record under Infrastructure > Servers > + Add. This example uses the following connection information: ``` Host: windows.example.com Port: 3389 User: Administrator Password: windowstest123 ``` Once configured it should look like this: (note the name and type assigned to this server) ![Create Windows Server](/img/fixed_infrastructure/windows-server.webp) The value of **Max Simultaneous Sessions** is limited to one as this is a single Windows server without sharing. Click submit, and then link this server to a Workspace that can be launched from the User dashboard. Click on Workspaces > Workspaces > + Add Workspace. Select **Server** as **Workspaces Type**, choose a friendly name and description, click enabled, and select the server that was just configured from the **Server** dropdown. In this case **windows.example.com : Windows Test**. Once configured it should look like this: ![Create Windows Workspace](/img/fixed_infrastructure/windows-workspace.webp) Click Save and the server will be available to launch from the User Dashboard: ![Button in User Dashboard](/img/fixed_infrastructure/windows-launch.webp) ### Advanced Settings **Connection info (JSON)** settings can be found [here](../../../reference/settings.mdx). These can be used on a per server basis to override the defaults found under **Settings**. Some features like file upload/downloads, screenshots, and resource monitoring are only available on a Windows RDP server with a Kasm Desktop Service installed. For installation instructions please see [here](./windows/kds-windows-service.mdx). Connections to standard RDP servers will still function without these additional features if this service is not installed and running. #### Forcing login on connection When connecting to a Windows RDP endpoint it is possible to omit the **Connection Username** and **Connection Password** settings to force the user to login when launching the workspace. If omitted the user will be presented with a web based login page each time they launch the Workspace. ## VNC In this example a VNC endpoint is an external Linux server with VNC installed and configured that is always online and waiting for an external connection. This server is not managed by Kasm Workspaces in any way, Kasm Workspaces is simply providing a web based methodology of connecting to it. In order to add the server, first create a server record under Infrastructure > Servers > + Add. This example uses the following connection information: ``` Host: vnc.example.com Port: 5901 Password: windowstest123 ``` Once configured it should look like this: (note the name and type assigned to this server) ![Create VNC Server](/img/fixed_infrastructure/vnc-server.webp) The value of **Max Simultaneous Sessions** is limited to one as VNC only allows one user to have control. Click Save, and now this server will need linked to a Workspace that can be launched from the User dashboard. Click on Workspaces > Workspaces > + Add Workspace. Select **Server** as **Workspaces Type**, choose a friendly name and description, click enabled, and select the server that was just configured from the **Server** dropdown. In this case **vnc.example.com : VNC Test**. Once configured it should look like this: ![Create VNC Workspace](/img/fixed_infrastructure/vnc-workspace.webp) Click Save and the server will be available to launch from the User Dashboard: ![Button in User Dashboard](/img/fixed_infrastructure/vnc-launch.webp) ### Advanced Settings **Connection info (JSON)** settings can be found [here](../../../reference/settings.mdx). These can be used on a per server basis to override the defaults found under **Settings**. #### Forcing login on connection When connecting to a VNC endpoint it is possible to omit the **Connection Password** setting to force the user to login when launching the workspace. If omitted the user will be presented with a web based login page each time they launch the Workspace. ## SSH In this example an SSH endpoint is an external Linux server with SSH enabled that is always online and waiting for an external connection. This server is not managed by Kasm Workspaces in any way, Kasm Workspaces is simply providing a web based methodology of connecting to it. In order to add the server, first create a server record under Infrastructure > Servers > + Add. This example uses the following connection information: ``` Host: ssh.example.com Port: 22 User: Administrator Connection Private Key: ``` Once configured it should look like this: (note the name and type assigned to this server) ![Create SSH Server](/img/fixed_infrastructure/ssh-server.webp) Click Save, and then link this server to a Workspace that can be launched from the User dashboard. Click on Workspaces > Workspaces > + Add Workspace. Select **Server** as **Workspaces Type**, choose a friendly name and description, click enabled, and select the server that was just configured from the **Server** dropdown. In this case **ssh.example.com : SSH Test**. Once configured it should look like this: ![Create SSH Workspace](/img/fixed_infrastructure/ssh-workspace.webp) Click Save and the server will be available to launch from the User Dashboard: ![Button in User Dashboard](/img/fixed_infrastructure/ssh-launch.webp) ### Advanced Settings **Connection info (JSON)** settings can be found [here](../../../reference/settings.mdx). These can be used on a per server basis to override the defaults found under **Settings**. To use the locale and timezone settings the SSH server must allow guacamole to set two environment variables, in the sshd_config of the target server ensure `AcceptEnv TZ` and `AcceptEnv LANG` are configured. In addition, any locales that are to be used must be installed on the server and defined localedef as the ISO 639-1 language code, an '_', the ISO 3166 Territory/county code, and the encoding. For instance: en_GB.UTF-8 this is english, United Kingdom encoded in UTF-8. Kasm assumes UTF-8 for all encodings. #### Forcing login on connection When connecting to a SSH endpoint it is possible to omit the **Connection Username** and the **Connection Password** or **Connection Private Key** settings to force the user to login when launching the workspace. If omitted the user will be presented with a web based login page each time they launch the Workspace. ## KasmVNC In this example a KasmVNC endpoint is an external stand alone Linux machine running [KasmVNC](https://github.com/kasmtech/KasmVNC). This server is not managed by Kasm Workspaces in any way, Kasm Workspaces is simply providing an enhanced web based methodology of connecting to it. In order to add the server, first create a server record under Infrastructure > Servers > + Add. This example uses the following connection information: ``` Host: kasm.example.com Port: 6901 User: admin Password: admin123 ``` Once configured it should look like this: (note the name and type assigned to this server) ![Create KasmVNC Server](/img/fixed_infrastructure/kasm-server.webp) Click Save and then link this server to a Workspace that can be launched from the User dashboard. Click on Workspaces > Workspaces > + Add Workspace. Select **Server** as **Workspaces Type**, choose a friendly name and description, click enabled, and select the server that was just configured from the **Server** dropdown. In this case **kasm.example.com : Kasm Test**. Once configured it should look like this: ![Create KasmVNC Workspace](/img/fixed_infrastructure/kasm-workspace.webp) Click Save and the server will be available to launch from the User Dashboard: ![Button in User Dashboard](/img/fixed_infrastructure/kasm-launch.webp) ### Advanced Settings **Connection info (JSON)** settings can be found [here](../../../reference/settings.mdx). These can be used on a per server basis to override the defaults found under **Settings**. ## Server Pools The previously configured individual server endpoints were linked to Workspaces that can be launched from the user dashboard. These individual servers can also be tagged to a Pool of servers and launched from a single Workspace using any available server from the pool. This example will be adding a server pool and tagging two servers to it. First from the Admin dashboard click on Infrastructure > Pools > + Add. Assign a name to the pool and select **Server** under **Type**, when finished it should look like this: ![Create Server Pool](/img/fixed_infrastructure/server-pool.webp) After clicking Save the administrator will be presented with the ability to add new servers or assign existing servers. This example will be assigning the servers created previously in this document: ![Servers in Pool](/img/fixed_infrastructure/servers-in-pool.webp) This server pool can be any combination of RDP/KasmVNC server endpoints, but in a production scenario they will likely be a series of similar Virtual or Bare metal servers available for users to connect to. Outside of editing the existing pool, individual servers can also be assigned to a pool by editing them and selecting the pool the administrator wants to use under the **Pool** setting. With a pool of servers configured the Workspace will need to be created. Click on Workspaces > Workspaces > + Add Workspace. Select **Pool** as **Workspaces Type**, choose a friendly name and description, click enabled, and select the pool that was just configured from the **Pool** dropdown. In this case **Test**. Once configured it should look like this: ![Create Pool Workspace](/img/fixed_infrastructure/pool-workspace.webp) Click Save and the pool of servers will be available to launch from the User Dashboard: ![Button in User Dashboard](/img/fixed_infrastructure/pool-launch.webp) --- ## Authentication # Linux Authentication When defining a [single static server](../static-servers.mdx) or an [auto-scaled pool](../auto-scaled-servers.mdx), the administrator needs to provide a **Connection Credential Type**, **Connection Username**, and **Connection Password** to use to connect to the server(s). There are three options administrators have when considering the connection credentials. ### Static Credentials The administrator would select *Static Credentials* for the **Connection Credential Type** and put in a static username and password into the **Connection Username** and **Connection Password** of the Server or Auto-Scale configuration. All Kasm user's connections would use these credentials for authentication. **Advantages** - Simple **Disadvantage** - All Kasm users are the same user on the Linux system. This has security and auditing ramifications. - Only a single concurrent session per server could be allowed. When using Static Credentials authentication, both a download directory (for example, ~/Downloads) that does not exist or is not owned by the authenticated user and a missing Connection Username (which leaves the Kasm Desktop Service unable to resolve a session username, so it falls back to a default of username not found) cause uploaded and downloaded files to be stored in the default upload and download directories configured for the Kasm Desktop Service (by default /opt/kasm-desktop-service/Upload and /opt/kasm-desktop-service/Download) rather than in the user's home directory. ### Prompt User If the **Connection Username** and **Connection Password** fields are left blank in the Server or Auto-Scaling configuration and *Static Credentials* is selected for the **Connection Credential Type**, the user will be prompted to enter their Linux username and password. **Advantages** - Simple - Allows for multiple concurrent user sessions per Linux server - All users could have a different account in Linux **Disadvantage** - Users have to enter their credentials every time they connect to a Linux system. - Features that rely on a resolved Kasm Desktop Service username (e.g., screenshots, storage mounts, scripts and user profile based file mappings) will not be available. When using Prompt User authentication with Web Native RDP, uploaded and downloaded files are not placed into the user's home or profile directory (for example, /home/<username>/Downloads on Linux). Instead, files are stored in the default upload and download directories configured for the Kasm Desktop Service. ### Single Sign-On with Dynamic Local Accounts With the [Kasm Desktop Service](linux-service.mdx) installed, Kasm can automatically manage local Linux user accounts on the target server. Each time a user creates a Kasm session to a Linux server, a local user account is created on the Linux server if it does not already exist. A random password is assigned to the local Linux user account with each session. The username generated by Kasm is the first 9 characters of the Kasm Workspaces username in lower case, with special characters replaced with a `-`, followed by a `-` and 10 characters from the Kasm Workspaces User ID. For example, `Jon.Doe@example.com` with a Kasm User ID of `bf262ada-0a7f-4f49-b435-e50537caa013` would result in a local Linux account of `jon-doe-e-bf262ada0a`. To configure dynamic local accounts, the Kasm Desktop Service must be installed and registered. In the server or auto-scale configuration, select *Dynamic User Accounts* for the **Connection Credential Type**. and the **Kasm Desktop Service Installed** option must be enabled. The Kasm Desktop Service comes with built-in bash scripts which are executed for various purposes. There is a bash script responsible for creating local users and setting the password for an incoming session. If you have special requirements, you may edit this script for your exact needs. See the [Service scripts](./linux-service.mdx#scripts) section for more details. **Advantages** - Allows for multiple concurrent user sessions per Linux server. - All users have different accounts in Linux. - Single Sign-on from Kasm to Linux, so users don't get prompted to enter credentials when connecting to Linux. - Works with any authentication mechanism, OIDC, SAML, LDAP, local Kasm accounts. - Simple configuration with no requirement for Active Directory or other external dependencies. **Disadvantages** - Currently only supported for use with RDP connections. ### Single Sign-on with Active Directory This option applies only if users authenticate to Kasm using Active Directory credentials with Kasm configured with [LDAP Authentication](../../../security/users-groups-mgmt/ldap.mdx). Additionally, the Linux servers being connected to must be a member of the same Active Directory domain that LDAP authentication is configured for. Auto-scaling configurations can [join new VMs to the domain](../auto-scaled-servers.mdx) and remove them. When using auto-scaling to join VMs to Active Directory, review the [Linux VM startup script README](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/blob/develop/linux_vms/README.md) for the required configuration. Usernames used by users to authenticate to Kasm must match the username that users would use to authenticate to Linux systems. In the server or auto-scale configuration, select *SSO User Accounts* for the **Connection Credential Type**. Leave the **SSO Domain** blank if the domain the user logs into Kasm with is the same as the domain name used for Linux login. You may specify a different *SSO Domain* to change the username's domain. For example, if a user logs into Kasm with `jon.smith@public.domain.com`, but Linux login expects `jon.smith@private.domain.local`, set the *SSO Domain* to `private.domain.local`. After configuring LDAP based SSO and/or providing a user access to a Workspace that is configured for LDAP based SSO, users must sign out of Kasm and then back in, in order for SSO to work. **Advantages** - All users have different accounts in Linux. - Single Sign-on from Kasm to Linux, so users don't get prompted to enter credentials when connecting to Linux. **Disadvantages** - More complexity in additional configuration and systems to manage. - SAML and OIDC not supported as Kasm authentication methods. --- ## Managing Linux VMs with Kasm Workspaces: Admin Guide # Linux This guide is intended to help administrators understand how they can manage and support Linux VMs through Kasm Workspaces. --- ## Linux Service # Kasm Desktop Service Kasm Desktop Service is a service that provides additional capabilities to users that are connected to the desktop through Kasm Workspaces: - Upload files to the remote desktop - Download files from the remote desktop - See a preview screenshot of the desktop in the Kasm Workspaces dashboard - Run bash [scripts](linux-service.mdx#scripts) on session start, session end, or service start - [Kasm managed local users](authentication.mdx#single-sign-on-with-dynamic-local-accounts) and credentials - [File Mapping](../../file-mappings.mdx) - Supports multiple concurrent users on the same system ### Video Tutorial ### Installation The Kasm Desktop Service can be installed using one of the installers below. Service files and scripts are placed in `/opt/kasm-desktop-service/`, configuration and certificates in `/etc/kasm-desktop-service/`, and logs in `/var/log/kasm-desktop-service/`. You should use the latest version that supports the version of Kasm Workspaces you have installed. #### .deb Packages | Installer Version | Installer Links | Kasm Workspaces Compatibility | SHA256 | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | Developer Preview | [amd64](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service_0.0%2Bdevelop_amd64.deb) [arm64](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service_0.0%2Bdevelop_arm64.deb) | develop | Rolling. Checksums available [here](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service-sha256sum.txt) | | 1.8 | [amd64](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_linux_service_installer_x86_64_1.8_8e3b288d3.deb) [arm64](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_linux_service_installer_arm64_1.8_8e3b288d3.deb) | 1.19.0 | amd64: 25613f3979eb2596c3d7a289d2e49fa26670fc77397615f3f53afbf59f959e32 arm64: 10d16e3a632f273f61f7d12d5997088bf175eb355c30e254c423581ec666f54c | After downloading, install with (replace the filename with the one you downloaded): ```bash sudo apt-get update -y sudo apt-get install -y ./kasm-desktop-service.deb ``` #### .rpm Packages | Installer Version | Installer Links | Kasm Workspaces Compatibility | SHA256 | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | Developer Preview | [amd64](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service_0.0%2Bdevelop_amd64.rpm) [arm64](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service_0.0%2Bdevelop_arm64.rpm) | develop | Rolling. Checksums available [here](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm-desktop-service-sha256sum.txt) | | 1.8 | [amd64](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_linux_service_installer_x86_64_1.8_8e3b288d3.rpm) [arm64](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_linux_service_installer_arm64_1.8_8e3b288d3.rpm) | 1.19.0 | amd64: 50c0774fc1183f1a5844fabf53dc7e12bf358cc827633c16fd3be418fd1f6d26 arm64: 79a937a2ac6a36517ae152502e3a392a655352af902012ea383f350b5dd4f719 | After downloading, install with (replace the filename with the one you downloaded): ```bash sudo dnf install -y ./kasm-desktop-service.rpm ``` When installing KDS on RHEL-based operating systems, it is recommended to enable the EPEL repository beforehand, as it is required for installing certain dependencies( eg. rclone, gnome-screenshot). It is also recommended to use RHEL 9, as RHEL 10 is still maturing at this time. Additionally, please install the recommended gnome-screenshot package, if available, as it is required for the screenshot API. Since some desktop environments have not yet fully matured, this dependency is currently provided as optional in RPM packages. The [Developer Preview Build](../../../../reference/builds.mdx) of the Kasm Desktop Service listed above should only be used with the developer preview build of Kasm Workspaces on non-production systems. The documentation on this page is for the latest version of the installer listed in the table above and may not be accurate for older versions. The Kasm Desktop Service uses HTTPS/SSL to communicate with the rest of the Kasm Workspace services. For `ufw` and `firewall-cmd` firewall services, the KDS installer will attempt to open TCP port 4902. Ensure that firewalls and/or cloud security groups allow the following connections: | Direction | Protocol | Port | Use | |----------|----------|------|-----| | Inbound | TCP | 4902 | Control communication from Kasm Services | | Inbound | TCP | 3389 | RDP connection from the user or Kasm Services | | Outbound | TCP | 443 (default) | KDS communication to Kasm Services | The following instructions are for static servers. 1. Login to Kasm as an administrator 2. Create a [new Server](../static-servers.mdx#servers), you can optionally make the server part of a [Pool](../static-servers.mdx#server-pools) 3. Ensure the `Kasm Desktop Service Installed` option is enabled when creating the server. 4. On the server, download the appropriate version of the Kasm Desktop Service from the table above. 5. Run the installer. The installer does not prompt for registration details — it installs the service and starts it. 6. After installation completes, register the service by running: ```bash sudo bash /opt/kasm-desktop-service/scripts/register_wizard.sh --register ``` If a graphical display is available, a GUI dialog will appear. Over SSH or on a headless system, it will prompt on the command line.
7. Enter the Kasm API host, port (default 443), and the Registration Token. In the Kasm Admin UI, navigate to **Infrastructure → Servers → Servers**, find the target server and click **Edit**. In the Kasm Agent section, press the copy button on the **Registration Token** field.
8. (Optional) Enter the API path prefix if your Kasm deployment is hosted behind a path-based proxy (for example, /kasmapp). #### Registration Troubleshooting During registration, the Kasm Desktop Service will attempt to connect to the Kasm Workspaces deployment. During the registration process the following checks are performed. * Can the Kasm Desktop Service talk to the Kasm Workspaces deployment on the specified port and hostname. * Can the Kasm Workspaces deployment talk to the Kasm Desktop Service on port 4902 using the hostname/IP specified in the Server record in Kasm Workspaces. * Is the registration token digitally signed by the Kasm Workspaces deployment, not expired, and assigned to the server being registered. If any of these conditions fail, you will get an error message during registration. Please attempt to correct issues such as DNS resolution of hostname, firewall rules, or expired registration token. You can retry registration with the following command: ```bash sudo bash /opt/kasm-desktop-service/scripts/register_wizard.sh --register ``` If the network check fails, update your firewall rules to allow the required ports (see the table above), then restart the service before retrying: ```bash sudo systemctl restart kasm-desktop.service ``` You can then prompt another network check from Kasm Workspaces using the following: ```bash sudo bash /opt/kasm-desktop-service/scripts/register_wizard.sh --network-check ``` #### Scripted Installation The installation and registration of the Kasm Desktop Service can also be scripted. The installation is non-interactive — no registration prompts occur during `apt install` or `dnf install`. After installing, register using one of the commands below. Register with interactive command-line prompts: ```bash sudo bash /opt/kasm-desktop-service/scripts/register_wizard.sh --register --no-gui ``` Register without interactive input: ```bash # Note: set the variables used in the following command with values appropriate for your deployment sudo bash /opt/kasm-desktop-service/scripts/register_wizard.sh --register --no-gui \ --api-host="$API_HOST" \ --api-port="$API_PORT" \ --token="$REG_TOKEN" \ --api-url-prefix="$API_URL_PREFIX" # optional: only needed if Kasm is behind a path-based proxy ``` After re-registering, restart the service for changes to take effect: ```bash sudo systemctl restart kasm-desktop.service ``` The registration command will auto-detect the absence of a display, e.g. when you are using a SSH session. In this scenario, it will use `--no-gui` by default and prompt on the command line for the registration details. The service directory `/opt/kasm-desktop-service/` will have its own isolated userspace as per the systemd file. For the best possible security, ensure that normal users do not have read access to the Kasm service directories (`/opt/kasm-desktop-service/` and `/etc/kasm-desktop-service/`) as they contain potentially sensitive information. #### XRDP Setup Kasm Desktop Service on Linux requires XRDP with XFCE for reliable multi-user operation, below script can be used to setup the environment. ```bash #!/usr/bin/env bash set -euo pipefail sudo apt update -y || true sudo apt install -y \ xrdp \ xfce4 \ xfce4-goodies \ dbus-x11 \ xorg \ x11-xserver-utils # Allow XRDP to access SSL certs sudo adduser xrdp ssl-cert # Enable and start XRDP sudo systemctl enable xrdp sudo systemctl restart xrdp # Set XFCE as default session for all dynamic users sudo bash -c 'echo "xfce4-session" > /etc/skel/.xsession' sudo bash -c 'echo "xfce4-session" > /etc/skel/.Xsession' sudo chmod 644 /etc/skel/.xsession /etc/skel/.Xsession # Ensure XRDP launches XFCE reliably sudo bash -c 'cat >/etc/xrdp/startwm.sh </etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-screensaver.xml < EOF' sudo bash -c 'cat >/etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml < EOF' # Fix Polkit color-manager permission prompts sudo mkdir -p /etc/polkit-1/localauthority/50-local.d sudo bash -c 'cat >/etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla </home/<username>/Downloads on Linux). Instead, files are stored in the default upload and download directories configured for the Kasm Desktop Service. When using Static Credentials authentication, both a download directory (for example, ~/Downloads) that does not exist or is not owned by the authenticated user and a missing Connection Username (which leaves the Kasm Desktop Service unable to resolve a session username, so it falls back to a default of username not found) cause uploaded and downloaded files to be stored in the default upload and download directories configured for the Kasm Desktop Service (by default /opt/kasm-desktop-service/Upload and /opt/kasm-desktop-service/Download) rather than in the user's home directory. #### Authentication of Service All requests to the application must contain a JWT token parameter that will be verified against the provided JWT key. The JWT key (also referred to as the **API Cert**) is generated upon Kasm Workspaces installation and can be retrieved from Kasm `Settings` panel section. The public JWT token is retrieved during registration. If you change the JWT cert and key on your Kasm Workspaces deployment, you will need to re-register your Kasm Desktop Service. ### Scripts Kasm utilizes a number of scripts and provides administrators hooks to execute their own scripts during certain events. When scripts get executed by the Kasm Service, environment variables are automatically injected so that your script has access to contextually relevant information. See the [variables](linux-service.mdx#variables) section for more details. The default location for scripts is `/opt/kasm-desktop-service/scripts`. [File Mapping](../../file-mappings.mdx) can be used to manage custom scripts within the Kasm UI. With this directory there are the following sub directories with the following purposes. **Script Directories** | Directory | Description | |-----------------|-----------------------------------------------------------------------------------------------------| | builtin | Scripts ran by the Kasm Service to execute specific actions. See the following section for details. | | service_startup | Scripts placed here will automatically be executed when the Kasm service starts. | | session_start | Scripts placed here will automatically be executed before a user session starts. | | session_end | Scripts placed here will automatically be executed before a user session is terminated. | #### Builtin Scripts The following builtin scripts exist for the defined purpose. These built-in scripts require a resolved username variable. As a result, they are **not executed for Prompt User connections**, where no system username is available. **create_local_account.sh** This script is executed during session creation, if [Dynamic Local Account SSO](authentication.mdx#single-sign-on-with-dynamic-local-accounts) is configured. This script creates a local account for the requesting user, if it does not already exist, and retrieves a one-time random password to set for the user account. The API call to retrieve the one-time password uses a JWT token that is defined in a [builtin variable](linux-service.mdx#variables). The JWT token has short expiration time and can only be used once to retrieve the one-time password. The script also creates a user-specific environment file at `$HOME/.kasm_env` and configures it to be sourced by standard shell startup files, making the variables available to all interactive shells. The user can modify this file, e.g. to comment-out variables they do not want loaded in interactive sessions. Storing sensitive variable values in this file is discouraged. **logoff_user.sh** This script will log the user off the session when the user deletes their Kasm session. Dynamic session users are added to the `sudo` group, but the per-session account password is generated by Kasm and used only for the RDP handshake. It is never shown to the user, so interactive `sudo` prompts (for example, `sudo apt install ...`) cannot be answered, and software installs fail even though the user has `sudo` rights. Choose the option below that fits your deployment. SSH into the server and install the required packages system wide. The software is then available to every session, with no changes to sudo or to the Kasm scripts. ```bash sudo apt-get install -y ``` For autoscaled pools you cannot install on each ephemeral VM by hand, so modify the [autoscale startup script](https://github.com/kasmtech/workspaces-autoscale-startup-scripts/blob/develop/linux_vms/README.md) to install the required packages when the VM is provisioned, or grant the dynamically created user passwordless `sudo` so they can install packages themselves. To grant passwordless `sudo`, add a sudoers drop-in for the session user in `create_local_account.sh`, immediately after the account is created: ```bash # Allow the Kasm session user to install software without knowing the # Kasm-generated password. Validated with visudo before it takes effect. sudoers_file="/etc/sudoers.d/kasm-${username}" echo "${username} ALL=(ALL) NOPASSWD: ALL" | sudo tee "$sudoers_file" > /dev/null sudo chmod 0440 "$sudoers_file" sudo visudo -cf "$sudoers_file" || { echo "Invalid sudoers entry; removing"; sudo rm -f "$sudoers_file"; } ``` `logoff_user.sh` deletes the account with `userdel -r`, which does not remove files under `/etc/sudoers.d/`. Add a matching cleanup line next to the `userdel` call so a reused dynamic username cannot inherit passwordless root: ```bash rm -f "/etc/sudoers.d/kasm-${username}" ``` If a user needs specific packages, use a [session_start script](linux-service.mdx#scripts) to install them into the dynamically created user's session when the session starts. `NOPASSWD: ALL` grants unrestricted passwordless root for the life of the session. If sessions only need to install software, scope the rule to the package manager instead, keeping the `visudo` validation and the logoff cleanup either way: ```bash echo "${username} ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get, /usr/bin/dpkg, /usr/bin/snap" | sudo tee "$sudoers_file" > /dev/null ``` **load_persistent_profile.sh** This script is called during session creation, before a user connects and after create_local_account.sh is called (if required). The script is empty in the current version but provides the administrator the ability to define their own hook to load persistent profiles from users using third party solutions. The script has access to builtin variables defined below. **save_persistent_profile.sh** This script is called during session termination, after the user is logged out. The script is empty in the current version but provides the administrator the ability to define their own hook to save persistent profiles for users using third party solutions. The script has access to builtin variables defined below. **map_storage.sh** This script is called during session creation, before a user connects and after create_local_account.sh is called (if required). This script is used to map in [Cloud Storage](../../../data-storage/storage-mappings/index.mdx) definitions for users. This script has access to [builtin variables](linux-service.mdx#variables) in addition to a `storage_mapping` variable, which contains the storage mapping definition in JSON format. This script is called for each storage mapping that is applicable to the user that is creating the session. All storage mappings are placed on the user's Desktop. If, for example, a Storage Mapping with a target of /OneDrive would be mapped to `/home//Desktop/OneDrive` on a Linux system. This script requires rclone. **unmap_storage.sh** This script is called during session termination, after the user is logged off. The script removes any mapped [Cloud Storage](../../../data-storage/storage-mappings/index.mdx) volumes that were added with the map_storage script. This script has access to [builtin variables](linux-service.mdx#variables) in addition to a `storage_mapping` variable, which contains the storage mapping definition in JSON format. This script is called for each storage mapping that is applicable to the user that is creating the session. #### Variables The following variables are builtin and available for any script executed by the Kasm Service. | Name | Description | |------------------|-----------------------------------------------------------------------------------------------------| | user_id | The Kasm User ID for the user creating/terminating the session. | | username | The username of the user creating/terminating the session. | | kasm_id | The Kasm session ID for the session being created/terminated. | | kasm_user | (session_start scripts only) The Kasm username starting the session. | | jwt_token | A limited access and short lived JWT token that can be used to make API calls to Kasm. | | api_host | The IP address or hostname of the API server or load balancer for the API servers. | | api_port | The port number of the API server. | | api_url_prefix | (Optional) The path prefix for API requests if Kasm is hosted behind a path-based proxy. | These variables can be referenced in scripts defined by the administrator. The full output of any script that runs, including its exit code, is logged. ### Logging By default, all log messages are written to standard output and captured by systemd/journald. Administrators can inspect service logs using: `journalctl -u kasm-desktop.service` Registration and installation logs are available under: `/var/log/kasm-desktop-service/` In addition, all application logs are also sent to the Kasm Workspaces deployment and can be viewed in the Kasm Admin UI under Diagnostics->Logging. ### Launching a GUI application GUI applications can be launched manually by users from within an active XRDP session. When automating application startup with Kasm Desktop Service, GUI applications are typically launched using session_start scripts located at: `/opt/kasm-desktop-service/scripts/session_start/` XRDP assigns X11 displays dynamically for each user session, so automated scripts cannot assume a static display such as :0 and must determine the active DISPLAY at runtime. In addition, the desktop environment (XFCE) may not be fully initialized when the script executes, requiring scripts to wait for the session to become ready before launching applications. Below is a simple example of launching a GUI application using a simple session_start script, ```bash #!/usr/bin/env bash set -euo pipefail echo "[gui-start] Starting GUI app launcher..." # Provided by KDS username="$username" home="/home/$username" AUTH="$home/.Xauthority" uid=$(id -u "$username") # Needed for GUI apps export XDG_RUNTIME_DIR="/run/user/$uid" export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus" # Find REAL XRDP DISPLAY for this user find_display() { # Find displays owned by the user for d in $(pgrep -au "$username" Xorg | grep -o ":[0-9]\+"); do # Check if XFCE window manager is running on this display if sudo -u "$username" DISPLAY="$d" XAUTHORITY="$AUTH" \ pgrep -u "$username" xfwm4 >/dev/null 2>&1; then echo "$d" return fi done } # Wait for DISPLAY for i in {1..30}; do DISP=$(find_display) if [[ -n "${DISP:-}" ]]; then export DISPLAY="$DISP" export XAUTHORITY="$AUTH" echo "[gui-start] Using DISPLAY=$DISPLAY" break fi echo "[gui-start] Waiting for XRDP display..." sleep 1 done if [[ -z "${DISPLAY:-}" ]]; then echo "[gui-start] FAIL: Could not detect XRDP display" exit 1 fi # Wait for XFCE session for i in {1..20}; do if pgrep -u "$username" xfwm4 >/dev/null && pgrep -u "$username" xfce4-session >/dev/null; then echo "[gui-start] XFCE session ready" break fi echo "[gui-start] Waiting for XFCE startup..." sleep 1 done # LAUNCH the GUI app -- using a game as example APP="/usr/games/chromium-bsu" # Ensure installed if [[ ! -x "$APP" ]]; then echo "[gui-start] Installing chromium-bsu..." apt-get update -y && apt-get install -y chromium-bsu fi echo "[gui-start] Launching chromium-bsu..." sudo -u "$username" DISPLAY="$DISPLAY" XAUTHORITY="$AUTH" "$APP" >/dev/null 2>&1 & echo "[gui-start] GUI app launched." exit 0 ``` --- ## Remote macOS Access Configuration # MacOS Workspaces This step-by-step tutorial will walk you through the process of enabling remote management on MacOS and configuring the server in Kasm Workspaces. By following these instructions, you'll be able to seamlessly access and utilize MacOS systems remotely. ## Enabling Remote Management in MacOS To begin, you need to enable remote management on your MacOS system. Remote management allows you to access and control your MacOS system from a remote location. 1. Open the `Settings` app on your MacOS system and navigate to the `General` section. 2. Scroll down to locate and click on `Sharing`. ![Location of Sharing Section](/img/macos_servers/image1.webp) 3. Within the `Sharing` settings, find the option labeled `Remote Management` and enable it. 4. Click on the `information icon` next to the Remote Management toggle. ![Location of Remote Management](/img/macos_servers/image2.webp) 5. (Optional) If you want to customize the remote management options further, click on the computer settings button. Uncheck all the boxes and click OK. ![Remote Management Options](/img/macos_servers/image3.webp) 6. To refine access permissions, change the option from `All Users` to `Only these users`. 7. Add your user account to the list of allowed users. 8. Click on your user account and select `Options`. - Check the `Observe` checkbox to enable viewing the MacOS system remotely. - Check the `Control` checkbox to allow remote control of the MacOS system. - Click `OK` to save the settings. ![Adding User to Only These Users](/img/macos_servers/image4.webp) By completing these steps, you have successfully enabled remote management on your MacOS system, allowing it to be accessed remotely. ## MacOS Server Configuration Now that remote management is enabled on your MacOS system, it's time to configure it in Kasm Workspaces. Follow the steps below to set up the server: 1. Log in to Kasm as an administrator using your credentials. 2. In the Kasm dashboard, navigate to the `Infrastructure` section and select `Servers`. 3. Locate the `Servers List` and click on the `Add` button. 4. In the `Create Server` panel, provide the following information: - Choose a `Friendly name` for your server to easily identify it. - Enter the `IP address` of the MacOS system you want to connect to. - Select `VNC` as the `Connection Type`, which is the remote access protocol used by MacOS. - Set the `Port` to `5900`, the default port for VNC. - Enter your MacOS `Username` and `Password` to authenticate the connection. - Set the `Max Simultaneous Sessions` to 1, ensuring exclusive access to the server. - Select the desired `deployment zone`. - Click `Save` to save the server configuration. ![Adding A Server to Kasm Workspaces](/img/macos_servers/image5.webp) Congratulations! You have successfully configured your MacOS system as a server in Kasm Workspaces. ## Create a Workspace To make the MacOS system accessible to users in Kasm Workspaces, you need to create a workspace. The workspace provides a virtual environment for users to interact with the MacOS system. Follow the steps below to create a workspace: 1. Log in to Kasm as an administrator using your credentials. 2. In the Kasm dashboard, go to the `Workspaces -> Workspaces` section in the Admin UI. 3. Locate the list of workspaces and click on `Add Workspace`. 4. In the `Create Workspace` panel, provide the required information: - Select `Server` as the `Workspace Type` to connect to the previously configured MacOS server. - Enter a `friendly name` for the workspace, which will be displayed to users. - Provide a `description` of the workspace to give users an idea of its purpose. This step is optional: If you want to personalize the workspace, you can provide a **URL** to a thumbnail image that will be displayed as an icon for this workspace. - Check the `Enable` box to activate the workspace. - From the `server` dropdown, select the server you created in the previous section. - Click the `Save` button to save the workspace configuration. By following these steps, you have successfully created a workspace, allowing users to access and utilize the MacOS system remotely through Kasm Workspaces. Now, users can enjoy the convenience of remotely accessing and interacting with MacOS systems using Kasm Workspaces. --- ## Static Servers Kasm supports managing user session and user access to fixed servers on Windows and Linux. These backend servers can be virtual machines running on-premise, the cloud, or physical servers. #### Windows The above video walks through the process of adding fixed Windows servers to your Workspaces deployment. ### Server Pools Server pools is an optional concept for fixed servers. Administrators have the option to group fixed servers into a [Server Pool](../../infra-autoscale/pools.mdx). This allows you to then provide users access to a pool of servers, rather than individual servers. When you create a [Workspace](../container-workspace/workspaces.mdx) that targets a pool, users are automatically load balanced to the pool of servers. Kasm knows how many concurrent user sessions each server is configured to allow and tracks which users are using a session on each server. Kasm allows for users to have multiple sessions open to different servers, if your configuration allows for that. To create a Pool, go to Infrastructure, Pools, and click the Add button in the Pools list. Provide a name, select `Server` in the Type drop down, and click Save. From the edit pool page, you can add and remove servers from the pool. ### Servers A server in Kasm is an individual system that Kasm brokers a user connection to. A [Workspace](../container-workspace/workspaces.mdx) can point to an individual server or a pool of servers. To create a server, go to Infrastructure, Servers, and click Add in the Server list. **Common Steps:** 1. Provide a name and IP address or hostname for the server. 2. Select RDP from the connection type drop down. 3. Configure the port to use for the RDP connection, the default RDP port is 3389. 4. Select the deployment zone, by default there is only one zone called `default`. **Windows-Specific Steps:** 5. There are multiple options for [authentication](windows/authentication.mdx) to Windows servers, the example screenshot below just uses a static username and password. 6. Enter the maximum number of concurrent sessions the Windows server will handle. For static credentials, only a single concurrent session can be allowed. In order for more than 1 simultaneous sessions to be allowed, you need to configure SSO for authentication to Windows from Kasm and you need to use a Windows operating system that supports multiple concurrent RDP sessions. Multiple concurrent RDP sessions require a Windows operating system that supports this feature. Kasm will ensure each server is only assigned the maximum number of current user sessions specified. **Linux-Specific Steps:** 5. There are multiple options for [authentication](linux/authentication.mdx) to Linux servers. 6. Enter the maximum number of concurrent sessions the Linux server will handle. Make sure the Linux system supports multiple concurrent RDP sessions. 7. Enter the maximum number of simultaneous users per server. For static credentials, only a single user can be allowed. **Finalize:** 8. Click Save ### Workspace A Workspace is how you provide end-users with access to resources, such as a server. In the Workspaces is where you define the user facing name, description, categories, and thumbnail image. To create a Workspace, go to Workspaces -> Workspaces in the Admin dashboard and click Add Workspace in the Workspaces list. 1. Select `Server` from the Type drop down. Select `Pool` if configuring a pool of servers. 2. Provide a short user friendly name for the Workspace. 3. Provide a description of the Workspaces. 4. Provide a thumbnail URL that will be displayed to the user. 5. Check the Enabled checkbox. 6. Select the target server/pool from the dropdown. 7. In the **RDP Client Options** dropdown, select one of: - *Web native client* to access the instance using Kasm's in browser access method. - *RDP local client* to access the instance using the client endpoint's RDP client software authenticated through the Kasm RDP gateway. 8. Optionally provide a category(s), users will be able to search for the Workspaces using the categories. 9. Click Save ### Groups By default, new Workspaces are added automatically to the All Users group. Therefore, all users will have access to any newly defined Workspace. This default behavior can be changed in the [Server Settings](../../../reference/settings.mdx) under Images, Add Images to Default Group checkbox. In more secure environments you will want to uncheck that setting, remove all Workspaces from the All Users group, and then add Workspaces to individual groups as needed. --- ## User-Server Assignment Kasm Workspaces supports the management of persistent Servers. The use case for such a Server may be for one or more specific Users to have access to it as a dedicated resource. The User-Server assignment feature of Kasm Workspaces allows this kind of assignment for Servers that are part of Server Pools with assignment enabled. * A User may be assigned to any number of Servers * A Server may have any number of Users assigned to it * For a Workspace configured with a Server Pool that has assignment enabled, a User will only be able to create a session if they have one or more assigned Servers in the pool. ## Enabling Assignment User-Server Assignment is specified during Server Pool creation. Additionally, the setting can be changed on the Server Pool Edit page. * Disabling assignment for a pool does not remove User-Server assignments within the pool; they remain in the system for use if the setting is re-enabled. After turning off the setting, all Servers in the pool are considered available for use by all Users with access, regardless of previous assignment. * User-server assignment cannot be enabled for pools that have attached autoscale configurations. ## Making Assignments User-Server assignment is available from the User Update, Server Update, and Server Creation pages. ### User Update The "Assigned Servers" tab in the User Update view displays an editable list of all Servers assigned to the User. Each row indicates whether that Server is currently part of a Server Pool with user assignment enabled. **Only Servers in Pools with assignment enabled are able to be assigned from this page.** ### Server Update The "Assigned Users" tab in the Server Update view displays an editable list of all Users assigned to the Server. **This tab only appears when the Server is part of a Server Pool that has assignment enabled.** ### Server Creation When a Server Pool that supports User assignment is selected on the Server Creation page, a new field appears that allows the Administrator to assign a User to the new Server. This assignment is optional. --- ## Authentication(Windows) # Windows Authentication When defining a [single static server](../static-servers.mdx) or an [auto-scaled pool](../auto-scaled-servers.mdx), the administrator needs to provide a **Connection Credential Type**, **Connection Username**, and **Connection Password** to use to connect to the server(s). There are four options administrators have when considering the connection credentials. ### Static Credentials The administrator would select *Static Credentials* for the **Connection Credential Type** and put in a static username and password into the **Connection Username** and **Connection Password** of the Server or Auto-Scale configuration. All Kasm user's connections would use these credentials for authentication. **Advantages** - Simple **Disadvantage** - All Kasm users are the same user on the Windows system. This has security and auditing ramifications. - Only a single concurrent session per server could be allowed. ### Prompt User If the **Connection Username** and **Connection Password** fields are left blank in the Server or Auto-Scaling configuration and *Static Credentials* is selected for the **Connection Credential Type**, the user will be prompted to enter their Windows username and password. **Advantages** - Simple - Allows for multiple concurrent user sessions per Windows server - All users could have a different account in Windows **Disadvantage** - Users have to enter their credentials every time they connect to a Windows system. When using Prompt User authentication with Web Native RDP, uploaded and downloaded files are not placed into the user's Windows profile directory (for example, C:\Users\<username>\Downloads). Instead, files are stored in the default upload and download directories configured for the Kasm Desktop Service on the Windows server. ### Single Sign-On with Static Local Accounts This option applies only if users authenticate to Kasm using users managed by Kasm, as opposed to using SAML, OIDC, or LDAP authentication. Administrators can configure Kasm to use a user's Kasm credentials when connecting to remote servers. The remote servers will need local accounts that match the username and password of the Kasm users. In the server or auto-scale configuration, select *SSO User Accounts* for the **Connection Credential Type**. In the **SSO Domain**, type `localhost` to have Kasm log the user in as a local Windows account. **Advantages** - Allows for multiple concurrent user sessions per Windows server. - All users have different accounts in Windows. - Single Sign-on from Kasm to Windows, so users don't get prompted to enter credentials when connecting to Windows. **Disadvantages** - Complexity in managing separate accounts for each user across different systems. ### Single Sign-On with Dynamic Local Accounts With the [Kasm Desktop Service](kds-windows-service.mdx) installed, Kasm can automatically manage local Windows user accounts on the target server. Each time a user creates a Kasm session to a Windows server, a local user account is created on the Windows server, if it does not already exist. A random password is assigned to the local Window user account with each session. The username generated by Kasm is the first 9 characters of the Kasm Workspaces username in lower case, with special characters replaced with a `-`, followed by a `-` and 10 characters from the Kasm Workspaces User ID. For example, `Jon.Doe@example.com` with a Kasm User ID of `bf262ada-0a7f-4f49-b435-e50537caa013` would result in a local Windows account of `jon-doe-e-bf262ada0a`. To configure dynamic local accounts, the Kasm Desktop Service must be installed and registered. In the server or auto-scale configuration, select *Dynamic User Accounts* for the **Connection Credential Type**. and the **Kasm Desktop Service Installed** option must be enabled. When configuring server via RDP for full desktop sessions, only a single concurrent session per Kasm user is allowed on the server. The Kasm Desktop Service comes with built-in PowerShell scripts which are executed for various purposes. There is a PowerShell script responsible for creating local users and setting the password for an incoming session. If you have special requirements, you may edit this script for your exact needs. See the [Service scripts](./kds-windows-service.mdx#scripts) section for more details. **Advantages** - Allows for multiple concurrent user sessions per Windows server. - All users have different accounts in Windows. - Single Sign-on from Kasm to Windows, so users don't get prompted to enter credentials when connecting to Windows. - Works with any authentication mechanism, OIDC, SAML, LDAP, local Kasm accounts. - Simple configuration with no requirement for Active Directory or other external dependencies. ### Single Sign-on with Active Directory This option applies only if users authenticate to Kasm using Active Directory credentials with Kasm configured with [LDAP Authentication](../../../security/users-groups-mgmt/ldap.mdx). Additionally, the Windows servers being connected to must be a member of the same Active Directory domain that LDAP authentication is configured for. Auto-scaling configurations can [join new VMs to the domain](../auto-scaled-servers.mdx#join-active-directory) and remove them. Usernames used by users to authenticate to Kasm must match the username that users would use to authenticate to Windows systems. In the server or auto-scale configuration, select *SSO User Accounts* for the **Connection Credential Type**. Leave the **SSO Domain** blank if the domain the user logs into Kasm with is the same as the domain name used for Windows login. You may specify a different *SSO Domain* to change the username's domain. For example, if a user logs into Kasm with `jon.smith@public.domain.com`, but Windows login expects `jon.smith@private.domain.local`, set the *SSO Domain* to `private.domain.local`. After enabling LDAP-based SSO or granting access to an LDAP SSO Workspace, users must sign out of Kasm and back in for SSO to work. If access is granted after the user is already logged in, they may see "Unable to connect. Please contact an administrator." until they log out and log back in. **Advantages** - Allows for multiple concurrent user sessions per Windows server. - All users have different accounts in Windows. - Single Sign-on from Kasm to Windows, so users don't get prompted to enter credentials when connecting to Windows. **Disadvantages** - More complexity in additional configuration and systems to manage. - SAML and OIDC not supported as Kasm authentication methods. ### SmartCard authentication This option applies only if the Windows servers are configured to authenticate via SmartCard. This is accomplished through active directory or LDAP Windows configuration. The Kasm user does not have to be an LDAP user in Kasm for this method to work. In the server or auto-scale configuration, select *Authenticate with SmartCard* for the **Connection Credential Type**. The workspace must be configured with **RDP Client Options** set to *RDP local client* for this feature to work. **Advantages** - Allows for multiple concurrent user sessions per Windows server. - All users have different accounts in Windows. - Windows uses smart card authentication so the user only needs their smart card and pin to sign on, no password is needed. - Kasm can use any authentication method the administrator chooses as it is not tied to how Windows authenticates. **Disadvantages** - Complexity in managing separate accounts for each user across different systems. - Users have to enter their credentials every time they connect to a Windows system. --- ## Overview # Windows Overview Kasm Workspaces supports Windows through a variety of methods and includes features that are specifically for Windows environments. Supporting Windows is a complicated topic due to a combination of technical implementations and licensing restrictions within the Microsoft eco-system. ### Supported Architectures * [Static Windows Servers](../static-servers.mdx) - Kasm can provide users access to static individual servers running RDP. * [Auto-Scaled Windows Servers](../auto-scaled-servers.mdx) - Kasm can auto-scale servers in supported cloud providers and manage user sessions to VMs. * [Microsoft RDS](rds.mdx) - Kasm can sit in front of a Microsoft RDS deployment and provide users access to desktops and apps managed by RDS. * Azure Virtual Desktops - Kasm supports managing access to AVD (Azure Virtual Desktop) deployments. * Microsoft Windows365 - Put Kasm in front of your Windows365 deployments to implement DLP and isolation. ### Licensing Restrictions Any stated or implied licensing restrictions with respect to Microsoft products and services are to the best of our knowledge and may not represent the current state and may not be an accurate summarization of what are complicated licensing restrictions. Ensure to consult with Microsoft to fully understand your rights as a licensee of their products and services. First, it's important to note that Microsoft has specific licensing requirements for accessing their software applications through remote desktop services (RDS) and virtual desktop infrastructure (VDI) solutions. These licensing requirements can be complex and may vary depending on the specific scenario and product being used. In general, if you are using Kasm Workspaces as an RDP connection to an RDP application or RDS Session host, you will need to ensure that you have the appropriate Microsoft licenses for the software being accessed. This may include licenses for Windows Server, Remote Desktop Services (RDS) Client Access Licenses (CALs), and/or Microsoft Office. Kasm Workspaces provides the ability to connect to RDP applications and RDS Session hosts using the internal [Connection Proxy](../../../../explanations/connection-proxies.mdx) service, which allows for secure remote access to Windows-based applications and desktops from any device or browser. If the Windows VMs are in the cloud, you have the option to use pay-as-you-go (PAYG) licensing or bring-your-own-licensing (BYOL). When using PAYG licensing, the Windows licensing costs are built into your cloud costs. Some cloud providers charge the Microsoft licensing fee separately, so it may not be included directly in the estimated instance pricing. See your cloud provider for details on Microsoft licensing. If you decide to use the BYOL approach, you will be responsible for either manually licensing your servers or automating the licensing process of Windows servers. Kasm does not provide support or assistance with licensing Microsoft products. The following Microsoft licensing restrictions should be evaluated when selecting an architecture and/or cloud provider. * Microsoft explicitly disallows running versions of Office later than 2019 on a VM in any cloud provider other than Microsoft Azure. * Microsoft explicitly does not support Windows 11/10 multi-session images running in any cloud provider other than Microsoft Azure. The result is that running Windows 10/11 in any cloud provider, other than Azure, will require 1 VM per user, which will have profound licensing cost implications. * Running of Windows 10/11 in a cloud provider other than Azure is heavily restricted by Microsoft. While you will not find Windows 10/11 images in any cloud provider's image marketplace, you can still create custom images on your own and handle licensing of the operating system yourself. Kasm does not provide support for licensing of Microsoft products. --- ## Windows Service # Kasm Desktop Service - Windows Kasm Desktop Service for Windows is a service that provides additional capabilities to users that are connected to the desktop through Kasm Workspaces: - Upload files to the remote desktop - Download files from the remote desktop - See a preview screenshot of the desktop in the Kasm Workspaces dashboard - Run PowerShell [scripts](kds-windows-service.mdx#scripts) on session start, session end, or service start - [Kasm managed local Windows users](authentication.mdx#single-sign-on-with-dynamic-local-accounts) and credentials - [File Mapping](../../file-mappings.mdx) - Supports multiple concurrent users on the same Windows system ### System Requirements | Supported Operating Systems | |-----------------------------| | Windows 10 (x86_64) | | Windows 11 (x86_64) | | Windows Server 2019 (x86_64) | | Windows Server 2022 (x86_64) | | Windows Server 2025 (x86_64) | ### Installation The Kasm Desktop Service for Windows can be installed using one of the installers below, which places all the necessary files in `C:\Program Files\Kasm`. You should use the latest version that supports the version of Kasm Workspaces you have installed. | Installer Version | Installer Link | Kasm Workspaces Compatibility | SHA256 | |-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|------------------------------------------------------------------| | Developer Preview | [kasm_windows_service_installer_x86_64_develop.exe](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_desktop_service/kasm_windows_service_installer_x86_64_develop.exe) | Developer Preview | _rolling_ | | 1.8.8e3b288d3 | [kasm_windows_service_installer_x86_64_1.8_8e3b288d3.exe](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_windows_service_installer_x86_64_1.8_8e3b288d3.exe) | 1.19.0 | 04a4650a1ba5465b97159be62a4db7d246b92c813c3550e842ebb1e70521c21e | | 1.7.c54746a56 | [kasm_windows_service_installer_x86_64_1.7_c54746a56.exe](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_windows_service_installer_x86_64_1.7_c54746a56.exe) | 1.18.0, 1.18.1 | cfb3fc77d624a9e664eef536b1f4160e0bab90ee923d2067a291d89187dcba02 | | 1.6.8c568cfb1 | [kasm_windows_service_installer_x86_64_1.6_8c568cfb1.exe](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_windows_service_installer_x86_64_1.6_8c568cfb1.exe) | 1.16.0, 1.16.1, 1.17.0 | 4b2eba790ba45af4ddd6d202894ee25b6b904ce4de0f0ea1c3892a35c6c2d40e | | 1.5.5972ac21d | [kasm_windows_service_installer_x86_64_1.5_5972ac21d.exe](https://kasm-static-content.s3.us-east-1.amazonaws.com/kasm_windows_service_installer_x86_64_1.5_5972ac21d.exe) | 1.16.0, 1.16.1, 1.17.0 | 6485ce5743046f02c27cb22628559ac81ad3bc5a413cdf44735bffca28bdca70 | | 1.4.7f51b2de | [kasm_windows_service_installer_x86_64_1.4_7f51b2de.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.4_7f51b2de.exe) | 1.16.0, 1.16.1, 1.17.0 | 9b6739385a4a55244bf46fd26f0c7465a395a5a5c67f9da6d118232a417a6758 | | 1.3.af09998b6 | [kasm_windows_service_installer_x86_64_1.3.af09998b6.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.3.af09998b6.exe) | 1.16.0 | f7c18cf85570143a840e1e4d151f858e5352fbc2fd0f9fe90db02f9de7f29494 | | 1.2.22550d18 | [kasm_windows_service_installer_x86_64_1.2.22550d18.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.2.22550d18.exe) | 1.15.0 | afa6705c502b63c2610b93d8ded81f05f47d094d15964bf30d1ab523da20ccb3 | | 1.1.2b3f26b | [kasm_windows_service_installer_x86_64_1.1.2b3f26b.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.1.2b3f26b.exe) | 1.14.0 | 51b2a83d63a0ccf7634272e68695bbd37731a57bb06b28482471e2f75d925d40 | | 1.0.616b3bea | [kasm_windows_service_installer_x86_64_1.0.616b3bea.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_1.0.616b3bea.exe) | 1.12.0, 1.13.0, 1.14.0 | 5022bf6b9f508447c5913b6ed336646c624edb095c1083460e0d780f4a54a02a | | 0.9 | [kasm_windows_service_installer_x86_64_02beec.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_02beec.exe) | 1.12.0, 1.13.0 | ea20d43129c3145306922e05b2643cadf6bc04ec6d66539979b3cc16dfbb4e21 | | 0.8 | [kasm_windows_service_installer_x86_64_5a2950.exe](https://kasm-static-content.s3.amazonaws.com/kasm_windows_service_installer_x86_64_5a2950.exe) | 1.12.0, 1.13.0 | 9f514b913a9ebff1686695f3bf430958a59776c7bb1c5d0cac98a3510769ed67 | The [Developer Preview Build](../../../../reference/builds.mdx) of the Kasm Desktop Service - Windows listed above should only be used with the developer preview build of Kasm Workspaces on non-production systems. The documentation on this page is for the latest version of the installer listed in the table above and may not be accurate for older versions. The Kasm Desktop Service uses HTTPS/SSL to communicate with the rest of the Kasm Workspace services. The service installer will open the Windows firewall for TCP port 4902, ensure that firewalls and/or cloud security groups allow inbound TCP port 4902 coming from Kasm API server and Connection Proxy servers. The Kasm Desktop Service will talk outbound to the API Server on the port your deployment utilizes, TCP port 443 by default. Ensure security groups and our firewall rules allow this communication. The following instructions are for static Windows servers. Auto scaled servers will install the service as part of the PowerShell startup scripts, see [Auto Scaled Servers startup scripts](../auto-scaled-servers.mdx#vm-startup-scripts) for more details. 1. Login to Kasm as an administrator 2. Create a [new Server](../static-servers.mdx#servers), you can optionally make the server part of a [Pool](../static-servers.mdx#server-pools) 3. Ensure the `Kasm Desktop Service Installed` option is enabled when creating the server. 4. On the Windows server download the appropriate version of the Kasm Desktop Service from the table above. 5. Launch the Kasm Desktop Service installer. You will be prompted to provide information.
6. Enter the hostname or IP address of the Kasm API (WebApp Role) services. This is normally the same hostname or IP that end-users use to access your Kasm deployment. 7. Enter the port number for Kasm Workspaces, the default is port 443. 8. Provide the registration token for this server. In the Kasm Admin UI, Navigate to Infrastructure->Servers->Servers, find the target server and click **Edit**. In the Kasm Agent section, press the copy button on the **Registration Token** field and paste this into the Kasm Desktop Service installer Registration Token field.
9. (Optional) Enter the API path prefix if your Kasm deployment is hosted behind a path-based proxy (for example, /kasmapp). 10. Press **Ok** on the above dialog after you have filled in the required information. When registration is complete the above dialog will close and the installer will show completed. You may close the installer.
#### Installation Troubleshooting During the installation, the Kasm Desktop Service will attempt to register itself with the Kasm Workspaces deployment using the registration token provided. During the registration process the following checks are performed. * Can the Kasm Desktop Service talk to the Kasm Workspaces deployment on the specified port and hostname. * Can the Kasm Workspaces deployment talk to the Kasm Desktop Service on port 4902 using the hostname/IP specified in the Server record in Kasm Workspaces. * Is the registration token digitally signed by the Kasm Workspaces deployment, not expired, and assigned to the server being registered. If any of these conditions fail, you will get an error message during the installation when hitting **Ok** on the below dialog box. Attempt to correct issues such as DNS reslolution of hostname, firewall rules, or expired registration tokens and press **Ok** again to try again. #### Scripted Installation The installation and registration of the Kasm Desktop Service can also be scripted. In the example below, replace `kasm.exmaple.net` with the hostname or IP address of your Kasm deployment, the port number if different than 443, and the registration token for the server. ```yml # Download appropriate version of the kasm installer from the above table kasm_windows_service_installer_x86_64_1.2.22550d18.exe /S net stop kasm cd "C:\Program Files\Kasm" .\agent.exe --register-host kasm.example.net --register-port 443 --register-token "" net start kasm ``` The installation directory, `C:\Program Files\Kasm` will inherit Windows ACL permissions from the parent directory. For the best possible security, ensure that normal users do not have read access to the Kasm service installation directory as the directory contains potentially sensitive information. ### Server Enrollment Tokens To install the Kasm Desktop Service and register it with a server enrollment token, first follow the normal [installation](#installation) until step 8. Replace step 8 with the following: 8. Provide the registration token for this server. In the Kasm Admin UI, Navigate to Infrastructure->Servers->Server Enrollment Tokens, find the target server and click the copy button on the **Token** field and paste this into the Kasm Desktop Service installer Registration Token field.
#### Scripted Installation When scripting the registration of the Kasm Desktop Service using an enrollment token, an additional step is required. The agent must first be executed in the background before attempting registration. ```yml #ps1 Start-Process -ArgumentList "/S" -Wait net stop kasm Start-Process agent.exe -ArgumentList "--cfg config.yaml" -WorkingDirectory "C:\\Program Files\\Kasm" Start-Sleep -Seconds 2 Start-Process agent.exe -ArgumentList "--register-host --register-port 443 --register-token " -Wait -WorkingDirectory "C:\\Program Files\\Kasm" Stop-Process -Name agent -Force net start kasm ``` Normally, the server hostname value is used to connect to the server however it cannot currently be templated and must be dynamically detected. In order to do so we attempt to connect to the server, first via the server's FQDN and if that fails we attempt to connect using the request IP address. If both attempts to establish connectivity to the server are unsuccessful, enrollment will fail. ### Optional Dependencies Kasm uses [WinSfp](https://github.com/winfsp/winfsp) to facilitate [Cloud Storage Mappings](../../../data-storage/storage-mappings/index.mdx) in Windows. Download the latest Windows msi installer from the WinSfp [release page](https://github.com/winfsp/winfsp/releases). Alternatively, you can use the following PowerShell script to install WinFsp non-interactively. ```js $winfsp_url = "https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi" $winfsp_msi = "winfsp-2.0.23075.msi" Function Install-Winfsp { Invoke-WebRequest -Uri $winfsp_url -OutFile $Env:temp\$winfsp_msi Write-Host "Installing WinFSP" Start-Process -FilePath $Env:temp\$winfsp_msi -ArgumentList '/q' -WorkingDirectory "C:\Windows\Temp\" -Wait Remove-Item $Env:temp\$winfsp_msi -Force } Install-Winfsp ``` ### SSL Certificates As part of the installation, the service is assigned an SSL certificate. Kasm utilizes a self sign certificate for the service. You can optionally replace the auto generated self-signed certs with certs that are signed by your organization's CA. The cert and key need to be in PEM format and are stored at `C:\Program Files\Kasm\certs`. ### Upgrade When running the installer on a machine with an existing Kasm Desktop Service an upgrade will be performed. The existing configuration file, as well as the certificates and any files in the upload and download folders will be preserved. ### Uninstall If the Kasm Desktop Service needs to be uninstalled it can be removed by going to `Add or remove programs` / `Apps & features` on the Windows server and selecting the ``Kasm - KasmAgent `` and then selecting ``Uninstall``. There will be a dialog box asking you to confirm you wish to remove the Kasm Desktop Service, click ``OK`` to continue. All files under `C:\Program Files\Kasm` will be deleted during the uninstall process. ### Configuration Below is an example config with the appropriate settings for Kasm Desktop Service annotated. This file is automatically generated during the registration process, however, it can be overridden for custom deployments. All paths should be absolute and without slashes at the end. Backslashes should be escaped with a backslash. The referenced PEM formatted certificate files must not have Windows carriage returns. ```yml # server HTTP(s) configuration ssl: true port: 4902 server_private_key: "C:\\Program Files\\Kasm\\certs\\key.pem" server_public_key: "C:\\Program Files\\Kasm\\certs\\cert.pem" # path to JWT's RSA certificate for token verification jwt_public_key: "C:\\Program Files\\Kasm\\certs\\jwt.pem" # path to upload/download folders upload_dir: "C:\\Program Files\\Kasm\\Upload" download_dir: "C:\\Program Files\\Kasm\\Download" # (optional) path to the log file log_file: "C:\\Program Files\\Kasm\\log.txt" # (optional) path prefix for API requests if Kasm is hosted behind a path-based proxy api_url_prefix: /kasmapp # Settings for multiple user machines multi_user: false user_sso: false debug: false ``` **Settings** | Name | Description | |----------------------|-------------------------------------------------------------------------------------------------------------------| | ssl | Enables SSL for the services. Kasm Workspaces only supports communications with this service over SSL. | | port | The port to run the services on. Kasm Workspaces uses port `4902` for this service by default. | | server_private_key | The private key used for the SSL service. | | server_public_key | The public key used for the SSL service. | | jwt_public_key | The public key used to authenticate API calls received from Kasm Workspaces. | | upload_dir | Directory to place files uploaded by users. | | download_dir | Directory to allow users to download files from. | | log_file | Optionally writes logs to this file. Logs can also be viewed in Windows Event Viewer. | | multi_user | Boolean indicating the Windows instance the service is installed on will support multiple users | | user_sso | Boolean indicating that users in Kasm are mapped to Windows users through SSO. | | api_host | The hostname or ip address of an API server or load balancer in front of Kasm API servers. | | api_port | The port number used for your deployments API Servers, port 443 by default. | | api_url_prefix | (Optional) The path prefix for API requests if Kasm is hosted behind a path-based proxy (e.g., /kasmapp). | | registered | Has the agent already been registered with the deployment. | | script_path | Directory where scripts are located. | | server_id | The UUID of the server in Kasm Workspaces. | | debug | Enable verbose logging. | The `multi_user` and `user_sso` are updated automatically when the serivce checks into the deployment, based on the configuration in Kasm Workspaces for this server. #### Uploads and Downloads on Multi-user Systems When a user uploads files from their local computer to the remote Kasm Windows session, the file is placed in the Downloads directory of their home path. When a user wants to download a file from the remote Kasm Windows session to their local computer, they can use the control panel. The control panel will display files located in the Downloads directory of their home path. There may be security concerns when Kasm and the Windows environment is not setup for SSO either using [LDAP SSO](authentication.mdx#single-sign-on-with-active-directory), [static accounts](authentication.mdx#single-sign-on-with-static-local-accounts), [Kasm managed Windows accounts](authentication.mdx#single-sign-on-with-dynamic-local-accounts), or [Smart card authentication](authentication.mdx#smartcard-authentication). If all users are connecting to the remote Windows server using the same credentials, they will all share the same Windows profile. When using Prompt User authentication with Web Native RDP, uploaded and downloaded files are not placed into the user's Windows profile directory (for example, C:\Users\<username>\Downloads). Instead, files are stored in the default upload and download directories configured for the Kasm Desktop Service on the Windows server. #### Authentication of Service All requests to the application must contain a JWT token parameter that will be verified against the provided JWT key. The JWT key (also referred to as the **API Cert**) is generated upon Kasm Workspaces installation and can be retrieved from Kasm `Settings` panel section. The public JWT token is retrieved during registration. If you change the JWT cert and key on your Kasm Workspaces deployment, you will need to re-register your Kasm Desktop Service. ### Scripts Kasm utilizes a number of PowerShell scripts and provides administrators hooks to execute their own PowerShell scripts during certain events. When PowerShell scripts get executed by the Kasm Service, PowerShell variables are automatically injected so that your script has access to contextually relevant information. See the [variables](kds-windows-service.mdx#variables) section for more details. The default location for scripts is `C:\Program Files\Kasm\scripts`. [File Mapping](../../file-mappings.mdx) can be used to manage custom scripts within the Kasm UI. With this directory there are the following sub directories with the following purposes. **Script Directories** | Directory | Description | |-----------------|-----------------------------------------------------------------------------------------------------| | builtin | Scripts ran by the Kasm Service to execute specific actions. See the following section for details. | | service_startup | Scripts placed here will automatically be executed when the Kasm service starts. | | session_start | Scripts placed here will automatically be executed before a user session starts. | | session_end | Scripts placed here will automatically be executed before a user session is terminated. | | registry | Registry setting export files. | #### Builtin Scripts The following builtin scripts exist for the defined purpose. **create_local_account.ps1** This script is executed during session creation, if [Dynamic Local Account SSO](authentication.mdx#single-sign-on-with-dynamic-local-accounts) is configured. This script creates a local Windows account for the requesting user, if it does not already exist, and retrieves a one-time random password to set for the Windows account. The API call to retrieve the one-time password uses a JWT token that is defined in a [builtin variable](kds-windows-service.mdx#variables). The JWT token has short expiration time and can only be used once to retrieve the one-time password. **logoff_user.ps1** This script will log the user off the Windows session when the user deletes their Kasm session. **load_persistent_profile.ps1** This script is called during session creation, before a user connects and after create_local_account.ps1 is called (if required). The script is empty in the current version but provides the administrator the ability to define their own hook to load persistent profiles from users using third party solutions. The script has access to builtin variables defined below. **save_persistent_profile.ps1** This script is called during session termination, after the user is logged out. The script is empty in the current version but provides the administrator the ability to define their own hook to save persistent profiles for users using third party solutions. The script has access to builtin variables defined below. **map_storage.ps1** This script is called during session creation, before a user connects and after create_local_account.ps1 is called (if required). This script is used to map in [Cloud Storage](../../../data-storage/storage-mappings/index.mdx) definitions for users. This script has access to [builtin variables](kds-windows-service.mdx#variables) in addition to a `storage_mapping` variable, which contains the storage mapping definition in JSON format. This script is called for each storage mapping that is applicable to the user that is creating the session. All Windows storage mappings are placed on the user's Desktop. If, for exmaple, a Storage Mapping with a target of /OneDrive would be mapped to C:\Users\\Desktop\OneDrive on a Windows system. This script requires [WinSfp](#optional-dependencies). **unmap_storage.ps1** This script is called during session termination, after the user is logged off. The script removes any mapped [Cloud Storage](../../../data-storage/storage-mappings/index.mdx) volumes that were added with the map_storage script. This script has access to [builtin variables](kds-windows-service.mdx#variables) in addition to a `storage_mapping` variable, which contains the storage mapping definition in JSON format. This script is called for each storage mapping that is applicable to the user that is creating the session. #### Variables The following variables are builtin and available for any PowerShell script executed by the Kasm Service. | Name | Description | |------------------|-----------------------------------------------------------------------------------------------------| | user_id | The Kasm User ID for the user creating/terminating the session. | | username | The Windows username of the user creating/terminating the session. | | kasm_id | The Kasm session ID for the session being created/terminated. | | jwt_token | A limited access and short lived JWT token that can be used to make API calls to Kasm. | | api_host | The IP address or hostname of the API server or load balancer for the API servers. | | api_port | The port number of the API server. | | api_url_prefix | (Optional) The path prefix for API requests if Kasm is hosted behind a path-based proxy. | | ts_session_id | The associated Windows Terminal Session ID. | | is_remote_app | Is the session a RemoteApp. | | is_web_native | Is the user's session using Kasm's web native access or is the user connected with an RDP client. | | auto_logout_user | Will the Kasm Desktop Service automatically log the user out when the session closes. | These variables can be referenced in PowerShell scripts defined by the administrator as such. ```PowerShell Write-Host "Session starting for $username" ``` The full output of scripts is logged if either the exit code is a non-zero value or if debug is enabled in the [configuration](kds-windows-service.mdx#configuration). ### Logging By default, all log messages are written to Windows event log (under `Applications->KasmService`) but can be also redirected to a file by specifying the `log_file` parameter in `config.yaml`. Logs are also sent to the Kasm Workspaces deployment and can be searched for the Kasm Admin UI under Diagnostics->Logging. ### Manage Registry Settings Kasm administrators can use [File Mappings](../../file-mappings.mdx) to map registry setting export files to `C:\Program Files\Kasm\scripts\registry`. These files must end in `.reg` and should be exports created by Microsoft regedit. When the Kasm Desktop Service starts, it will download new file mappings and apply any `.reg` files that exist in that directory. This can be used, for example, to configure RDP settings for systems outside of a domain.. --- ## Windows Persistent Profiles with FSLogix :::note For automated FSLogix setup with Kasm autoscaled VMs see the [FSLogix Container Profiles](../auto-scaled-servers.mdx#fslogix-container-profiles) section of Auto Scale Configuration. ::: ## FSLogix Overview Kasm Workspaces can leverage [FSLogix Profile Containers](https://learn.microsoft.com/en-us/fslogix/concepts-container-types#profile-container) to deliver high-performance, persistent user profiles for Windows Desktops and Remote Apps. FSLogix provides a local profile experience ensuring that personal settings, application data, and customizations remain persistent across sessions, while allowing the underlying VM infrastructure to be stateless and disposable. For additional information, see [Learn Microsoft - What is FSLogix?](https://learn.microsoft.com/en-us/fslogix/overview-what-is-fslogix) ## Prerequisites **Supported Operating Systems**\ Windows 10, Windows 11, and Windows Server 2016, 2019, 2022, and 2025 **Directory Services**\ FSLogix utilizes Windows identities to secure and assign Windows profiles to user sessions. To utilize FSLogix, your Windows VMs and storage provider must share an identity source. Supported configurations include: Active Directory, Microsoft Entra ID, or Entra Domain Services domain joined VMs. **Profile Storage Location**\ SMB share (Azure Files or on-premise file servers) or Azure Page Blobs **Kasm Connection Credential Type**\ The Kasm Connection Credential Type for the Windows server must be [Single Sign-on with Active Directory](./authentication.mdx#single-sign-on-with-active-directory) or [Prompt User](./authentication.mdx#prompt-user) ## Create a SMB Share Proper permissions are required to ensure user profile isolation, prevent unauthorized access, and maintain system stability. This guide outlines the recommended NTFS and share permissions along with PowerShell commands for manual configuration. For additional information, see [Learn Microsoft - Configure SMB Storage Permissions](https://learn.microsoft.com/en-us/fslogix/how-to-configure-storage-permissions) #### Create SMB Share and set Permissions * Administrators: Full Control * Domain Users: Change ```powershell $SharePath = "C:\FSLogixProfiles" $ShareName = "FSLogixProfiles" # Create the directory New-Item -Path "C:\FSLogixProfiles" -ItemType Directory -Force # Create the SMB share New-SmbShare -Name $ShareName -Path $SharePath -FullAccess "Administrators" -ChangeAccess "Domain Users" ``` #### Configure NTFS Permissions * CREATOR OWNER: Full Control (Subfolders and files only) * Domain Users: Modify (This folder only) * Administrators: Full Control (This folder, subfolders, and files) * SYSTEM: Full Control (This folder, subfolders, and files) ```powershell # Disable inheritance and remove inherited permissions $ACL = Get-Acl -Path $SharePath $ACL.SetAccessRuleProtection($true, $false) Set-Acl -Path $SharePath -AclObject $ACL # Remove all existing permissions $ACL = Get-Acl -Path $SharePath $ACL.Access | ForEach-Object { $ACL.RemoveAccessRule($_) } | Out-Null # Add SYSTEM - Full Control $SystemRule = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow") $ACL.AddAccessRule($SystemRule) # Add Administrators - Full Control $AdminRule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow") $ACL.AddAccessRule($AdminRule) # Add CREATOR OWNER - Full Control (Subfolders and files only) $CreatorRule = New-Object System.Security.AccessControl.FileSystemAccessRule("CREATOR OWNER", "FullControl", "ContainerInherit,ObjectInherit", "InheritOnly", "Allow") $ACL.AddAccessRule($CreatorRule) # Add Domain Users - Modify (This folder only) $UsersRule = New-Object System.Security.AccessControl.FileSystemAccessRule("Domain Users", "Modify", "None", "None", "Allow") $ACL.AddAccessRule($UsersRule) # Apply the ACL Set-Acl -Path $SharePath -AclObject $ACL ``` #### Print Network Path Print the network path of the SMB share. You will need this to configure FSLogix on the Windows VM. ```powershell Write-Host "Network path: \\$env:COMPUTERNAME\$ShareName" ``` ## Install FSLogix On your Windows VM install and configure FSLogix. ```powershell $Archive = "FSLogix_latest.zip" $Installer = ".\FSLogix_latest\x64\Release\FSLogixAppsSetup.exe" # Download and extract installer Invoke-Webrequest -Uri "https://aka.ms/fslogix_download" -OutFile $Archive Expand-Archive -Path $Archive # Run installer Start-Process -FilePath $Installer -ArgumentList "/install /quiet /norestart" -Wait ``` ```powershell # Replace with network path from above $Hostname = "" $VHDLocations = "\\$Hostname\FSLogixProfiles" $RegistryPath = "HKLM:\SOFTWARE\FSLogix\Profiles" New-Item -Path $RegistryPath -Force # Add registry settings for profile container configuration New-ItemProperty -Path $RegistryPath -Name VHDLocations -PropertyType string -value $VHDLocations -Force New-ItemProperty -Path $RegistryPath -Name ProfileType -PropertyType dword -Value 3 -Force New-ItemProperty -Path $RegistryPath -Name Enabled -PropertyType dword -Value 1 -Force New-ItemProperty -Path $RegistryPath -Name DeleteLocalProfileWhenVHDShouldApply -PropertyType dword -Value 1 -Force New-ItemProperty -Path $RegistryPath -Name FlipFlopProfileDirectoryName -PropertyType dword -Value 1 -Force New-ItemProperty -Path $RegistryPath -Name LockedRetryCount -PropertyType dword -Value 3 -Force New-ItemProperty -Path $RegistryPath -Name LockedRetryInterval -PropertyType dword -Value 15 -Force New-ItemProperty -Path $RegistryPath -Name ReAttachIntervalSeconds -PropertyType dword -Value 15 -Force New-ItemProperty -Path $RegistryPath -Name ReAttachRetryCount -PropertyType dword -Value 3 -Force New-ItemProperty -Path $RegistryPath -Name SizeInMBs -PropertyType dword -Value 30000 -Force New-ItemProperty -Path $RegistryPath -Name VolumeType -PropertyType string -Value vhdx -Force ``` For more information on FSLogix configurations, see [Learn Microsoft - Configuration Setting Reference](https://learn.microsoft.com/en-us/fslogix/reference-configuration-settings?tabs=profiles) --- ## Rds # RDS This guide will walk you through the benefits of using RDS to manage your RDS farm, and how to connect to those resources via Kasm's secure RDP capabilities with Data Loss Prevention \(DLP\) features. RDS is a collection of Microsoft tools and services that allow multiple users to access a shared desktop or applications on a server. RDS is designed to allow users to connect to a server and use shared resources, such as files and applications, in a secure and controlled environment. RDS provides features such as load balancing, remote app publishing, and session virtualization. RDS application/session/desktops pools give users access to applications that run on servers in a data center instead of on their personal computers or devices. RDS Farms are logical groupings of RDS-enabled Windows Server operating systems that contain common configurations and installed applications. The RDS Connection Broker Service is the communication point for the RDS Farm. Application pools and RDS desktop pools use RDS farms to deliver hosted desktops and applications to multiple instances of Kasm Agents. These are RDS Collections where Session hosts or Application server reside. RDS farms can be used to silo applications for effective application performance and load management, deliver groups of RDS Hosted Applications using a single RDP session, or to deliver RDS hosted virtual desktops. RDS farms can contain physical or virtual servers. See Microsoft's [RDS Documentation](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-deploy-infrastructure?source=recommendations) for assistance with configuring an RDS deployment. ### Kasm Configuration Kasm integrates with RDS as a single fixed server, follow the [Fixed Server](../static-servers.mdx) guide to add a Kasm Server that points to the RDS deployment. You will need to set the Maximum Simultaneous Sessions and Maximum Simultaneous Users on the server as appropraite for your deployment. Kasm only allows 1 desktop session per user per individual server, however, Kasm does allow for multiple concurrent RemoteApp sessions per user per individual server. Microsoft RDS CALs and other Microsoft licensing restrictions may apply. In order for Kasm to support multiple concurrent users to the same backend deployment, single sign-on must be configured. See the [Windows Authentication](authentication.mdx) guide for details on configuring sign sign-on. #### Desktops From Kasm Workspaces perspective, an RDS deployment appears as a single fixed server that supports multiple users. For this reason, [Active Directory integration](authentication.mdx#single-sign-on-with-active-directory) is required so that Kasm users login to Workspaces with their Windows domain credentials and Kasm facilitates single sign-on to the Windows RDS deployment. Follow these steps to configure a [Server](../../../infra-autoscale/servers.mdx) that points to the RDS deployment and then a [Workspace](../../container-workspace/workspaces.mdx) to provide users access. **Create a Server** 1. In the Kasm Admin Dashboard, navigate to Infrastructure->Servers->Servers. 2. In the Server list, click Add 3. Check the **Enabled** box. 4. Provide a friendly name. 5. Provide an IP address or hostname for the RDS deployment. 6. Select RDP as the **Connection Type**. 7. Provide a **Connection Port**, RDP uses 3389 by default. 8. Follow the [Active Directory integration](authentication.mdx#single-sign-on-with-active-directory) guidance for the **Connection Credential Type**, **Connection Username**, and **Connection Password** fields. 9. The **Connection Info** field allows you to optionally override settings that are not exposed in the UI. 10. Specify a maximum number of concurrent user sessions that the RDS deployment can support. The number should be greater than 1. 11. Choose a [Deployment Zone](../../../infra-autoscale/deployment-zones.mdx). 12. Optionally specify a server [Pool](../../../infra-autoscale/pools.mdx). Using a pool will cause Kasm to distribute users between the servers in the pool. **Create a Workspace** 1. In the Kasm Admin Dashboard, navigate to Workspaces -> Workspaces 2. In the Workspaces list, click Add Workspace 3. Select `Server` from the **Workspace Type** drop down, unless you added the server to a pool in step 12 in the previous section. 4. Provide a Friendly Name that will be displayed to users. 5. Provide a description that will be displayed to admins. 6. Optionally provide a URL to a thumbnail that will be displayed on the user dashboard. 7. Check the enabled box. 8. Select the Server/Pool from the dropdown. 9. In the **RDP Client Options** dropdown, select one of: - *Web native client* to access the Windows instance using Kasm's in browser access method. - *RDP local client* to access the Windows instance using the client endpoint's RDP thick client software authenticated through the Kasm RDP gateway. 10. Click **Save** Users should now see the Workspace on their dashboard and be able to create sessions. #### RemoteApps Kasm supports connecting to RDS deployments configured with RemoteApps. Microsoft RemoteApp is a technology allowing users to work with remote applications. Coupling Kasm Workspaces with an RDS deployment and RemoteApp allows administrators to provide remote users access to Windows applications through a web native portal. The following walks through adding a server and adding a Workspace that uses the defined server to create a RemoteApp session. **Create a Server** 1. In the Kasm Admin Dashboard, navigate to Infrastructure->Servers->Servers. 2. In the Server list, click Add 3. Check the **Enabled** box. 4. Provide a friendly name. 5. Provide an IP address or hostname for the RDS deployment. 6. Select RDP as the **Connection Type**. 7. Provide a **Connection Port**, RDP uses 3389 by default. 8. Follow the [Active Directory integration](authentication.mdx#single-sign-on-with-active-directory) guidance for the **Connection Username** and **Connection Password** fields. 10. Specify a maximum number of concurrent users and maximum number of concurrent sessions that the RDS deployment can support. Both numbers should be greater than 1. For RemoteApp Workspaces, you may desire a configuration where the server can only have one concurrent user, but 10 concurrent sessions, allowing the user to utilize the same server for up to 10 RemoteApps at once. Microsoft RDS CALs and other licensing restrictions may apply. 11. Choose a [Deployment Zone](../../../infra-autoscale/deployment-zones.mdx). 12. Optionally specify a server [Pool](../../../infra-autoscale/pools.mdx). Using a pool will cause Kasm to distribute users between the servers in the pool. **Create a Workspace** 1. In the Kasm Admin Dashboard, navigate to Workspaces -> Workspaces 2. In the Workspaces list, click Add Workspace 3. Select `Server` from the **Workspace Type** drop down, unless you added the server to a pool in step 12 in the previous section. 4. Provide a Friendly Name that will be displayed to users. 5. Provide a description that will be displayed to admins. 6. Optionally provide a URL to a thumbnail that will be displayed on the user dashboard. 7. Check the enabled box. 8. Select the Server/Pool from the dropdown. 9. In the **RDP Client Options** dropdown, select one of: - *Web native client* to access the Windows instance using Kasm's in browser access method. - *RDP local client* to access the Windows instance using the client endpoint's RDP thick client software authenticated through the Kasm RDP gateway. 11. Turn on the **Enable RemoteApp** setting. 12. Provide a **RemoteApp Friendly Name**, which may be displayed to the user. 13. Provide a **RemoteApp Program Name/Path**. Registered RemoteApp names must be prepended with double pipes, such as `||Microsoft Excel`. See the [Workspaces RemoteApp](../../container-workspace/workspaces.mdx#remoteapp) section for details. 14. Provide any optional arguments to be passed to the RemoteApp program. 10. Click **Save** ### Group Policy Configurations There are certain behaviors of Kasm Workspaces that may require GPO configurations. #### Remove Logout This setting will remove the logout button from the Windows desktop. Users should instead destroy their Kasm session from the session control panel or the Kasm user dashboard. An auto logout policy should be in place. #### Remove Disconnect Button Users should logout using the Kasm control panel. When the user uses the Windows disconnect button, it will disconnect the session and Kasm will display a disconnected blue screen. The user would then need to use the Kasm control panel to return to the dashboard. The Windows disconnect button can lead to confusion and it is recommended to be removed by GPO. #### Auto logout As of the current version of Kasm, when a user destroys a session, the user is not logged off the Windows server. If the VMs are static or multi-session, administrators should configure an auto logout policy, to automatically log a user out of Windows after an inactivity timeout. --- ## Windows RemoteApp: Setup & Configuration # Windows RemoteApps Microsoft RDP and RDS support running single applications over an RDP connection. This technology is called RemoteApp, by Microsoft. Kasm Workspaces supports Microsoft RemoteApp whether part of a Microsoft RDS infrastructure or backed by stand-alone Windows servers managed by Kasm. ## Microsoft RDS See our [RDS](rds.mdx) for more details. See the Microsoft documentation for more details on publishing RemoteApps in RDS: [https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-create-collection](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-create-collection). ## Stand-alone Servers Stand-alone Windows servers can be configured to server RemoteApps. This can be a static server, a pool of static servers, or an auto-scaled pool of servers managed by Kasm. For RemoteApps to work, the application either needs to be registered as a RemoteApp or you need to configure the server to allow RDP connections to pass the full path to the RemoteApp. Registering RemoteApps is considered more secure. ### Registering a RemoteApp The following is an example of a Microsoft Registry export file containing the registry settings needed to register Microsoft Edge as a RemoteApp. ``` Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TSAppAllowList\Applications] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TSAppAllowList\Applications\Microsoft Edge] "Name"="Microsoft Edge" "Path"="C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" "VPath"="C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" "RequiredCommandLine"="" "CommandLineSetting"=dword:00000001 "IconPath"="C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" "IconIndex"=dword:00000000 "ShowInTSWA"=dword:00000000 ``` This file can be applied in one of two ways. 1. Manually import the file `reg import filename.reg` 2. Use Kasm's [File Mapping](../../file-mappings.mdx) feature to map a file with the above contents to the `C:\Program Files\Kasm\scripts\registry\edge_remoteapp.reg`. The [Kasm Desktop Service](kds-windows-service.mdx) must be installed on the target server. When the service starts, it will downlaod any file mappings and apply any `.reg` files in the stated location. ### Enabling multiple RemoteApps for a single user By default, Windows limits users to a single instance of a RemoteApp. To overcome this limitation and allow multiple instances of a RemoteApp for a single user, you need to disable a specific group policy setting: Use the Windows key + R shortcut to open the Run prompt. 1. Type in `gpedit.msc` and click OK. 2. Navigate to `Computer Configuration`. 3. Select `Administrative Templates`. 4. Choose `Windows Components`. 5. Expand `Remote Desktop Services`. 6. Go to `Remote Desktop Session Host`. 7. Select `Connections`. 8. Open the `Restrict Remote Desktop Services users to a single Remote Desktop Services session` setting. 9. Set it to `Disabled` to enable multiple instances of a RemoteApp for a single user. ## Configuring Kasm Kasm can be configured to point to a single fixed Windows server, a pool of fixed Windows servers, or a pool of auto scaled Windows servers. We recommend watching the following Windows Guide video to get a baseline knowledge of Windows in Kasm Workspaces. ### Create a Server Pool If you want to create a pool of identical servers that Kasm can load balance users between, first [Create a Pool](../../../infra-autoscale/pools.mdx). Then create each server following the guidance in the next session, selecting the pool you created when creating each server. ### Fixed Servers 1. In the Kasm Admin Dashboard, navigate to Infrastructure->Servers->Servers. 2. In the Server list, click Add 3. Check the **Enabled** box. 4. Provide a friendly name. 5. Provide an IP address or hostname for the RDS deployment. 6. Select RDP as the **Connection Type**. 7. Provide a **Connection Port**, RDP uses 3389 by default. 8. Follow the [Active Directory integration](authentication.mdx) guidance for the **Connection Username** and **Connection Password** fields. 10. Specify a maximum number of concurrent user sessions that the RDS deployment can support. The number should be greater than 1. 11. Choose a [Deployment Zone](../../../infra-autoscale/deployment-zones.mdx). 12. Optionally specify a server [Pool](../../../infra-autoscale/pools.mdx). Using a pool will cause Kasm to distribute users between the servers in the pool. ### Create a Workspace 1. In the Kasm Admin Dashboard, navigate to Workspaces -> Workspaces 2. In the Workspaces list, click Add Workspace 3. Select `Server` from the **Workspace Type** drop down, unless you added the server to a pool in step 12 in the previous section. 4. Provide a Friendly Name that will be displayed to users. 5. Provide a description that will be displayed to admins. 6. Optionally provide a URL to a thumbnail that will be displayed on the user dashboard. 7. Check the enabled box. 8. Select the Server/Pool from the dropdown. 9. In the **RDP Client Options** dropdown, select one of: - *Web native client* to access the Windows instance using Kasm's in browser access method. - *RDP local client* to access the Windows instance using the client endpoint's RDP thick client software authenticated through the Kasm RDP gateway. 11. Turn on the **Enable RemoteApp** setting. 12. Provide a **RemoteApp Friendly Name**, which may be displayed to the user. 13. Provide a **RemoteApp Program Name/Path**. Registered RemoteApp names must be prepended with double pipes, such as `||Microsoft Excel`. See the [Workspaces RemoteApp](../../container-workspace/workspaces.mdx) section for details. 14. Provide any optional arguments to be passed to the RemoteApp program. 10. Click **Save** ### Developer API The above steps work great for user requested sessions through the Kasm User interface. Developers, however, may wish to launch Kasm sessions and specify the RemoteApp to launch along with RemoteApp arguments. The Kasm Workspaces [Developer API](../../../../reference/developer-api.mdx) allows for this. The below example shows a JSON payload using the [/api/public/request_kasm](../../../../reference/developer-api.mdx) API. ```json { "api_key": "YOUR_API_KEY", "api_key_secret": "YOUR_API_KEY_SECRET", "user_id": "USER_ID", "image_id": "IMAGE_ID", "enable_sharing": false, "connection_info": { "guac": { "type": "rdp", "settings": { "security": "any", "ignore-cert": true, "enable-font-smoothing": true, "enable-wallpaper": true, "enable-theming": true, "enable-full-window-drag": false, "enable-menu-animations": false, "resize-method": "display-update", "server-layout": "en-us-qwerty", "printer-name": "Kasm", "remote-app": "||KasmLauncher", "remote-app-args": "\"C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE\" C:\\Users\\Public\\Documents\\example.xlsx" } }, "rdp_thick_client_properties": { "connection type": 6, "networkautodetect": 1, "bandwidthautodetect": 1, "screen mode id": 2, "singlemoninwindowedmode": 1, "keyboardhook": 2, "disable full window drag": 1, "disable menu anims": 1, "bitmapcachepersistenable": 1, "session bpp": 32, "dynamic resolution": 1, "autoreconnection enabled": 1, "videoplaybackmode": 1, "allow desktop composition": 1, "disable themes": 0, "allow font smoothing": 1, "smart sizing": 1, "desktopscalefactor": 100 }, "kasm_svc": { "port": 4902 } } } --- ## Session Casting: External & Anonymous Access # Session Casting Session Casting allows administrators to expose external facing URLs that will automatically launch a Kasm session. These Casting URLs can optionally be unauthenticated and protected by ReCAPTCHA, Referrer, and IP rate limits. Administrators may find this feature useful for offering no-auth access to the Kasm environments. ![Casting Workflow](/img/casting/workflow.png) ## Configuration - Log into the Kasm Web UI as an administrator. - Click **Sessions** -> **Casting**. - Click **Add Config**. ![Casting Config](/img/casting/create_casting_config.webp) | Name | Description | | --- | --- | | **Configuration Name** | The unique name to reference this specific configuration. For administration purposes only. | | **URL Key** | The unique identifier for a Casting URL. If **123abc** is the key, users will launch sessions via the following URL https://my.kasm.server/#/cast/**123abc** | | **Workspace** | The Kasm **Worksapce** to use for the created sessions. | | **Launcher Background URL** | URL for the background image for the Workspaces launcher. See the "Default Backgrounds" section of [Custom Branding](../../administration/branding.mdx) for a list of available default images. | | **Allow Resume** | When enabled, authenticated users who already have a running session will have their session resumed instead of having a new session created when connecting to the same **Casting URL** | | **Allow Anonymous** | If checked, requests to the **Casting URL** will not require authentication. Instead the system will create an anonymous users account for each new request. | | **Require reCAPTCHA** | When **Allow Anonymous** is enabled, administrators can choose to have requests validated by [Google reCAPTCHA](https://www.google.com/recaptcha/about/) . To use this feature, the **Google reCAPTCHA Private Key** and **Google reCAPTCHA Site Key** properties must be set in the [Server Settings](../../../reference/settings.mdx). | | **Anonymous User Group** | When **Allow Anonymous** is checked, the system will create new user accounts for each new request. These anonymous users accounts will automatically be added to the **All Users** Group and an additional Group defined here. Administrators can configure the appropriate Group Settings to configure permissions such as **allow_kasm_downloads** etc on this Group. | | **Limit Total Session** | When enabled, the administrator can configure a maximum number of sessions that will be served via this Casting URL. | | **Sessions Remaining** | Sets the total number of sessions that can be requested. This value will automatically decrement as new sessions are served. When the value reaches zero, users will receive an error when attempting to request subsequent sessions. | | **Limit Requests Per IP** | When enabled, the system will limit the number of requests that will employ rate-limiting based on the source IP of the request. (e.g limiting requests to 1 sessions per 60 seconds) | | **Sessions Allowed** | When **Limit Requests Per IP** is enabled, this value is used as the total number of sessions that are allowed for the given time period as defined in **Within Seconds**. | | **Within Seconds** | When **Limit Requests Per IP** is enabled, this value sets the timeframe (in seconds) that is used for the source IP. | | **Kasm URL** | If defined, this value will populate as the **KASM_URL** environment variable for created or assigned [Staged Sessions](session-staging.mdx). These values are often used in the [Docker Exec Configs](../container-workspace/workspaces.mdx) of the browser Workspaces. | | **Allow Dynamic Kasm URL Parameter** | When checked, the user is allowed to append a `kasm_url` query argument to the cast url. e.g `https://kasm.server/#/cast/123?kasm_url=example.com` If present the system will use this value as the **KASM_URL**. When used in conjunction with **Allow Resume**, this will open a new tab with the specified **KASM_URL** when the session is resumed. | | **Allow Dynamic Docker Network URL Parameter** | When checked, the user is allowed to append a `docker_network` query argument to the cast url. e.g `https://kasm.server/#/cast/123?docker_network=example_network` The Workspace used must have **Allow Network Selection** enabled. | | **Error URL** | If defined, the user will be pushed to this URL when an error (such as IP rate limit violation) occurs. Redirection to an external site is only supported if this value begins with a scheme (`https://`); scheme-less URLs will be treated as paths relative to the Kasm installation. If left blank, an internal error page is shown. | | **Disable Control Panel** | When checked, the Control Panel widget is not shown for the sessions. | | **Disable Tips** | When checked, the Tips dialogue is not shown when a user enters a session. | | **Enable Sharing** | When checked, this session will automatically have sharing activated. | | **Disable Shared Fixed Resolution** | When checked and the session is in sharing mode, the resolution will be dynamic. The resolution is typically fixed when a session enters sharing mode. | | **Restrict to Referrers** | Administrators may chose to restrict where the Casting URLs can be accessed from. If a user were to click a Casting URL link that was embedded on a 3rd party website, the system can detect the website domain. It the address is not in the list defined in this setting, the request will be denied. Enter one domain (e.g acme.com) per line. If the option is left blank, requests from all domains are accepted. | | **Enforce Client Settings** | When enabled, the client settings listed below will be enforced on the session , overriding the client settings attached to the user's group(s). | | **Allow Audio** | When enabled, the staged session will support streaming audio from the session to the user. | | **Audio Default On** | When disabled, the audio service will be muted by default. | | **Allow Downloads** | When enabled, the staged session will allow download files from the session to their local computer via the control panel download widget. | | **Allow Clipboard Down** | When enabled, the staged session will allow copying data from the session to the users local computer via the clipboard. | | **Allow Clipboard Up** | When enabled, the staged session will allow copying data from the user’s local computer to the session. | | **Allow Microphone** | When enabled, the staged session will allow the user to pass their local microphone into the session. | | **Allow Uploads** | When enabled, the staged session will allow the user to upload files from their local computer to the session via the upload widget in the control panel. | | **Allow Gamepads** | When enabled, the created session will allow the user to pass through gamepads from their local computer to the session via the gamepads widget in the control panel. | | **Allow Sharing** | When enabled, the user will be able to place their session in sharing mode. | | **IME Default On** | When enabled, IME mode will be enabled by default if the doesnt already have a local preference set. | | **Remote App Configuration (JSON)** | When defined this configures Microsoft RDS/RDP remoteApp settings. See the `Remote App Configuration`_ section for details. | | **Valid Until** | When defined, the casting link will only be valid until this time, after which the client will be presented with an error. | | Direct Install URL | Workspaces and casting links can be installed as standalone PWA applications, this is the direct url that can be used for automatic installation via management systems such as Windows Group Policy and Chrome Managed Policies. | - Fill out the form then click **Save**. - A list of all Casting Configs is shown. ![Casting Config List](/img/casting/casting_config_list.webp) - Test by navigating to the defined URL in a new browser window (e.g [https://my.kasm.server/#/cast/123abc](https://my.kasm.server/#/cast/123abc) ) ![Casting reCAPTCHA Check](/img/casting/casting_captcha.webp) **Restrict to Referrers** is not a strict access-control mechanism and should not be the sole safeguard for a Casting Config. If the selected Workspace is configured with persistent profiles, and the Casting Config enforces authentication, the session launched will always load the user's persistent profile. ## Error Page When an error occurs that prevents the user from loading a session via a Casting URL, the system will send the user to an internal error page with an appropriate error message. If desired, the administrator can chose to redirect the user to a page of their choosing by configuring the **Error URL** setting in the Casting Config. ![Error Message](/img/casting/casting_error.png) ## Remote App Configuration The Remote App Configuration section allows the administrator to define characteristics about a casting session that can be used to control the remote application name and remote application arguments, which are injected into the `remote-app` and `remote-app-args` fields of the connection details of the RDP session. The administrator can take, for example, URL parameters and map them to remote application arguments. The following example defines Microsoft Excel as a remote app and the target file is passed in with the URL as a parameter. ```json { "remote_app_name": "||Microsoft Excel", "args": [ { "url_param_name": "file", "value_pattern": "([a-zA-Z]:\\\\)([^\\x00-\\x1F\\*\\\"/:<>\\?\\\\\\|]+\\\\)*([^\\x00-\\x1F\\*\\\"/:<>\\?\\\\\\|]+\\.(xls|xlsx|csv))", "required": true } ] } ``` The above example sets the Microsoft RemoteApp Name to "||Microsoft Excel", this must match the RemoteApp name defined on the server. See our [RemoteApp](../server-workspace/windows/remote-apps.mdx) guide for more information. The example above also defines a single argument which will be passed in with a URL parameter named file. The value_pattern field is optional and defines a regular expression. The example is a regular expression to validate the provided URL parameter value matches a Windows file path. If the regular expression does not match the value, the user will get an error page. This can be used to protect against inappropriate usage of the system, for example, command injection attempts. It could also be used to limit file path directories or file extensions. In the above example, the filename would be encoded in the target URL with the `file` parameter name. If the Casting configuration key was `excel`, the URL would be: `https://127.0.0.1/#/cast/excel?file=C%3A%5CUsers%5CPublic%5CDocuments%5CUbuntu_Security.xlsx` The following table defines all available options for each argument defined in the args array. | Name | Description | |---|---| | url_param_name | (optional) The URL parameter name to expect in the casting link URL. The value of this parameter will be used as the argument value. | | required | (optional) Defines whether the argument is required. The default value is false. If it is required and the url_param_name is defined, the user will get an error page if the URL did not contain a URL parameter matching the url_param_name. | | argument_name | (optional) The command line switch/argument name to specify. | | value | (optional) Defines a static value for the argument. If not defined, the value will be provided by a URL parameter, if url_param_name is defined. If neither is defined, only the argument_name will be provided, which can be useful for switches/arguments that have no expected values. | | value_pattern | (optional) A regular expression to be ran on the value. If defined and the regular expression does not match, the user will be directed to an error page. | The Workspace that this Casting configuration is targeting should be of type [Server](../../infra-autoscale/servers.mdx) or [Pool](../../infra-autoscale/pools.mdx) and be backed by a Windows Server running RDP with an application registered as a [RemoteApp](../server-workspace/windows/remote-apps.mdx) or a Windows RDS deployment. --- ## Session History & Recording Administration # Session History Administrators can view historic sessions by visiting the Sessions / History page from the Admin panel. ![Session History](/img/sessions/session_history.webp) Clicking the arrow for the session will present a list of potential actions: ![Options](/img/sessions/history_preview_option.webp) - **Download** - Downloads all the video files for the historic section in a ZIP file. - **Preview** - Opens a popup that allows you to preview the video files for the session. It also gives information such as duration and allows you to download individual clips. ![Session Preview](/img/sessions/history_preview.webp) ## Recording sessions In order to record sessions there are a couple of steps that need to be followed. ### Set up S3 Storage Storage must be set up first, if you are using persistent profiles, this may already be done as the same credentials are used for both. ### Set the recording location Set the session recording details, defaults are set for most of the inputs, but you will need to specify the upload location. ### Enable session recording in group settings The final piece of the puzzle is to enable session recording in group settings. Go to Access Management / Groups, Edit the group you want to record. Click the Settings tab, Click Add Settings button and type `record_sessions` then set the value to True and Click Submit --- ## Session Recording for Compliance This feature requires an Enterprise license. Please contact a Kasm Technologies representative for details. # Session Recording The Session Recording feature allows administrators to record user activities passively for compliance or monitoring purposes. These recordings are initially saved in segments on local storage. Later, they are converted to videos and uploaded to a pre-configured storage bucket. Session recording is supported on container based workspaces as well as RDP, VNC, and SSH server based workspaces. Containers must be either 1st party Kasm published images, or built upon the 1st party images with 1.15.0 tags or newer. Session recording is a CPU intensive task and will have an effect on the sizing of Connection Proxies and Agents. Refer to the [Kasm sizing guide](../../../explanations/sizing-operations.mdx) for more information. Session recording is not supported on staged sessions. If a user has a group with record_sessions set to True, and selects a workspace that has staged sessions provisioned a fresh on demand session will be provisioned for the user instead. ## Configuration - Log into the Kasm Web UI as an administrator. - Click **Settings->Global**. - Configure session recording (see [settings](../../../reference/settings.mdx#recording) for more detail): - Define **Object Storage Key** - Define **Object Storage Secret** - Define **Session Recording Upload Location** - Modify **Session Recording Bitrate** if desired - Modify **Session Recording Framerate** if desired - Modify **Session Recording Width** if desired - Modify **Session Recording Height** if desired - Modify **Session Recording Retention Period** if desired - Modify **Session Recording Queue Length** if desired - Enable session recording for the desired groups: - Click **Access Management->Groups** - Edit the desired group - Click **Settings** - Click **Add Setting** - Search for **record_sessions** setting and set to True For container based Workspaces, Workspaces that have sudo or root access enabled will result in the user having enough permissions to subvert the session recording process and prevent those recordings from being uploaded to the cloud. Changes to feature licensing may take up to 10 minutes to be applied since certain requests are cached by the system. If after applying the license and making all of the above configuration changes sessions are still not being recorded check the logs for warning/errors. If Kasm logs that the feature is not licensed wait 10 minutes for the cache to be refreshed and try again. ### S3 Policy Configurations This feature utilizes pre-signed URLs to facilitate uploading artifacts to S3. The minimum S3 bucket policy required to use this feature is: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "PolicyForAllowKasmS3UserReadWrite", "Effect": "Allow", "Principal": { "AWS": "" }, "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:DeleteObject" ], "Resource": [ "", "/*" ] }, { "Sid": "PolicyForAllowKasmS3UserListLocate", "Effect": "Allow", "Principal": { "AWS": "" }, "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "" } ] } ``` The minimum IAM policy for the S3 credentials used in Kasm are: ```json { "Statement": [ { "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:DeleteObject" ], "Effect": "Allow", "Resource": [ "", "/*" ] }, { "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Effect": "Allow", "Resource": "" } ], "Version": "2012-10-17" } ``` ### S3 Endpoint configuration By default, the endpoint used for S3 access is `s3.amazonaws.com`. Administrators may desire to specify a custom endpoint in order to support the following use cases. - A private VPC Endpoint - AWS Gov Cloud end-points - Region specific end-points - AWS S3 Accelerated Endpoints - S3 Compatible Solutions To specify a custom endpoint, in the Workspaces settings, format the Session Recording Upload Location path in the following format: ```text s3://bucket-name@endpoint/folder/{username}/{kasm_id}.mp4 ``` The following example configures Kasm to use GCP Cloud Storage (an S3 compliant cloud storage provider) for a session recording storage, where `kasm` is the bucket name, `storage.googleapis.com` is the endpoint name, and the remaining is the path with `{user_id}` replaced by the Kasm user ID, `{image_friendly_name}` replaced by the workspace name, and `{start_date}` is replaced by the date the user started the session. ```text s3://kasm@storage.googleapis.com/recordings/{user_id}/{image_friendly_name}-{start_date}.mp4 ``` Some S3 compatible providers will have additional requirements to be compatible. For instance GCP cloud storage also requires the use of [HMAC keys](https://cloud.google.com/storage/docs/authentication/hmackeys) for authentication. Please consult the documentation for the choosen provider to ensure all neccesary configuration is met. #### S3 Session Recording Variable Substitution The session recording upload location setting provides the ability to specify template variables that are automatically filled in by Kasm when uploading the recording clip. The table below lists each valid template value and an example of what the value looks like. | Template name | Example Value | |---------------------|-------------------------------------------| | kasm_id | 386b2eef-9bfb-443f-9eb6-6ee3331c38b4 | | user_id | 4dabe919-c5e9-4839-9bf3-07675f08a507 | | username | admin@kasm.local | | image_id | 3ea00a8b-7598-408d-8574-dbebc8304ff4 | | image_friendly_name | windows | | created_timestamp | 2023-12-12 21:12:45.386547 | | created_date | 2023-12-09 | | start_timestamp | 2023-12-13 20:27:13.853047 | | start_date | 2023-12-10 | | current_epoch | 1706554545220 (in millisecond resolution) | ## RDP, VNC, and SSH The connection proxy, which relies on Guacamole, records RDP, VNC, and SSH sessions in a rolling fashion, breaking the data into 150MB segments. These segments are initially stored in an intermediate format and are later converted into a playable video using the guacenc encoding tool. These are video only recordings, audio from the session, or recording of what the user says into their microphone is not recorded. If recording is set to true and the system is unable to initiate recording, for instance because the connection_proxy has run out of space, or because the global settings are invalid, then the session is not provisioned for the user to prevent an unrecorded session the administrator intended to be recorded. ### Resource Considerations It's important to note that session recording involves CPU-intensive video encoding. The number of videos that can be concurrently encoded is controlled by the **Session Recording Queue Length** setting. Each concurrent video encoding process typically utilizes one CPU core. To prevent negative impact on session performance, adequate resources should be allocated to the connection proxy. Additionally, session recording requires local storage space for the real-time encoding of active sessions. As a general guideline, at least 1GB of local storage should be available for each connected user. The system will prevent new users from connecting if the available local storage falls below 500MB and session recording is required for the connecting user. ### Recording Failure and Recovery #### Encoding Failure Corrupted recording files cause the encoding process to fail. When this occurs, the user is immediately disconnected from the session so that the Administrator may investigate. Until the Administrator has resolved the situation, the user will see an error screen informing them of the issue and will be unable to reconnect to the session. All unprocessed recording files for the session will remain in `/opt/kasm/current/tmp/guac/recordings/` on the connection proxy host, with filenames beginning with the session ID. If the Administrator wants the session's user to be able to resume the same session, then they must remove the session's recording files. The following snippet would remove all recording files for the session `501d2a83dc044c6d9bd1c709d3a346e6` and enable the user of that session to reconnect. Session recording would begin again when the user reconnected. ``` sudo rm -f /opt/kasm/current/tmp/guac/recordings/501d2a83dc044c6d9bd1c709d3a346e6-* ``` Session recordings that fail to encode properly will remain on the connection proxy's filesystem at the location referenced above until they are manually removed. The Administrator must clean up these artifacts, otherwise failed session recordings may fill the disk and cause storage issues. #### Upload Failure In cases where there are interruptions in user connectivity or instances of reconnection, the system will still proceed with the encoding and uploading of pending session recordings. This guarantees that no session data is lost due to these disruptions. The recorded files will remain on local storage and the system will attempt to upload them periodically. The duration for which these files will be locally retained is controlled by the **Session Recording Retention Period** setting. ## Viewing Session Recordings Users will need the **SESSIONS_VIEW** group permission to view the **session history** page. Users will need the **SESSION_RECORDINGS_VIEW** group permission to be able to view the session recordings on the **session history** page. There is a new administration page under **Sessions->History** that displays a history of all past sessions. This is also where users can view the recordings for each session. If session recordings are available there is a side arrow for that session row that will expand to allow selecting either a download or a view option. Clicking the download button will zip up and download all clips for that session. For the **Download All** option to work the s3 bucket must be configured for CORS. See the section on setting up s3 bucket CORS configuration below. A log similar to `User admin@kasm.local downloaded entire session: 10307f51fd2749f3a84a7aaa2f81d26e` will be generated whenever a User downloads all recordings for a session. This allows an administrator to track when recordings are downloaded. When clicking on the preview (eye) icon the user is taken to a screen that lists all the clips for the session along with thumbnails, a download button (small cloud icon with a down arrow next to the clip number) for each individual clip, and a video playback window. For the Download button to work the s3 bucket must be configured for CORS. See the section on setting up s3 bucket CORS configuration below. Clicking on the video player window will initiate playback of the selected clip. A log similar to `User admin@kasm.local played 10307f51fd2749f3a84a7aaa2f81d26e video: s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066120.mp4` will be generated whenever a User plays a recording for a session. This allows an administrator to track when recordings are viewed. Clicking the download button will allow the user to download the individual clip that is selected. A log similar to `User admin@kasm.local downloaded 10307f51fd2749f3a84a7aaa2f81d26e video: s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066120.mp4` will be generated whenever a User plays a recording for a session. This allows an administrator to track when recordings are viewed. ## S3 CORS configuration When utilizing the download options for the recording clips there are CORS settings on the s3 bucket that have to be configured. Two providers are covered here, Amazon S3, and GCP cloud storage. ### Amazon S3 Select the Amazon S3 bucket that will be used for storing session recordings. Select the permissions tab and scroll down until you see the *Cross-origin resource sharing (CORS)* section click edit and configure it as below replacing https://kasm.acme.com with the appropriate origin (the Kasm domain). ```json title="CORS configuration" [ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET", "PUT", "POST", "DELETE" ], "AllowedOrigins": [ "https://kasm.acme.com" ], "ExposeHeaders": [] } ] ``` ### GCP Cloud Storage Like Amazon S3 GCP cloud storage buckets need to have CORS configuration applied for Kasm to be able to provide the download access for recording clips. GCP only supports bucket CORS configuration through the commandline gcloud client. Download and install the [gcloud client](https://cloud.google.com/sdk/docs/install) follow the instructions to apply a [CORS configuration](https://cloud.google.com/storage/docs/using-cors#command-line) the following is an example configuration that should work when replacing https://kasm.acme.com with the Kasm domain of the installation. ```json title="CORS configuration" [ { "origin": ["https://kasm.acme.com"], "method": ["GET", "PUT", "POST", "DELETE"] } ] ``` --- ## Session Sharing & Remote Assistance # Session Sharing The Session Sharing feature in Kasm allows users to place an existing session in “sharing mode”. This generates a unique URL that can be shared with other authenticated users, granting them the ability to view or interact with the session. When session sharing is enabled, the shared session is framed within a user interface that allows participants to see who is also viewing the shared session. Any authenticated user may join a shared session if the URL is known. ![Shared Session](/img/session_sharing/Shared_Session.webp) ## Benefits and Use Cases Session sharing offers several benefits and can be used in various scenarios, including: - **Collaborative Work:** Users can work together in real-time, reviewing and editing documents, code, or designs. - **Remote Assistance:** Experts can provide guidance and support by remotely accessing and assisting users in their sessions. - **Presentations and Demos:** Users can share their sessions to demonstrate software, conduct training sessions, or deliver presentations to a wider audience. ## Security Considerations It's important to consider the following security aspects when using session sharing: - **Trustworthy Participants:** Only share the session URL with trusted individuals, as anyone with the URL can join the shared session. - **Confidential Information:** Avoid sharing sensitive or confidential information during shared sessions to maintain data security and privacy. ## Shared Session Group Settings The shared session control panel item is only available to users if the Workspaces administrator has configured the **allow_kasm_sharing** [Group Setting](../../security/users-groups-mgmt/groups.mdx) configured to **True** (Default: True). By default, only the initiator of the shared session will be able to control the session, while all other participants are in view-only mode. If the **shared_session_full_control** (Default: False) [Group Setting](../../security/users-groups-mgmt/groups.mdx) is enabled, all users who join the shared session will have the ability to control the mouse and keyboard input. Have multiple users interacting with a single shared session simultaneously can result in an inconsistent user experience. ## Session Control By default, only the initiator of the shared session has control over the session, while other participants are in view-only mode. It is important to clarify that participants cannot control the session unless the initiator grants them control. Consider specifying whether participants can request control or perform limited actions in view-only mode. ## User Interface The user interface for participants in a shared session includes the following elements: - Participant List: A list displaying the users who are currently viewing the shared session. - Additional Controls: Any specific controls or features designed for shared sessions. ## Video and Audio Settings During a shared session, video and audio settings available to participants if allowed via Group settings by the administrator. It is essential to clarify any restrictions or limitations on video and audio functionality during shared sessions. By default, when the shared session is initiated, the streaming resolution and aspect ratio for the session is fixed to 720p to reduce bandwidth consumption and to ensure all users have a consistent user experience. If the admin disables the **lock_sharing_video_mode** (Default: True) the session initiator is able to change the video settings to allow for higher resolutions or for the stream to match their browser window. Mixing video mode resolutions across multiple participants with different screens sizes/resolutions can result in an inconsistent user experience. ![Shared Session Group Settings](/img/session_sharing/Shared_Session_Group_Settings.webp) ## Initiating a shared session - Launch a Kasm session. - Expand the control panel and click the **Share Instance** button. - Click **Share Session**, the URL you need to pass on to users will automatically be added to your clipboard and you will receive a notification. ![Configuring a shared session](/img/session_sharing/Configuring_A_Shared_Session.webp) - You can also get the URL from the control panel menu as well as stop sharing. ![Configuring a shared session](/img/session_sharing/Configuring_A_Shared_Session_2.webp) --- ## Session Staging for Faster Access # Session Staging By default, when users create a new Kasm session, the container for that session is created on-demand. In some use-cases, administrators may wish to **Stage** (Pre-Provision) containers, so when a user requests a session, it pulls from a pool of staged containers that are already running. This may be useful to reduce the time it takes for a user to connect to a session, or if the Image has a lengthy run-time initialization routine. As part of the configuration, administrators must configure a set of default permissions (e.g. **Allow Audio**) that will be enabled/disabled for the session. Because these settings must be configured at the invocation of the container, for enhanced security, users whose group permissions do not match these will not be assigned a staged session and instead will trigger the system to create one on demand. ## Configuration - Log into the Kasm Web UI as an administrator. - Click **Sessions** -> **Staging**. - Click **Add Config**. ![Staging Config](/img/staging/create_staging_config.webp) | **Property** | **Description** | | --- | --- | | **Zone** | The [Deployment Zone](../../infra-autoscale/deployment-zones.mdx) for the configuration | | **Workspace** | The desired [Workspace](../container-workspace/workspaces.mdx) to be staged. | | **Desired Sessions** | The number of sessions the system will attempt to have staged at any given time. As users are assigned sessions from the pool, the system will automatically attempt to provision more to keep the pool at this number. Reducing this number will cause the system to destroy excess staged sessions. | | **Expiration (Hours)** | Staged sessions that have not been assigned to a user will expire after this amount of time. The system will destroy the staged sessions and re-created them. | | **Allow Audio** | When enabled, the staged session will support streaming audio from the session to the user. | | **Allow Clipboard Down** | When enabled, the staged session will allow copying data from the session to the users local computer via the clipboard | | **Allow Clipboard Up** | When enabled, the staged session will allow copying data from the user's local computer to the session. | | **Allow Downloads** | When enabled, the staged session will allow download files from the session to their local computer via the control panel download widget. | | **Allow Microphone** | When enabled, the staged session will allow the user to pass their local microphone into the session. | | **Allow Uploads** | When enabled, the staged session will allow the user to upload files from their local computer to the session via the upload widget in the control panel. | | **Allow Gamepad** | When enabled, the staged session will allow the user to pass through gamepads from their local computer to the session via the gamepads widget in the control panel. | - Fill out the form then click **Save**. - Click **Infrastructure** -> **Zones**. - Click **Edit** next to the desired Zone. - Update the **Allow Origin Domain** and the **Upstream Auth Address** settings to be the appropriate domain. The default `$request_host$` variable cannot be used for staged sessions. ## Desired Sessions The system will begin creating the staged sessions a few moments after the configuration is applied. If the **Current Sessions** does not match the **Desired Sessions** after a few minutes , consult the logs for warning or error messages. It is likely the system doesn't have enough resources (Agent Capacity) to fulfill the request, or an Image is disabled or unavailable ![Staging Configs](/img/staging/staging_list.webp) ## Session List Staged sessions will appear without a User assigned in the **Sessions** list. Once the sessions are **assigned** to a user, the username will appear. ![Staged Sessions](/img/staging/staged_sessions.webp) ## Incompatible Settings Certain Group and Image level settings are not compatible with Staged Sessions as they require the workspace to be originally created with the settings applied. If a user requests a Kasm session but has an incompatible setting applied, the violation will be logged, and the system will provision a workspace on-demand. | Setting Location | Setting | Notes | |------------------|------------------------------|----------------------------------------------------------------------------------------| | Workspace | Persistent Profiles | | | Workspace | Volume Mappings* | Volume mappings cannot reference `{username}` or `{user_id}` tokens. | | User | File Mappings | Administrators can apply a File Mapping to a Workspace instead. | | User | Kasm Session Language | This only fails if the user language and the staged session language are not the same. | | User | Kasm Session Timezone | This only fails if the user timezone and the staged session timezone are not the same. | | Group | File Mappings | Administrators can apply a File Mapping to a Workspace instead. | | Group Setting | expose_user_environment_vars | | | Group Setting | inject_ssh_keys | | | Group Setting | record_sessions | | | Group Setting | run_config | | | Group Setting | volume_mapping | | | Group Setting | web_filter_policy | Administrators can apply a filter policy to the Image instead. | | Group Setting | enable_container_logging | | ### Language and Timezone settings Users can set specific language and timezone settings on their profile or automatically use the language and timezone settings from their browser. By default, when accessing a staged session Kasm will attempt to match a staged session with the user preferred language and timezone settings. If a staged session with those settings is unavailable then a new session on-demand is created for the user. As the default settings for Kasm workspaces are Etc/UTC timezone and en_EN.UTF-8 language users may find that they frequently are using workspace on-demand instead of staged sessions. To avoid this the Administrator has a few options. Administrators can override this behavior with the group setting **staged_session_language_and_timezone_preference_override** see the [group settings](../../security/users-groups-mgmt/groups.mdx#group-settings) documentation for more information. Administrators can also override the default language and timezone settings for a Workspace using the [docker-run-config](../container-workspace/workspaces.mdx) section on configuring the language and timezone to match the language and timezone settings of their users. Administrators can check the logs to see if staged sessions are being used to fulfill user session requests and if not, what the cause is. ![Logged settings violation](/img/staging/incompatible_settings.webp) ## Egress Gateways Session Staging supports Workspaces that have an egress gateway configured at the image level, subject to the following constraints. If your VPN provider has a maximum connection time make sure to use staged session rotation. **Supported:** Workspaces with `Override Egress Gateways` enabled and **exactly one** egress gateway/credential pair mapped to the image. In this configuration the staging manager pre-warms standby sessions with the gateway already applied (the sidecar network is configured at container creation time, the same as a live session). When a user requests a session, the system will only assign a standby whose pre-applied gateway matches the user's selection. If no matching standby is available, the system falls back to creating an on-demand session. **Not supported:** Workspaces with multiple egress gateways mapped, or Workspaces where users select their own egress gateway at launch time (i.e., `Override Egress Gateways` is not enabled). In the multiple-gateway case, staging is skipped for that configuration entirely and sessions are always created on-demand. In the user-selected case, the gateway choice is request-specific and cannot be pre-applied to a standby. If staging is skipped due to egress resolution failure, a warning is recorded in the logs indicating the cause. ## Multi-Zone Behavior When a user makes a request to launch a session the system will prefer to assign a staged session in all applicable Zones prior to attempting to create an on-demand container. The process is as follows: 1. Attempt to assign a staged session in the current Zone. 2. Attempt to assign a staged session in other Zones if **Search Alternate Zones** is configured on the current Zone. 3. Attempt to create a new on-demand session in the existing Zone. 4. Attempt to create a new on-demand session in other Zones if **Search Alternate Zones** is configured on the current Zone. ## Docker Exec The Docker Exec Config supports a top level key named `assign`. This command is executed when the user is assigned a staged session. For more information please see [Docker Exec Config](../container-workspace/workspaces.mdx) --- ## Managing Sessions: Stop, Pause, Delete # Sessions Administrators can view the active sessions by visiting the Sessions page from the Admin panel. Clicking the arrow for the session will present a list of potential actions: - **View** - View more details about the session. - **Stop** - The session is stopped, preserving the disk state. Sessions resumed from a stopped state will have the previous files intact, but previously running programs will need to be restarted. This option is applicable to container-based Workspaces only. - **Pause** - The session is paused, preserving the disk, process and memory state. Paused sessions will still consume resources in physical memory and/or swap. Sessions resumed from a paused state will still have the previous programs launched and active. This action is only applicable to container-based Workspaces. - **Start** - Re-start a stopped or paused session. - **Delete** - The session is deleted. ## Create Image from Session Administrators can create new docker images from active container-based Workspace sessions. While it is recommended to utilize a more formal [build process](../container-workspace/customization/building-images.mdx) for creating images, automatically creating them from active sessions presents a simple process creating images that may require steps that cannot be automated. 1. From the Sessions page, click the arrow to show the actions menu. 2. Select **Create Image** 3. A form is displayed. The only required entry is **New Docker Image** (repo + tag). A name will automatically be generated with the current date and time. If registry information is provided, the system will attempt a push of the newly created image. The **Additional Changes** field accepts a limited number of `DOCKERFILE` instructions that can be called during the commit. The following instructions are supported: `CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR` See [https://docs.docker.com/engine/reference/commandline/commit/](https://docs.docker.com/engine/reference/commandline/commit/) for more details. Below are examples of Image/Registry configurations for common Docker registries. | Field | Value | | :--------------- | :---------------------------------- | | New Docker Image | `myrepo/firefox:2023-03-13.00.40` | | Registry URL | `https://index.docker.io/v1/` | | Field | Value | | :--------------- | :-------------------------------------------------------------------- | | New Docker Image | `registry.gitlab.com/mygroup/image-repo/firefox:2023-03-13.00.40` | | Registry URL | `https://registry.gitlab.com` | When finished, click **Submit**. 4. A task will be sent to the Kasm Agent, to conduct a `docker commit` with the new image, and if configured in the previous from will attempt a `docker push` to the registry provided. This is a background task, so administrators may need to review the logs to identify failures in the process. For example, an error is shown below for a failed image push. 5. A Workspace entry is automatically created and presented to the Administrator for additional configurations. When complete, click **Submit** 6. Back on the Workspace Launcher, the new Workspace should be visible. (e.g `Snapshot of Firefox - (develop-2023-03-12.23.44)`) . If the commit succeeds, the image will be marked as available. Depending on the size of the image, this process may take several minutes. --- ## Smartcard Native Client # Smartcard Bridge (Native Client) Kasm Smartcard Bridge (Native Client) is a Windows/MacOS application and Chrome extension that works together to enable passing a smartcard connected to a local machine into a Workspace. ### System Requirements | Supported Operating Systems | |-----------------------------| | Windows 10 (x86_64) | | Windows 11 (x86_64) | | Windows Server 2019 (x86_64) | | Windows Server 2022 (x86_64) | | Windows Server 2025 (x86_64) | | Supported Operating Systems | |-----------------------------| | MacOS Sonoma (Intel/Apple Silicon) | | MacOS Sequoia (Intel/Apple Silicon) | | MacOS Tahoe (Intel/Apple Silicon) | ### Installation The Kasm Smartcard Bridge can be installed using one of the installers below which places all the necessary files in `C:\Program Files\Kasm` on Windows and '/Library/Application Support/Kasm' on MacOS. You should use the latest version that supports the version of Kasm Workspaces you have installed. | Installer Version | Installer Link | Kasm Workspaces Compatibility | SHA256 | |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|------------------------------------------------------------------| | Developer Preview | [Kasm_Smart_Card_Bridge_develop_1.0.90f5dda2.msi](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/90f5dda206b22917ddb22ac1b352026769c827fa/Kasm_Smart_Card_Bridge_develop_1.0.90f5dda2.msi) | Developer Preview | _rolling_ | | 1.0.47121342 | [Kasm_Smart_Card_Bridge_1.0.0_1.0.47121342.msi](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/47121342b740ddc3b80b092f5c747232b30cbef9/Kasm_Smart_Card_Bridge_1.0.0_1.0.47121342.msi) | 1.18.1 | d3202cd2d387c7926bb75245e4d47d068138d704160143d7da40f70226cbba05 | | 1.0.4304bc51 | [Kasm_Smart_Card_Bridge_1.0.0_1.0.4304bc51.msi](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/4304bc5193263eb702f8eaa36ffa7a714cf22de8/Kasm_Smart_Card_Bridge_1.0.0_1.0.4304bc51.msi) | 1.18.0 | 3b0a58c2950927b53e1668990a3a47ff29d08cc0cf91acc01482b6c5ad572104 | | Installer Version | Installer Link | Kasm Workspaces Compatibility | SHA256 | |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|------------------------------------------------------------------| | Developer Preview | [Kasm_Smart_Card_Bridge_develop_1.0.90f5dda2.signed.pkg](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/90f5dda206b22917ddb22ac1b352026769c827fa/Kasm_Smart_Card_Bridge_develop_1.0.90f5dda2.pkg) | Developer Preview | _rolling_ | | 1.0.47121342 | [Kasm_Smart_Card_Bridge_release_1.0.47121342.signed.pkg](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/47121342b740ddc3b80b092f5c747232b30cbef9/Kasm_Smart_Card_Bridge_1.0.0_1.0.47121342.pkg) | 1.18.1 | e7ca0d54819b681112acc4157c1d964faf31cdc516b1439c028f227e13f5c5d1 | | 1.0.4304bc51 | [Kasm_Smart_Card_Bridge_release_1.0.4304bc51.signed.pkg](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/4304bc5193263eb702f8eaa36ffa7a714cf22de8/Kasm_Smart_Card_Bridge_develop_1.0.4304bc51.pkg) | 1.18.0 | 3f089e73a08233aad7be037d5f46a4d9ffeabdcdcc3e949cbe8c85ffbb8f001a | The [Developer Preview Build](../../reference/builds.mdx) of the Kasm Smartcard Bridge Service listed above should only be used with the developer preview build of Kasm Workspaces on non-production systems. The documentation on this page is for the latest version of the installer listed in the table above and may not be accurate for older versions. #### Installation Troubleshooting During the installation on Windows, the Kasm Smartcard Bridge installer will attempt to add a path to a config file at: 'HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\KasmSmartCardBridge' in the Windows Registry. If endpoint security softwer is configured to prevent installers from editing the Windows Registry, the install may fail. ### Upgrade When running the installer on a machine with an existing Kasm Smartcard Bridge an upgrade will be performed. You should close all of your browser windows prior to updating the Kasm Smartcard Bridge. ### Uninstall If the Kasm Smartcard Bridge needs to be uninstalled it can be removed by going to `Add or remove programs` / and selecting the ``Kasm Smartcard Bridge`` and then selecting ``Uninstall``. There will be a dialog box asking you to confirm you wish to remove the Kasm Smartcard Bridge, click ``OK`` to continue. You can manually remove the folder/file or use the uninstaller: **Folder:** /Library/Application Support/Kasm/Smart Card Bridge **File:** /Library/Google/Chrome/NativeMessagingHosts/com.kasm.smartcard.json **Uninstaller:** [Kasm_Smart_Card_Bridge_Uninstaller](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_smart_card_bridge/c318d4613fe7379b112db758e7d53c400f7643bd/Kasm_Smart_Card_Bridge_Uninstaller.pkg) ### Logging By default, only warring and error log messages are written to Windows event log (under `Applications->KasmSmartcardBridge`) or the MacOS syslog, and all log messages are written to log files on the local machine. **Log file path:** %APPDATA%\Kasm\Smart Card Bridge\logs\kasm_scard_bridge.log **Alternative log file path:** C:\temp\kasm-logs\kasm_scard_bridge.log **Log file path:** ~/Library/Logs/Kasm Smart Card Bridge/kasm_scard_bridge.log **Alternative log file path:** /tmp/kasm-logs/kasm_scard_bridge.log The alternative log file path is used when the Smartcard bridge is unable to write to the normal log path. This is usually due to the Smartcard Bridge not having write permissions to the desired folder. A new log file is generated each time the Smartcard Bridge is launched, or when the active log file reaches a size of 10 MB. The system maintains a maximum of four log files. Once this limit is reached, the Smartcard Bridge will overwrite the oldest log file with a new one, ensuring that only the four most recent log files are retained. but can be also redirected to a file by specifying the `log_file` parameter in `config.yaml`. Logs are also sent to the Kasm Workspaces deployment and can be searched for the Kasm Admin UI under Diagnostics->Logging. --- ## Smart Card Pass-through in Kasm Workspaces # Smart Card Pass-through Kasm Workspaces supports passing through smart card devices into both RDP-based Windows sessions and containerized workspace sessions. This feature enables users to use their physical smart cards within applications and systems, supporting various use cases such as PIN-based authentication, digital signing, and certificate-based operations. ## For RDP-based Windows Sessions ### Configuration ### Group Settings Ensure the `allow-kasm-smartcard-passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` prior to launching sessions that require smart card passthrough (both container-based and RDP-based workspaces). ### Windows Target Environments 1. Prepare the environment by installing the manufacturer provided drivers, middleware, and certificates for the smart card readers and smart cards that will be used. ### For Web Native Client To enable this feature on ChromeOS: 1. Ensure the `allow-kasm-smartcard-passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` 2. Download and install the `Kasm Native Smartcard Client` as per the instructions in the [Kasm Native Smartcard Client](#kasm-native-smartcard-client) section below 3. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo) 4. Launch a container-based Kasm session. 3. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo). 4. Ensure the `allow_kasm_smart_card_passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` prior to launching the session. 6. The smart card should now be automatically detected and made available to applications within the container. 1. Ensure the `allow-kasm-smartcard-passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` 2. Download and install the `Kasm Native Smartcard Client` as per the instructions in the [Kasm Native Smartcard Client](#kasm-native-smartcard-client) section below 3. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo) 4. Launch a container-based Kasm session. 5. Once enabled, the live smartcard passthrough status will be visible under "Control Panel > Smartcard Passthrough". 6. The smart card should now be automatically detected and made available to applications within the container. 1. Ensure the `allow-kasm-smartcard-passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` 2. Install the `Google Smart Card Connector App` from the [Chrome Web Store](https://chrome.google.com/webstore/detail/smart-card-connector/khpfeaanjngmcnplbdlpegiifgpfgdco) 3. Install the `DriveLock Smart Card Middleware (CSSI)` from the [Chrome Web Store](https://chromewebstore.google.com/detail/drivelock-smart-card-midd/haeblkpifdemlfnkogkipmghfcbonief) 4. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo) 2. Ensure the `allow_kasm_smart_card_passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` prior to launching the session. 6. Once enabled, the live smartcard passthrough status will be visible under "Control Panel > Smartcard Passthrough". 7. The smart card should now be automatically detected and made available to applications within the container. ### Technical Details For Web Native Client This feature works by extending the guacamole protocol to enable smart card passthrough capabilities. The implementation leverages the Remote Desktop Protocol's smart card channel to securely transmit smart card operations between the client and the remote Windows system. While the implementation is PC/SC (Personal Computer/Smart Card) compliant, the available functions are limited to the functionality provided by the ChromeOS Smart Card Connector App. Any application attempting to use a PC/SC function unsupported on ChromeOS will receive an `S_CARD_E_UNSUPPORTED` error code as per PC/SC standard. Due to the nature of smart card passthrough, cache related functionality (which is normally part of the Windows platform) had to be emulated. For security reasons, the corresponding PC/SC functions (`SCardReadCache` and `SCardWriteCache`) are implemented in the Chrome extension rather than on the server side. This approach ensures that sensitive cached smart card data remains local to the user's browser. ### Technical Details For RDP Local Client This feature is implemented via the RDP client's implementation of the feature and may have limitations based on that specific implementation. ### Troubleshooting #### For Web Native Client If you encounter issues with smart card passthrough: 1. Ensure your smart card reader is properly connected 2. Ensure the `allow_kasm_smart_card_passthrough` group setting is enabled 3. Ensure the `Google Smart Card Connector App` Chrome extension is enabled 4. Ensure the `DriveLock Smart Card Middleware (CSSI)` Chrome extension is enabled 5. Ensure the `Kasm Workspaces Smart Card Extension` Chrome extension is enabled 6. Ensure that any drivers, middleware, or certificates that are required by the smartcard and smartcard reader manufacturers are installed on the system. 7. If the smart card appears to be in an unresponsive state, try removing and reinserting the card If you're still experiencing issues, these additional troubleshooting tools are available: Client-side Troubleshooting: 1. Check `chrome://extensions` and inspect the `Kasm Workspaces Smart Card Extension` service worker for detailed logs about client-side smart card operations. 2. Check the Native Client detailed logs: **Log file path:** %APPDATA%\Kasm\Smart Card Bridge\logs\kasm_scard_bridge.log **Alternative log file path:** C:\temp\kasm-logs\kasm_scard_bridge.log **Log file path:** ~/Library/Logs/Kasm Smart Card Bridge/kasm_scard_bridge.log **Alternative log file path:** /tmp/kasm-logs/kasm_scard_bridge.log The alternative log file path is used when the Native Client is unable to write to the normal log path. This is usually due to the Native Client not having write permissions to the desired folder. A new log file is generated each time the Native Client is launched, or when the active log file reaches a size of 10 MB. The system maintains a maximum of four log files. Once this limit is reached, the Native Client will overwrite the oldest log file with a new one, ensuring that only the four most recent log files are retained. Server-side Troubleshooting: 1. Check the `kasm_guac` container logs for smartcard related messages 2. Look for a `Registering smartcard` container log message to confirm smartcard support was enabled for the session Diagnostic Tools: 1. Open Command Prompt or PowerShell in the Windows session 2. Run `certutil -scinfo` to get detailed information about connected smart card readers and cards. This tool can help identify if Windows properly recognizes the smart card hardware. For certificate-enabled smartcards: 1. Verify the certificate has been recognized: - Press `Win + R`, type `certmgr.msc`, and press Enter. - In the left pane, expand **Personal** → **Certificates**. - Look for a certificate issued by your smartcard's Certificate Authority. 2. In case of a missing client certificate, verify the presence of necessary configuration entries in the Windows registry at `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards` for your smartcard. Missing entries can prevent proper smartcard certificate propagation, affecting smartcard functionality. #### For RDP Local Client 1. Ensure your smart card reader is properly connected 2. Ensure the `allow_kasm_smart_card_passthrough` group setting is enabled 3. Ensure that any drivers, middleware, or certificates that are required by the smartcard and smartcard reader manufacturers are installed on the system. 4. If the smart card appears to be in an unresponsive state, try removing and reinserting the card If you're still experiencing issues: Check the documentation and troubleshooting guides for the RDP client. Diagnostic Tools: 1. Open Command Prompt or PowerShell in the Windows session 2. Run `certutil -scinfo` to get detailed information about connected smart card readers and cards. This tool can help identify if Windows properly recognizes the smart card hardware. ## For Container-based Workspaces Container-based workspaces support smart card passthrough by creating a virtual smartcard reader within the container that forwards commands to the physical smartcard connected to the user's device via the Kasm Smartcard Chrome extension. The implementation maintains full container isolation as it requires no privileged container access or external host mounts. For performance reasons, while disconnecting the reader or card will have immediate effect within the container, an inserted card might be detected with a slight delay (no longer than 2-3 seconds). ### Configuration To enable this feature: 1. Ensure the `allow_kasm_smart_card_passthrough` [Group Setting](../security/users-groups-mgmt/groups.mdx) is set to `true` prior to launching the session. 2. Install the required components for your operating system: 1. Download and install the `Kasm Native Smartcard Client` as per the instructions in the [Kasm Native Smartcard Client](#kasm-native-smartcard-client) section below 2. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo) 1. Install the `Google Smart Card Connector App` from the [Chrome Web Store](https://chrome.google.com/webstore/detail/smart-card-connector/khpfeaanjngmcnplbdlpegiifgpfgdco) 2. Install the `DriveLock Smart Card Middleware (CSSI)` from the [Chrome Web Store](https://chromewebstore.google.com/detail/drivelock-smart-card-midd/haeblkpifdemlfnkogkipmghfcbonief) 3. Install the `Kasm Workspaces Smart Card Extension` from the [Chrome Web Store](https://chromewebstore.google.com/detail/cjkohjfgidilbllbjkdhpoeonjanpomo) 3. Launch a container-based Kasm session. 4. Once enabled, the live smartcard passthrough status will be visible under "Control Panel > Smartcard Passthrough". 5. The smart card should now be automatically detected and made available to applications within the container. ### Kasm Native Smartcard Client The Kasm Native Smartcard Client is a native host application that enables smartcard functionality for container-based workspaces by bridging communication between the browser extension and local smartcard readers on Windows and macOS systems. #### Installation **Windows:** - Download and run the .msi installer package - The installer automatically places the application in `C:\Program Files\Kasm\Smart Card Bridge\` and registers it with Chrome for native messaging **macOS:** - Download and run the .pkg installer package - The installer places the application in `/Library/Application Support/Kasm/Smart Card Bridge/` and configures native messaging in `/Library/Google/Chrome/NativeMessagingHosts/` #### Verification To verify the native client is working properly: 1. Open `chrome://extensions/` in your browser 2. Find the `Kasm Workspaces Smart Card Extension` 3. Click `background page` under the extension 4. Look for the following messages in the console: ``` Initializing smartcard native client... Smartcard native client initialized ``` ### Technical Implementation Container-based smart card passthrough uses a multi-component architecture that maintains container security through virtual device emulation: - **PC/SC Daemon** (`pcscd`) runs within the container to provide standard PC/SC services - **VPCD (Virtual PC/SC Device)** creates a virtual smartcard reader named "Kasm Remote Smartcard" that appears as a standard PC/SC reader to applications within the container - **Kasm Smartcard Bridge** (`kasm_smartcard_bridge`) acts as a VPCD server, translating between the VPCD protocol and KasmVNC's relay protocol - **Kasm Web App** coordinates communication between browser and container - **Kasm Chrome Extension** communicates with either the native client (Windows/macOS) or directly with ChromeOS exposed APIs - **Kasm Native Smartcard Client** interfaces with the physical smartcard reader on Windows and macOS This architecture allows applications to use standard PC/SC APIs seamlessly without requiring privileged container access or host system mounts. The communication flow is: Container Applications → PC/SC Daemon → VPCD ("Kasm Remote Smartcard") → Smartcard Bridge → KasmVNC Relay → Web App → Chrome Extension → Native Client/ChromeOS APIs → Physical Reader ### Troubleshooting For Container-based Workspaces If you encounter issues with smart card passthrough in containers: 1. Ensure your smart card reader is properly connected 2. Ensure the `allow_kasm_smart_card_passthrough` group setting is enabled 3. Ensure the `Kasm Native Smartcard Client` is installed and running 4. Ensure the `Kasm Workspaces Smart Card Extension` Chrome extension is enabled 5. Check the smartcard status under "Control Panel > Smartcard Passthrough" to verify the status of each component (extension/reader/card) 6. Verify that the container has smartcard support enabled (`KASM_SVC_SMARTCARD=1`) 7. If the smart card appears to be in an unresponsive state, try removing and reinserting the card Client-side Troubleshooting: 1. Check the smartcard status under "Control Panel > Smartcard Passthrough" to verify the status of each component (extension/reader/card) 2. Check `chrome://extensions` and inspect the `Kasm Workspaces Smart Card Extension` service worker for detailed logs about client-side smart card operations 3. Verify the native client is running in the system process list Container-side Troubleshooting: 1. Check the container logs for smartcard related errors (pcscd/bridge) 2. Check if the PC/SC daemon is running: `docker exec CONTAINER_ID ps aux | grep pcscd` 3. Check if the smartcard bridge is running: `docker exec CONTAINER_ID ps aux | grep kasm_smartcard_bridge` 4. Test PC/SC connectivity within the container: `docker exec CONTAINER_ID opensc-tool -l -a` Diagnostic Tools: 1. Within the container, run `docker exec CONTAINER_ID opensc-tool --list-readers` to see available readers 2. Run `docker exec CONTAINER_ID opensc-tool --atr` to verify the card is detected 3. Run `docker exec CONTAINER_ID opensc-tool --serial` to verify the card data transmission works 4. Use `docker exec CONTAINER_ID pkcs15-tool --list-certificate` to list certificates on the card --- ## Kasm Workspaces Documentation | Secure Access Built for Enterprise Operations export const ActionCard = ({ icon, title, description, secondDescription = "", bullets = [], subtitle, href, bgColor = '#f5f5f5', borderColor = '#e5e7eb', textColor = '#1a1a1a', mutedColor = '#ffffff' }) => { const card = ( {icon && } {title} 0 ? styles.cardDescriptionWithBullets : styles.cardDescriptionWithoutBullets, ].filter(Boolean).join(' ')} > {description} {bullets.length > 0 && ( {bullets.map((bullet, index) => ( {bullet} ))} )} {secondDescription && ( {secondDescription} )} {subtitle && ( {subtitle} )} ); if (href) { return ( {card} ); } return card; }; export const FeatureCard = ({ icon, customIcon, title, description, outcome, measure, href, bgColor = '#ffffff', borderColor = '#e5e7eb', textColor = '#1a1a1a', mutedColor = '#666' }) => { const card = ( {customIcon && ( {customIcon} )} {!customIcon && icon && ( )} {title} {description && ( {description} )} {outcome && ( Outcomes: {outcome} )} {measure && ( Measure success by: {measure} )} ); if (href) { return ( {card} ); } return card; }; # Kasm Workspaces Documentation ## Access the Resource, Not the Network Security-focused organisations that currently operate VPN, VDI, and Remote Browser Isolation (RBI) products increasingly want a safer, simpler way to provide secure access to sensitive enterprise resources and risky web destinations. Kasm Workspaces is a browser-delivered Zero Trust access platform that reduces the client software, endpoint dependencies, and persistent infrastructure commonly associated with traditional remote access architectures such as Citrix Virtual Apps and Desktops, Omnissa Horizon, VPNs, and RBI solutions. ## Zero Trust Workspace Architecture Kasm Technologies holds [SOC 2 Type 2](https://trust.kasm.com/) and [CMMC 2.0 Level 2 certifications](https://trust.kasm.com/), aligned with [NIST SP 800-171](https://csrc.nist.gov/pubs/sp/800/171/r3/final) requirements. This gives regulated organizations and any team that wants a Zero Trust access platform a proven security foundation for secure workspace delivery. The platform uses standard HTTPS and WebSockets to deliver browser-based access to Windows, Linux, and macOS systems. Users can access applications, desktops, and isolated browser sessions without requiring direct network-level access from the endpoint. ## Built for Enterprise Adoption Deploy Kasm Workspaces alongside existing identity, security, logging, and infrastructure investments while maintaining control over policy, topology, capacity, and operations. The platform supports Windows, Linux, macOS and Android systems. It also provides automated scaling and Kasm-maintained workspace images to simplify deployment. ## Isolate Risk in Both Directions Use the same controlled session architecture to protect users from untrusted content and to protect enterprise resources from unmanaged devices. Start with the isolation requirement that presents the highest risk or operational burden. Validate the outcome with a defined user group before extending the architecture to additional workloads. Protect users from untrusted destinations High-risk websites and applications run inside isolated environments instead of executing directly on the user's local device. The session is discarded when the user is finished. } bgColor="#ffffff" /> Protect enterprise resources from untrusted devices Contractors, partners, BYOD users, and remote employees can interact with authorized resources through a browser while the endpoint remains separated from the protected environment. } bgColor="#ffffff" /> ## A Common Platform for Desktops, Secure Access and Isolation Kasm Workspaces brings virtual desktops, enterprise access, remote browser isolation (RBI), application streaming, and secure AI environments onto a common Zero Trust platform. Start with the highest-priority access requirement, prove the outcome, then extend the same identity, policy, and delivery model to additional use cases. } outcome="Deliver managed desktops through the browser while reducing persistent per-user infrastructure and simplifying provisioning and patching." bgColor="#FFFFFF" /> } outcome="Provide contractors, partners, and remote users access to approved resources without extending network-level access to unmanaged devices." bgColor="#FFFFFF" /> } outcome="Provide controlled access to approved applications without requiring endpoint installation or exposing the underlying application environment." bgColor="#FFFFFF" /> } outcome="Reduce the risk of exposing analyst identity, endpoints, or organizational infrastructure during sensitive OSINT research." bgColor="#FFFFFF" /> } outcome="Reduce endpoint exposure to untrusted web content while maintaining access to the websites users need." bgColor="#FFFFFF" /> } outcome="Enable approved AI use while maintaining control over access, sensitive data, and audit requirements." bgColor="#FFFFFF" /> ## Business Value at Enterprise Scale Kasm Workspaces can reduce infrastructure and operational overhead by scaling compute capacity to match demand, see how one municipal customer benefited below. For contractor and BYOD access, Kasm Workspaces can provide approved resources through the browser without requiring a traditional VDI or VPN client. This can reduce the number of deployment steps required for access. Together, these capabilities give organizations a practical path to lower cost, faster access, validated security, and scalable operations on a common platform. Explore additional solutions and integrations at [Kasm Insights](https://kasm.com/kasm-insights). The City of Hamina used Kasm Workspaces to shift from dedicated end-user computing toward real-time workspace orchestration and shared compute. The city reported a 45% reduction in recurring IT operational costs, a 15% reduction in hardware purchase expense, and 2X more computing power. Read the Hamina customer story } bgColor="#ffffff" /> Kasm Technologies has achieved CMMC Level 2 certification, providing independent validation of its security practices for protecting Controlled Unclassified Information (CUI) and supporting organizations within the Defense Industrial Base. Review compliance and security validation } bgColor="#ffffff" /> Kasm Workspaces core services can be deployed with Kubernetes and Helm. This provides a declarative and portable deployment model while allowing workspace session infrastructure to scale independently of the core services. Explore Kubernetes workspace delivery } bgColor="#ffffff" /> Kasm Workspaces integrates with existing infrastructure, security, and endpoint technologies, while a broad selection of Kasm-maintained workspace images helps reduce the effort required to prepare common deployments. Explore validated integrations } bgColor="#ffffff" /> ## Choose the Right Kasm Solution Kasm Technologies offers two purpose-built solutions. Choose Kasm Workspaces for centralized enterprise workspace delivery, or KasmVNC when your engineering team wants the streaming technology and plans to provide its own orchestration. ## Help and Support Resources Support is part of the product, not an afterthought. Get the documentation, community resources, and commercial support needed to evaluate, deploy, operate, and scale Kasm Workspaces successfully in production. Official Kasm Customer Support {" - Get direct assistance from Kasm experts with guaranteed response times."} Knowledge Base {" - In-depth how-to guides and advanced troubleshooting articles."} Troubleshooting Guide {" - Find configuration walkthroughs, implementation guidance, and advanced troubleshooting."} GitHub Community Issue Tracker {" - Submit reproducible bugs, search known issues, or request product enhancements."} Reddit Community (r/kasmweb) {" - Exchange deployment ideas, use cases, and practical lessons with other Kasm users."} YouTube Video Tutorials {" - Watch guided demonstrations, administration, integrations, and end-user workflows."} FAQ {" - Quick answers to the most common installation, configuration, licensing, and architecture questions."} The Kasm Customer Support team and community resources are available to help your organization deploy and operate the Kasm Workspaces platform successfully. ## How This Documentation Is Organized This documentation follows the [Diataxis framework](https://diataxis.fr/). Choose the resource type that matches your task, from initial evaluation through production deployment, operation and integration. --- ## KasmGPT - Overview and Capabilities # KasmGPT --- ## Kasm Workspaces: Frequently Asked Questions (FAQs) # Frequently Asked Questions
I have a question or issue that isn't covered in the frequently asked questions where else can I get help? We have several options for support with the Kasm community. * Our public issue tracker on [GitHub](https://github.com/kasmtech/workspaces-issues/issues). * Our [r/kasmweb subreddit](https://www.reddit.com/r/kasmweb/). * Our [YouTube channel](https://www.youtube.com/c/KasmWorkspaces). * Our [support for paid customers](https://www.kasmweb.com/support.html).
## Licensing
Which version of Kasm Workspaces is right for me? We have a detailed page on all editions and license tiers for Kasm Workspaces here: [license information](license.mdx).
## Kasm Workspaces Installation / Setup
How is Kasm Workspaces hosted? There are several options for hosting Kasm Workspaces: * You can self-host Kasm Workspaces on a server at your residence or business * We have guides for [single server installation](../tutorials/install/single-server-install.mdx) and [multiple server installation](../tutorials/install/multi-server-install.mdx). * You can setup Kasm Workspaces on a cloud service of your choice. * You can follow the above guides for single or multiple server installation on the cloud instances you provision. * Kasm Technologies has available in the Digital Ocean marketplace a droplet [1-click installer](https://marketplace.digitalocean.com/apps/kasm-workspaces) that will create a Digital Ocean hosted Kasm Workspaces instance. * Individuals looking for a managed service can use Kasm Cloud Personal. * https://www.kasmweb.com/kasm_cloud_personal.html * Businesses looking for a managed service can contact us for Kasm Workspaces Cloud SaaS options.
What are the system requirements and how do I optimize the performance of Kasm Workspaces? The basic system requirements are listed in the installation guide: [system requirements](../explanations/system-requirements.mdx). In addition for a more complex deployment we have a [system sizing and deployment guide](../explanations/sizing-operations.mdx).
Does Kasm Workspaces support Ansible or Terraform? Kasm Workspaces supports both Ansible and Terraform: * For our Ansible documentation and example scripts visit our [Ansible GitHub repo](https://github.com/kasmtech/ansible). * For our Terraform documentation and example scripts visit our [Terraform GitHub repo](https://github.com/kasmtech/terraform).
The default installation has more Workspaces than I need/want, can I customize the set of Workspaces installed? There are two options for customizing the Workspace set at installation time. * There is a -I or --no-images option for install.sh that will instruct the installer to not pre seed any default Kasm Workspaces. * After extracting the installation zip, but before running the install.sh, you can edit “kasm_release/conf/database/seed_data/default_images_amd64.yaml” or “kasm_release/conf/database/seed_data/default_images_arm64.yaml” depending on the architecture of the host you are installing on. Editing these files will allow you to customize the set of Workspaces that are installed during Kasm Workspaces installation.
How can I ensure that my Kasm Workspaces default images are up to date? Kasm Technologies publishes new images with every Kasm workspaces release, but the team also publishes daily and weekly "rolling" images that have program and security updates. * By default Kasm Workspaces installs the static release tagged images, but by specifying -O or \-\-use-rolling-images option Kasm Workspaces will install the rolling daily updated images. * If your Kasm Workspaces instance is already installed '-rolling-daily' can be appended to the tag of any default Kasm Workspaces image to get the latest program and security updates applied daily or 'rolling-weekly' can be used to receive weekly updates. * Check out [rolling-images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx#rolling-docker-images) for more information Note: In order to use the rolling tags your Kasm Workspaces installation must be internet connected so it can pull down image updates.
There was an error during my installation or upgrade of Kasm Workspaces. How can I find out what went wrong? The installation/upgrade scripts will output a log file that will contain details on any errors encountered when performing the installation/upgrade. Upon a successful proceedure the install file is removed. If an error does occur the file will be present in the folder that the installation or upgrade was ran from and a file named `kasm_install_${TIMESTAMP}.log` or `kasm_upgrade_${TIMESTAMP}.log` will be present. This file will be important for diagnosing the error and will be requested by Kasm support when troubleshooting.
Where can I find the install files and their SHA256 sums? | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] |
## Kasm Workspaces Configuration
The admin account is locked, how do I reset the password? On a self-hosted deployment you can use our [admin account recovery instructions](../how-to/security/admin-account-recovery.mdx) to unlock the account and set a new password. On a Kasm Technologies managed SaaS deployment, please contact our support team for assistance [support for paid customers](https://www.kasmweb.com/support.html).
Can I install my own software or customize my desktops? Check out our page on [creating custom Kasm images](../how-to/workspaces-sessions/container-workspace/customization/building-images.mdx) and [maintaining custom Kasm images](../how-to/workspaces-sessions/container-workspace/image-maintenance.mdx).
I need to run my Workspace as root. If you are looking for a way to install additional software or change settings on the Workspace please check out *Can I install my own software or customize my desktops* above. If you are looking to enable root permissions because they are required for an application to run correctly this is possible, however, it does carry security implications and should be avoided if possible. * Documentation on running a container as the [root user](../how-to/workspaces-sessions/container-workspace/running-as-root.mdx).
How can I keep my profile data between Kasm sessions? We have a guide on enabling a [persistent profile (home directory)](../how-to/data-storage/persistent-profiles.mdx).
I have an app that requires persistent data between Kasm sessions, or I want to be able to have a common share for all users mapped into a Kasm session. There is a guide on enabling [persistent data](../how-to/data-storage/volume-mapping.mdx)
My Kasm session is torn down too quickly when idle, how can I set the session timeout to be longer? The default timeouts can be changed on the workspaces based upon the user’s group's [Group Session Timing Settings](../how-to/security/users-groups-mgmt/groups.mdx#group-settings). Here is a video clip that walks through the setting changes [group settings video](https://www.youtube.com/watch?v=teJSUxKEbfE&t=140s).
I'd like to run a Windows or Mac OSX image in Kasm Workspaces. Kasm Workspaces supports session handling and rendering for arbitrary systems that support RDP, VNC, SSH, or KasmVNC. These systems can be fixed assets or they can be auto-scaled with Kasm Workspaces in a supported cloud environment. Windows 10, 11, and Server 2019 have been tested and are known to work with Workspaces. For more information or to see a demonstration please visit our [Kasm Workspaces Windows Guide](https://youtu.be/_WCee4-E4vA). If you are looking to set up MacOS Workspaces for remote access, we recommend referring to our [Setting Up MacOS Workspaces for Remote Access](../how-to/workspaces-sessions/server-workspace/macos-servers.mdx) documentation page for detailed instructions and guidance. Please note that the documentation page provides step-by-step instructions and best practices for configuring MacOS systems with Kasm Workspaces for remote access.
When I reconnect to my fixed infrastructure SSH session I lose my history and any work I was doing. Kasm workspaces can be configured to leverage tmux or screen to allow resuming your work when reconnecting to an [SSH session](../how-to/infra-autoscale/servers.mdx).
My AutoScaled servers are consuming resources even during long periods where my Kasm installation has no active users (such as overnight). Kasm workspaces can be configured to follow a schedule for AutoScale configurations [AutoScale Schedules](../how-to/troubleshooting).
## Using Kasm Workspaces
When I am browsing the internet on my computer. Is there an easy way to open a link inside a Kasm session? Kasm Technologies provides a browser extension that enables a right click menu for opening a link inside a Kasm session. * For the [Chrome extension](https://chrome.google.com/webstore/detail/kasm-open-in-isolation/pamimfbchojeflegdjgijcgnoghgfemn?hl=en). * For the [Firefox extension](https://addons.mozilla.org/en-US/firefox/addon/kasm-open-in-isolation/). * Check out our documentation for how to install and configure the [browser extensions](../tutorials/kasm-extension.mdx). * Video demonstrating the browser extensions: https://youtu.be/U7e-mcJdZok?t=594
Do you have a developer API? We do have a developer api available, more information is available [here](developer-api.mdx).
I'm getting a 'No Resources Available' error when trying to launch a workspace. There are quite a few reasons you could be seeing a No Resources Available error, our [troubleshooting guide](../how-to/workspaces-sessions/container-workspace/no-resources-available.mdx) has more information on how to diagnose and correct the error.
My native language isn't English. How can I use the UI and Kasm sessions in my own language? In Kasm Workspaces 1.14.0 the Kasm team released translations for the Kasm Workspaces UI and added internalization support to the Kasm containerized workspaces. The language and timezone can be changed at the [user](../tutorials/user-guide/profile.mdx), [group](../how-to/security/users-groups-mgmt/groups.mdx#group-settings), and [workspace](../how-to/workspaces-sessions/container-workspace/workspaces.mdx) levels.
## Troubleshooting
When trying to launch a workspace, the session hangs at 'Creating a secure connection'. If your session is failing to create a secure connection, then refer to our [troubleshooting guide](../how-to/workspaces-sessions/container-workspace/advanced-connection-troubleshooting.mdx) which has more information on how to diagnose and correct this error.
I am getting a 'No Resources Available' error when trying to launch a workspace. If you are encountering a "No Resources" Error, then refer to our [troubleshooting guide](../how-to/workspaces-sessions/container-workspace/no-resources-available.mdx) which has more information on how to diagnose and correct this error.
I am having difficulty setting up GPU passthrough support. If you are looking for additional information on GPU Passthrough Support, then refer to our [troubleshooting guide](../how-to/troubleshooting/gpu-issues.mdx) which has more information on how to diagnose and correct this error.
Why am I unable to print documents after resuming the session? In the current version the printer will no longer work if the Kasm session is stopped.
Why does the desktopscalefactor property in the `.rdp` file seem to not have an effect? This is due to behavior on the RDP client. Kasm passes the `desktopscalefactor` setting even if it is not overridden by `rdp_thick_client_properties` in the `connection_info` setting of the Server. The `desktopscalefactor` setting is derived from the browser DPI and written into the generated .rdp. However, since RDP 8.1 most clients prefer dynamic DPI/resolution sync and often ignore this setting or only apply it in very specific scenarios. ### Alternate RDP scaling properties options By default, Kasm sets the following properties true when generating a session: **Smart Sizing** : Determines whether the local device scales the content of the remote session to fit the window size.\ **Dynamic Resolution** : Determines whether the resolution of a remote session is automatically updated when the local window is resized. ### Forcing DPI scaling on Windows hosts If the client ignores the scaling settings from the `.rdp` file, scaling can be enforced on the host server itself by setting the following per-user registry keys: ```reg [HKEY_CURRENT_USER\Control Panel\Desktop] "Win8DpiScaling"=dword:00000001 "LogPixels"=dword:00000096 ; 96=100%, 120=125%, 144=150%, etc. ``` The **Win8DpiScaling=1** setting forces Windows to honor the LogPixels setting. Without it, Windows may ignore the LogPixels setting and instead rely only on client DPI sync. **Note**: A logoff/restart is required to apply these changes.
--- ## Developer Preview Builds for Testing # Developer Preview Builds Developers and system administrators may access preview builds of Kasm Workspaces and Workspaces Images to test the latest features and integrations before they are officially published in a release build. - Preview builds are published regularly, often daily or multiple times per day. - Preview build may contain bugs or unfinished features and are therefore not suitable for production environments. - Official customer support cannot be given for preview builds. - There is no supported upgrade mechanism from preview builds to official releases. ## Feedback While preview builds are not officially supported, feedback is welcome and can be submitted at in the appropriate community issue trackers. - Kasm Workspaces: [https://github.com/kasmtech/workspaces-issues/issues](https://github.com/kasmtech/workspaces-issues/issues) - Workspaces Images: [https://github.com/kasmtech/workspaces-images/issues](https://github.com/kasmtech/workspaces-images/issues) - Workspaces Core Images: [https://github.com/kasmtech/workspaces-core-images/issues](https://github.com/kasmtech/workspaces-core-images/issues) - Kasm Helm Chart: [https://github.com/kasmtech/kasm-helm/issues](https://github.com/kasmtech/kasm-helm/issues) ## Documentation Documentation for new/updated features in preview builds of Kasm Workspaces is published in step with the code and may be accessed using the `Developer` version of this site: `https://docs.kasm.com/docs/develop` Notable updates are annotated in the upcoming ([[next_release]]) version of the Release Notes: - [Developer Preview Docs](/docs/develop) - [Release Notes](/docs/develop/reference/release-notes/[[next_release]]) ## Builds **Installer** | **Build** | **Link** | |-----------|----------| | **Workspaces Installer** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/kasm_workspaces_develop.tar.gz) [Build Info](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/build_info.json) | | **Helm Chart** | [Helm repo](https://hub.docker.com/r/kasmweb/kasm-helm)[Chart source](https://github.com/kasmtech/kasm-helm) | **Workspaces** All Developer Preview versions of the [Default Docker Images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx) are published to Dockerhub under the `develop` tag. e.g (`kasmweb/chrome:develop`). Source code is available in Github at the links below - Workspaces Images: [https://github.com/kasmtech/workspaces-images](https://github.com/kasmtech/workspaces-images) - Workspaces Core Images: [https://github.com/kasmtech/workspaces-core-images](https://github.com/kasmtech/workspaces-core-images) **Offline Install Files** | **Build** | **Link** | |-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| | **Workspaces Service Images amd64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/kasm_workspaces_service_images_develop_amd64.tar.gz) | | **Workspaces Service Images arm64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/kasm_workspaces_service_images_develop_arm64.tar.gz) | | **Workspaces Images amd64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/kasm_workspaces_workspace_images_develop_amd64.tar.gz) | | **Workspaces Images arm64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_backend/branches/develop/kasm_workspaces_workspace_images_develop_arm64.tar.gz) | | **Kasm Network Plugin amd64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_network_plugin/develop/kasmweb_network_plugin_amd64_develop.tar.gz) | | **Kasm Network Plugin arm64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_network_plugin/develop/kasmweb_network_plugin_arm64_develop.tar.gz) | | **Kasm Logging Plugin amd64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_logging_plugin/develop/kasmweb_logging_plugin_amd64_develop.tar.gz) | | **Kasm Logging Plugin arm64** | [Download](https://kasmweb-build-artifacts.s3.amazonaws.com/kasm_logging_plugin/develop/kasmweb_logging_plugin_arm64_develop.tar.gz) | --- ## Kasm Workspaces Developer API: Integration and Management # Developer API The 1.19 release includes some changes and new endpoints to the Developer API. See the [1.19.0 release notes](./release-notes/1.19.0.mdx) for full details. The Kasm Workspaces Developer API can be leveraged to extend the systems functionality and/or integrate with an exiting platform. Integrators interface with the API to create and manage sessions, users and groups. ![Integration Workflow](/img/api/workflow.png) ## Code-less Integration Options Integrators are encouraged to review [Session Casting](../how-to/workspaces-sessions/sessions/session-casting.mdx) which provides an easy way to expose access to Kasm sessions via special URLs. ## API Keys API Keys can be generated via the **Settings** -> **Developers** -> **Add API Key**. An **API_KEY** and **API_KEY_SECRET** will be automatically generated. Administrators can optionally set an expiration date for the API key. ![Creating an API Key](/img/api/api_key.webp) ## Authentication The API key and secret must be sent with all of the following requests as json data. ```js { "api_key": "bMjMwTT0JKUQ" "api_key_secret": "KUNAvRw4KLHGmldBxhRUD5sAhWkvJVzS" } ``` ## Permissions By default, API keys have no permissions. To define permissions for API keys, edit the API Key configuration and go to the permissions tab. The `Read Only` setting on the API key overrides permissions defined and is enforced via a separate mechanism. **Two permissions are needed to perform actions as another user with the DevAPI**, such as creating a Workspace session for a user. The `Users Auth Session` permission is require in order to run requests as another user and the `User` permission is needed to run standard user API calls. ![API Key Permissions](/img/api/api_key_permissions.webp) The following table lists each permission and its description. | Name | Description | |------|-------------| | User | Default level of permissions for normal users. | | Global Admin | Global Administrator with all permissions. | | Users View | View users and user information. | | Users Modify | Modify existing users. | | Users Create | Create new users. | | Users Delete | Delete exiting users. | | Users Modify Admin | Modify users with Global Admin permissions. | | Users Auth Session | Login and logout on behalf of another user. | | Groups View | View groups, group members, and group settings. | | Groups Modify | Modify group members and settings. | | Groups Create | Create new groups. | | Groups Delete | Delete existing groups. | | Groups View IfMember | View groups you are a member of, excluding system groups. | | Groups Modify IfMember | Modify groups you are a member of, excluding system groups. | | Groups View System | View groups, group members and group settings of system defined groups. | | Groups Modify System | Modify group members and settings of system groups. | | Groups Delete System | Delete a system group. | | Agents View | View agents and agent settings. | | Agents Modify | Modify agent settings. | | Agents Create | Create agents. | | Agents Delete | Delete existing agents. | | Staging View | View staging list and stage configuration settings. | | Staging Modify | Modify existing staging settings. | | Staging Create | Create new staging configurations. | | Staging Delete | Delete existing staging configurations. | | Casting View | View casting list and casting configuration settings. | | Casting Modify | Modify existing casting settings. | | Casting Create | Create new casting configurations. | | Casting Delete | Delete existing casting configurations. | | Sessions View | View all user sessions. | | Sessions Modify | Perform modifications to a session of another user. | | Sessions Delete | Delete the session of another user. | | Session Recordings View | View user session recordings. | | Images View | View images | | Images Modify | Modify image configurations. | | Images Create | Create new images. | | Images Delete | Delete existing images. | | Images Modify Resources | Modify image resource settings, such as CPU and Memory settings. | | DevAPI View | View developer API list. | | DevAPI Modify | Modify developer API configurations. | | DevAPI Create | Create a new developer API key. | | DevAPI Delete | Delete an existing developer API key. | | Webfilters View | View webfilters | | Webfilters Modify | Modify existing webfilters | | Webfilters Create | Create a new webfilter. | | Webfilters Delete | Delete an existing webfilter | | Brandings View | View branding configurations. | | Brandings Modify | Modify existing branding configurations. | | Brandings Create | Create new branding configurations. | | Brandings Delete | Delete existing branding configurations. | | Settings View | View global settings. | | Settings Modify | Modify global settings in all categories. | | Settings Modify Auth | Modify global settings in the authentication category. | | Settings Modify Auth Captcha | Modify global settings in the authentication captcha category. | | Settings Modify Cast | Modify global settings in the casting category. | | Settings Modify Images | Modify global settings in the images category. | | Settings Modify License | Modify global settings in the license category. | | Settings Modify Logging | Modify global settings in the logging category. | | Settings Modify Manager | Modify global settings in the manager category. | | Settings Modify Scale | Modify global settings in the scale category. | | Settings Modify Subscription | Modify global settings in the subscription category. | | Settings Modify Filter | Modify global settings in the filter category. | | Settings Modify Storage | Modify global settings in the storage category. | | Settings Modify Connections | Modify global settings in the connections category. | | Settings Modify Theme | Modify global settings in the theme category. | | Auth View | View LDAP/OIDC/SAML configurations. | | Auth Modify | Modify LDAP/OIDC/SAML configurations. | | Auth Create | Create LDAP/OIDC/SAML configurations. | | Auth Delete | Delete LDAP/OIDC/SAML configurations. | | Licenses View | View licenses. | | Licenses Create | Add new licenses. | | Licenses Delete | Delete licenses. | | System View | View system information. | | System Export Schema | Export system schema. | | System Import Data | Import system data. | | System Export Data | Export system data. | | Reports View | View system reports and logging. **Warning**: Providing access to logs can provide a lot of potentially sensitive information. | | Managers View | View the managers. | | Managers Modify | Modify existing managers. | | Managers Create | Create a new manager. | | Managers Delete | Delete existing managers. | | Zones View | View Zones and Zone settings. | | Zones Modify | Modify Zone settings. | | Zones Create | Create new Zones. | | Zones Delete | Delete existing Zones. | | Companies View | View companies. | | Companies Modify | Modify existing company. | | Companies Create | Create a new company. | | Companies Delete | Delete an existing company. | | Connection Proxy View | View connection proxies. | | Connection Proxy Modify | Modify connection proxies. | | Connection Proxy Create | Create a connection proxy. | | Connection Proxy Delete | Delete an existing connection proxy. | | Physical Tokens View | View physical 2FA tokens. | | Physical Tokens Modify | Assign/Unassign physical 2FA tokens. | | Physical Tokens Create | Import or create physical 2FA tokens. | | Physical Tokens Delete | Delete a physical 2FA token. | | Servers View | View servers. | | Servers Modify | Modify existing servers. | | Servers Create | Create new servers. | | Servers Delete | Delete servers. | | Server Pools View | View server pools. | | Server Pools Modify | Modify server pools. | | Server Pools Create | Create a new server pool. | | Server Pools Delete | Delete a server pool. | | Autoscale View | View AutoScale configurations. | | Autoscale Modify | Modify an existing AutoScale configuration. | | Autoscale Create | Create a new AutoScale configuration. | | Autoscale Delete | Delete AutoScale configurations. | | VM Provider View | View VM Provider configurations. | | VM Provider Modify | Modify VM Provider configurations. | | VM Provider Create | Create new VM Provider configurations. | | VM Provider Delete | Delete VM Provider configurations. | | Autoscale Schedule View | View an AutoScale schedule. | | Autoscale Schedule Modify | Modify an AutoScale schedule. | | Autoscale Schedule Create | Create an AutoScale schedule. | | Autoscale Schedule Delete | Delete an AutoScale schedule. | | DNS Providers View | View DNS provider configurations. | | DNS Providers Modify | Modify DNS provider configurations. | | DNS Providers Create | Create new DNS Provider configurations. | | DNS Providers Delete | Delete DNS Provider configurations. | | Registries View | View Workspace Registries. | | Registries Modify | Modify existing Workspace Registries. | | Registries Create | Add new Workspace Registries | | Registries Delete | Delete a Workspace Registry | | Storage Providers View | View Storage Providers. | | Storage Providers Modify | Modify existing Storage Providers. | | Storage Providers Create | Create new Storage Providers. | | Storage Providers Delete | Delete an existing Storage Provider. | | Egress Providers View | View Egress Providers. | | Egress Providers Modify | Modify existing Egress Providers. | | Egress Providers Create | Create new Egress Providers. | | Egress Providers Delete | Delete an existing Egress Provider. | | Egress Gateways View | View Egress Gateways. | | Egress Gateways Modify | Modify existing Egress Gateways. | | Egress Gateways Create | Create new Egress Gateways. | | Egress Gateways Delete | Delete an existing Egress Gateway. | | Egress Credentials View | View Egress Credentials. | | Egress Credentials Modify | Modify existing Egress Credentials. | | Egress Credentials Create | Create new Egress Credentials. | | Egress Credentials Delete | Delete an existing Egress Credential. | | Banners View | View banners. | | Banners Modify | Modify existing banners. | | Banners Create | Create new banners. | | Banners Delete | Delete an existing banner. | | AD User Management View | View AD User Management Configurations. | | AD User Management Modify | Modify existing AD User Management Configurations. | | AD User Management Create | Create new AD User Management Configurations. | | AD User Management Delete | Delete an existing AD User Management Configuration. | ### Permission changes Kasm embeds a user's permissions in their session token, which is generated on login. The **Session Lifetime** global setting controls the token lifetime. The UI requests a new session token every 5 minutes. To apply new permissions fastest, have the user log out and log back in. Otherwise, the change applies within 5 minutes. ### Permission dependencies Most permissions stand alone, but some permissions depend on others. Generally, a `Modify`, `Create`, or `Delete` permission needs the corresponding `View` permission. The following additional dependencies require you to grant multiple permissions to achieve the desired effect. - `Licenses View` requires `System View` - `Permissions View` requires `Groups View` - `Registries View` requires `Images View`, `System View`, and `Agents View` - `Autoscale View` requires `Server Pools View` - `Autoscale Schedule View` requires `Server Pools View` - `DNS Providers View` requires `Server Pools View` - `VM Providers View` requires `Server Pools View` and `Autoscale View` - `Users Delete` requires `Sessions Delete` if the target user has running sessions and `Users Modify` - `Users Delete` requires `Users Modify Admin` to delete a user that has the `Global Admin` permission - `Egress Gateways Create`, `Egress Gateways Modify`, `Egress Gateways Delete`, `Egress Credentials Create`, `Egress Credentials Modify` and `Egress Credentials Delete` require `Egress Providers Modify`. - `Servers View` and `Server Templates View` requires `Server Pools View` and `Zones View` In many cases multiple permissions are not required. However, Kasm hides certain UI elements when the user lacks the permissions to view them. For example, a user may have `View Images` permissions but not `View Servers` permissions. When that user views an individual Workspace Image that targets a Server, the drop-down to view or edit the targeted server stays hidden. ### Special permissions Groups offer more permissions beyond the basic View, Create, Modify, and Delete actions. The `Groups View IfMember` and `Groups Modify IfMember` permissions allow a user to view or modify a group when they are a member of that group. This access does not extend to built-in system groups (All Users and Administrator). To edit or view system groups, the user also needs the Groups View/Modify System permission. An additional permission protects the modification of users with the `Global Admin` permission. To modify a `Global Admin`, the requesting user must be a `Global Admin` or hold the `User Modify Admin` permission. Two permissions allow modifications to Workspace Images: `Images Modify` and `Images Modify Resources`. The `Images Modify` permission allows modification of all Image settings except those that change the physical or virtual compute resources. The following settings require the `Images Modify Resources` permission to edit: - GPU Count - Cores - Memory - CPU Allocation Method - Uncompressed Image Size - Docker Registry - Docker Registry Username - Docker Registry Password - Hash - Volume Mappings - Docker Run Config Override - Docker Exec Config ## Base URL All Dev APIs documented here are under the path api/public/: `https:///api/public/` ## Errors In the event of an error processing an api request, Kasm will respond with an **error_message** in the body of the json response Some APIs were returning incorrect 401 and 403 error status codes, and in the 1.19.0 release, this has been addressed. **Example Response** > ```js > {"error_message": ""} > ``` ## Pagination and Filtering Endpoints that return lists support pagination, sorting, and filtering. **Pagination Parameters** | Name | Type | Description | |------|------|-------------| | page | integer | Page number (default: 0). | | page_size | integer | Results per page (default: 20). | | sort_by | string | Field to sort by (see endpoint-specific fields). | | sort_direction | string | `asc` or `desc`. | | filters | array | Array of filter objects. | **Filter Format** Filters are passed as an array of objects with `id` and `value` keys: ```json { "filters": [ { "id": "enabled", "value": true }, { "id": "hostname", "value": "workstation" } ] } ``` **Paginated Response Format** ```json { "": [...], "total": 100, "page": 0, "page_size": 20, "sort_by": "name", "sort_direction": "asc" } ``` ## Users ### Create User Create a new user. **Permission Required**: `Users Create` ```bash POST /api/public/create_user ``` **Example request**: ```json { "api_key":"{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "username" : "test_user1@example.com", "first_name" : "Bob", "last_name" : "Williams", "locked": false, "disabled": false, "organization": "example", "phone": "123-456-7890", "password": "3UPKGg7g!a9g2@39v6" } } ``` **Example response**: ```json { "user": { "first_name": "Bob", "username": "test_user1@example.com", "realm": "local", "last_name": "Williams", "phone": "123-456-7890", "last_session": null, "notes": null, "user_id": "50faa5439c574b518cd868dac9256e4b", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" } ], "disabled": false, "organization": "example", "locked": false } } ``` ### Batch Create Users Create multiple users by uploading a CSV file. This endpoint expects a multi-part form upload containing the CSV file contents. See the [Users Bulk Import section](../how-to/security/users-groups-mgmt/users.mdx#bulk-import) for details on the CSV file format. **Permission Required**: * `Users Create` * `Groups Modify` if using `group_*` columns * `Groups Modify System` if those groups include system groups like `Administrators`. ```bash POST /api/public/batch_create_user ``` **Example request**: Headers ``` Content-Type: multipart/form-data api-key: api-key-secret: ``` The CSV file content is expected in the `file_content` field. ``` file_content= ``` The `view` query parameter controls the format of the data returned. Validation data will always be returned in the `csv_validation_data` field when there is an error. In the success case: | View Value | Default | Response.csv_validation_data | Response.resources | | --- | --- | --- | --- | | api | No | `null` | Contains db results | | table | Yes | Contains validation results | `null` | | all | No | Contains validation results | Contains db results | **Example success response**: Request was made with `?view=all` ```json { "error_message": null, "csv_validation_data": { "headers": ["username", "realm", "first_name", "last_name", "phone_number", "organization", "force_password_reset", "city", "state", "country", "email", "group_1"], "total_errors": 0, "global_errors": [], "total_rows": 1, "row_data": [ { "total_errors": 0, "contextual_errors": [], "fields": [ { "field": "username", "value": "test_user1@example.com" }, { "field": "realm", "value": "local" }, { "field": "first_name", "value": "Bob" }, { "field": "last_name", "value": "Williams" }, { "field": "phone_number", "value": "+1 234-567-8900" }, { "field": "organization", "value": "Test Org" }, { "field": "force_password_reset", "value": true }, { "field": "city", "value": "Springfield" }, { "field": "state", "value": "IL" }, { "field": "country", "value": "USA" }, { "field": "email", "value": "test_user1@example.com" }, { "field": "group_1", "value": "GroupA" } ] } ], "file_bom": "" }, "resources": { "users": [ { "user_id": "09b91b1fb9d1447e91fba42fe288aa1c", "username": "test_user1@example.com", "locked": false, "failed_pw_attempts": 0, "plan_start_date": null, "plan_end_date": null, "plan_id": null, "anonymous": false, "first_name": "Bob", "last_name": "Williams", "phone": "+1 234-567-8900", "organization": "Test Org", "notes": null, "realm": "local", "saml_id": null, "oidc_id": null, "subscription_id": null, "company_id": null, "company": null, "program_id": null, "disabled": false, "created": "2025-07-24 20:48:37.695074", "password_set_date": null, "city": "Springfield", "state": "IL", "country": "USA", "email": "test_user1@example.com", "custom_attribute_1": null, "custom_attribute_2": null, "custom_attribute_3": null, "crypt_password": "**********", "crypt_salt": "**********", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" }, { "name": "GroupA", "group_id": "0fb98d3c248b4cb8a0e905d549777f38" } ] } ] } } ``` **Example error response - invalid credentials** Status Code: `401` ```json { "error_message": "Invalid user name or password." } ``` **Example error response - invalid scope** Status Code: `403` ```json { "error_message": "Unauthorized." } ``` **Example error response - unparsable CSV data** Status Code: `400` ```json { "error_message": "Invalid file format: ...", "csv_validation_data": null } ``` **Example error response - invalid CSV data** Status Code: `400` ```json { "error_message": "Failed to import CSV file data", "csv_validation_data": { "headers": ["username", "realm", "first_name", "group_1"], "total_errors": 3, "global_errors": [ { "code": "CSV_ERROR_002", "message": "Missing required fields", "field_names": ["required_field_1"] } ], "total_rows": 1, "row_data": [ { "total_errors": 2, "contextual_errors": [ { "code": "CSV_ERROR_011", "message": "Groups(['missing_group_a']) not found", "fields": ["group_*"] } ], "fields": [ { "field": "username", "value": "test_user1@example.com" }, { "field": "realm", "value": "locals", "error": { "code": "CSV_ERROR_009", "message": "Input should be 'ldap', 'local', 'oidc' or 'saml'" } }, { "field": "first_name", "value": "Bob" }, { "field": "group_1", "value": "missing_group_a" } ] } ], "file_bom": "" } } ``` See the [Appendix: CSV Error Codes](#csv-error-codes) for a complete list of validation error codes. ### Get User Retrieve the properties of an existing user. `target_user.user_id` or `target_user.username` can be passed **Permission Required**: `Users View`. Additionally, `Servers View` to receive assigned server information. ```bash POST /api/public/get_user ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "4bbb6998064a4d1ea4685f3cdd05feb4", "username": "user@kasm.local" } } ``` **Example response**: ```json { "user": { "user_id": "4bbb6998064a4d1ea4685f3cdd05feb4", "username": "user@kasm.local", "locked": false, "last_session": "2020-11-09 14:41:33.578622", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" } ], "first_name": null, "last_name": null, "phone": null, "organization": null, "notes": null, "kasms": [ { "kasm_id": "28cfc2a510bb424cad18e571f11ee26c", "start_date": "2020-11-09 14:46:42.321900", "keepalive_date": "2020-11-09 14:46:43.140623", "expiration_date": "2020-11-09 15:46:43.140623", "server": { "server_id": "36e2aeff0e02445db26a521c9c85f1c1", "hostname": "proxy", "port": 443 } } ], "assigned_servers": [ { "server_id": "4afd4760-f4b9-400b-98e7-a4c678540e63", "hostname": "persistant.host.local", "friendly_name": "Persistant Server A", "server_assignment_enabled": true } ], "realm": "local", "two_factor": false, "program_id": null, "hash": "9fdfdaad0098cdd8a466b2badbaf962e40214affb07596a6e9d776a409793780" } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_user.user_id | string (UUID)| The ID of the specifc target user| | target_user.username | string | The ID of the specific target user| ### Get Users Retrieve the list of users registered in the system. **Permission Required**: `Users View`. Additionally, `Servers View` to receive assigned server information. ```bash POST /api/public/get_users ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", } ``` **Example response**: ```json { "users": [ { "kasms": [], "assigned_servers": [], "company": {}, "username": "user@kasm.local", "locked": false, "realm": "local", "phone": null, "first_name": null, "notes": null, "user_id": "57e8fc1a-fa86-4ff4-9474-60d9831f42d5", "last_session": "2020-11-12 14:29:25.808258", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" } ], "disabled": true, "organization": null, "last_name": null }, { "kasms": [], "assigned_servers": [ { "server_id": "4afd4760-f4b9-400b-98e7-a4c678540e63", "hostname": "persistant.host.local", "friendly_name": "Persistant Server A", "server_assignment_enabled": true } ], "company": {}, "username": "admin@kasm.local", "locked": false, "realm": "local", "phone": null, "first_name": null, "notes": null, "user_id": "4acb13bf-1215-4972-9f0d-8c537d17f2da", "last_session": "2020-11-12 14:35:19.700863", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" }, { "name": "Administrators", "group_id": "31aa063c670648589533d3c42092d02a" } ], "disabled": false, "organization": null, "last_name": null } ] } ``` **Arguments** | Name | Type | Default | Description | |------|------|---------|-------------| | page | integer | `0` | Zero-based page index. Use with `page_size` to paginate through large user sets. | | page_size | integer | `100` | Number of users to return per page. Maximum value is `1000`. | | anonymous | boolean | `false` | Include anonymous users in results. | | anonymous_only | boolean | `false` | Return only anonymous users. | | sort_by | string | — | Field to sort results by. Supported values: `username`, `created`, `last_session`. | | sort_direction | string | `"desc"` | Sort direction. Accepted values: `"asc"` or `"desc"`. | | filters | array | `[]` | Array of `{"id": "", "value": }` objects to filter results. See filter table below. | **Filter IDs for `filters`** | Filter ID | Value Type | Behavior | |-----------|-----------|----------| | `username` | string | Case-insensitive partial match on username. | | `locked` | boolean | Exact match on locked status. | | `disabled` | boolean | Exact match on disabled status. | | `created` | `{"from": , "to": }` | Date range filter on account creation date. | | `exclude_group` | string (UUID) | Excludes users who belong to the specified group. | | `oidc_id` | string | Exact match on OIDC identity. | | `saml_id` | string | Exact match on SAML identity. | **Response Format** | Name | Type | Description | |------|------|-------------| | users | array | List of user objects matching the request. | | users[].user_id | string (UUID) | Unique identifier for the user. | | users[].username | string | The user's login username. | | users[].anonymous | boolean | Whether the user is an anonymous (ephemeral) user. | | users[].first_name | string | The user's first name. | | users[].last_name | string | The user's last name. | | users[].locked | boolean | Whether the account is locked. | | users[].disabled | boolean | Whether the account is disabled. | | users[].realm | string | Authentication realm (e.g. `local`, `ldap`). | | users[].organization | string | The user's organization. | | users[].phone | string | The user's phone number. | | users[].notes | string | Admin notes for the user. | | users[].created | string | ISO timestamp of when the account was created. | | users[].last_session | string | ISO timestamp of the user's last session. | | users[].groups | array | Groups the user belongs to, each with `name` and `group_id`. Requires `Groups View` permission. | | users[].kasms | array | Active Kasm sessions for the user. Requires `Sessions View` permission. | | users[].assigned_servers | array | Servers assigned to the user, each with `server_id`, `hostname`, `friendly_name`, and `server_assignment_enabled`. Requires `Servers View` permission. | | users[].company | object | Company information associated with the user. Requires `Companies View` permission. | | total | integer | Total number of users matching the query. Use with `page` and `page_size` for pagination. | | page | integer | The page number returned. Only present in the response when `page` was included in the request. | ### Update User Update the properties of an existing user. **Permission Required**: `Users Modify` and `Users Modify Admin` to update users with Global Admin permission. ```bash POST /api/public/update_user ``` **Example request**: ```json { "api_key":"{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "4acb13bf-1215-4972-9f0d-8c537d17f2da", "username" : "test_user1@example.com", "first_name" : "Bob", "last_name" : "Williams", "locked": false, "disabled": false, "organization": "example", "phone": "123-456-7890", "password": "3UPKGg7g!a9g2@39v6" } } ``` **Example response**: ```json { "user": { "first_name": "Bob", "username": "test_user1@example.com", "realm": "local", "last_name": "Williams", "phone": "123-456-7890", "last_session": null, "notes": null, "user_id": "50faa5439c574b518cd868dac9256e4b", "groups": [ { "name": "All Users", "group_id": "68d557ac4cac42cca9f31c7c853de0f3" } ], "disabled": false, "organization": "example", "locked": false } } ``` ### Delete User Delete an existing user. If the user has any existing Kasm sessions, deletion will fail. Set the **force** option to true to delete the user's sessions and delete the user. **Permission Required**: `Users Delete` and `Users Modify`, `Users Modify Admin` is required to delete a user with Global Admin permission. ```bash POST /api/public/delete_user ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "4bbb6998064a4d1ea4685f3cdd05feb4" }, "force": false } ``` **Example response**: ```json {} ``` ### Logout User Logout all sessions for an existing user. **Permission Required**: `Users Auth Session` ```bash POST /api/public/logout_user ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "4bbb6998064a4d1ea4685f3cdd05feb4" } } ``` **Example response**: ```json {} ``` ### Get User Attributes Get the attribute (preferences) settings for an existing user. **Permission Required**: `Users View` ```bash POST /api/public/get_attributes ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0", } } ``` **Example response**: ```json { "user_attributes": { "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjy8izTD7DlykY0J7iiBn4ysIRqLBwM94ZnjfYH1XAo96ay3grQjSDl5f4u0hrVz6bX62kgPlm9QvTqceNZ+rC/anKp/9nQIrDM6y2W3jNUM6Eo+Ryh7xIOII2lnCbtE/M4urX4lZx3oB2JyIMSIN3yvKUBCSht5FsFabguc8i+nwLvXjmnZx+fcR2/BNcIM9UjCfYBjLFd1XFER7aIXjRy7y2MJQHCFrzhDThNllJ6C1oMZiBsBJ5lXpBmlim80A9IvcW7YBgsAQoqLgrCvRc7IdENTzPAyyhODE/ib5SkwK/peUuCRM+SZnPpUGlv9emLXVjrg5P+TPO/N/v7lyj", "show_tips": false, "user_id": "57e8fc1afa864ff4947460d9831f42d5", "toggle_control_panel": false, "user_attributes_id": "ef7b72db25b14ab1ac98ac19676ac93f", "default_image": null, "auto_login_kasm": null } } ``` ### Update User Attributes Update a users attributes. **Permission Required**: `Users Modify` and `Users Modify Admin` if the target user has the `Global Admin` permission. ```bash POST /api/public/update_user_attributes ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user_attributes": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0", "auto_login_kasm": false, "default_image": "b2609fbf72954b20a56c1fe502aa2c41", "show_tips": false, "toggle_control_panel": false } } ``` **Example response**: ```json {} ``` ### Assign User to Server Assigns a User to a Server in a Server Pool. The relationship between User and Server is many-to-many. See [User-Server Assignment](../how-to/workspaces-sessions/server-workspace/user-server-assignment.mdx) for more information. **Permission Required**: `Servers Modify` and `Users Modify`. Also `Users Modify Admin` if the target user has the `Global Admin` permission. ```bash POST /api/public/assign_user_server ```` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0" }, "target_server": { "server_id": "4afd4760-f4b9-400b-98e7-a4c678540e63" } } ``` **Example response**: Status Code: `200` ```json { "user_server_assignment": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0", "server_id": "4afd4760-f4b9-400b-98e7-a4c678540e63" } } ``` ### Unassign User from Server Unassigns a User from a Server in a Server Pool. See [User-Server Assignment](../how-to/workspaces-sessions/server-workspace/user-server-assignment.mdx) for more information. **Permission Required**: `Servers Modify` and `Users Modify`. Also `Users Modify Admin` if the target user has the `Global Admin` permission. ```bash POST /api/public/unassign_user_server ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0" }, "target_server": { "server_id": "4afd4760-f4b9-400b-98e7-a4c678540e63" } } ``` **Example response**: Status Code: `204` (No Content) ## Kasms ### Workflow The following diagram outlines the basic workflow for requesting a session and verifying its status before delivering it to the end user. ![Session Workflow](/img/api/session_workflow.png) 1. The end-user initiates an action to create a Kasm session. 2. The integrator app backend requests a session from Kasm via `/api/request_kasm`. 3. The integrator app calls `/api/get_kasm_status` to interrogate `operational_status` or `kasm.operational_status`. The session should only be considered ready for user consumption if the `kasm.operational_status` is `running`. If the status is not running, the integrator should poll at regular intervals to retrieve the updated status. A number of factors may delay the session from reaching the `running` status quickly, such as loading [S3 Persistent Profiles](../how-to/data-storage/persistent-profiles.mdx) , or waiting for [Autoscaled compute](../how-to/infra-autoscale/autoscale/index.mdx) to fully provision. Integrators should be aware of these factors and tune the system accordingly to achieve an acceptable user experience. 4. The session is delivered to the user via the integrators app. 5. The user requests that the session is deleted via a mechanism within the integrator's app, or the integrator app determines the session should be deleted. 6. The integrator app calls `/api/delete_kasm`. The return of `/api/delete_kasm`, does not guarantee that the session is fully deleted. The session may be deleted as part of a background task, or waiting for a persistent profile to be synchronized. 7. The integrator app calls `/api/get_kasm_status` to confirm the session is deleted. While optional, this step should be considered required if the session utilizes persistent profiles. ### Request Kasm Request for a new Kasm session to be created. Integrators should submit follow up requests to [get_kasm_status](#get-kasm-status) to ensure the session reaches a **running** state, prior to directing the user to the session. **Permission Required**: `Users Auth Session` and `User` If you intend to integrate Kasm into your app and will utilize iframes to load user sessions, be sure to set the **Same Site Cookie Policy** [Global Setting](./settings.mdx#authentication) to None if the Kasm Workspaces server is hosted under a different domain name. Reference: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) ```bash POST /api/public/request_kasm ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "user_id": "8affcdbc16fc4910acb8a6dc268cd7ed", "image_id": "6a2d63fa8959412ca5fddd3890fb7223", "enable_sharing": true, "environment": { "ENV_VAR": "value" } } ``` **Example response**: ```json { "kasm_id": "6d62ec66-3062-4f1d-b861-aeb3f5ca2390", "username": "1d47uudwcynkd2su", "status": "starting", "share_id": "fe9770a4", "user_id": "8affcdbc16fc4910acb8a6dc268cd7ed", "session_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiY2E4ODFkOGEtNzNhMi00M2IzLThkZmMtYzAxZGU4YmY5YzMyIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODI5NjEyfQ.UlHuZ7pSz2a74sqj8toyveKX2xmJMIapTD-e9x9fQZyXRiJv2J0jZ9g6sjLXxvtYgxtnK-0MMwMI80gLGSXapnB3JGur_4khQh-PnuQQP1o-KFM0_tTgs6O6OyXApli3x_ko9v5c_Ze-uCo2rJtjwHct7Y1HVa_pFBIBR8bvvfyigFm2DQjZ_eNTE9qxPGHtPocid_D-lg6hNWSIjMsCuUH5j7dcuS70D3kThkD98iPXlJAuUUqXqWGL5AnayPxDD7hRBPVNLuz1R2IO2rjQmkbXHY8XINLGTAunVGsIl6IEVCqKkFHwjDMmGn_jLgL9S4g7ZQEMm4wNBqh-EjSQLg", "kasm_url": "/#/connect/kasm/9b50379d-d04c-4037-81ef-6ac77b696e22/766384b9955c42da905888f84db9660e/eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiY2E4ODFkOGEtNzNhMi00M2IzLThkZmMtYzAxZGU4YmY5YzMyIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODI5NjEyfQ.UlHuZ7pSz2a74sqj8toyveKX2xmJMIapTD-e9x9fQZyXRiJv2J0jZ9g6sjLXxvtYgxtnK-0MMwMI80gLGSXapnB3JGur_4khQh-PnuQQP1o-KFM0_tTgs6O6OyXApli3x_ko9v5c_Ze-uCo2rJtjwHct7Y1HVa_pFBIBR8bvvfyigFm2DQjZ_eNTE9qxPGHtPocid_D-lg6hNWSIjMsCuUH5j7dcuS70D3kThkD98iPXlJAuUUqXqWGL5AnayPxDD7hRBPVNLuz1R2IO2rjQmkbXHY8XINLGTAunVGsIl6IEVCqKkFHwjDMmGn_jLgL9S4g7ZQEMm4wNBqh-EjSQLg" } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | user_id | string | If specified, the Kasm session will be created under this user. If omitted, an anonymous user will be created and used. | | image_id | string | The ID of the image to use for the Kasm session. If omitted, the default image set at the group or user level will be used. | | enable_sharing | boolean | If set to `true`, the Kasm session will be created with sharing mode enabled by default. | | kasm_url | string | If specified, the browser inside the session will navigate to this URL. Only applicable to browser-based images (e.g., Kasm Chrome, Firefox, Tor Browser). | | environment | dict | Environment variables to inject into the created container session. | | connection_info | dict | Custom RDP/VNC/SSH connection settings. Not applicable for container-based sessions. | | client_language | string (optional) | Language to be passed as an environment variable to the Kasm session. Refer to "Valid Languages" documentation for accepted values. | | client_timezone | string (optional) | Timezone to be passed as an environment variable to the Kasm session. Refer to "Valid Timezones" documentation for accepted values. | | egress_gateway_id | string (optional) | ID of the Egress Gateway the session should connect to at launch. The user must have permission and an associated Egress Credential. Only applies to container-based sessions. See the Egress documentation for details. | | persistent_profile_mode | string (optional) | Controls behavior of persistent profiles (only for container sessions with persistent profile path configured). Valid values:• `Enabled`: Uses a persistent profile. If it doesn't exist, it will be created.• `Disabled`: Does not load a persistent profile.• `Reset`: Deletes any existing profile and creates a new one. | | rdp_client_type | string (optional) | Required when the Workspace image is an RDP Server and the RDP Client option is set to *User Selectable*. Valid values:• `GUAC` – Session is web-native.• `RDP_CLIENT` – User connects using an RDP client. | | server_id | string (optional) | Only applicable for sessions using non-container-based Server Pools. Specifies the exact server in the pool to use for the session. | **Response Format** | Name | Type | Description | |------|------|-------------| | kasm_id | string | Returns the ID for the newly created Kasm. | | session_token | string | Returns the JWT token created for the user used in authorization of the Kasm. | | username | string | Returns the username of the specified or newly created user. | | status | string | Returns the operational status of the Kasm. Will be in Starting, Running or Stopped state. Users should not be directed into Kasm sessions unless the status is **Running**. Followup calls to the [get-kasm-status](./builds.mdx) endpoint may be called to verify the sessions current status. | | share_id | string | Returns the Share id | | user_id | string | Returns the user id of the specified or newly created user | | kasm_url | string | The URL path to the specified Kasm in the form of `/#/connect/kasm///`. Append this value to the current Kasm Workspaces server address to create a full URL for accessing the Kasm. Directing the user's browser to the full URL will connect them to the Kasm session. | The `kasm_url` and resulting full URL should not be re-used for different users. **Unstructured Notes:** Direct the user's browser to this url to access the Kasm session. This link should not be re-used for different users. See [this](../how-to/workspaces-sessions/server-workspace/windows/remote-apps.mdx#developer-api) how-to guide for an example JSON that defines custom connection_info. The returned `kasm_url` is applicable to web native sessions, users can be directed to the returned URL once the session status is **running** as returned by the [get_kasm_status](#get-kasm-status) API call. For RDP native clients, an additional API call is needed to [get_rdp_client_connection_info](#get-rdp-client-connection-info) in order to retrieve the RDP file or URL. ### Get Kasm Status After creating a kasm the status can be checked with get_kasm_status. This call also updates the session token for the user creating a new connection link and invalidating the old one. Integrators should wait until the sessions reaches a **running** operational_status prior to directing the end user into the session via `kasm.operational_status`. If the session is not in a running state, the `kasm` object may not be provided, in which case the caller should interrogate the top level `operational_status`. `operational_progress` and `operational_message` may be used to provide context to the user. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/get_kasm_status ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "user_id": "c7357f11eb4d47ad8021b5847d8415d8", "kasm_id": "d79ccb22-f6e7-4473-b8a2-a77da82278da" } ``` **Example response - Starting**: ```json { "error_message": "This session is currently starting.", "operational_message": "Loading User Profile", "operational_progress": 50, "operational_status": "starting" } ``` **Example response - Running**: ```json { "current_time": "2020-11-12 13:30:24.833834", "kasm_url": "/#/connect/kasm/9b50379d-d04c-4037-81ef-6ac77b696e22/766384b9955c42da905888f84db9660e/eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiY2E4ODFkOGEtNzNhMi00M2IzLThkZmMtYzAxZGU4YmY5YzMyIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODI5NjEyfQ.UlHuZ7pSz2a74sqj8toyveKX2xmJMIapTD-e9x9fQZyXRiJv2J0jZ9g6sjLXxvtYgxtnK-0MMwMI80gLGSXapnB3JGur_4khQh-PnuQQP1o-KFM0_tTgs6O6OyXApli3x_ko9v5c_Ze-uCo2rJtjwHct7Y1HVa_pFBIBR8bvvfyigFm2DQjZ_eNTE9qxPGHtPocid_D-lg6hNWSIjMsCuUH5j7dcuS70D3kThkD98iPXlJAuUUqXqWGL5AnayPxDD7hRBPVNLuz1R2IO2rjQmkbXHY8XINLGTAunVGsIl6IEVCqKkFHwjDMmGn_jLgL9S4g7ZQEMm4wNBqh-EjSQLg", "kasm": { "expiration_date": "2020-11-12 14:28:40.446756", "container_ip": "192.168.32.9", "start_date": "2020-11-12 13:28:40.446737", "point_of_presence": null, "token": "43ab8a765e1e42fe9ee637783731f577", "image_id": "e12266d0f5f44bf5afb80b6c41fabce2", "view_only_token": "6f756f76e8704772bd8e32eb4d7bb835", "cores": 1.0, "hostname": "kasm.server", "kasm_id": "116f18170fdc4a1a87146164a880fb93", "port_map": { "audio": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/audio" }, "vnc": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/vnc" }, "audio_input": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/audio_input" }, "uploads": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/uploads" } }, "image": { "image_id": "e12266d0f5f44bf5afb80b6c41fabce2", "name": "kasmweb/chrome:1.8.0", "image_src": "img/thumbnails/chrome.png", "friendly_name": "Kasm Chrome" }, "is_persistent_profile": false, "memory": 1768000000, "operational_status": "running", "client_settings": { "allow_kasm_audio": false, "idle_disconnect": 20, "lock_sharing_video_mode": true, "allow_persistent_profile": false, "allow_kasm_clipboard_down": false, "allow_kasm_microphone": false, "allow_kasm_downloads": false, "kasm_audio_default_on": false, "allow_point_of_presence": false, "allow_kasm_uploads": false, "allow_kasm_clipboard_up": false, "enable_webp": false, "allow_kasm_sharing": true, "allow_kasm_clipboard_seamless": false }, "container_id": "dbc977159f79e55c466fec52a5b4954b7c26ba88e51937d85a5077d7c79e92e5", "port": 443, "keepalive_date": "2020-11-12 13:28:40.446754", "user_id": "583035bb58194e5183b921223badc569", "persistent_profile_mode": null, "share_id": "30a09d61", "host": "192.168.32.8", "server_id": "8270f8f0acfd4a34a56cc9a9cb7a67d9" } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | user_id | string | The user ID associated with the requested kasm. | | kasm_id | string | The ID of the desired Kasm. | | skip_agent_check | bool | Skip connecting out to the agent to verify status of the container, instead use the current value in the database for the status.| **Response Format** | Name | Type | Description | |------|------|-------------| | current_time | string | Returns the time at which the call was recieved in UTC. | | kasm | json object | Returns the Kasm object containing all of the current information. | | kasm_url | string | Returns the link path to the specified kasm. This path must be appended to the current Kasm Workspaces server address. It is in the form of `/#/connect/kasm///` | | operational_message | string | Provided if the session is not in a running state. May include a short description of the status of the request such as. "Loading User Profile" | | operational_progress | number | Provided if the session is not in a running state. A number between 0 and 100 representing the precentage complete of the request. | | operational_status | string | Provided if the session is not in a running state. The current status of the session. | ### Join Kasm Join Kasm returns the status of the shared kasm and a join url to connect to the Kasm session as a view-only user. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/join_kasm ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "user_id":"c7357f11eb4d47ad8021b5847d8415d8", "share_id":"89cc8cd3" } ``` **Example response**: ```json { "current_time": "2020-11-12 13:36:16.065711", "session_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiZjFmZWFiY2MtNzU2Yi00MmZiLThiODUtODQ1ODE0MjdjMzNjIiwiYXV0aG9yaXphdGlvbnMiOlsxMDBdLCJleHAiOjE3MTE4NDc0NDB9.agZubjVeUUmG3dV6IukU5JsOMoH4K9k98k8WjTecCBdgjhC0lEKBvs7257X6cbeavZE0ZRjKHkbrUlmJ18eVdss1j79DVdIyEqHVQX2ue9h2AKVYIi4LBGYJd-PXUeUadVUOopRrZcww1MgTTyDTqB8ZGbn3lR_wd2Jrk0_QMx5n046ShE7lL9De66_AapRbVk_vhWcMEdWHK7QTmMn7Qn1bHKFiDss9IhFVdzk6oSryaTgnK6YrvY7S7OOMcSXuaa2MEzYUCKmyau1LBCHyk_OpeHtJhrlw4gZXWerakfKlh6ghO2CnsK7MfPIYner6oimyLbXmztDbTrQD0yD4xA", "user_id": "583035bb58194e5183b921223badc569", "kasm": { "port_map": { "vnc": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/vnc" }, "audio": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/audio" } }, "port": 443, "hostname": "kasm.server", "image": { "image_id": "e12266d0f5f44bf5afb80b6c41fabce2", "name": "kasmweb/chrome:1.8.0", "image_src": "img/thumbnails/chrome.png", "friendly_name": "Kasm Chrome" }, "view_only_token": "6f756f76e8704772bd8e32eb4d7bb835", "user": { "username": "anon_2wipg0symxwmm4i1" }, "share_id": "30a09d61", "host": "192.168.32.8", "client_settings": { "allow_kasm_audio": false, "idle_disconnect": 20, "lock_sharing_video_mode": true, "allow_persistent_profile": false, "allow_kasm_clipboard_down": false, "allow_kasm_microphone": false, "allow_kasm_downloads": false, "kasm_audio_default_on": false, "allow_point_of_presence": false, "allow_kasm_uploads": false, "allow_kasm_clipboard_up": false, "enable_webp": false, "allow_kasm_sharing": true, "allow_kasm_clipboard_seamless": false }, "kasm_id": "116f18170fdc4a1a87146164a880fb93" }, "username": "anon_2wipg0symxwmm4i1", "kasm_url": "/#/connect/join/a35f030c/4cea872ff36044c690751e41ba2ec0e1/eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiZjFmZWFiY2MtNzU2Yi00MmZiLThiODUtODQ1ODE0MjdjMzNjIiwiYXV0aG9yaXphdGlvbnMiOlsxMDBdLCJleHAiOjE3MTE4NDc0NDB9.agZubjVeUUmG3dV6IukU5JsOMoH4K9k98k8WjTecCBdgjhC0lEKBvs7257X6cbeavZE0ZRjKHkbrUlmJ18eVdss1j79DVdIyEqHVQX2ue9h2AKVYIi4LBGYJd-PXUeUadVUOopRrZcww1MgTTyDTqB8ZGbn3lR_wd2Jrk0_QMx5n046ShE7lL9De66_AapRbVk_vhWcMEdWHK7QTmMn7Qn1bHKFiDss9IhFVdzk6oSryaTgnK6YrvY7S7OOMcSXuaa2MEzYUCKmyau1LBCHyk_OpeHtJhrlw4gZXWerakfKlh6ghO2CnsK7MfPIYner6oimyLbXmztDbTrQD0yD4xA" } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | user_id | string | The user ID used to create the join link. If none supplied an anonymous user will be created. | | share_id | string | The share ID of the desired kasm. | **Response Format** | Name | Type | Description | |------|------|-------------| | current_time | string | The UTC timestamp at which the API call was received. | | kasm | object | A JSON object containing all current metadata and configuration details about the Kasm session. | | kasm_url | string | A URL path used to access the specified shared Kasm session. The path should be appended to your Kasm server address. Format: `/#/connect/join///`.**Note:** This link is user-specific and should not be reused for different users. | | session_token | string | JWT token generated for the user, used for authorization when connecting to the Kasm session. | | username | string | The username of the specified or newly created user. | | user_id | string | The user ID of the specified or newly created user. | ### Get RDP Client Connection Info After creating a session that requires the user to connect via an RDP native client, this API call allows you to retrieve a URL or file used by the RDP client to connect. Some clients, such as MacOS, allow opening the RDP client using a URL, while other clients, such as Windows, require downloading the RDP file and having the user opening the downloaded file. The DevAPI cannot determine what the client supports, it is up to your code to determine which format to request for the client. The file method is supported by most clients, while the url method provides a better user experience, but may not be supported. You are responsible for writing client side code to take the returned file or url data and either creating a download with the returned content or launching a window with the returned url. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/get_rdp_client_connection_info ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "user_id": "c7357f11eb4d47ad8021b5847d8415d8", "kasm_id": "d79ccb22-f6e7-4473-b8a2-a77da82278da", "connection_type": "download" } ``` **Example response - File**: ```json { "file": "full address:s:myrdpgateway.com\r\nusername:s:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJrYXNtX2lkIjoiY2IzYTU1OGUtNjY3OS00NjMxLTk1M2YtMGUwOGY0OTA0YjBkIiwia2FzbV9jbGllbnRfa2V5IjpudWxsLCJpcCI6IjEyOS4yMTMuMTQxLjMxIiwiZXhwIjoxNzI0NDMyMzk2LCJhdXRob3JpemF\r\ndomain:s:0aW9ucyI6WzkxXX0._Y2B26S4mT7ZfJIbtVnPzXLUn3j-VIZngUl6zKUkmJeXjXO73GJVe1dzU5n1tuD75fFjw_3ELfbH7xmQS4jPzA\r\nconnection type:i:6\r\nnetworkautodetect:i:1\r\nbandwidthautodetect:i:1\r\nscreen mode id:i:2\r\nuse multimon:i:0\r\nsinglemoninwindowedmode:i:1\r\nkeyboardhook:i:2\r\ndisable full window drag:i:1\r\ndisable menu anims:i:1\r\nbitmapcachepersistenable:i:1\r\nsession bpp:i:32\r\ndynamic resolution:i:1\r\nautoreconnection enabled:i:1\r\nvideoplaybackmode:i:1\r\nallow desktop composition:i:1\r\ndisable themes:i:0\r\ndisable cursor setting:i:0\r\nallow font smoothing:i:1\r\ngatewayhostname:s:myrdpgateway.com\r\ngatewaycredentialssource:i:5\r\ngatewayusagemethod:i:1\r\ngatewayprofileusagemethod:i:1\r\ngatewaybrokeringtype:i:0\r\ngatewayaccesstoken:s:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJrYXNtX2lkIjoiY2IzYTU1OGUtNjY3OS00NjMxLTk1M2YtMGUwOGY0OTA0YjBkIiwia2FzbV9jbGllbnRfa2V5IjpudWxsLCJpcCI6IjEyOS4yMTMuMTQxLjMxIiwiZXhwIjoxNzI0NDMyMzk2LCJhdXRob3JpemF0aW9ucyI6WzkxXX0._Y2B26S4mT7ZfJIbtVnPzXLUn3j-VIZngUl6zKUkmJeXjXO73GJVe1dzU5n1tuD75fFjw_3ELfbH7xmQS4jPzA\r\nalternate full address:s:myrdpgateway.com\r\nsignscope:s:Full Address,Alternate Full Address,AutoReconnection Enabled,GatewayHostname,GatewayUsageMethod,GatewayProfileUsageMethod,GatewayCredentialsSource\r\nsignature:s:AQABAAEAAAA/BQAAMIIFOwYJKoZIhvcNAQcCoIIFLDCCBSgCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0BBwGgggL3MIIC8zCCAdugAwIBAgIUaI7fR/Q9ye6euOQnARerWpON3XwwDQYJKoZIhvcNAQELBQAwJzElMCMGA1UEAwwcS2FzbSBSRFAgU2lnbmluZyBDZXJ0aWZpY2F0ZTAeFw0yNDA4MjMxNjI4MDRaFw0yNTA4MjMxNjI4MDRaMCcxJTAjBgNVBAMMHEthc20gUkRQIFNpZ25pbmcgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF49LtjS9G+NUh+vz3Gaj70tqPFcUKDk51wU3YxnnVeuGZzxR/iW0rdqeOEyl8aXj6pBQCvM4t2G+eTvw8wT1CQ/ftNGLsGLK76hql1F9AGf383BNoIpz0Q5UGHNDEzSfDGcnQbaT6ebMpmVSBr3IvakIvllo5oPA4SR5YVll76KLKXmeG6W/vsp5u/VoRo5HjqONIx1eDjYBwxDyJMlLDklc2VXBew4/AvAMZ2VX91vH5YnWHvckjGaGUfrMjx5QqPW+a+p4rQlOqvUBNtc8JSbgcIqxIbT4y663mv2jzM74/NcfuR616NvObJJtgMtdoJ1N2LBSsKw1gDcprFEaXAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQARVRSL8MjZhjTqCgYlGWszA6bKh3jgjWE1ThPLl5VeRLUp9p2NLXxGaDzOakjXsZWWb8RQZTAGWjLrgU47D/WTGOVbrIpior4LHIyPkgWICUfzGKJA31MrLREKRZrlvsjvaP20CSRc9KIfefosEcDfttEBQI8pAiXZDqAXeXG5nz2f9BS5DenkK/s6yv2+LhHs2j5ea1wMwdVKh3ym4l3uqybSzDtRGHesZN3dhk+2uTq1G5VhWCFCCs96Wkh4F4sGfDwqTTcKZ17XiSp6hpFT6FBYOJFt+wL0PTS60fio1TDWjSY0yPWuH9Q7l1hwKnzuejwn7wLl9j5PiR7T4whDMYICCDCCAgQCAQEwPzAnMSUwIwYDVQQDDBxLYXNtIFJEUCBTaWduaW5nIENlcnRpZmljYXRlAhRojt9H9D3J7p645CcBF6tak43dfDANBglghkgBZQMEAgEFAKCBmzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA4MjMxNjU0NTZaMC8GCSqGSIb3DQEJBDEiBCDZceUCavSWsoTcIXgZu7WRh6eyVM9cwbPcoOVJmzx0NDAwBgkqhkiG9w0BCQ8xIzAhBglghkgBZQMEASoGCWCGSAFlAwQBFgYJYIZIAWUDBAECMA0GCSqGSIb3DQEBCwUABIIBAAKUyHSVmLYwogu7H91sY7NBE3+fpBhIC+nxz5vKsC/698QjtlmmhKyyeCdclxgVufoSWj6jkCgTs45ocQE2/+30f7PCSt8vSK+3FWXn140DeEg60bcQX8+ke4htJBv1H2aRjeabD531zzn2bgi45OYBoBHu78s3cI2/B8xFaikxc90x5/xUNCNiVhJgJ+IajXCRmrDKT/Cwby9JEW0aQYS0BLK0/CRrN5V9QWicUi0tbDoVy4z9BfVbceXK6XGyI+mtV1Jk1K43Ww2xqO1gnOjmyEiwuIofSOzSV+dcWc8XCH9T4P60OUVNuYIRw9YFbIbOabtm67+3venea77ZIkg=\r\n" } ``` **Example response - URL**: ```json { "url": "rdp://full+address=s:myrdpgateway.com&username=s:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJrYXNtX2lkIjoiY2IzYTU1OGUtNjY3OS00NjMxLTk1M2YtMGUwOGY0OTA0YjBkIiwia2FzbV9jbGllbnRfa2V5IjpudWxsLCJpcCI6IjEyOS4yMTMuMTQxLjMxIiwiZXhwIjoxNzI0NDMyMzgzLCJhdXRob3JpemF&domain=s:0aW9ucyI6WzkxXX0.3uAxQGIOMEHw8InGXU89Jw9vTBzgIPA42s3uYHMRaj2W1ZkhX1ff0i5dtgtuBlNvupPP7KdWBngGjoVN4YqHdQ&connection+type=i:6&networkautodetect=i:1&bandwidthautodetect=i:1&screen+mode+id=i:2&use+multimon=i:0&singlemoninwindowedmode=i:1&keyboardhook=i:2&disable+full+window+drag=i:1&disable+menu+anims=i:1&bitmapcachepersistenable=i:1&session+bpp=i:32&dynamic+resolution=i:1&autoreconnection+enabled=i:1&videoplaybackmode=i:1&allow+desktop+composition=i:1&disable+themes=i:0&disable+cursor+setting=i:0&allow+font+smoothing=i:1&gatewayhostname=s:myrdpgateway:443&gatewaycredentialssource=i:5&gatewayusagemethod=i:1&gatewayprofileusagemethod=i:1&gatewaybrokeringtype=i:0&gatewayaccesstoken=s:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJrYXNtX2lkIjoiY2IzYTU1OGUtNjY3OS00NjMxLTk1M2YtMGUwOGY0OTA0YjBkIiwia2FzbV9jbGllbnRfa2V5IjpudWxsLCJpcCI6IjEyOS4yMTMuMTQxLjMxIiwiZXhwIjoxNzI0NDMyMzgzLCJhdXRob3JpemF0aW9ucyI6WzkxXX0.3uAxQGIOMEHw8InGXU89Jw9vTBzgIPA42s3uYHMRaj2W1ZkhX1ff0i5dtgtuBlNvupPP7KdWBngGjoVN4YqHdQ" } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | user_id | string | The user ID associated with the requested kasm. | | kasm_id | string | The ID of the desired Kasm. | | connection_type | string | Must be set to file or url. For file, the returned value contains the file contents of an RDP file. For url the repsonse contains a URL, which the user can be directed to, which will open their native RDP client.| **Response Format** | Name | Type | Description | |------|------|-------------| | file | string | The file contents for an RDP file. | | url | string | The url to launch the client's native RDP client with connection details. | ### Get Kasms Retrieve a list of live sessions. **Permission Required**: `Sessions View` ```bash POST /api/public/get_kasms ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" } ``` **Example response**: ```json { "current_time": "2020-11-12 13:45:33.253299", "kasms": [ { "expiration_date": "2020-11-12 14:28:40.446756", "container_ip": "192.168.32.9", "server": { "port": 443, "hostname": "proxy", "zone_name": "default", "provider": "hardware" }, "user": { "username": "anon_2wipg0symxwmm4i1" }, "start_date": "2020-11-12 13:28:40.446737", "point_of_presence": null, "token": "43ab8a765e1e42fe9ee637783731f577", "image_id": "e12266d0f5f44bf5afb80b6c41fabce2", "view_only_token": "6f756f76e8704772bd8e32eb4d7bb835", "cores": 1.0, "hostname": "proxy", "kasm_id": "116f18170fdc4a1a87146164a880fb93", "port_map": { "audio": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/audio" }, "vnc": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/vnc" }, "audio_input": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/audio_input" }, "uploads": { "port": 443, "path": "desktop/116f1817-0fdc-4a1a-8714-6164a880fb93/uploads" } }, "image": { "image_id": "e12266d0f5f44bf5afb80b6c41fabce2", "name": "kasmweb/chrome:1.8.0", "image_src": "img/thumbnails/chrome.png", "friendly_name": "Kasm Chrome" }, "is_persistent_profile": false, "memory": 1768000000, "operational_status": "running", "client_settings": { "allow_kasm_audio": false, "idle_disconnect": 20, "lock_sharing_video_mode": true, "allow_persistent_profile": false, "allow_kasm_clipboard_down": false, "allow_kasm_microphone": false, "allow_kasm_downloads": false, "kasm_audio_default_on": false, "allow_point_of_presence": false, "allow_kasm_uploads": false, "allow_kasm_clipboard_up": false, "enable_webp": false, "allow_kasm_sharing": true, "allow_kasm_clipboard_seamless": false }, "container_id": "dbc977159f79e55c466fec52a5b4954b7c26ba88e51937d85a5077d7c79e92e5", "port": 443, "keepalive_date": "2020-11-12 13:28:40.446754", "user_id": "583035bb58194e5183b921223badc569", "persistent_profile_mode": null, "share_id": "30a09d61", "host": "192.168.32.8", "server_id": "8270f8f0acfd4a34a56cc9a9cb7a67d9" } ] } ``` ### Destroy Kasm Destroy a Kasm session. The backend system my destroy the session immediately or queue the task for further processing prior to deletion such as saving off persistent profiles. If integrators wish to confirm the session is fully deleted, follow-up calls to [get-kasm-status](builds.mdx) may be called, to confirm the session no longer exists. An error will be thrown **Permission Required**: `Users Auth Session` and `User` ```JSON { "error_message": "Invalid kasm_id (7540775ad7d54634b8e7f5ec38b6373a)" } ``` ```bash POST /api/public/destroy_kasm ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8", "user_id": "4d892bf39321494da9a159178972c147", } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | user_id | string | The user ID used of the kasm owner. | | kasm_id | string | The ID of the kasm to be destroyed. | **Response Format** If empty response is sent the request was processed correctly. ### Keepalive Issue a keepalive to reset the expiration time of a Kasm session. The new expiration time will be updated to reflect the **keepalive_expiration** [Group Setting](../how-to/security/users-groups-mgmt/groups.mdx) assigned to the Kasm's associated user. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/keepalive ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8" } ``` **Example response**: ```json { "usage_reached": false } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the kasm to issue the expiration update. | **Response Format** The response returns a single value **usage_reached**. If `true`, the user has exceeded the quota defined be the **usage_limit** group setting and the expiration time was **not** reset. ### Frame Stats Gets timing statistics for the next processed frame for a Kasm session. A user must be logged in and using a session for this API call to work. The stats include detailed timing stats on the processing of a single frame. Stats include frame analysis, jpeg/webp encoding, time in flight to client, and more. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/get_kasm_frame_stats ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8", "user_id": "4035b5e67750416cb8d6db14573ea38c", "client": "auto" } ``` **Example response**: ```json { "frame": { "resx": 1512, "resy": 858, "changed": 10, "server_time": 12}, "clients": [ { "client": "172.18.0.8_1635856777.276370::websocket", "client_time": 0, "ping": 27, "processes": [{"process_name": "scanRenderQ", "time": 0}] } ], "analysis": 2, "screenshot": 2, "encoding_total": 2, "videoscaling": 0, "tightjpegencoder": {"time": 0, "count": 5, "area": 23005}, "tightwebpencoder": {"time": 0, "count": 0, "area": 0} } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the Kasm session to retrieve statistics for. | | user_id | string | The ID of the user who owns the session. | | client | string | Specifies which client to retrieve stats for. Options include:• `auto` (default) – Automatically selects the client-side stats for the owner of the Kasm session.• `none` – Retrieves server-side stats only.• `all` – Retrieves stats for all connected websocket clients.• `` – Specifies a specific KasmVNC websocket client ID, e.g., `172.18.0.8_1627985086.157123::websocket`. | **Response Format** | Name | Type | Description | |------|------|-------------| | resx | integer | Horizontal resolution (in pixels) of the processed frame. | | resy | integer | Vertical resolution (in pixels) of the processed frame. | | changed | integer | Percentage of the frame that changed compared to the previous frame. | | server_time | integer | Total wall-clock time (in milliseconds) taken to process the frame on the server. Reflects total time, not CPU time, and includes multi-threaded processing. | | analysis | integer | Time in milliseconds taken to pre-process the frame and detect changes. | | encoding_total | integer | Wall-clock time (in milliseconds) to encode the frame. Encoding uses multiple threads and a mix of JPEG and WebP encoders. | | videoscaling | integer | Time in milliseconds taken to scale the frame during video mode. | | tightjpegencoder | integer | Aggregate CPU time (in milliseconds) used by all threads to encode JPEG rects. Not equivalent to wall-clock time. | | tightwebpencoder | integer | Aggregate CPU time (in milliseconds) used by all threads to encode WebP rects. Not equivalent to wall-clock time. | | clients | array | Array of client-side stats. Each object contains metrics such as `ping`, which represents the round-trip time in milliseconds. Divide by two for one-way latency. | ### Bottleneck Stats Returns CPU and network bottleneck statistics that are relevant to the Kasm rendering process, KasmVNC. These metrics may be used to determine if rendering performance issues are CPU constraints on the server-side KasmVNC process or network bandwidth constraints. Stats are returned for each connected client. Since Kasm supports sharing sessions, there can be multiple clients connected to a single session. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/get_kasm_bottleneck_stats ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8", "user_id": "4035b5e67750416cb8d6db14573ea38c" } ``` **Example response**: ```json { "kasm_user": { "172.18.0.8_1635858087.783615::websocket": [ 9.8, 9.8, 9.7, 9.7 ] } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the kasm to issue the expiration update.| | user_id | string | The ID of the user that owns the session. **Response Format** The response is JSON data containing an array of kasm user sessions. Each session has a dictionary entry with the key being the KasmVNC identifier for that websocket connection. The value is an array of decimal values ranging from 0 to 10. They represent, in order: CPU, CPU average, network, and network average. The lower the number, the moreconstrained KasmVNC is in being able to keep up with the target framerate. ### Screenshot Gets a screenshot of the requested session. **Permission Required**: `Users Auth Session` and `User` ```bash POST /api/public/get_kasm_screenshot ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8", "user_id": "4035b5e67750416cb8d6db14573ea38c", "width": 300, "height": 300 } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the Kasm session for which the expiration update is issued. | | user_id | string | The ID of the user to whom the session belongs. | | width | integer | The target width of the image. Default is `300`. | | height | integer | The target height of the image. This value may be overridden to preserve aspect ratio based on the provided width. | **Response Format** The response is a JPEG image. ### Exec Command Execute an arbitrary command inside of a user's session. **Permission Required**: `Users Auth Session` and `Sessions Modify` ```bash POST /api/public/exec_command_kasm ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "kasm_id": "1a85859d-9d75-45e1-a173-e720472a24f8", "user_id": "4035b5e67750416cb8d6db14573ea38c", "exec_config": { "cmd": "xterm -c 'echo hello'", "environment": { "SOME_ENV_VAR": "some value" }, "workdir": "/home/kasm-user", "privileged": false, "user": "root" } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the Kasm session for which the expiration update is being issued. | | user_id | string | The ID of the user to whom the session belongs. | | exec_config | dict | Dictionary of execution settings and the command to run in the session container. | | exec_config.cmd | string | The command to execute inside the user's container. | | exec_config.environment | dict | Environment variables to set for the exec session. | | exec_config.workdir | string | The working directory path for the exec session inside the container. | | exec_config.privileged | bool | If true, runs the exec session with privileged permissions. | | exec_config.user | string | The user to run the command as. By default, the session runs as the sandboxed user. Set to `"root"` to run as root, which disables sandbox protections. Any value other than `"root"` or omitted may cause the command to fail. | **Response Format** | Name | Type | Description | |------|------|-------------| | kasm | dict | A dictionary containing details about the container that the command was executed on. | | current_time | timestamp | The date and time the command was executed, in UTC. | ### Exec Kasm Execute a predefined command inside of a user's session. **Permission Required**: `Users Auth Session` and `Sessions Modify` ```bash POST /api/public/exec_kasm ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "user_id": "640d34fcaf3e435d88d7c8f30e56be90", "kasm_id": "ca8e24fc6b9d4fabbdb94c412f95439c", "kasm_exec": "go", "kasm_url": "https://kasmweb.com/" } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | kasm_id | string | The ID of the Kasm session on which to execute the command. | | user_id | string | The ID of the user to whom the session belongs. | | kasm_exec | string | The name of the predefined exec action to execute (e.g., `go`). | | kasm_url | string | Used by some exec actions (e.g., when opening a URL in a browser workspace). Must be a valid URL, even if not used — one can supply a dummy value such as https://localhost/. | **Response Format** | Name | Type | Description | |------|------|-------------| | kasm | dict | A dictionary containing details about the container that the command was executed on. | | current_time | timestamp | The date and time the command was executed, in UTC. | ### Session Component Control The developer may choose to hide the display of certain visual components that normally appear during a Kasm session. This is done by appending the following query arguments to any of the `kasm_url` response urls generated by the apis above. **Example** > ``` > /#/connect/join/89cc8cd3/c7357f11eb4d47ad8021b5847d8415d8/070fce1f-86c6-4e05-9b10-935632acb8ce?disable_control_panel=1&disable_tips=1&disable_viewers=1&disable_fixed_res=1 > ``` **Query Arguments** > disable_control_panel=1 > > Hides the Kasm control panel that is normally used for uploads, downloads etc. Users will be unable to access this functionality. > > disable_tips=1 > > Stops the tips modal from showing when the user connects to a session. > > disable_viewers=1 > > Hides the list of viewers for shared sessions. > > disable_fixed_res=1 > > By default, shared sessions are forced into a fixed resolution and aspect ratio. When specified this will allow the shared session to operate with a dynamic resolution and aspect ratio. ## Images ### Get Images Retrieve a list of available images. **Permission Required**: `Images View` ```bash POST /api/public/get_images ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" } ``` **Example response**: ```json { "images": [ { "restrict_to_network": false, "memory": 768000000, "zone_name": null, "x_res": 800, "description": "Single-Application : Chrome", "image_id": "b483f0a4fb6546f79064f9b6759758cb", "persistent_profile_path": null, "friendly_name": "Kasm Chrome", "volume_mappings": {}, "restrict_to_zone": false, "docker_token": null, "persistent_profile_config": {}, "cores": 1.0, "cpu_allocation_method": "Inherit", "docker_registry": "https://index.docker.io/v1/", "available": true, "run_config": { "hostname": "kasm" }, "imageAttributes": [ { "image_id": "b483f0a4fb6546f79064f9b6759758cb", "attr_id": "11cd3b92d73c4caaa84c70e75190ec25", "name": "vnc", "category": "port_map", "value": "6901/tcp" }, { "image_id": "b483f0a4fb6546f79064f9b6759758cb", "attr_id": "ec1531322190445db70d10c31766503a", "name": "audio", "category": "port_map", "value": "4901/tcp" }, { "image_id": "b483f0a4fb6546f79064f9b6759758cb", "attr_id": "3634ba1144bc4f64a932a561983c64f5", "name": "uploads", "category": "port_map", "value": "4902/tcp" } ], "docker_user": null, "restrict_to_server": false, "enabled": true, "name": "kasmweb/chrome:1.8.0", "zone_id": null, "y_res": 600, "server_id": null, "network_name": null, "exec_config": { "first_launch": { "environment": { "LAUNCH_URL": "" }, "cmd": "bash -c 'google-chrome --start-maximized \"$KASM_URL\"'" }, "go": { "cmd": "bash -c 'google-chrome --start-maximized \"$KASM_URL\"'" } }, "hash": null, "image_src": "img/thumbnails/chrome.png" } ] } ``` ### Get Session Recordings Retrieve data for all of a specific session's recordings. optionally get preauthorized download links for the clips from S3 compatible storage **Permission Required**: `Session Recordings View` ```bash POST /api/public/get_session_recordings ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_kasm_id": "10307f51-fd27-49f3-a84a-7aaa2f81d26e", "preauth_download_link": true } ``` **Example response**: ```json { "session_recordings": [ { "recording_id": "c6113d5d419948e4910ec3cac91ea480", "account_id": "267e50ef66c94f88bfd1c39c413bc4d1", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066120.mp4", "session_recording_metadata": { "duration": 63, "thumbnail": "", "timestamp": 1702065982 }, "session_recording_download_url": "" }, { "recording_id": "ebfd13f2dafc45fd956e8e574430f08e", "account_id": "267e50ef66c94f88bfd1c39c413bc4d1", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066225.mp4", "session_recording_metadata": { "duration": 52, "thumbnail": "", "timestamp": 1702066047 }, "session_recording_download_url": "" } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_kasm_id | string | The ID of the kasm to get the recordings for | | preauth_download_link | bool | whether or not to generate preauth download links for the recording clips. Defaults to False | | page | integer | Page number, defaults to 1. Page size is hardcoded to 5 | **Response Format** | Name | Type | Description | |------|------|-------------| | session_recordings | array | List of all session recordings for the specified kasm ID | | items | integer | Total number of recordings for that kasm | | page | integer | Current page returned | | per_page | integer | Always 5 (hardcoded) | | total_duration |integer | Sum of all recording durations in seconds | ### Get Sessions Recordings Retrieve data for all recordings for a list of sessions. Optionally get preauthorized download links for the clips from S3 compatible storage **Permission Required**: `Session Recordings View` ```bash POST /api/public/get_sessions_recordings ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_kasm_ids": ["10307f51-fd27-49f3-a84a-7aaa2f81d26e","d7f6c231-aded-4747-9fb4-742f5182ed5d"], "preauth_download_link": true } ``` **Example response**: ```json { "kasm_sessions": { "d7f6c231-aded-4747-9fb4-742f5182ed5d": { "session_recordings": [ { "recording_id": "dd1492515f2c4af8bcea184b3eb25f9c", "account_id": "68c7e26ebdc34818a30198ada507dc7a", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-07/d7f6c231-aded-4747-9fb4-742f5182ed5d.1701980442.mp4", "session_recording_metadata": { "duration": 79, "thumbnail": "", "timestamp": 1701979849 }, "session_recording_download_url": "" }, { "recording_id": "c886da0df36749308cc7b57c5668a8dd", "account_id": "68c7e26ebdc34818a30198ada507dc7a", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-07/d7f6c231-aded-4747-9fb4-742f5182ed5d.1701980443.mp4", "session_recording_metadata": { "duration": 80, "thumbnail": "", "timestamp": 1701979930 }, "session_recording_download_url": "" }, { "recording_id": "cef476ec8ec7473e9b5b7a3ed2e245db", "account_id": "68c7e26ebdc34818a30198ada507dc7a", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-07/d7f6c231-aded-4747-9fb4-742f5182ed5d.1701980444.mp4", "session_recording_metadata": { "duration": 36, "thumbnail": "image data", "timestamp": 1701980011 }, "session_recording_download_url": "" } ] }, "10307f51-fd27-49f3-a84a-7aaa2f81d26e": { "session_recordings": [ { "recording_id": "c6113d5d419948e4910ec3cac91ea480", "account_id": "267e50ef66c94f88bfd1c39c413bc4d1", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066120.mp4", "session_recording_metadata": { "duration": 63, "thumbnail": "", "timestamp": 1702065982 }, "session_recording_download_url": "" }, { "recording_id": "ebfd13f2dafc45fd956e8e574430f08e", "account_id": "267e50ef66c94f88bfd1c39c413bc4d1", "session_recording_url": "s3://kasm_session_recordings@storage.googleapis.com/recordings/admin@kasm.local/2023-12-08/10307f51-fd27-49f3-a84a-7aaa2f81d26e.1702066225.mp4", "session_recording_metadata": { "duration": 52, "thumbnail": "", "timestamp": 1702066047 }, "session_recording_download_url": "" } ] } } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_kasm_ids | array | List of IDs of the kasms to get the recordings for | | preauth_download_link | bool | whether or not to generate preauth download links for the recording clips. Defaults to False | **Response Format** | Name | Type | Description | |------|------|-------------| | kasm_sessions | dict | Dictionary of all session recordings for the specified kasm IDs | ## Groups ### Add User to Group Add a user to an existing group. **Permission Required**: `Groups Modify`, `Groups Modify System` to add the user to the built-in **All Users** or **Administrator** groups. ```bash POST /api/public/add_user_group ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0" }, "target_group": { "group_id": "87fd617577984033be5bd269b4d170c6" } } ``` **Example response**: ```json {} ``` ### Remove User from Group Remove a user from an existing group. **Permission Required**: `Groups Modify`, `Groups Modify System` to remove a user from a built-in group **All Users** or **Administrators**. ```bash POST /api/public/remove_user_group ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0" }, "target_group": { "group_id": "87fd617577984033be5bd269b4d170c6" } } ``` **Example response**: ```json {} ``` ## Login ### Get Login Generate a link for the user to login to Kasm without the need to enter a username or password. Redirect the user to the provided url. **Permission Required**: `Users Auth Session` ```bash POST /api/public/get_login ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "67d7c4e6-f891-4900-897f-ce5ed62fecc0" } } ``` **Example response**: ```json { "url": "https://kasm.server/#/connect/login/dash/57e8fc1afa864ff4947460d9831f42d5/930d6a5d-082e-438a-b5cf-98ae7ca5b67c" } ``` ## Licensing ### Activate License the deployment by submitting an activation key. If valid, the returned license key will automatically be applied to the deployment. **Permission Required**: `Licenses Create` ```bash POST /api/public/activate ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "activation_key": "-----BEGIN ACTIVATION KEY-----eyJ0eXAiOiJ...-----END ACTIVATION KEY-----", "seats" : 10, "issued_to": "ACME Corp" } ``` **Example response**: ```json { "license": { "license_id": "12e887e9e94a4615849f7963e9c85363", "expiration": "2022-11-06 18:07:08", "issued_at": "2021-11-05 18:07:08", "issued_to": "ACME Corp", "limit": 10, "is_verified": true, "license_type": "Per Concurrent Kasm", "features": { "auto_scaling": true, "branding": true, "session_staging": true, "session_casting": true, "log_forwarding": true, "developer_api": true, "inject_ssh_keys": true, "saml": true, "ldap": true, "session_sharing": true, "login_banner": true, "url_categorization": true, "usage_limit": true }, "sku": "Enterprise" } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | activation_key | string | The activation key provide by Kasm Technologies. | | seats | integer | The desired number of seats to license the deployment for. If omitted the deployment will be licensed using the maximum number of seats as dictated by the entitlement. | | issued_to | string | A string representing the organization the deployment is licensed for. | **Response Format** | Name | Type | Description | |------|------|-------------| | license | json object | The detailed information about the license generated. | ## Session Staging ### Get Staging Configs Get a list of Staging Configs. **Permission Required**: `Staging View` ```bash POST /api/public/get_staging_configs ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" } ``` **Example response**: ```json { "staging_configs": [ { "staging_config_id": "73f18b8826b74fb29a1066fb394878bc", "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "zone_name": "default", "image_id": "77b244ea4586469abde4feade309c377", "image_friendly_name": "Chrome", "num_sessions": 2, "num_current_sessions": 0, "expiration": 1, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": true, "allow_kasm_clipboard_down": true, "allow_kasm_clipboard_up": true, "allow_kasm_microphone": true } ] } ``` **Response Format** | Name | Type | Description | |------|------|-------------| | staging_configs | json object | A list of Staging Configs. | ### Get Staging Config Get an existing Staging Config. **Permission Required**: `Staging View` ```bash POST /api/public/get_staging_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_staging_config": { "staging_config_id": "ac3f18aa42ca4365874e51ab24f893c6" } } ``` **Example response**: ```json { "staging_config": { "staging_config_id": "ac3f18aa42ca4365874e51ab24f893c6", "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "zone_name": "default", "image_id": "23b8330701e8492d985c25b2736ab522", "image_friendly_name": "Kali Linux", "num_sessions": 1, "num_current_sessions": 0, "expiration": 1.0, "allow_kasm_audio": true, "allow_kasm_uploads": true, "allow_kasm_downloads": true, "allow_kasm_clipboard_down": true, "allow_kasm_clipboard_up": true, "allow_kasm_microphone": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_staging_config.staging_config_id | string | The ID of the staging config to be updated. | **Response Format** | Name | Type | Description | |------|------|-------------| | staging_config | json object | The requested staging config. | ### Create Staging Config Create a new Staging Config. **Permission Required**: `Staging Create` ```bash POST /api/public/create_staging_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_staging_config": { "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "image_id": "23b8330701e8492d985c25b2736ab522", "num_sessions": 1, "expiration": 1, "allow_kasm_audio": true, "allow_kasm_uploads": true, "allow_kasm_downloads": true, "allow_kasm_clipboard_down": true, "allow_kasm_clipboard_up": true, "allow_kasm_microphone": true } } ``` **Example response**: ```json { "staging_config": { "staging_config_id": "ac3f18aa42ca4365874e51ab24f893c6", "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "zone_name": "default", "image_id": "23b8330701e8492d985c25b2736ab522", "image_friendly_name": "Kali Linux", "num_sessions": 1, "num_current_sessions": 0, "expiration": 1, "allow_kasm_audio": true, "allow_kasm_uploads": true, "allow_kasm_downloads": true, "allow_kasm_clipboard_down": true, "allow_kasm_clipboard_up": true, "allow_kasm_microphone": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_staging_config.zone_id | string | The Zone ID for the staging config. | | target_staging_config.image_id | string | The Image ID to use for the staging config. | | target_staging_config.num_sessions | integer | Number of sessions the system will attempt to keep staged at all times. | | target_staging_config.expiration | integer | Time in hours after which unassigned staged sessions expire and are re-created. | | target_staging_config.allow_kasm_audio | bool | Enables audio streaming from the session to the user. | | target_staging_config.allow_kasm_uploads | bool | Allows users to upload files from their local computer to the session using the upload widget. | | target_staging_config.allow_kasm_downloads | bool | Allows users to download files from the session to their local computer via the download widget. | | target_staging_config.allow_kasm_clipboard_down | bool | Enables copying data from the session to the user's clipboard. | | target_staging_config.allow_kasm_clipboard_up | bool | Enables copying data from the user's clipboard into the session. | | target_staging_config.allow_kasm_microphone | bool | Allows the user to pass their local microphone into the session. | **Response Format** | Name | Type | Description | |------|------|-------------| | staging_config | json object | The created staging config. | ### Update Staging Config Get a list of Staging Configs. **Permission Required**: `Staging Modify` ```bash POST /api/public/update_staging_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_staging_config": { "staging_config_id": "73f18b8826b74fb29a1066fb394878bc", "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "image_id": "77b244ea4586469abde4feade309c377", "num_sessions": 2, "expiration": 2, "allow_kasm_audio": false, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false } } ``` **Example response**: ```json { "staging_config": { "staging_config_id": "73f18b8826b74fb29a1066fb394878bc", "zone_id": "e35b0ebd444d4120ad6d4f3db221003d", "zone_name": "default", "image_id": "77b244ea4586469abde4feade309c377", "image_friendly_name": "Chrome", "num_sessions": 2, "num_current_sessions": 0, "expiration": 2, "allow_kasm_audio": false, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_staging_config.staging_config_id | string | The ID of the staging config to be updated. | | target_staging_config.zone_id | string | The Zone ID to associate with the staging config. | | target_staging_config.image_id | string | The Image ID to use for the staging config. | | target_staging_config.num_sessions | integer | Number of sessions the system will attempt to keep staged at all times. | | target_staging_config.expiration | integer | Duration in hours after which unassigned staged sessions expire and are recreated. | | target_staging_config.allow_kasm_audio | bool | Enables audio streaming from the staged session to the user. | | target_staging_config.allow_kasm_uploads | bool | Allows users to upload files from their local computer to the session using the control panel. | | target_staging_config.allow_kasm_downloads | bool | Allows users to download files from the session to their local computer using the control panel. | | target_staging_config.allow_kasm_clipboard_down | bool | Enables copying data from the session to the user’s local clipboard. | | target_staging_config.allow_kasm_clipboard_up | bool | Enables copying data from the user’s clipboard into the session. | | target_staging_config.allow_kasm_microphone | bool | Allows users to pass their local microphone input into the session. | **Response Format** | Name | Type | Description | |------|------|-------------| | staging_config | json object | The updated staging config. | ### Delete Staging Config Delete an existing Staging Config. **Permission Required**: `Staging Delete` ```bash POST /api/public/delete_staging_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_staging_config": { "staging_config_id": "ac3f18aa42ca4365874e51ab24f893c6" } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_staging_config.staging_config_id | string | The ID of the staging config to be updated. | **Response Format** If empty, the delete request was successful ## Deployment Zones ### Get Zones Get a list of Deployment Zones. **Permission Required**: `Zones View` ```bash POST /api/public/get_zones ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "brief" : true } ``` **Example response** (Truncated for brevity): ```json { "zones": [ { "zone_id": "556641990fbd433197b9e8f0d1e0404a", "zone_name": "default", "auto_scaling_enabled": false, "aws_enabled": false, "aws_region": "us-east-1", "aws_access_key_id": "changeme", "aws_secret_access_key": "**********", "ec2_agent_ami_id": "changeme" } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | brief | bool | Limit the information returned for each zone. | **Response Format** | Name | Type | Description | |------|------|-------------| | zones | json object | A list of Deployment Zones. | ## Servers Servers are non-docker-agent hosts that run workspaces. For example, a workstation that is accessible via SSH. ### Batch Create Servers Create multiple (Server Pool) servers by uploading a CSV file. This endpoint expects a multi-part form upload containing the CSV file contents. See the [Servers Bulk Import section](../how-to/infra-autoscale/servers.mdx#bulk-import) for details on the CSV file format. **Permission Required**: * `Servers Create` * `Users Modify` if using the `assigned_username` column * `Users Modify Admin` if those users include system / admin users. ```bash POST /api/public/batch_create_server ``` **Example request**: Headers ``` Content-Type: multipart/form-data api-key: api-key-secret: ``` The CSV file content is expected in the `file_content` field. ``` file_content= ``` The `view` query parameter controls the format of the data returned. Validation data will always be returned in the `csv_validation_data` field when there is an error. In the success case: | View Value | Default | Response.csv_validation_data | Response.resources | | --- | --- | --- | --- | | api | No | `null` | Contains db results | | table | Yes | Contains validation results | `null` | | all | No | Contains validation results | Contains db results | **Example success response**: Request was made with `?view=all` ```json { "error_message": null, "csv_validation_data": { "headers": ["name", "ip_hostname", "port", "zone_name", "connection_type", "connection_credential_type", "use_user_private_key", "pool_id", "assigned_username", "labels"], "total_errors": 0, "global_errors": [], "total_rows": 1, "row_data": [ { "total_errors": 0, "contextual_errors": [], "fields": [ { "field": "name", "value": "Bob's Desktop" }, { "field": "ip_hostname", "value": "bob1.local" }, { "field": "port", "value": "22" }, { "field": "zone_name", "value": "default" }, { "field": "connection_type", "value": "SSH" }, { "field": "connection_credential_type", "value": "STATIC" }, { "field": "use_user_private_key", "value": true }, { "field": "pool_id", "value": "ae838047842840908b6dcb7ad1101626" }, { "field": "assigned_username", "value": "test_user1@example.com" }, { "field": "labels", "value": ["shared", "personal"] } ] } ], "file_bom": "" }, "resources": { "servers": [ { "server_id": "f542db0e23234f0096dd9fba78ac66a6", "created": "2025-07-24 21:59:11.870792", "server_type": "Desktop", "agent_version": null, "container_limit": 0, "cores": 0, "docker_images": {}, "hostname": "bob1.local", "instance_id": null, "last_reported": null, "memory": 0, "operational_status": "running", "provider": null, "docker_info": {}, "memory_stats": {}, "disk_stats": {}, "network_interfaces": {}, "cpu_percent": 0.0, "last_reported_elapsed": null, "cores_override": 0, "memory_override": 0, "manager_id": null, "manager": null, "core_calculations": { "percentage": 0, "used": 0, "max": 0 }, "memory_calculations": { "percentage": 0, "used": 0, "max": 0 }, "public_ip": null, "enabled": true, "prune_images_mode": "Aggressive", "gpus": 0, "gpu_info": {}, "gpu_percent": {}, "gpu_memory_used_percent": {}, "gpu_temp": {}, "gpus_override": 0, "connection_type": "SSH", "connection_info": null, "max_simultaneous_sessions": 1, "zone_id": "189c9a9b288c4dd49fc1274cc527a49d", "server_pool_id": "ae838047842840908b6dcb7ad1101626", "server_pool_name": "local-individual-machines", "zone_name": "default", "friendly_name": "Bob's Desktop", "is_autoscaled": false, "connection_username": null, "connection_password": null, "connection_port": 22, "connection_private_key": null, "use_user_private_key": true, "connection_passphrase": null, "agent_installed": false, "connection_credential_type": "STATIC", "connection_sso_username_domain": null, "max_simultaneous_users": 1, "labels": [ "shared", "personal" ], "inherited_labels": [ "shared", "personal" ], "assigned_users": [ { "user_id": "e39cb0579edb488c91f7600208a37243", "username": "test_user1@example.com" } ] } ] } } ``` **Example error response - invalid credentials** Status Code: `401` ```json { "error_message": "Invalid user name or password." } ``` **Example error response - invalid scope** Status Code: `403` ```json { "error_message": "Unauthorized." } ``` **Example error response - unparsable CSV data** Status Code: `400` ```json { "error_message": "Invalid file format: ...", "csv_validation_data": null } ``` **Example error response - invalid CSV data** Status Code: `400` ```json { "error_message": "Failed to import CSV file data", "csv_validation_data": { "headers": ["zone_name", "ip_hostname", "port", "connection_type", "connection_credential_type", "pool_id", "labels"], "total_errors": 3, "global_errors": [ { "code": "CSV_ERROR_002", "message": "Missing required fields", "field_names": ["name"] } ], "total_rows": 1, "row_data": [ { "total_errors": 2, "contextual_errors": [ { "code": "CSV_ERROR_012", "message": "ConnectionType(SSH) cannot use CredentialType(PROMPT_USER)", "fields": ["connection_type", "connection_credential_type"] } ], "fields": [ { "field": "zone_name", "value": "default" }, { "field": "ip_hostname", "value": "bob1.local" }, { "field": "port", "value": "22" }, { "field": "connection_type", "value": "SSH" }, { "field": "connection_credentials_type", "value": "PROMPT_USER" }, { "field": "pool_id", "value": "00001111222233334444555566667777", "error": { "code": "CSV_ERROR_011", "message": "ServerPool(00001111222233334444555566667777) does not exist" } }, { "field": "labels", "value": ["shared", "personal"] } ], "file_bom": "" } ] } } ``` See the [Appendix: CSV Error Codes](#csv-error-codes) for a complete list of validation error codes. ### Set Drain Server Set server draining status. **Permission Required**: `Agents Modify` ```bash POST /api/public/set_drain_server ``` **Example Request** ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_server": { "server_id": "ae6478f8bc5d474889254c8d8b4a8538", "is_draining": true } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_server.server_id | string | The ID of the Server to set draining status on. | | target_server.is_draining | boolean | The draining status to set the server to. | ### Get Server Retrieve a single server by ID. **Permission Required**: `Servers View` or `Agents View` ```bash POST /api/public/get_servers ``` **Example Request** ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_server": { "server_id": "f542db0e23234f0096dd9fba78ac66a6" } } ``` **Example Response** ```json { "server": { "server_id": "a171c3f8e2b94d6a8f1e5c9d0b7a2f4e6", "created": "2025-10-15 14:32:18.452631", "server_type": "host", "agent_version": null, "container_limit": 10, "cores": 4, "docker_images": {}, "hostname": "docker-agent-prod-0012", "instance_id": "i-0a1b2c3d4e5f67890", "last_reported": "2025-12-23T08:15:22.318456", "memory": 64000000000, "operational_status": "running", "provider": "aws", "docker_info": {}, "memory_stats": { "total": 64000000000, "used": 28500000000, "available": 35500000000, "percent": 44 }, "disk_stats": { "total": 250000000000, "used": 89000000000, "free": 161000000000, "percent": 36 }, "network_interfaces": null, "cpu_percent": 23.5, "last_reported_elapsed": "0:04:38", "cores_override": 4, "memory_override": 64000000000, "manager_id": "c7d92a1e5f3b4c8d9e0a1b2c3d4e5f67", "manager": { "manager_id": "c7d92a1e5f3b4c8d9e0a1b2c3d4e5f67", "manager_version": "1.16.0", "manager_hostname": "manager-east-1.example.com", "first_reported": "2025-11-01 09:00:00.000000", "last_reported": "2025-12-23 12:15:00.000000", "last_reported_elapsed": "0:05:00", "last_reported_seconds": 300, "zone_id": "b8e4f2a1c6d9e3b7a5f8c2d1e4b9a6f3", "zone_name": "us-east-1", "is_primary": true, "operational_status": "running" }, "core_calculations": { "percentage": 25, "used": 1, "max": 4 }, "memory_calculations": { "percentage": 44, "used": 28500000000, "max": 64000000000 }, "public_ip": "203.0.113.42", "enabled": true, "prune_images_mode": "Aggressive", "gpus": 0, "gpu_info": {}, "gpu_percent": null, "gpu_memory_used_percent": null, "gpu_temp": null, "gpus_override": 0, "connection_type": "KasmVNC", "connection_info": {}, "max_simultaneous_sessions": 5, "zone_id": "b8e4f2a1c6d9e3b7a5f8c2d1e4b9a6f3", "server_pool_id": "d4a7b2c8e1f5936d0a2b4c6e8f1a3b5d", "server_pool_name": "production-pool", "zone_name": "us-east-1", "friendly_name": "Production Agent 0012", "is_autoscaled": true, "connection_username": null, "connection_password": null, "connection_port": null, "connection_private_key": null, "use_user_private_key": false, "connection_passphrase": null, "agent_installed": true, "connection_credential_type": null, "connection_sso_username_domain": null, "max_simultaneous_users": 5, "drain_time": null, "labels": ["production", "high-memory"], "inherited_labels": ["us-east", "tier-1"], "server_template_id": null, "autoscale_config": { "autoscale_config_id": "e5b8c2a1d4f7936e0a3b5c7d9f1a2b4c", "autoscale_config_name": "prod-autoscale" }, "zone": { "zone_id": "b8e4f2a1c6d9e3b7a5f8c2d1e4b9a6f3", "zone_name": "us-east-1" }, "registration_jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "registration_jwt_expiration": "2035-12-21T12:00:00.000000+00:00", "kasms": [ { "kasm_id": "f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6", "start_date": "2025-12-23 08:00:00.000000", "keepalive_date": "2025-12-23 12:10:00.000000", "user": { "username": "jsmith@example.com", "user_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" } } ], "sessions_count": 1, "assigned_users": [], "server_pool": { "server_pool_id": "d4a7b2c8e1f5936d0a2b4c6e8f1a3b5d", "server_pool_name": "production-pool" }, "server_assignment_enabled": false } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_server.server_id | string | The ID of the server to retrieve. | ### Get Servers Retrieve servers with optional filtering and pagination. See [Pagination and Filtering](#pagination-and-filtering). **Permission Required**: `Servers View` or `Agents View` ```bash POST /api/public/get_servers ``` **Example Request** ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "page": 1, "page_size": 20, "sort_by": "hostname", "sort_direction": "asc", "filters": [ { "id": "enabled", "value": true }, { "id": "server_type", "value": "Desktop" } ] } ``` **Example Response** ```json { "servers": [ { "server_id": "b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8", "created": "2025-11-25 06:12:28.931187", "server_type": "Desktop", "agent_version": null, "container_limit": 10, "cores": 16, "docker_images": {}, "hostname": "gpu-workstation-0003", "instance_id": null, "last_reported": "2025-12-20T14:25:18.525885", "memory": 128000000000, "operational_status": "running", "provider": "gcp", "docker_info": { "Runtimes": { "nvidia": {} }, "GPUs": [ { "ID": "0", "Model": "NVIDIA Tesla T4" }, { "ID": "1", "Model": "NVIDIA Tesla T4" } ] }, "memory_stats": { "total": 128000000000, "used": 55580140538, "available": 72419859462, "percent": 43 }, "disk_stats": { "total": 500000000000, "used": 189000000000, "free": 311000000000, "percent": 38 }, "network_interfaces": null, "cpu_percent": 62.4, "last_reported_elapsed": "0:12:42", "cores_override": 16, "memory_override": 128000000000, "manager_id": null, "manager": null, "core_calculations": { "percentage": 12, "used": 2, "max": 16 }, "memory_calculations": { "percentage": 43, "used": 55580140538, "max": 128000000000 }, "public_ip": null, "enabled": true, "prune_images_mode": "Aggressive", "gpus": 2, "gpu_info": [ { "ID": "0", "Model": "NVIDIA Tesla T4" }, { "ID": "1", "Model": "NVIDIA Tesla T4" } ], "gpu_percent": null, "gpu_memory_used_percent": null, "gpu_temp": null, "gpus_override": 0, "connection_type": "KasmVNC", "connection_info": {}, "max_simultaneous_sessions": 1, "zone_id": "c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4", "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6", "server_pool_name": "gpu-workstations", "zone_name": "us-west-2", "friendly_name": "GPU Workstation 0003", "is_autoscaled": false, "connection_username": null, "connection_password": null, "connection_port": null, "connection_private_key": null, "use_user_private_key": false, "connection_passphrase": null, "agent_installed": false, "connection_credential_type": null, "connection_sso_username_domain": null, "max_simultaneous_users": 1, "drain_time": null, "labels": ["gpu", "high-performance"], "inherited_labels": ["workstation", "us-west"], "server_template_id": null, "autoscale_config": { "autoscale_config_id": null, "autoscale_config_name": null }, "zone": { "zone_id": "c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4", "zone_name": "us-west-2" }, "kasms": [], "sessions_count": 0, "assigned_users": [], "server_pool": { "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6", "server_pool_name": "gpu-workstations" }, "server_assignment_enabled": true }, [...] ], "total": 455, "page": 0, "page_size": 20, "sort_by": "hostname", "sort_direction": "asc" } ``` **Available Filters** | Filter ID | Type | Description | |-----------|------|-------------| | hostname | string | Substring match on hostname. | | friendly_name | string | Substring match on friendly name. | | search_term | string | Substring match across hostname and friendly_name. | | server_type | string | Exact match: `Host` or `Desktop`. | | operational_status | string | Exact match: `running`, `starting`, `stopped`, etc. | | enabled | boolean | Filter by enabled status. | | zone_id | string | Filter by zone ID. | | server_pool_id | string | Filter by server pool ID. | | is_autoscaled | boolean | Filter autoscaled servers. | | autoscale_config_id | string | Filter by autoscale config ID. | | provider | string | Exact match on provider. | | manager_id | string | Filter by manager ID. | | instance_id | string | Filter by cloud instance ID. | | server_assignment_enabled | boolean | Filter by server pool assignment enabled. | **Sortable Fields** | Field | Description | |-------|-------------| | hostname | Server hostname. | | friendly_name | Server display name. | | server_type | Server type `Host` or `Desktop`. | | operational_status | Current status. | | enabled | Enabled state. | | zone_name | Zone name. | | server_pool_name | Server pool name. | | sessions_count | Active session count. | | last_reported | Last agent report time. | ## Server Pools Server Pools are logical groupings of servers. They can contain Docker Agents or Desktop/Server type machines. ### Get Server Pool Retrieve a single server pool by ID, including its servers. **Permission Required**: `Server Pools View` ```bash POST /api/public/get_server_pools ``` **Example Request** ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_server_pool": { "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6" } } ``` **Example Response** ```json { "server_pool": { "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6", "server_pool_name": "gpu-workstations", "server_pool_type": "Server Pool", "server_assignment_enabled": true, "connection_type": "KasmVNC", "labels": ["gpu", "high-performance", "linux"], "servers_count": 3, "servers": [ { "server_id": "b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8", "hostname": "gpu-workstation-0001", "friendly_name": "GPU Workstation 0001", "connection_type": "KasmVNC", "connection_credential_type": null }, [...] ], "images": [ { "image_id": "3abeea7420ab40a7ab9998aa6f845ce3", "cores": 2, "description": null, "enabled": true, "friendly_name": "Ubuntu Desktop", "memory": 2048000000, "name": "ubuntu-desktop", "image_src": "/img/thumbnails/ubuntu.svg", "available": true, "image_type": "Container", "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6" }, [...] ], "autoscale_configs": [ { "autoscale_config_id": "737ab1f5263340af9d7dd9e57c243c84", "enabled": true, "autoscale_config_name": "gpu-workstations-autoscale", "autoscale_type": "Server Pool", "standby_cores": 4, "standby_memory_mb": 8192, "standby_gpus": 0, "downscale_backoff": 600, "zone_id": "7411ddd381a24c11b4db79f66a085168", "zone_name": "us-east-1", "connection_type": "KasmVNC", "reusable": false, "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6", "max_simultaneous_sessions_per_server": 1, "max_simultaneous_users": 1 }, [...] ] } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_server_pool.server_pool_id | string | The ID of the server pool to retrieve. | ### Get Server Pools Retrieve server pools with optional filtering and pagination. See [Pagination and Filtering](#pagination-and-filtering). **Permission Required**: `Server Pools View` ```bash POST /api/public/get_server_pools ``` **Example Request** ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "page": 0, "page_size": 20, "sort_by": "server_pool_name", "sort_direction": "asc", "filters": [ { "id": "server_pool_type", "value": "Server" } ] } ``` **Example Response** ```json { "server_pools": [ { "server_pool_id": "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6", "server_pool_name": "gpu-workstations", "server_pool_type": "Server", "server_assignment_enabled": true, "labels": ["gpu", "high-performance"], "servers_count": 3 }, { "server_pool_id": "d4a7b2c8e1f5936d0a2b4c6e8f1a3b5d", "server_pool_name": "production-agents", "server_pool_type": "Docker Agent", "server_assignment_enabled": false, "labels": ["production"], "servers_count": 12 } ], "total": 24, "page": 0, "page_size": 20, "sort_by": "server_pool_name", "sort_direction": "asc" } ``` **Available Filters** | Filter ID | Type | Description | |-----------|------|-------------| | server_pool_name | string | Substring match on pool name. | | server_pool_type | string | Exact match: `Docker Agent` or `Server`. | | server_assignment_enabled | boolean | Filter by user assignment enabled. | **Sortable Fields** | Field | Description | |-------|-------------| | server_pool_name | Pool name. | | server_pool_type | Pool type. | | server_assignment_enabled | Assignment enabled state. | | servers_count | Number of servers in pool. | ## Session Tokens Session tokens authenticate user’s requests to access functionality within the system. **Attributes** * **session_token** * This is the value of the token: (UUID) * **session_date** * The time the token was created or last promoted (DateTime) * **expires_at** * The time the token will no longer be valid. This is session_date + the global setting “Session Lifetime” (DateTime) * **session_jwt** The JWT token used by clients for authentication. ### Create Session Token Create a session token for a user. **Permission Required**: `Users Auth Session` ```bash POST /api/public/get_session_token ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "009c3779-4fa0-4af8-9722-8daf195718c0" } } ``` **Example response**: ```json { "session_token": { "session_token": "c324f7296dd3406594a261b411c862bb", "session_token_date": "2021-12-22 08:05:44.508675", "expires_at": "2021-12-23 08:05:44.508675", "session_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiNGYxNTY3MzUtNzEzMC00MmVjLTg1NWUtM2ExOWNiMTM1OGJiIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODMzMTUzfQ.oC1Nmm7GjIVr7k1MTnnKOFu7SDv3IC7g8WDiMA94vbhn2W6-uaghtvXv4tCd1aN9OOBxpmCsJeks4uatl56JFYYUx23eW13v_hZvXILOLf7WqQIv9cFAz5J_xlf63R3_NYggC16vL1u4Rf8c7hmDp0s-LSQrOy8uh91SYPijzkWE-NCXMUUCCCZWOu0UU6XuyMfF4uUtN0jHOzLU5XUZUXrMNKAPLnFe1HGnCXrW1TtdI2pAJTxMfSiuUMLzlKDpLyzDpPozBHDASH9XzGwkOqlLseYD137FVGYImrGZnf1Jp8H0JWQ7m7Z0BAf76tl7sKiNN2icPKBZryl2AbyeRg" } } ``` ### Get Session Token Query the information about a specific session token. **Permission Required**: `Users Auth Session` ```bash POST /api/public/get_session_token ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_token": { "session_token": "b8885ffe108f491dbb66be31bceb34c2" } } ``` **Example response**: ```json { "session_token": { "session_token": "b8885ffe108f491dbb66be31bceb34c2", "session_token_date": "2021-12-22 08:00:24.033284", "expires_at": "2021-12-25 16:00:24.033284", "session_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiNGYxNTY3MzUtNzEzMC00MmVjLTg1NWUtM2ExOWNiMTM1OGJiIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODMzMTUzfQ.oC1Nmm7GjIVr7k1MTnnKOFu7SDv3IC7g8WDiMA94vbhn2W6-uaghtvXv4tCd1aN9OOBxpmCsJeks4uatl56JFYYUx23eW13v_hZvXILOLf7WqQIv9cFAz5J_xlf63R3_NYggC16vL1u4Rf8c7hmDp0s-LSQrOy8uh91SYPijzkWE-NCXMUUCCCZWOu0UU6XuyMfF4uUtN0jHOzLU5XUZUXrMNKAPLnFe1HGnCXrW1TtdI2pAJTxMfSiuUMLzlKDpLyzDpPozBHDASH9XzGwkOqlLseYD137FVGYImrGZnf1Jp8H0JWQ7m7Z0BAf76tl7sKiNN2icPKBZryl2AbyeRg" } } ``` ### Get Session Tokens Get all session tokens for a user. This returns only the ID and the validity period of listed tokens, use the `/api/public/get_session_token` to retrieve the JWT token value of an individual token. **Permission Required**: `Users Auth Sessions` ```bash POST /api/public/get_session_tokens ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "009c3779-4fa0-4af8-9722-8daf195718c0" } } ``` **Example response**: ```json { "session_tokens": [ { "session_token": "b8885ffe108f491dbb66be31bceb34c2", "session_token_date": "2021-12-22 07:50:11.047577", "expires_at": "2021-12-25 15:50:11.047577" }, { "session_token": "01904563d58f43f2b6e8fdcc610728dc", "session_token_date": "2021-12-22 07:53:54.742402", "expires_at": "2021-12-25 15:53:54.742402" } ] } ``` ### Update Session Token Promote an existing session token. **Permission Required**: `Users Auth Sessions` ```bash POST /api/public/update_session_token ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_token": { "session_token": "b8885ffe108f491dbb66be31bceb34c2" } } ``` **Example response**: ```json { "session_token": { "session_token": "b8885ffe108f491dbb66be31bceb34c2", "session_token_date": "2021-12-22 08:11:52.913849", "expires_at": "2021-12-23 08:11:52.913849", "session_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX3Rva2VuX2lkIjoiNGYxNTY3MzUtNzEzMC00MmVjLTg1NWUtM2ExOWNiMTM1OGJiIiwiYXV0aG9yaXphdGlvbnMiOlsxMDAsMjAwXSwiZXhwIjoxNzExODMzMjkyfQ.Oyo5OLUlGJtfTH-oX0KJK5BdK_s_LIZ17Trl8YyZBEqmgJIzFPdO_pwn3PjM4RW0KImZTnj-LCz1SmlR2oeRyP5GA8A2HbHTJRB_fmQIHhPnXNxOlmu0TEfXxykuXr930OH79QOxyF8xM7IzFf048bpmdrc_JsENryPDJYklZgGndTvoF4pwloU6K5EfoUSHrG-A29voFNwKfJhZ6nayWUxJtHuZkq3GZNZU2wayJls_3D4ojjDByZzUTDmLY15enJ3xhfJG0c0SJv5g-rQUo3rqTS11zOvQIAu9WLF2yJC9JzTIKL70oyzNRaStyrbgTYxr2IDGcXKzBq_QraGcpQ" } } ``` ### Delete Session Token Delete a single session token for the user. **Permission Required**: `User Auth Sessions` ```bash POST /api/public/delete_session_token ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_token": { "session_token": "b8885ffe108f491dbb66be31bceb34c2" } } ``` **Example response**: ```json {} ``` ### Delete Session Tokens Delete all session tokens for a given user. **Permission Required**: `User Auth Sessions` ```bash POST /api/public/delete_session_tokens ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "009c3779-4fa0-4af8-9722-8daf195718c0" } } ``` **Example response**: ```json {} ``` ## Shared Session Permissions Developers may wish to have more than one user access a single session. In order to give secondary users access to a given session, the developer must explicitly give another user access via Session Permissions after placing the session in Sharing mode. Session Permissions only apply to non-owners of the Kasm session. **Attributes** * **session_permissions_id** * A unique identifier given to the session permission entry * **kasm_id** * The Kasm session id for the permission * **user_id** * The User Id for the permission * **vnc_username** * The auto-generated vnc user that maps to the permission. This is exposed inside the session container. * **access** * Access flags that determine the level of permissions. E.g `"access": "r"`. * Freeze: `"access": ""`. The users us able to connect but will not receive screen updates, nor be able to imput controls * Read: `"access": "r"` The user will receive screen updates but will not be able to control inputs * Read/Write `"access": "rw"` (implied read). The user will receive screen updates and control inputs ### Set Session Permissions Give a set of users access to a Kasm session. **Permission Required**: `Sessions Modify` ```bash POST /api/public/set_session_permissions ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_permissions": { "kasm_id": "e31320b3-4ef2-41dd-aa6e-f9e85270cd7e", "session_permissions": [ { "user_id": "2e559e29-9bf1-45a2-8c08-c30c7c253e42", "access": "rw" }, { "user_id": "e64c996c-efc1-4754-8f71-816a78619f39", "access": "r" }, { "user_id": "5edbadc6-886e-4ad8-9ff7-97f396a9d747", "access": "" } ] } } ``` **Example response**: ```json { "session_permissions": [ { "session_permission_id": "c391e4267e574b3d90731b2a843a2b98", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "2e559e299bf145a28c08c30c7c253e42", "access": "rw", "vnc_username": "e9d2682a5e824de", "username": "user@kasm.local" }, { "session_permission_id": "62eb4ae2b0ec487db61e9dc36f47b342", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "e64c996cefc147548f71816a78619f39", "access": "r", "vnc_username": "49c073c7dd854ad", "username": "user2@kasm.local" }, { "session_permission_id": "b0e9d7ab859648289f70395570734a3e", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "5edbadc6886e4ad89ff797f396a9d747", "access": "", "vnc_username": "b8f50c6ba1cf424", "username": "user3@kasm.local" } ] } ``` ### Set All Session Permissions Set the permissions for all participants for a given Kasm session. **Permission Required**: `Sessions Modify` ```bash POST /api/public/set_session_permissions ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_permissions": { "kasm_id": "e31320b3-4ef2-41dd-aa6e-f9e85270cd7e", "access": "r" } } ``` **Example response**: ```json { "session_permissions": [ { "session_permission_id": "c391e4267e574b3d90731b2a843a2b98", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "2e559e299bf145a28c08c30c7c253e42", "access": "r", "vnc_username": "e9d2682a5e824de", "username": "user@kasm.local" }, { "session_permission_id": "62eb4ae2b0ec487db61e9dc36f47b342", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "e64c996cefc147548f71816a78619f39", "access": "r", "vnc_username": "49c073c7dd854ad", "username": "user2@kasm.local" }, { "session_permission_id": "b0e9d7ab859648289f70395570734a3e", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "5edbadc6886e4ad89ff797f396a9d747", "access": "r", "vnc_username": "b8f50c6ba1cf424", "username": "user3@kasm.local" } ] } ``` ### Get Session Permissions Get session permissions for a Kasm session and/or user **Permission Required**: `Sessions Modify` ```bash POST /api/public/get_session_permissions ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_permissions" :{ "kasm_id": "e31320b3-4ef2-41dd-aa6e-f9e85270cd7e", "user_id": "5edbadc6886e4ad89ff797f396a9d747" } } ``` **Example response**: ```json { "session_permissions": [ { "session_permission_id": "b0e9d7ab859648289f70395570734a3e", "kasm_id": "e31320b34ef241ddaa6ef9e85270cd7e", "user_id": "5edbadc6886e4ad89ff797f396a9d747", "access": "", "vnc_username": "b8f50c6ba1cf424", "username": "user3@kasm.local" } ] } ``` ### Delete Session Permissions Remove session permissions for a given Kasm session. **Permission Required**: `Sessions Modify` ```bash POST /api/public/delete_session_permissions ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_permissions":{ "kasm_id": "e31320b3-4ef2-41dd-aa6e-f9e85270cd7e", "user_ids": [ "2e559e29-9bf1-45a2-8c08-c30c7c253e42", "e64c996c-efc1-4754-8f71-816a78619f39" ] } } ``` **Example response**: ```json {} ``` ### Delete All Session Permissions Remove all participant session permissions for a given Kasm session. **Permission Required**: `Sessions Modify` ```bash POST /api/public/delete_all_session_permissions ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_session_permissions":{ "kasm_id": "e31320b3-4ef2-41dd-aa6e-f9e85270cd7e" } } ``` **Example response**: ```json {} ``` ## Session Casting ### Get Cast Configs Get a list of Casting Configs. **Permission Required**: `Casting View` ```bash POST /api/public/get_cast_configs ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" } ``` **Example response**: ```json { "cast_configs": [ { "casting_config_name" : "Chrome Configuration", "cast_config_id": "e7fed0de23234a3084bffa3e8397759f", "image_id": "90c473864949488c902aa6e4adbf89a6", "image_friendly_name": "Chrome", "allowed_referrers": [ "acme.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "abc123", "allow_anonymous": true, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "require_recaptcha": true, "group_name": "All Users", "kasm_url": "https://google.com", "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } ] } ``` **Response Format** | Name | Type | Description | |------|------|-------------| | cast_configs | json object | A list of Casting Configs. | ### Get Cast Config Get an existing Casting Config. **Permission Required**: `Casting View` ```bash POST /api/public/get_cast_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "cast_config_id": "ac3f18aa42ca4365874e51ab24f893c6" } ``` **Example response**: ```json { "cast_config": { "casting_config_name": "Chrome Configuration", "cast_config_id": "e7fed0de23234a3084bffa3e8397759f", "image_id": "90c473864949488c902aa6e4adbf89a6", "image_friendly_name": "Chrome", "allowed_referrers": [ "acme.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "abc123", "allow_anonymous": true, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "require_recaptcha": true, "group_name": "All Users", "kasm_url": "https://google.com", "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | cast_config_id | string | The ID of the casting config to be queried. | **Response Format** | Name | Type | Description | |------|------|-------------| | cast_config | json object | The requested Casting config. | ### Create Cast Config Create a Session Casting Config **Permission Required**: `Casting Create` ```bash POST /api/public/create_cast_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_cast_config": { "casting_config_name": "My New Configuration", "image_id": "5383dd0238a94554b4611d2a9f943cda", "allowed_referrers": [ "example.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "123", "allow_anonymous": false, "group_id": null, "require_recaptcha": false, "kasm_url": null, "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } } ``` **Example response**: ```json { "cast_config": { "casting_config_name": "My New Configuration", "cast_config_id": "c423b160dc884000981da374842b0ef8", "image_id": "5383dd0238a94554b4611d2a9f943cda", "image_friendly_name": "Ubuntu Jammy", "allowed_referrers": [ "example.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "123", "allow_anonymous": false, "group_id": null, "require_recaptcha": false, "group_name": null, "kasm_url": null, "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_cast_config.casting_config_name | string | The configuration name. | | target_cast_config.image_id | string | The Image Id to use for the casting config. | | target_cast_config.allowed_referrers | list | A list of domains allowed as referrers when a casting link is visited. | | target_cast_config.limit_sessions | bool | When enabled, the total number of sessions for this config will be limited. | | target_cast_config.session_remaining | integer | The number of sessions that are allowed to be spawned from this casting link. | | target_cast_config.limit_ips | integer | When enabled, the system will limit the number of requests that will employ rate-limiting based on the source IP of the request. (e.g limiting requests to 1 sessions per 60 seconds) | | target_cast_config.ip_request_limit | bool | When limit_ips is enabled, this value is used as the total number of sessions that are allowed for the given time period as defined in Within Seconds. | | target_cast_config.ip_request_seconds | bool | When Llimit_ips is enabled, this value sets the timeframe (in seconds) that is used for the source IP. | | target_cast_config.error_url | bool | If defined, the user will be pushed to this URL when an error (such as IP rate limit violation) occurs. If left blank, an internal error page is shown. | | target_cast_config.enable_sharing | bool | When enabled, this session will automatically have sharing activated. | | target_cast_config.disable_control_panel | bool | When enabled, the Control Panel widget is not shown for the sessions. | | target_cast_config.disable_tips | bool | When enabled, the Tips dialogue is not shown when a user enters a session. | | target_cast_config.disable_fixed_res | bool | When enabled and the session is in sharing mode, the resolution will be dynamic. The resolution is typically fixed when a session enters sharing mode. | | target_cast_config.key | bool | The unique identifier for a Casting URL. If 123abc is the key, users will launch sessions via the following URL https://my.kasm.server/#/cast/123abc | | target_cast_config.allow_anonymous | bool | If enabled, requests to the Casting URL will not require authentication. Instead the system will create an anonymous users account for each new request. | | target_cast_config.group_id | bool | When Allow Anonymous is enabled, the system will create new user accounts for each new request. These anonymous users accounts will automatically be added to the All Users Group and an additional Group defined here. Administrators can configure the appropriate Group Settings to configure permissions such as allow_kasm_downloads etc on this Group. | | target_cast_config.require_recaptcha | bool | When Allow Anonymous is enabled, administrators can choose to have requests validated by Google reCAPTCHA . To use this feature, the Google reCAPTCHA Private Key and Google reCAPTCHA Site Key properties must be set in the Server Settings. | | target_cast_config.kasm_url | bool | If defined, this value will populate as the KASM_URL environment variable for created or assigned Staged Sessions. These values are often used in the Docker Exec Configs of the browser Images. | | target_cast_config.dynamic_kasm_url | bool | When enabled, the user is allowed to append a kasm_url query argument to the cast url. e.g https://kasm.server/#/cast/123?kasm_url=example.com If present the system will use this value as the KASM_URL. When used in conjunction with Allow Resume, this will open a new tab with the specified KASM_URL when the session is resumed | | target_cast_config.dynamic_docker_network | bool | When enabled, the user is allowed to append a docker_network query argument to the cast url. e.g https://kasm.server/#/cast/123?docker_network=example_network The Image used must have Allow Network Selection enabled. | | target_cast_config.allow_resume | bool | When enabled, authenticated users who already have a running session will have their session resumed instead of having a new session created when connecting to the same Casting URL | | target_cast_config.enforce_client_settings | bool | When enabled, the client settings listed below will be enforced on the session , overriding the client settings attached to the user’s group(s) | | target_cast_config.allow_kasm_audio | bool | When enabled and, the staged session will support streaming audio from the session to the user. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_uploads | bool | When enabled, the staged session will allow the user to upload files from their local computer to the session via the upload widget in the control panel. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_downloads | bool | When enabled, the staged session will allow download files from the session to their local computer via the control panel download widget. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_clipboard_down | bool | When enabled, the staged session will allow copying data from the session to the users local computer via the clipboard. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_clipboard_up | bool | When enabled, the staged session will allow copying data from the user’s local computer to the session. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_microphone | bool | When enabled, the staged session will allow the user to pass their local microphone into the session. Applicable if enforce_client_settings is enabled. | | target_cast_config.valid_until | bool | When defined, the casting link will only be valid until this time, after which the client will be presented with an error. Defined in UTC. | | target_cast_config.allow_kasm_sharing | bool | When enabled, the user will be able to place their session in sharing mode. Applicable if enforce_client_settings is enabled. | | target_cast_config.kasm_audio_default_on | bool | When disabled, the audio service will be muted by default. Applicable if enforce_client_settings is enabled. | | target_cast_config.kasm_ime_mode_default_on | bool | When enabled, IME mode will be enabled by default if the doesnt already have a local preference set. Applicable if enforce_client_settings is enabled. | **Response Format** | Name | Type | Description | |------|------|-------------| | cast_config | json object | The updated casting config. | ### Update Cast Config Update a Session Casting Config **Permission Required**: `Casting Modify` ```bash POST /api/public/update_cast_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_cast_config": { "casting_config_name": "My New Configuration", "cast_config_id": "c423b160dc884000981da374842b0ef8", "image_id": "5383dd0238a94554b4611d2a9f943cda", "allowed_referrers": [ "example.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "123", "allow_anonymous": false, "group_id": null, "require_recaptcha": false, "kasm_url": null, "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } } ``` **Example response**: ```json { "cast_config": { "casting_config_name": "My New Configuration", "cast_config_id": "c423b160dc884000981da374842b0ef8", "image_id": "5383dd0238a94554b4611d2a9f943cda", "image_friendly_name": "Ubuntu Jammy", "allowed_referrers": [ "example.com", "contoso.com" ], "limit_sessions": false, "session_remaining": 0, "limit_ips": false, "ip_request_limit": 0, "ip_request_seconds": 0, "error_url": null, "enable_sharing": false, "disable_control_panel": false, "disable_tips": false, "disable_fixed_res": false, "key": "123", "allow_anonymous": false, "group_id": null, "require_recaptcha": false, "group_name": null, "kasm_url": null, "dynamic_kasm_url": false, "dynamic_docker_network": false, "allow_resume": true, "enforce_client_settings": true, "allow_kasm_audio": true, "allow_kasm_uploads": false, "allow_kasm_downloads": false, "allow_kasm_clipboard_down": false, "allow_kasm_clipboard_up": false, "allow_kasm_microphone": false, "valid_until": "2022-06-20 10:00:00", "allow_kasm_sharing": false, "kasm_audio_default_on": true, "kasm_ime_mode_default_on": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_cast_config.cast_config_id | string | The ID of the desired casting config to update. | | target_cast_config.image_id | string | The Image Id to use for the casting config. | | target_cast_config.allowed_referrers | list | A list of domains allowed as referrers when a casting link is visited. | | target_cast_config.limit_sessions | bool | When enabled, the total number of sessions for this config will be limited. | | target_cast_config.session_remaining | integer | The number of sessions that are allowed to be spawned from this casting link. | | target_cast_config.limit_ips | integer | When enabled, the system will limit the number of requests that will employ rate-limiting based on the source IP of the request. (e.g limiting requests to 1 sessions per 60 seconds) | | target_cast_config.ip_request_limit | bool | When limit_ips is enabled, this value is used as the total number of sessions that are allowed for the given time period as defined in Within Seconds. | | target_cast_config.ip_request_seconds | bool | When Llimit_ips is enabled, this value sets the timeframe (in seconds) that is used for the source IP. | | target_cast_config.error_url | bool | If defined, the user will be pushed to this URL when an error (such as IP rate limit violation) occurs. If left blank, an internal error page is shown. | | target_cast_config.enable_sharing | bool | When enabled, this session will automatically have sharing activated. | | target_cast_config.disable_control_panel | bool | When enabled, the Control Panel widget is not shown for the sessions. | | target_cast_config.disable_tips | bool | When enabled, the Tips dialogue is not shown when a user enters a session. | | target_cast_config.disable_fixed_res | bool | When enabled and the session is in sharing mode, the resolution will be dynamic. The resolution is typically fixed when a session enters sharing mode. | | target_cast_config.key | bool | The unique identifier for a Casting URL. If 123abc is the key, users will launch sessions via the following URL https://my.kasm.server/#/cast/123abc | | target_cast_config.allow_anonymous | bool | If enabled, requests to the Casting URL will not require authentication. Instead the system will create an anonymous users account for each new request. | | target_cast_config.group_id | bool | When Allow Anonymous is enabled, the system will create new user accounts for each new request. These anonymous users accounts will automatically be added to the All Users Group and an additional Group defined here. Administrators can configure the appropriate Group Settings to configure permissions such as allow_kasm_downloads etc on this Group. | | target_cast_config.require_recaptcha | bool | When Allow Anonymous is enabled, administrators can choose to have requests validated by Google reCAPTCHA . To use this feature, the Google reCAPTCHA Private Key and Google reCAPTCHA Site Key properties must be set in the Server Settings. | | target_cast_config.kasm_url | bool | If defined, this value will populate as the KASM_URL environment variable for created or assigned Staged Sessions. These values are often used in the Docker Exec Configs of the browser Images. | | target_cast_config.dynamic_kasm_url | bool | When enabled, the user is allowed to append a kasm_url query argument to the cast url. e.g https://kasm.server/#/cast/123?kasm_url=example.com If present the system will use this value as the KASM_URL. When used in conjunction with Allow Resume, this will open a new tab with the specified KASM_URL when the session is resumed | | target_cast_config.dynamic_docker_network | bool | When enabled, the user is allowed to append a docker_network query argument to the cast url. e.g https://kasm.server/#/cast/123?docker_network=example_network The Image used must have Allow Network Selection enabled. | | target_cast_config.allow_resume | bool | When enabled, authenticated users who already have a running session will have their session resumed instead of having a new session created when connecting to the same Casting URL | | target_cast_config.enforce_client_settings | bool | When enabled, the client settings listed below will be enforced on the session , overriding the client settings attached to the user’s group(s) | | target_cast_config.allow_kasm_audio | bool | When enabled and, the staged session will support streaming audio from the session to the user. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_uploads | bool | When enabled, the staged session will allow the user to upload files from their local computer to the session via the upload widget in the control panel. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_downloads | bool | When enabled, the staged session will allow download files from the session to their local computer via the control panel download widget. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_clipboard_down | bool | When enabled, the staged session will allow copying data from the session to the users local computer via the clipboard. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_clipboard_up | bool | When enabled, the staged session will allow copying data from the user’s local computer to the session. Applicable if enforce_client_settings is enabled. | | target_cast_config.allow_kasm_microphone | bool | When enabled, the created session will allow the user to pass their local microphone into the session. Applicable if enforce_client_settings is enabled. | | target_cast_config.valid_until | bool | When defined, the casting link will only be valid until this time, after which the client will be presented with an error. Defined in UTC. | | target_cast_config.allow_kasm_sharing | bool | When enabled, the user will be able to place their session in sharing mode. Applicable if enforce_client_settings is enabled. | | target_cast_config.kasm_audio_default_on | bool | When disabled, the audio service will be muted by default. Applicable if enforce_client_settings is enabled. | | target_cast_config.kasm_ime_mode_default_on | bool | When enabled, IME mode will be enabled by default if the doesnt already have a local preference set. Applicable if enforce_client_settings is enabled. | **Response Format** | Name | Type | Description | |------|------|-------------| | cast_config | json object | The updated casting config. | ### Delete Cast Config Get an existing Casting Config. **Permission Required**: `Casting Delete` ```bash POST /api/public/delete_cast_config ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "cast_config_id": "ac3f18aa42ca4365874e51ab24f893c6", "casting_config_name": "Chrome Configuration", } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | cast_config_id | string | The ID of the casting config to be queried. | ## Egress Providers ### Get Egress Providers Get existing Egress Providers. **Permission Required**: `Egress Providers View` ```bash GET /api/public/get_egress_providers ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" "target_egress_provider": { "enabled": true } } ``` **Example response**: ```json { "egress_providers": [ { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "created": "2024-04-09 20:16:33.122852", "name": "My Wireguard Provider", "egress_provider_type": "wireguard", "enabled": true }, { "egress_provider_id": "94414e5939e74717a13b1cedfa39d95c", "created": "2024-04-17 16:17:42.855382", "name": "My OpenVPN Provider", "egress_provider_type": "openvpn", "enabled": true } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider.egress_provider_type | string | The type of Egress Provider to filter on. | | target_egress_provider.enabled | boolean | Wether the egress provider is enabled. | | target_egress_provider.name | string | The name of the Egress Provider. | | target_egress_provider.egress_provider_id | string | The egress_provider_id to filter on. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_providers | json object | A list of Egress Providers. | ### Create Egress Provider Create a new Egress Provider. **Permission Required**: `Egress Providers Create` ```bash POST /api/public/create_egress_provider ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider": { "name": "My Wireguard Provider", "egress_provider_type": "wireguard", "enabled": true } } ``` **Example response**: ```json { "egress_provider": { "egress_provider_id": "a9899290c1254763b2919d4467b5b795", "created": "2024-04-17 16:44:45.266496", "name": "test2", "egress_provider_type": "wireguard", "enabled": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider.egress_provider_type | string | The type of Egress Provider to be created. | | target_egress_provider.enabled | boolean | Whether to enable the Egress Provider. | | target_egress_provider.name | string | The name of the created Egress Provider. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_provider | json object | The created Egress Provider. | ### Update Egress Provider Update an Egress Provider. **Permission Required**: `Egress Providers Modify` ```bash POST /api/public/update_egress_provider ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider": { "egress_provider_id": "a9899290c1254763b2919d4467b5b795", "name": "My Wireguard Provider", "egress_provider_type": "wireguard", "enabled": true } } ``` **Example response**: ```json { "egress_provider": { "egress_provider_id": "a9899290c1254763b2919d4467b5b795", "created": "2024-04-17 16:44:45.266496", "name": "test2", "egress_provider_type": "wireguard", "enabled": true } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider.egress_provider_id | string | The ID of the desired Egress Provider to update. | | target_egress_provider.egress_provider_type | string | The type of Egress Provider to be created. | | target_egress_provider.enabled | boolean | Whether to enable the Egress Provider. | | target_egress_provider.name | string | The name of the created Egress Provider. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_provider | json object | The created Egress Provider. | ### Delete Egress Provider Delete an Egress Provider. **Permission Required**: `Egress Providers Delete` ```bash POST /api/public/delete_egress_provider ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider": { "egress_provider_id": "a9899290c1254763b2919d4467b5b795" } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider.egress_provider_id | string | The ID of the desired Egress Provider to delete. | ## Egress Gateway ### Get Image Egress Gateways Get a list of a User's Permitted Egress Gateways for a specific Image. **Permission Required**: `Egress Gateways View`, `Users View`, `Images View` ```bash GET /api/public/get_image_egress_gateways ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_user": { "user_id": "57ce33ab262a4e18825f68403c8adb91" }, "target_image": { "image_id": "59d352ffd64b4ea2bbadb3324095c811" } } ``` **Example response**: ```json { "egress_gateways": [ { "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b", "egress_gateway_name": "NY22", "egress_credential_id": "b55fbf47f2f545ce87817bead6ce6ab9", "city": "New York", "country": "US", "egress_provider_name": "My Openvpn Provider" } ], "image_id": "59d352ffd64b4ea2bbadb3324095c811" } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_user.user_id | string | The ID of the User to get the list of Egress Gateways for. | | target_image.image_id | string | The ID of the Image to get the list of Egress Gateways for. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_gateways | json list | A list of the Users's Egress Gateways for the requested Image, along with the name of the attached Egress Provider, and the egress_credential_id that is paired with the Egress Gateway. image_id *string*: The ID of the Image we retrieved the Egress Gateways for. | | image_id | string | The ID of the Image we retrieved the Egress Gateways for. | ### Get Egress Gateways Get existing Egress Gateways. **Permission Required**: `Egress Gateways View` ```bash GET /api/public/get_egress_gateways ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider": { "enabled": true } } ``` **Example response**: ```json { "egress_gateways": [ { "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b", "name": "NY22", "enabled": true, "country": "US", "city": "New York", "config": "# ==============================================================================\n...", "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "active_connections": 0 }, { "egress_gateway_id": "ae68af8807034bcdb217a905fea37200", "name": "NJ13", "enabled": true, "country": "United States ", "city": "Secaucus", "config": "[Interface]\n...", "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "active_connections": 0 } ] } ``` **Arguments** * Optional | Name | Type | Description | |------|------|-------------| | target_egress_gateway.egress_provider_id | string | An Egress Provider ID to filter on. | | target_egress_gateway.enabled | boolean | Whether the Egress Gateway is enabled. | | target_egress_gateway.name | string | The name of the Egress Gateway. | | target_egress_gateway.country | string | The country of the Egress Gateway. | | target_egress_gateway.city | string | The city of the Egress Gateway. | | target_egress_gateway.egress_gateway_id | string | An Egress Gateway ID to filter on. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_gateways | json object | A list of Egress Gateways | ### Create Egress Gateway Create a new Egress Gateway. **Permission Required**: `Egress Gateway Create`, `Egress Providers Modify` ```bash POST /api/public/create_egress_gateway ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_gateway": { "enabled": true, "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "name": "NJ13", "country": "United States", "city": "Secaucus", "config": "[Interface]\n..." } } ``` **Example response**: ```json { "egress_gateway": { "egress_gateway_id": "ae68af8807034bcdb217a905fea37200", "name": "NJ13", "enabled": true, "country": "United States", "city": "Secaucus", "config": "[Interface]\n#..." "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "active_connections": 0 } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_gateway.egress_provider_id | string | The ID of the Egress Provider to attach the Egress Gateway to. | | target_egress_gateway.enabled | boolean | Whether to enable the Egress Gateway. | | target_egress_gateway.name | string | The name of the created Egress Gateway. | | target_egress_gateway.country | string | The country of the created Egress Gateway. | | target_egress_gateway.city | string | The city of the created Egress Gateway. | | target_egress_gateway.config | string | The config of the created Egress Gateway. This is relevant for wireguard, openvpn, and custom provider types. For a Wireguard gateway the PrivateKey field can be omitted since it will be set by the Egress Credential. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_gateway | json object | The created Egress Gateway | ### Update Egress Gateway Update an Egress Gateway. **Permission Required**: `Egress Gateways Modify`, `Egress Providers Modify` ```bash POST /api/public/update_egress_gateway ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_gateway": { "egress_gateway_id": "ae68af8807034bcdb217a905fea37200", "enabled": true, "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "name": "NJ13", "country": "United States", "city": "Secaucus", "config": "[Interface]\n..." } } ``` **Example response**: ```json { "egress_gateway": { "egress_gateway_id": "ae68af8807034bcdb217a905fea37200", "name": "NJ13", "enabled": true, "country": "United States", "city": "Secaucus", "config": "[Interface]\n#..." "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "active_connections": 0 } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_gateway.egress_gateway_id | string | The Id of the Egress Gateway to update. | | target_egress_gateway.egress_provider_id | string | The ID of the Egress Provider to attach the Gateway to. | | target_egress_gateway.enabled | boolean | Whether to enable the Egress Gateway. | | target_egress_gateway.name | string | The name of the created Egress Gateway. | | target_egress_gateway.country | string | The country of the created Egress Gateway. | | target_egress_gateway.city | string | The city of the created Egress Gateway. | | target_egress_gateway.config | string | The config of the created Egress Gateway. This is relevant for wireguard, openvpn, and custom provider types. For a Wireguard gateway the PrivateKey field can be omitted since it will be set by the Egress Credential. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_gateway | json object | The updated Egress Gateway | ### Delete Egress Gateway Delete an Egress Gateway. **Permission Required**: `Egress Gateways Delete`, `Egress Providers Modify` ```bash POST /api/public/delete_egress_gateway ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_gateway": { "egress_gateway_id": "ae68af8807034bcdb217a905fea37200" } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_gateway.egress_gateway_id | string | The ID of the desired egress gateway to delete. | ## Egress Provider Mapping ### Get Egress Provider Mappings Get existing Egress Provider Mapping. **Permission Required**: `Egress Providers View` ```bash GET /api/public/get_egress_provider_mapping ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider_mapping": { "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "user_id": null } } ``` **Example response**: ```json { "egress_provider_mappings": [ { "egress_provider_mapping_id": "c46ed8c2a251495488b6f1c75bf328dd", "enabled": true, "created": "2024-04-17 17:32:42.167447", "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "allow_all_gateways": true, "egress_provider": { "egress_provider_id": "c2c4e245ee5443fda4bc43d9eba4f198", "name": "My Wireguard Provider", "egress_provider_type": "wireguard" }, "egress_gateways": [] }, { "egress_provider_mapping_id": "994e1ec54aeb4f74af3603c5c77919ba", "enabled": true, "created": "2024-04-16 16:10:34.624680", "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "egress_provider": { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "name": "My Openvpn Provider", "egress_provider_type": "openvpn" }, "egress_gateways": [ { "name": "NY22", "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b" } ] } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider_mapping.enabled | string | Whether the Egress Provider Mapping is enabled. | | target_egress_provider_mapping.egress_provider_id | string | The Id of the egress_provider that the mapping is bound to. | | target_egress_provider_mapping.group_id | string | The id of the group to get the egress_provider_mappings from. | | target_egress_provider_mapping.user_id | string | The id of the user to get the egress_provider_mappings from. | | target_egress_provider_mapping.image_id | string | The id of the image to get the egress_provider_mappings from. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_provider_mappings | json object | A list of Egress Provider Mappings. | ### Create Egress Provider Mapping Create a new Egress Provider Mapping. One of user_id, group_id, and image_id are required. **Permission Required**: `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/create_egress_provider_mapping ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider_mapping": { "enabled": true, "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "selected_gateways": [ "0f518584dfd6471c9f962858ddf0509b" ] } } ``` **Example response**: ```json { "egress_provider_mapping": { "egress_provider_mapping_id": "a9017720bfb64a34b4d1147576c95c23", "enabled": true, "created": "2024-04-18 12:27:53.930234", "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider_mapping.enabled | string | Whether to enable the Egress Provider Mapping. | | target_egress_provider_mapping.egress_provider_id | string | The Id of the Egress Provider to attach the mapping to. | | target_egress_provider_mapping.allow_all_gateways | boolean | Whether to allow all gateways in the provider to be a part of this mapping. | | target_egress_provider_mapping.selected_gateways | list | Required when allow_all_gateways is false. List of Egress Gateway IDs that are to be a part of this mapping. | | target_egress_provider_mapping.user_id | string | The ID of the user to attach the mapping to. | | target_egress_provider.group_id | string | The ID of the group to attach the mapping to. | | target_egress_provider.image_id | string | The ID of the image to attach the mapping to. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_provider_mapping | json object | The created Egress Provider Mapping | ### Update Egress Provider Mapping Update an Egress Provider Mapping. **Permission Required**: `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/update_egress_provider_mapping ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider_mapping": { "egress_provider_mapping_id": "a9017720bfb64a34b4d1147576c95c23", "enabled": true, "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "selected_gateways": [ "0f518584dfd6471c9f962858ddf0509b" ] } } ``` **Example response**: ```json { "egress_provider_mapping": { "egress_provider_mapping_id": "a9017720bfb64a34b4d1147576c95c23", "enabled": true, "created": "2024-04-18 12:27:53.930234", "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false } } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider_mapping.egress_provider_mapping_id | string | The ID of the Egress Provider Mapping to update. | | target_egress_provider_mapping.enabled | string | Whether to enable the Egress Provider Mapping. | | target_egress_provider_mapping.egress_provider_id | string | The Id of the Egress Provider to attach the mapping to. | | target_egress_provider_mapping.allow_all_gateways | boolean | Whether to allow all gateways in the provider to be a part of this mapping. | | target_egress_provider_mapping.selected_gateways | list | Required when allow_all_gateways is false. List of Egress Gateway Ids that are to be a part of this mapping. | | target_egress_provider_mapping.user_id | string | The ID of the user to attach the mapping to. | | target_egress_provider.group_id | string | The ID of the group to attach the mapping to. | | target_egress_provider.image_id | string | The ID of the image to attach the mapping to. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_provider_mapping | json object | The created egress provider mapping | ### Delete Egress Provider Mapping Delete an Egress Provider mapping. **Permission Required**: `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/delete_egress_provider_mapping ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_provider_mapping": { "egress_provider_mapping_id": "ae68af8807034bcdb217a905fea37200" } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_provider_mapping.egress_provider_mapping_id | string | The ID of the desired egress provider mapping to delete. | ## Egress Credentials ### Get Egress Credentials Get existing Egress Credentials. **Permission Required**: `Egress Credentials View` ```bash GET /api/public/get_egress_credentials ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_credential": { "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null } } ``` **Example response**: ```json { "egress_credentials": [ { "egress_credential_id": "b55fbf47f2f545ce87817bead6ce6ab9", "name": "My Credential Name", "username": "myusername", "password": "**********", "enabled": true, "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "wireguard_private_key": null, "tailscale_key": null, "limit_active_connections": true, "active_connection_limit": 1, "active_connections": 0, "custom_credential": null, "egress_provider": { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "name": "My Openvpn Provider", "egress_provider_type": "openvpn" }, "egress_gateways": [ { "name": "NY22", "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b" } ] } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_credential.enabled | string | Whether the Egress Credential is enabled. | | target_egress_credential.egress_provider_id | string | The Id of the Egress Provider that the Egress Credential is attached to. | | target_egress_credential.name | string | The name of the Egress Credential. | | target_egress_credential.user_id | string | The ID of the user the Egress Credential is attached to. | | target_egress_credential.group_id | string | The ID of the group the Egress Credential is attached to. | | target_egress_credential.image_id | string | The ID of the image the Egress Credential is attached to. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_credentials | json object | A list of Egress Credentials. | ### Create Egress Credentials Create a new Egress Credential One of user_id, group_id, and image_id are required. **Permission Required**: `Egress Credentials Create`, `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/create_egress_credential ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_credential": { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "selected_gateways": [ "0f518584dfd6471c9f962858ddf0509b" ], "limit_active_connections": true, "enabled": true, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "user_id": null, "image_id": null, "username": "myusername", "password": "mypassword", "active_connection_limit": "1", "name": "My Credential Name" } } ``` **Example response**: ```json { "egress_credentials": [ { "egress_credential_id": "b55fbf47f2f545ce87817bead6ce6ab9", "name": "My Credential Name", "username": "myusername", "password": "**********", "enabled": true, "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "wireguard_private_key": null, "tailscale_key": null, "limit_active_connections": true, "active_connection_limit": 1, "active_connections": 0, "custom_credential": null, "egress_provider": { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "name": "My Openvpn Provider", "egress_provider_type": "openvpn" }, "egress_gateways": [ { "name": "NY22", "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b" } ] } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_credential.enabled | string | Whether to enable the Egress Credential. | | target_egress_credential.egress_provider_id | string | The Id of the Egress Provider to attach the Egress Credential to. | | target_egress_credential.allow_all_gateways | boolean | Whether to allow all gateways in the provider to be a part of this mapping. | | target_egress_credential.limit_active_connections | boolean | Whether to limit the number of simultaneous active connections on this Egress Credential. | | target_egress_credential.name | string | The name of this Egress Credential. | | target_egress_credential.username | string | The username for this Egress Credential. Required when using openvpn. | | target_egress_credential.password | string | The password for this Egress Credential. Required when using openvpn. | | target_egress_credential.wireguard_private_key | string | The Wireguard private key for this Egress Credential. Required when using wireguard. | | target_egress_credential.tailscale_key | string | The password of this Egress Credential. Required when using tailscale. | | target_egress_credential.custom_credential | string | The custom_credentials of this Egress Credential. Required when using custom credential. | | target_egress_credential.selected_gateways | list | Required when allow_all_gateways is false. List of Egress Gateway Ids that are to be a part of this credential. | | target_egress_credential.user_id | string | The ID of the user to attach the credential to. | | target_egress_credential.group_id | string | The ID of the group to attach the credential to. | | target_egress_credential.image_id | string | The ID of the image to attach the credential to. | | target_egress_credential.active_connections | integer | The number of simultaneous active connections allowed on this egress credential. Required when limit_active_connections is true. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_credential | json object | The created Egress Credential | ### Update Egress Credentials Update a new Egress Credential **Permission Required**: `Egress Credentials Modify`, `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/update_egress_credential ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_credential": { "egress_credential_id": "b55fbf47f2f545ce87817bead6ce6ab9", "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "selected_gateways": [ "0f518584dfd6471c9f962858ddf0509b" ], "limit_active_connections": true, "enabled": true, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "user_id": null, "image_id": null, "username": "myusername", "password": "mypassword", "active_connection_limit": "1", "name": "My Credential Name" } } ``` **Example response**: ```json { "egress_credentials": [ { "egress_credential_id": "b55fbf47f2f545ce87817bead6ce6ab9", "name": "My Credential Name", "username": "myusername", "password": "**********", "enabled": true, "user_id": null, "group_id": "68d557ac4cac42cca9f31c7c853de0f3", "image_id": null, "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "allow_all_gateways": false, "wireguard_private_key": null, "tailscale_key": null, "limit_active_connections": true, "active_connection_limit": 1, "active_connections": 0, "custom_credential": null, "egress_provider": { "egress_provider_id": "e6f5a178bcf747dd80feb641c04943a2", "name": "My Openvpn Provider", "egress_provider_type": "openvpn" }, "egress_gateways": [ { "name": "NY22", "egress_gateway_id": "0f518584dfd6471c9f962858ddf0509b" } ] } ] } ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_credential.egress_credential_id | string | The Id of the Egress Credential to update. | | target_egress_credential.enabled | string | Whether to enable the Egress Credential. | | target_egress_credential.egress_provider_id | string | The ID of the Egress Provider to attach the credential to. | | target_egress_credential.allow_all_gateways | boolean | Whether to allow all gateways in the provider to be a part of this mapping. | | target_egress_credential.limit_active_connections | boolean | Whether to limit the number of simultaneous active connections on this Egress Credential. | | target_egress_credential.name | string | The name of this Egress Credential. | | target_egress_credential.username | string | The username of this Egress Credential. Required when using openvpn. | | target_egress_credential.password | string | The password of this Egress Credential. Required when using openvpn. | | target_egress_credential.wireguard_private_key | string | The Wireguard private key of this Egress Credential. Required when using wireguard. | | target_egress_credential.tailscale_key | string | The password of this Egress Credential. Required when using tailscale. | | target_egress_credential.custom_credential | string | The custom_credentials of this Egress Credential. Required when using custom credential. | | target_egress_credential.selected_gateways | list | Required when allow_all_gateways is false. List of Egress Gateway Ids that are to be a part of this credential. | | target_egress_credential.user_id | string | The Id of the user to attach the credential to. | | target_egress_credential.group_id | string | The Id of the group to attach the credential to. | | target_egress_credential.image_id | string | The Id of the image to attach the credential to. | | target_egress_credential.active_connections | integer | The number of simultaneous active connections allowed on this egress credential. Required when limit_active_connections is true. | **Response Format** | Name | Type | Description | |------|------|-------------| | egress_credential | json object | The updated Egress Credential | ### Delete Egress Credential Delete an Egress Credential. **Permission Required**: `Egress Credential Delete`, `Egress Providers Modify`, `Users Modify` if mapped to a User, `Users Modify Admin` if mapped to Admin User, `Groups Modify` if mapped to Group, `Groups Modify System` if mapped to a System Group, and `Images Modify` if mapped to an Image. ```bash POST /api/public/delete_egress_provider_mapping ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "target_egress_credential": { "egress_provider_mapping_id": "b55fbf47f2f545ce87817bead6ce6ab9" } } ``` **Example response**: ```json {} ``` **Arguments** | Name | Type | Description | |------|------|-------------| | target_egress_credential.egress_credential_id | string | The ID of the desired Egress Credential to delete. | ## Appendix ### CSV Error Codes Bulk import routines that use CSV files use the same set of standard codes to indicate what errors occurred. Error codes will usually be accompanied by more detailed error messages and relevant field names. | Code | Error | | --- | --- | | `CSV_ERROR_000` | Pydantic Validation Error | | `CSV_ERROR_001` | Wrong Data Type | | `CSV_ERROR_002` | Missing required field | | `CSV_ERROR_003` | Value too big | | `CSV_ERROR_004` | Value too small | | `CSV_ERROR_005` | Value too long | | `CSV_ERROR_006` | Value too short | | `CSV_ERROR_007` | Unsupported encoding | | `CSV_ERROR_008` | Invalid format | | `CSV_ERROR_009` | Nonexistent enum value | | `CSV_ERROR_010` | Resource already exists | | `CSV_ERROR_011` | Resource does not exist | | `CSV_ERROR_012` | Invalid combination | | `CSV_ERROR_013` | Data state does not permit the operation | | `CSV_ERROR_014` | Invalid JSON | | `CSV_ERROR_015` | Database Error | ## System Metrics ### Get Metrics Catalog The metrics catalog provides a list of all available system metrics components that can be monitored. **Permission Required**: `System Metrics View` ```bash POST /api/public/get_metrics_catalog ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}" } ``` **Example response**: ```json { "data": [ { "id": "b3ff6703-3528-4e05-83f6-b8bc61ae3db0", "name": "health_monitoring", "title": "Health Monitoring", "description": "Monitoring of system health checks like resources and heartbeat.", "category": null, "items": [ { "id": "8abd9c74-d131-4815-bbe0-8f90653ddb9d", "name": "kasm_agents_health", "title": "Kasm Agents Health", "description": "Health checks for the Kasm Agents.", "category": "agent" } ] } ] } ``` ### Get System Metrics The system metrics endpoint returns the current status of monitored components, along with optional health summaries, grouped metric snapshots, individual metric records, and raw metric data. **Permission Required**: `System Metrics View` ```bash POST /api/public/get_system_metrics ``` **Example request**: ```json { "api_key": "{{api_key}}", "api_key_secret": "{{api_key_secret}}", "start_datetime": "2026-05-18T15:00:00Z", "end_datetime": "2026-05-18T15:05:00Z", "include_health_summaries": true, "include_metrics_group": true, "include_metrics": true, "include_raw_data": false } ``` **Example response**: ```json { "data": [ { "id": "b3ff6703-3528-4e05-83f6-b8bc61ae3db0", "name": "health_monitoring", "title": "Health Monitoring", "description": "Monitoring of system health checks like resources and heartbeat.", "rows": [ { "id": "8abd9c74-d131-4815-bbe0-8f90653ddb9d", "name": "kasm_agents_health", "title": "Kasm Agents Health", "description": "Health checks for the Kasm Agents.", "category": "agent", "status": "healthy", "statusCounts": { "error": 0, "warning": 0, "info": 0, "healthy": 3, "total": 3 }, "firstRecordedAt": "2026-05-18T15:00:10.195564+00:00", "lastRecordedAt": "2026-05-18T15:02:10.477092+00:00", "summaries": [ { "status": "healthy", "message": "Kasm Agents Health is currently in a healthy state.", "affectedZone": null } ], "metricsGroup": [ { "componentId": "8abd9c74-d131-4815-bbe0-8f90653ddb9d", "recordedAt": "2026-05-18T15:02:00+00:00", "zoneId": "8f5d3026-d7c3-4dd6-8235-6843b1ebfe3b", "zoneName": "default", "metricsCount": 1, "statusCounts": { "error": 0, "warning": 0, "info": 0, "healthy": 1, "total": 1 }, "metrics": [ { "metricId": "50173a9c-81ea-489b-bf58-64be65e9ac5d", "label": "Agent-proxy", "healthStatus": "healthy", "healthSummary": [ "Kasm Agents Health is currently in a healthy state." ], "dataSummary": { "id": "6a807563-2836-47a8-a2ad-5f4d72bb6d77", "hostname": "proxy", "operational_status": "running", "cpu_percent": 2.5, "memory_percent": 41.6, "disk_percent": 45.4, "cores": 4, "last_reported_seconds_ago": 17.14 } } ] } ] } ] } ] } ``` **Arguments** | Name | Type | Optional | Description | |------|------|----------|-------------| | `start_datetime` | string | No | The start date and time for the metrics query. Use an ISO-8601 format such as `YYYY-MM-DDTHH:MM[:SS][Z\|±HH:MM]`. If no timezone is included, the value is interpreted using `local_timezone`. | | `end_datetime` | string | Yes | The end date and time for the metrics query. If omitted, the current time is used. This value must be greater than or equal to `start_datetime`. | | `local_timezone` | string | Yes | The timezone used to interpret `start_datetime` and `end_datetime` when they do not include timezone information. Defaults to `UTC`. Must be a valid timezone name, such as `UTC` or `America/New_York`. | | `scopes` | array | Yes | Optional list of metric scopes or component groups to include in the response. | | `zone_ids` | array | Yes | Optional list of zone IDs used to filter zone-based metrics. | | `include_health_summaries` | boolean | Yes | Whether to include component health summary information in the response. Defaults to `false`. | | `include_metrics_group` | boolean | Yes | Whether to include grouped metric snapshot data in the response. Defaults to `false`. | | `include_metrics` | boolean | Yes | Whether to include individual metric records inside each metrics group. Defaults to `false`. | | `include_raw_data` | boolean | Yes | Whether to include the full raw metric payload for each metric record. Defaults to `false`. This can significantly increase the response size. | | `metrics_statuses` | array | Yes | Optional list of metric statuses used to filter returned metric records. Supported values include `healthy`, `info`, `warning`, and `error`. | | `metrics_search_query` | string | Yes | Optional search query used to filter metric records by matching available metric fields, such as label, summary, or related metadata. | | `metrics_sort_order` | string | Yes | Sort order for metric records. Defaults to `DESC`. Supported values are `ASC` and `DESC`. | | `metrics_limit` | integer | Yes | Maximum number of metric records to return for each metrics component. Defaults to `45000` and cannot exceed `45000`. This limit is applied per component, not across the entire API response. | --- ## Kasm Workspaces Launcher: Experimental Features | Index # Experimental Features Index This index lists all **current** and **past** Experimental Features in Kasm Workspaces. Each entry includes: - **Introduced In** – The version in which the feature first became available as experimental. - **Removed In** – The version in which the feature was either removed or promoted to **Generally Available (GA)**. - **Status** – The current state of the feature (**Active**, **GA**, or **Removed**). - **Description** – A summary of functionality, intended benefits, and any known limitations. Experimental Features are provided for **technical preview** purposes and may be changed or removed without notice. ### Current & Past Experimental Features - **Active** – The feature is currently available as an experimental feature. - **GA** – The feature has graduated to General Availability and is part of the main platform. - **Removed** – The feature has been removed and is no longer available. | Feature Name | Introduced In | Removed In | Status | Description | | --- | --- | --- | --- | --- | | **[S3 Persistent Profiles V2](../../how-to/data-storage/persistent-profiles.mdx#storage-mapping-based-profiles)** | 1.18.0 | - | Active | Kasm has implemented improvements to the existing S3 Persistent Profile capability. Persistent profiles allow user workspace profiles to persist across sessions, retaining application state, settings, and files. Designed to improve productivity and user experience by maintaining session continuity. As an experimental feature, the new S3 profiles may have storage limitations or performance considerations. | - Experimental features may be **removed at any time**. - When a feature is promoted to GA, it will be documented in the standard Kasm Workspaces documentation. - This index is retained for **historical reference**. --- ## Kasm Workspaces: Experimental Features # Experimental Features **Experimental Features** in Kasm Workspaces provide administrators with early access to capabilities that are fully developed but not yet **Generally Available (GA)**. These features may deliver new functionality, performance improvements, or workflow enhancements — but they may also contain bugs, incomplete functionality, or untested edge cases. The goals of offering Experimental Features are to: - Gather **real-world usage feedback**. - Allow customers to **preview and access upcoming functionality**. - Accelerate **refinement and stabilization** before GA release. ### Important Considerations Kasm recommends testing Experimental Features in **non-production environments** before enabling them in production. By enabling Experimental Features: - You acknowledge that these features may contain bugs or not support all use cases. - You accept that these features may impact system stability, performance, or data integrity. - You understand that support for these features may be limited, and they may change or be removed without notice. ### Enabling Experimental Features #### Prerequisites - Administrator access to **Global Settings**. #### Steps 1. Navigate to **Admin → Global Settings**. 1. Locate the setting: **Name:** Enable Experimental Features 1. Toggle the setting to **On**. 1. Review the confirmation popup: > Please confirm you are trying to enable Kasm Experimental Features. > By enabling these features, you accept any bugs or issues that may be introduced into the system. 5. Choose one of the following: - **I accept the risk** → Enables the setting. - **Leave disabled** → Cancels without changes. 6. Click **Save**. Disabling this setting does **not** require a confirmation popup. ### Current Experimental Features For a full list of current and past experimental features, see the [Experimental Features Index](./feature-index.mdx). --- ## Kasm Workspaces Glossary: Key Terms and Definitions # Glossary ### Activation Key An activation key is provided as part of the purchase process for a Kasm Workspaces license. It can be used to license a Kasm Workspaces installation. For an offline installation it can be used with the [Installation ID](#installation-id) to generate at license key: [Kasm Workspaces activation tool](https://kasm.com/activate.html). ### Agent The agent is responsible for provisioning instances of end user session containers when requested via the web application. The Agent reports the available system resources to the manager. These Agents are represented in the Servers tab in the Administration tab of the web application. This service automatically downloads all Kasm Images defined within the application so they are available to provision new sessions on demand. ### Database Kasm Workspaces uses a Postgres Database to keep track of application data. The Docker container kasm_db holds this database. ### Desktop (container: kasmweb/desktop) The default base desktop configuration based on ubuntu 16.04. This base image contains all the necessary configurations to allow this container to function within the Kasm ecosystem. All additional images are based off this base image. ### Desktop Deluxe (container: kasmweb/desktop-deluxe) Kasm image that is based off of the [desktop container](#desktop). An example custom configuration that provides additional productivity software. ### Deployment Zone For large or complex installations, multiple sets of Agents and Managers may be deployed in different logical or geographically areas, or "Zones". ### Docker Docker is the platform from which we create and receive containers. More information can be found at [Docker's Homepage](https://www.docker.com/) ### Egress Plugin Service When a License granting use of Managed Egress is applied to a Kasm Workspaces Installation, the Installation will communicate with Kasm cloud **Egress Plugin Service** to obtain Managed Egress Providers and Managed Egress Accounts. ### Firefox (container: kasmweb/firefox) Kasm image that is based off of the [desktop container](#desktop). An example of hosting a single application. In this example the popular Firefox browser is used. ### Installation ID The Installation ID is the key generated by the specific Server installation. It is used for licensing Kasm Workspaces. It can be found in the System Info tab on the navigation menu. ### Session End users request to create sessions that are on-demand instances of [workspaces](#workspace) registered in the application. These instances are provisioned by and on the [agent](#agent) These containers house the desktop or application presented to the end user via the web application. ### License Key Provided by the [Kasm Workspaces activation tool](https://kasm.com/activate.html) and used for licensing an offline Kasm Workspaces installation ### Manager This service is responsible for monitoring the status of [agents](#agent) and end user sessions. Agents report to this service via an automatic check in process. It can be found in the docker container kasm_agent. ### Proxy This container, based on nginx, is used to forward traffic to the correct service container. The Docker container kasm_proxy holds the nginx configuration. ### Web Application This is the user interface for the Kasm Workspaces server. It is usually hosted on the selected domain on port 443 for https traffic. It contains all of the tabs needed for use and administration of the server ### Server A Server refers to a physical or virtual machine that serves desktops or applications using RDP, VNC, SSH, or KasmVNC. Kasm Workspaces is able to manage sessions to fixed servers that support one or more users concurrently. Servers can also be auto scaled by Kasm in order to ensure there are enough servers to meet user demand. Linux and Windows servers are supported. ### Workspace A Workspace is full desktop, single application, or a direct web link made available to users based on their group membership. In the case of desktops and applications these can be containerized workloads that are spun up on demand or direct connections to KasmVNC/RDP endpoints. Any number of Workspaces can be registered via the web application and can be customized by the administrator to add additional software and configurations. The administrator can also configure the CPU, memory and network resources available to each Workspace via the [Workspace Settings](../how-to/workspaces-sessions/container-workspace/workspaces.mdx). By default several Docker images are installed and registered as Workspaces. See [Default Docker Images](../how-to/workspaces-sessions/container-workspace/custom-images.mdx) for a list.. --- ## Kasm Services Healthcheck ## Overview The healthcheck system is a **container-based** health monitoring solution that monitors the health of Kasm Workspaces Docker services. Each service container uses a custom script that performs health validation with exponential backoff retry logic and state persistence across container restarts. ## Healthcheck Endpoints Each service provides standardized healthcheck endpoints that return JSON responses indicating service status: ```bash > curl -k https:///api/__healthcheck {"ok": true} ``` ## Healthcheck Script Parameters The container healthcheck system uses `/usr/bin/healthcheck.sh` with the following parameters: ```bash /usr/bin/healthcheck.sh ``` ### Parameter Details | **Parameter** | **Description** | **Example** | **Required** | |---------------|-----------------|-------------|--------------| | **target_url** | HTTP/HTTPS endpoint to validate service health | `http://localhost:8080/api/__healthcheck` | Yes | | **port** | TCP port to verify is listening (use `""` to skip) | `3389` or `""` | No | | **retry_delay** | Delay between retries in seconds (default: `1`) | `5` | No | | **max_delay** | Maximum delay for exponential backoff (default: `30`) | `60` | No | | **healthcheck_timeout** | The maximum time allowed for performing the healthcheck curl command (default: `5`) | `10` | No | ### Example Configurations **API Service:** ```bash /usr/bin/healthcheck.sh http://localhost:8080/api/__healthcheck "" 5 60 ``` **RDP Gateway (with port check):** ```bash /usr/bin/healthcheck.sh http://localhost:5555/__healthcheck 3389 1 30 ``` **Agent Service (longer delays):** ```bash /usr/bin/healthcheck.sh http://localhost:4444/__healthcheck "" 30 90 ``` ## Docker Healthcheck Considerations While standard Docker healthcheck parameters (`interval`, `timeout`, `retries`, `start_period`) apply to all services, ensure the Docker `timeout` parameter is not less than the script's internal `healthcheck_timeout`. --- ## Kasm Performance Tuning: Optimizing Resource Utilization # Kasm Performance There are several factors that can influence the performance of a Workspaces session. Performance can refer to compute capacity assigned to a workspace or it could refer to the streaming performance of the session with regards to bandwidth usage or quality of the stream. ## Workspace Settings The individual [workspaces](glossary.mdx#workspace) can be configured for the desired resource utilization of the server. To learn how to configure the individual Workspaces go to [Workspaces](../how-to/workspaces-sessions/container-workspace/workspaces.mdx). To learn how to tune Kasm resources to handle more concurrent sessions, see [Agents](../how-to/infra-autoscale/docker-agent.mdx). ### Minimum Workspace Settings These settings can be used to save the most resources on the server and bandwidth. > - Setting the video settings to low > - disabling audio > - Max resolution of 1024 x 768 > - Firefox only container > - 0.5 core and 768 MB of RAM ### Standard Workspace Settings These settings can be used to provide a good default user experience. > - Setting the video settings to medium > - Enabling Audio > - No Resolution restriction > - 1.5 core and 2 GB of RAM ## KasmVNC Streaming [KasmVNC](https://docs.kasmvnc.com) is used to provide the stream of the remote desktop to the user's browser. There are several factors that can affect streaming quality and bandwidth usage. ### Streaming Mode KasmVNC supports different streaming modes. The following screenshot shows the [Group Setting](../how-to/security/users-groups-mgmt/groups.mdx) `kasmvnc_mode_preference` setting which controls which modes are supported and their order of preference. The screenshot shows the default allow list and preference order. The `JPEG/WEBP (Images)` is the default streaming mode and provides the most compatible solution for both the client and server-side. Generally speaking, however, most modern hardware on both the client and server-side will perform better with h.264 and KasmVNC will automatically fall back to image mode if there is a failure on either side. KasmVNC supports **H.264 (AVC)**, **H.265 (HEVC)**, and **AV1** streaming modes. Each codec can operate in either a **software-encoded** mode (CPU-based, available on all systems) or a **hardware-accelerated** mode backed by **VAAPI** or **NVENC** for improved performance and lower CPU usage. The following streaming modes are available to select, they are shown in the order that they will be attempted using default settings. To override this order you need to select a target group, go to the settings tab, and add a `kasmvnc_mode_preference` setting. Users will be able to switch between streaming modes in the session control panel, if the streaming mode is allowed per the group setting and the backend server and client both support the target streaming mode. With default settings, all streaming modes are allowed, but the connection starts in JPEG/WEBP mode. | Streaming Mode | Default | Description | |--------------------|---------|------------------------------------------------------------------------------------------------| | JPEG/WEBP (Images) | true | Most widely compatible mode, it cannot be disabled, but it can be moved to a lower preference. | | H.264/AVC | true | Includes all h.264 streaming modes that the backend server will support. | | HW H.264/AVC (VAAPI/NVENC) | implicit | Hardware accelerated h.264 encoding using VAAPI or NVENC. Requires supported hardware server-side. | | SW H.264/AVC | implicit | Software based h.264 encoding. This encoder will work on most hardware. | | H.265/HEVC | true | Includes all h.265 streaming modes that the backend server will support. | | HW H.265/HEVC (VAAPI/NVENC) | implicit | Hardware accelerated h.265 encoding using VAAPI or NVENC. Requires supported hardware server-side. | | SW H.265/HEVC | implicit | Software based h.265 encoding. This encoder will work on most hardware. | | AV1 | true | Includes all AV1 streaming modes that the backend server will support. | | HW AV1 (VAAPI/NVENC) | implicit | Hardware accelerated AV1 encoding using VAAPI or NVENC. Requires supported hardware server-side. | | SW AV1 | implicit | Software based AV1 encoding. | The following video demonstrates configuring group-level streaming mode preferences, including priority lists for hardware-accelerated AV1, H.264, and H.265. #### Hardware Accelerated Video Encoding Hardware encoding availability depends on the underlying GPU and driver support. Intel GPUs generally provide the most complete VAAPI support (including AV1 on newer Xe/Arc hardware), AMD GPUs support H.264 and H.265 broadly with more limited AV1 availability on newer generations, and NVIDIA GPUs support hardware encoding through NVENC rather than native VAAPI. For detailed, up-to-date information on supported hardware, drivers, and codec capabilities, refer to the FFmpeg documentation and vendor-specific resources: - [FFmpeg VAAPI Hardware Acceleration](https://trac.ffmpeg.org/wiki/Hardware/VAAPI) - [Intel Media Driver – Supported Platforms](https://github.com/intel/media-driver#supported-platforms) - [Mesa Radeon VAAPI Documentation](https://docs.mesa3d.org/drivers/radeonsi.html#video-acceleration) - [NVIDIA Video Encode and Decode Support Matrix](https://developer.nvidia.com/video-encode-decode-support-matrix) If agent systems have supported hardware, they can be passed into the Workspace containers, KasmVNC will automatically detect and use supported hardware. The following video demonstrates selecting graphics acceleration APIs and hardware-accelerated video encoding methods for a workspace. First check what renderD devices your system has available and take note of what group the renderD device belongs to. ```bash ubuntu@laptop-002:~$ ls -l /dev/dri total 0 drwxr-xr-x 2 root root 120 Jan 13 12:50 by-path crw-rw---- 1 root video 226, 0 Jan 13 12:50 card0 crw-rw---- 1 root video 226, 1 Jan 13 12:50 card1 crw-rw---- 1 root render 226, 128 Jan 13 12:50 renderD128 crw-rw---- 1 root render 226, 129 Jan 13 12:50 renderD129 ``` You can use the utility `vainfo` to check if an Intel or AMD device is supported by VAAPI. `vainfo` does not validate NVENC support. This example system has an Intel GPU and NVIDIA GPU. The output shows that the Intel GPU is supported by VAAPI while the NVIDIA GPU is not supported by VAAPI. ```bash ubuntu@laptop-002:~$ sudo vainfo --display drm --device /dev/dri/renderD128 libva info: VA-API version 1.20.0 libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so libva info: Found init function __vaDriverInit_1_20 libva info: va_openDriver() returns 0 vainfo: VA-API version: 1.20 (libva 2.12.0) vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.1.0 () vainfo: Supported profile and entrypoints VAProfileMPEG2Simple : VAEntrypointVLD VAProfileMPEG2Main : VAEntrypointVLD VAProfileH264Main : VAEntrypointVLD VAProfileH264Main : VAEntrypointEncSliceLP VAProfileH264High : VAEntrypointVLD VAProfileH264High : VAEntrypointEncSliceLP VAProfileJPEGBaseline : VAEntrypointVLD VAProfileJPEGBaseline : VAEntrypointEncPicture VAProfileH264ConstrainedBaseline: VAEntrypointVLD VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP VAProfileVP8Version0_3 : VAEntrypointVLD VAProfileHEVCMain : VAEntrypointVLD VAProfileHEVCMain10 : VAEntrypointVLD VAProfileVP9Profile0 : VAEntrypointVLD VAProfileVP9Profile2 : VAEntrypointVLD ubuntu@laptop-002:~$ sudo vainfo --display drm --device /dev/dri/renderD129 libva info: VA-API version 1.20.0 libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/nvidia_drv_video.so libva info: va_openDriver() returns -1 vaInitialize failed with error code -1 (unknown libva error),exit ``` You will also need to know the group number of the group that owns the device, in this example it is the `render` group. On this system the group number is `993`. ```bash ubuntu@laptop-002:~$ getent group render render:x:993: ``` To pass the `/dev/dri/renderD128` device into a user Workspaces, navigate to the Admin panel in Kasm Workspaces, click on Workspaces, find the target Workspace Image and click Edit. Scroll down to the **Docker Run Configuration Override** setting and in the appropriate device mapping and group_add setting. The below example passes in the device `/dev/dri/renderD128` and adds group 993 to the resulting containers. ```json { "hostname": "kasm", "devices": [ "/dev/dri/renderD128:/dev/dri/renderD128:rw" ], "group_add": [ "993" ] } ``` All agents that this Workspaces can run in must be identical with respect to the device location and group id the device is owned by. #### Bandwidth and CPU Utilization Tests All of the following tests were performed on medium stream quality, which is capped at 24 fps for each streaming mode. All streaming modes use negligable bandwidth and CPU when no movement occurs on the screen. **Playing Video Fullscreen (Software Encoding)** This test is playing video full screen within the session. The resolution is 1080p for both the video being played and the user's KasmVNC session. This test was performed on a server with an AMD EPYC 7J13 CPU without support for hardware based encoding. | Streaming Mode | KasmVNC CPU | Client CPU | Frame Rate | Bandwidth | |----------------|-------------|------------|------------|--------------| | SW H.264/AVC | 74% | 3.5% | 21 fps | 14.35 MBit/s | | SW H.265/HEVC | 230% | 3.5% | 13.2 fps | 6.53 MBit/s | | JPEG/WEBP | 64% | 18% | 21 fps | 33.48 MBit/s | **Playing Video Fullscreen (Hardware Encoding)** This test is playing video full screen within the session. The resolution is 1080p for both the video being played and the user's KasmVNC session. This test was performed on a server with an i5-10400H CPU using the Intel embedded GPU. | Streaming Mode | KasmVNC CPU | Client CPU | Frame Rate | Bandwidth | |----------------------|-------------|------------|------------|--------------| | HW H.264/AVC (VAAPI) | 43% | 1.5% | 22 fps | 7.78 MBit/s | **Medium movement (Software Encoding)** This test running glxgears in full screen, which generates moderate movement with a lot of solid colors, providing a good facsimile to users using browsers or office applications within a session. The resolution is 1080p for both the video being played and the user's KasmVNC session. This test was performed on a server with an AMD EPYC 7J13 CPU without support for hardware based encoding. | Streaming Mode | KasmVNC CPU | Client CPU | Frame Rate | Bandwidth | |----------------|-------------|------------|------------|--------------| | SW H.264/AVC | 69% | 3.5% | 24 fps | 9.85 MBit/s | | SW H.265/HEVC | 260% | 3.5% | 21.6 fps | 12.69 MBit/s | | JPEG/WEBP | 64% | 18% | 24 fps | 8.22 MBit/s | **Lowest Bandwidth Utilization** This tests uses the lowest quality settings available to achieve the lowest bandwidth utilization, for situations where users may be connecting over low bandwidth links. The `Low` streaming quality was used. The test was playing a 1080p resolution video in full screen. | Streaming Mode | KasmVNC CPU | Client CPU | Frame Rate | Bandwidth | |----------------|-------------|------------|------------|--------------| | SW H.264/AVC | 48% | 3.5% | 20 fps | 1.01 MBit/s | | HW H.264/AVC (VAAPI) | 36% | 1.5% | 20 fps | 731 KBit/s | | SW H.265/HEVC | 175% | 3.5% | 21.6 fps | 531 KBit/s | | JPEG/WEBP | 72% | 4.7% | 24 fps | 9.82 MBit/s | **Conclusion** From these test results you can see that hardware based h.264 encoding provides the highest compression at the lowest CPU utilization on the server-side. H.265 encoding provides the lowest bandwidth usage on low quality settings, at the cost of roughly 3 times the CPU utilization of h.264. The default JPEG/WEBP stream mode generally consumes more bandwidth, but has the broadest compatibility for both clients and servers. ### GPU Passthrough To support hardware based acceleration of h.264 and h.265 video encoding, a GPU must be passed through that supports VAAPI or NVENC. Intel and AMD based GPUs generally support VAAPI. NVIDIA GPUs use NVENC and require the NVIDIA container runtime. See our [Intel/AMD GPU Guide](../tutorials/install/manual-intel-amd.mdx) and [NVIDIA GPU Guide](../tutorials/install/gpu.mdx) for more. --- ## Licensing: Community, Starter & Activation export const FeatureCard = ({ title, description, bgColor = '#ffffff', borderColor = '#e5e7eb', textColor = '#2A2D31', }) => { return ( {title} {description} ); }; # Licensing Kasm Workspaces provides licensing options for evaluation and production deployments with different user, capacity, procurement, and operational requirements. Community Edition lets teams validate Kasm Workspaces in their own environment before purchasing. Commercial licensing is available through Named User and Concurrent Session models, allowing organizations to align licensing with actual usage. ## Choose the Licensing Model That Fits Your Environment Kasm Workspaces provides licensing options for evaluation, dedicated user access, and shared session capacity. Choose the model that best aligns with your deployment stage and usage pattern. For non-commercial use Free for testing, nonprofit, and eligible non-commercial use. Best for: Validating architecture, application compatibility, and operational fit before purchasing. Capacity model: Up to 5 concurrent sessions and community support through the public issue tracker. } bgColor="#EFEFEF" textColor="#2A2D31" /> For consistent, predictable access Licensed by the number of registered users. Best for: A defined group of users who access Kasm Workspaces regularly. Capacity model: Scales with the number of licensed users. } bgColor="#183E52" borderColor="#183E52" textColor="#ffffff" /> For flexible, shared access Licensed by the number of sessions running at the same time. Best for: Contractors, shift workers, occasional users, shared services, or distributed teams. Capacity model: Scales with peak concurrent session demand. } bgColor="#C2E5F4" borderColor="#C2E5F4" textColor="#2A2D31" /> Requests for Kasm Workspaces pricing can be submitted at [kasm.com/quote](https://kasm.com/quote). ## Buying a License There are two paths to a license, depending on how your organization handles procurement. ### Purchase through instant checkout This path is fastest when a purchase does not need to route through a separate invoicing process. 1. Use our [checkout process](https://kasm.com/checkout.html), which issues an [activation key](glossary.mdx#activation-key) immediately on completion. 2. Select the license type and number of users, and choose whether to add PureVPN egress. Click **CHECKOUT**. 3. Enter your email and click **SEND EMAIL VERIFICATION**. 4. Kasm Technologies sends a one time verification code to that email address. 5. Enter the code, and the credit card information section will appear. 6. Enter your credit card information, review and accept the EULA, and click **COMPLETE CHECKOUT**. ### Request an invoice If your purchasing process requires a formal invoice rather than a card transaction, request a [quote](https://kasm.com/quote.html) instead. This routes the purchase through our standard invoicing process rather than instant checkout. ## Adding a license If you have an activation key it can be passed to the installation script and activation will be completed on your behalf as part of the install. Create a file for the activation key e.g. `activation_key.txt` and paste in the activation key you received in your confirmation email. When running the install.sh use the parameter `-a or --activation-key-file` so your command might look something like this `sudo bash kasm_release/install.sh -a activation_key.txt`. This will not work with an offline air-gapped install, as Kasm Workspaces must contact an activation server to complete licensing your installation. In a multi server install this option only applies to the database role. To license an existing Kasm Workspaces installation, you will need the activation key provided at the time of purchase. ### Getting the license key for an offline Kasm Workspaces installation If your installation does not have outbound internet access, use the [Kasm Workspaces activation tool](https://kasm.com/activate.html) to convert your activation key into a license key before continuing. This keeps the activation step self-contained even when the server itself is air-gapped. 1. Retrieve the [activation key](glossary.mdx#activation-key) you received at the time of purchase. 2. Retrieve your [Installation ID](glossary.mdx#installation-id) from the Kasm Workspaces installation: 1. Navigate to the [web application](glossary.mdx#web-application). 2. Navigate to **Diagnostics** -> **System Info** and locate the entry for **Installation ID**. 3. Navigate to the [Kasm Workspaces activation tool](https://kasm.com/activate.html). 4. Paste in the [Installation ID](glossary.mdx#installation-id) and the [activation key](glossary.mdx#activation-key). 5. Click **Submit**. ### Licensing the Kasm Workspaces installation 1. Navigate to the [web application](glossary.mdx#web-application). 2. Navigate to **Diagnostics** -> **System Info** -> **Licenses** tab. 3. Select **Add License** from the Licenses tab. 4. Copy the activation key or license key into the box and click **Add**. 5. The license information appears in the Licenses card. ## Programmatically applying a license For teams that manage infrastructure through automation rather than manual UI steps, licensing fits into the same deployment pipeline as the rest of the install. This applies to systems with outbound access to the Kasm license servers at `https://license.kasmweb.com`. ### Programmatically apply a license during install Use this approach to activate a deployment as part of installation. For a multi-server installation, apply it when installing the **Database Role**. See the [Multi-Server Installation Guide](../tutorials/install/multi-server-install.mdx#installation-guide) for more detail. 1. Save the **Activation Key** to a file on the deployment server (for example, `/tmp/activation_key.txt`). 2. During install, add the `--activation-key-file` argument pointing to that file: ```bash sudo bash /tmp/kasm_release/install.sh --activation-key-file /tmp/activation_key.txt ``` 3. Log into the Kasm UI as an administrator to confirm the key applied. 4. Navigate to **Diagnostics** -> **System Info** -> **Licenses** tab. 5. The license should be visible. ### Programmatically apply a license after install Use this approach to license an existing deployment with an **Activation Key**, using the [Licensing Developer API Endpoints](developer-api.mdx#licensing). 1. Log into the Kasm UI as an administrator. 2. Select **Settings** -> **Developers** and click **Add API Key**. Fill out the form to generate an `API_KEY` and `API_KEY_SECRET`. 3. Call the [/api/public/activate](developer-api.mdx#licensing) endpoint. A `curl` example: ```bash curl -X POST -H "Content-Type: application/json" -d '{ "api_key": "{{api key}}", "api_key_secret": "{{api key secret}}", "activation_key": "-----BEGIN ACTIVATION KEY-----eyJ0eXAiOiJ-----END ACTIVATION KEY-----" }' https:///api/public/activate ``` Kasm partners may be issued special **Activation Keys** that support the `seats` and `issued_to` fields in this call. When an **Activation Key** is purchased, its entitlement carries a high water mark of **seats** (for example, 100 concurrent users or 500 concurrent sessions). Those seats can be split across multiple Workspaces installations if needed. One deployment might use 25 concurrent users while another uses 40, for instance. The `issued_to` field is informational and can help attribute a license key in later reporting. To split seats this way, specify the number in the API call: ```bash curl -X POST -H "Content-Type: application/json" -d '{ "api_key": "{{api key}}", "api_key_secret": "{{api key secret}}", "seats": 10, "issued_to": "Environment X" "activation_key": "-----BEGIN ACTIVATION KEY-----eyJ0eXAiOiJ-----END ACTIVATION KEY-----" }' https:///api/public/activate ``` Administrators can call the API multiple times to add more seats to an existing deployment as needs grow. 4. Log into the Kasm UI as an administrator to confirm the key applied. 5. Navigate to **Diagnostics** -> **System Info** -> **Licenses** tab. 6. The license should be visible. --- ## Kasm Workspaces: Product Maintenance Lifecycle # Product Maintenance Lifecycle The Kasm Workspaces Product Maintenance Lifecycle defines how long each release is maintained and supported. This lifecycle ensures customers have a clear understanding of when updates, bug fixes, and technical assistance will be available for specific versions of Kasm Workspaces. ## Version Lifecycle Matrix The table below lists currently maintained and supported versions of Kasm Workspaces, along with their respective General Availability (GA), End of Maintenance (EOM), and End of Support (EOS) dates. --- ## 1.10.0 # What's new in Kasm 1.10.0 --- ## 1.11.0 # What's new in Kasm 1.11.0 --- ## 1.12.0 # What's new in Kasm 1.12.0 --- ## 1.13.0 # What's new in Kasm 1.13.0 --- ## 1.13.1 # What's new in Kasm 1.13.1 --- ## 1.14.0 # What's new in Kasm 1.14.0 --- ## 1.15.0 # What's new in Kasm 1.15.0 --- ## 1.16.0 # What's new in Kasm 1.16.0 --- ## 1.16.1 # What's new in Kasm 1.16.1 --- ## 1.17.0 # What's new in Kasm 1.17.0 --- ## 1.18.0 # What's new in Kasm 1.18.0 --- ## 1.18.1 # What's new in Kasm 1.18.1 --- ## 1.19.0 # What's new in Kasm 1.19.0 --- ## 1.2.0 # What's new in Kasm 1.2.0 --- ## 1.3.0 # What's new in Kasm 1.3.0 --- ## 1.4.0 # What's new in Kasm 1.4.0 --- ## 1.5.0 # What's new in Kasm 1.5.0 --- ## 1.6.0 # What's new in Kasm 1.6.0 --- ## 1.7.0 # What's new in Kasm 1.7.0 --- ## 1.8.0 # What's new in Kasm 1.8.0 --- ## 1.9.0 # What's new in Kasm 1.9.0 --- ## 1.8 # What's new in Kasm Desktop Service - Linux, 1.8 --- ## 1.8(Windows-desktop-service) # What's new in Kasm Desktop Service - Windows, 1.8 --- ## Reporting, Logging & SIEM Integration # Reporting and Logging Kasm offers built in reporting and logging dashboards. The logging settings can be changed in the Settings dashboard and more information on those can be found [Here](settings.mdx#logging). By default the logs are retained for one week which would be the maximum amount of time to see the reporting in the dashboard and logs. For large production deployments, it is recommended that administrators utilize an external logging / SIEM solution and ingest Kasm's [File Based Logs](#file-based-logs) . ## Dashboard The reports show the last day of data by default but can be changed by the Time Period dropdown menu. ![Report Options](/img/reporting/report_options.webp) The Real-Time option will display the last hour of data and refresh the data every five minutes. this is the only option with automatic refresh enabled. Custom will open a custom time selection menu that allows specific time frames and auto refresh times to be selected. Select custom from the Time Period dropdown and configure the time period needed in the pop up. ![Custom Time Range](/img/reporting/custom_modal.webp) ## Logging Dashboard The logging dashboard displays logs collected from the entire application. These can be searched separately and split up by process or host. Basic log options are logging level, limit, which is the amount of logs returned, and Time, which is in minutes from the current time. ![Default Log Options](/img/reporting/log_options.webp) Selecting the more filters option will display advanced log filters. The time selection will be set by custom start and end dates and the logs can be filtered by application, process and host. The logs may also be filtered using a username or message. i.e. putting "destroyed" in the search message box will return the logs of the destroyed sessions. ![Advanced Log Options](/img/reporting/log_options_2.webp) You can also click on a single entry to get more options. If you click on the **Export** button you will get options to provide context for the item you have selected. The details will be zipped up into an AES256 encrypted zip file with a password of your choosing, that you will need to provide in order to extract, and will include up to 3 files. 1. `export.json` This includes the log entry selected, the options chosen and the username. 2. `context.json` All the log entries (including the selected entry) in the time frame chosen. 3. `system_info.json` This is an optional file that is only included if the option is checked when exporting As the zip file utilizes AES256 encryption, a utility such as 7zip is needed to extract the data. This is because many zip utilities built into operating systems like Windows and MacOS do not support AES256 for zip files. ![Context options for exporting](/img/reporting/log-context.webp) ## File Based Logs Each role service emits a set of enriched json formatted logs that can be ingested into a SIEM solution of choice. - `/opt/kasm/current/log/agent_json.log` - `/opt/kasm/current/log/api_server_json.log` - `/opt/kasm/current/log/manager_api_server_json.log` - `/opt/kasm/current/log/web_filter_access_json.log` - `/opt/kasm/current/log/share_json.log` - `/opt/kasm/current/log/nginx/access_json.log` ### Metrics Important application log events will include an attribute `metric_name`. This message is likely something helpful that can be used for visualization and analysis. A few examples include: - `provision.create` - `provision.destroy` - `provision.cast.create` - `account.login.successful` - `provision.destroy` - `account.login.failed_invalid_password` - `account.login.failed_ldap_error` - `scaling.status.resources` - `scaling.provider.aws.status` Many metric logs contain additional data useful for analysis. Administrators can inspect the logs for details. ### Common Attributes Where possible and applicable, the application logs will emit additional attributes Administrators may find useful for context. - `message` - `levelname` - `request_ip` - `user_agent` - `server_id` (Agent ID) - `kasm_user_id` - `kasm_user_name` - `kasm_image_id` - `kasm_image_name` - `kasm_image_friendly_name` - `kasm_id` --- ## Server Settings Configuration # Server Settings Server settings are settings that are global, as opposed to those that are per user group. They can be found in the Settings tab on the left side of the Administrative Web UI. In most cases, a change to a global setting requires a restart of some or all components. For a single server environment that would mean just restarting the kasm services on the server. For distributed environments you may only need to restart certain components. The tables below indicate which components need restarted for each setting. The following shows how to restart all services or individual services. ```yml # restart all services on a server cd /opt/kasm/bin ./stop ./start # restart individual components sudo docker restart kasm_agent sudo docker restart kasm_api sudo docker restart kasm_manager sudo docker restart db sudo docker restart proxy sudo docker restart kasm_guac sudo docker restart rdp_gateway sudo docker restart kasm_rdp_https_gateway ``` **Note**: Kasm Workspaces also provides a `restart` script. Use the --help flag with the restart and stop scripts in `/opt/kasm/bin` to view all available options. ## Authentication | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Anonymous User Expiration** | Anonymous user accounts are deleted from the system after the defined number of hours. Set this value to 0 to disable automatic deletion. | None | | **Enable Kasm Authorization** | Requires client requests to the Kasm for content such as downloads and uploads to be authenticated with the user's current session token. | None | | **Enable SAML** | Enables Single Sign on with SAML 2.0 for users. | None | | **Kasm Authorization Domain** | Override the domain used in the Kasm session cookie. The default value will use the domain name the user request came in on, which will fit most use cases. Statically setting the domain name will ensure your Workspaces deployment cannot be proxied under different domain names. | None | | **Login Assistance** | An optional link to display on the login page that will direct users to another site for login assistance. | None | | **Max Login Attempts** | The number of invalid login attempts before an account is locked out. This setting only applies to local accounts. | None | | **Notice Message** | A login banner message to show to users at the login page. | None | | **Notice Title** | The title of the login banner to show to users at the login page. | None | | **Component Registration Token** | Used for multi-server deployments to register new components to the deployment. | None | | **Same Site Cookie Policy** | Configures the SameSite attribute for the Set-Cookie HTTP response headers. Valid options are Lax, Strict and None. | API | | **Session Lifetime** | The number of seconds a session token is valid for. | API | | **Token Drift** | How many minutes plus and minus to allow TOTP tokens to drift from the server's UTC time. | API | | **WebAuthn Request Lifetime** | The number of seconds a WebAuthn Authenticator or Registration session is valid for. | API | | **API Token Lifespan (seconds)** | Lifespan of the component auth tokens used for back-end requests, in seconds. | None | | **API Token Refresh Leeway (seconds)** | Additional refresh window for API tokens, in seconds. | None | ## CAPTCHA Settings The CAPTCHA settings allow administrators to select which type of CAPTCHA they want to use if they choose to use CAPTCHA. This is used on session casting. | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **CAPTCHA Selection** | Choose which type of CAPTCHA to use, selecting one will automatically attempt to set the API URL. | None | | **CAPTCHA API URL** | The API URL to use for verifying results, the correct URL should automatically be set when a CAPTCH type is selected. | None | | **CAPTCHA Private Key** | The CAPTCHA Private Key, | None | | **CAPTCHA Site Key** | The CAPTCHA Site Key. | None | ## Password Requirements {#password-requirements} Controls password complexity for local accounts. | **Name** | **Description** | **Default** | | --- | --- | --- | | **Minimum Password Length** | Minimum number of characters required. | 8 | | **Require Lowercase Letter** | Password must contain at least one lowercase letter (a–z). | Enabled | | **Require Numbers** | Password must contain at least one digit (0–9). | Enabled | | **Require Special Characters** | Password must contain at least one special character (`! # $ % ^ & * @`). | Enabled | | **Require Uppercase Letter** | Password must contain at least one uppercase letter (A–Z). | Enabled | The **Force Password Reset** toggle appears at the bottom of this group. When saved, all local users will be required to set a new password on next login. This action only affects local accounts. Enable it after tightening policy to ensure existing passwords comply with the new rules—changes may take **up to 30 seconds** to be reflected. ## Connections | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Default VM RDP Connection Settings** | See detailed description below. | API | | **Default VM SSH Connection Settings** | See detailed description below. | API | | **Default VM VNC Connection Settings** | See detailed description below. | API | | **RDP config file expiration** | How long the authentication token in the generated RDP file is valid. | API | | **RDP Private Key** | This key is used to generate the JWT tokens used for authenticating the RDP file by the RDP Gateway. | API | | **RDP Public Cert** | This certificate is used to validate the JWT tokens used for authenticating the RDP file by the RDP Gateway. | API | | **RDP File Signing Private Key** | The private key that is used to sign the RDP file. | API | | **RDP File Signing Cert** | The certificate used to verify the signed RDP file has not been modified, this is also used to set the trusted publishers setting in microsoft group policy. | API | ### Default VM RDP Connection Settings This Kasm setting is used to define a series of connection parameters for connecting to external RDP/KasmVNC endpoints. It is defined as a single JSON string, a default example is: ```json { "guac": { "type": "rdp", "settings": { "security": "any", "ignore-cert": true, "enable-font-smoothing": true, "enable-wallpaper": true, "enable-theming": true, "enable-full-window-drag": false, "enable-menu-animations": false, "resize-method": "display-update", "server-layout": "en-us-qwerty", "printer-name": "Kasm" } }, "kasm_svc": { "port": 4902 } } ``` A break-down of the [Guacamole](https://guacamole.apache.org/) (guac/rdp) settings can be found below: | **Name** | **Description** | | --- | --- | | **security** | The security mode to use for the RDP connection. This mode dictates how data will be encrypted and what type of authentication will be performed, if any. Options any,nla,nla-ext,tls,vmconnect,rdp. | | **ignore-cert** | If set to “true”, the certificate returned by the server will be ignored, even if that certificate cannot be validated. | | **enable-font-smoothing** | If set to “true”, text will be rendered with smooth edges. Text over RDP is rendered with rough edges by default. | | **enable-wallpaper** | If set to “true”, enables rendering of the desktop wallpaper. By default, wallpaper will be disabled, such that unnecessary bandwidth need not be spent redrawing the desktop. | | **enable-theming** | If set to “true”, enables use of theming of windows and controls. By default, theming within RDP sessions is disabled. | | **enable-full-window-drag** | If set to “true”, the contents of windows will be displayed as windows are moved. By default, the RDP server will only draw the window border while windows are being dragged. | | **enable-menu-animations** | If set to “true”, menu open and close animations will be allowed. Menu animations are disabled by default. | | **resize-method** | The method to use to update the RDP server when the width or height of the client display changes. Options display-update,reconnect. | | **fixed-display-size** | If this is set to "true", the resolution of the RDP session will be fixed to the resolution specified by the provided width and height settings. | | **server-layout** | The server-side keyboard layout. Options da-dk-qwerty,de-ch-qwertz,de-de-qwertz,en-gb-qwerty,en-us-qwerty,es-es-qwerty,fr-ch-qwertz,fr-fr-azerty,it-it-qwerty,ja-jp-qwerty,pt-br-qwerty,sv-se-qwerty,tr-tr-qwerty. | | **timezone** | This parameter allows control of the timezone that is sent to the server over the RDP connection, which will change the way local time is displayed on the server when that server is part of a RDS cluster. Kasm will auto fill in this parameter based on the Kasm Session Timezone [user profile setting](../tutorials/user-guide/profile.mdx) when not overridden in the [server configuration](../how-to/infra-autoscale/servers.mdx) or this global setting. | | **printer-name** | The name of the redirected printer device that is passed through to the RDP session. The final name displayed in all printing related settings will be in the format `printer_name (redirected session_id)`. This is a naming convention imposed by Windows to indicate that it is a redirected printer, with `session_id` denoting the specific session the printer is associated with. | Additional Guacamole connection settings can be found [here](https://guacamole.apache.org/doc/1.5.5/gug/configuring-guacamole.html#rdp). ##### Examples for Keyboard Layout setup ###### Example 1 When using an RDP connection to a Windows VM configured with a German keyboard layout, the correct way to inform Guacamole is by setting server-layout to `de-de-qwertz`. This ensures that Guacamole interprets the client’s keycodes according to the German layout expected by the server, regardless of the client’s actual keyboard. ```json { "guac": { "type": "rdp", "settings": { "server-layout": "de-de-qwertz" } } } ``` This allows users with different local layouts (such as US or UK keyboards) to connect and still have keys correctly mapped according to the German layout used on the remote system. ###### Example 2 In contrast, if using a general VNC connection, Guacamole relies on the keyboard-layout setting to interpret the key presses as if the client is using a specific layout. For example, to interpret the keyboard input as coming from a Swedish keyboard, you would configure: ```json { "guac": { "type": "rdp", "settings": { "keyboard-layout": "sv-se-qwerty" } } } ``` This is useful when the remote environment does not dictate the keyboard mapping, and the desired behavior is to match the client’s keyboard layout. **Note**: Administrators can explicitly define display-related settings such as `dpi`, `width`, and `height` in the `rdp_thick_client_properties`. If these values are not provided, the system will automatically populate them based on the user's display scaling preferences in the browser at session launch time. However, its observed that many RDP client applications ignore the specific scaling in favor of dynamic DPI/resolution sync. #### RDP Session Watermarking Kasm supports watermarking RDP sessions with customizable text overlays as well as images. The watermark settings are configured within the `kasm_svc` section of the VM RDP connection settings JSON. The connection settings can be overridden at the [Server](../how-to/infra-autoscale/servers.mdx#server-configuration) level or in [AutoScale Configs](../how-to/infra-autoscale/autoscale/infrastructure-components/autoscale-config-server#autoscale-settings-for-server-pool) for auto-scaled servers. The watermark feature is limited to configurations where the username is known at session creation time. This includes [Static Credentials](../how-to/workspaces-sessions/server-workspace/windows/authentication.mdx#static-credentials), [Single Sign-On with Static Local Accounts](../how-to/workspaces-sessions/server-workspace/windows/authentication.mdx#single-sign-on-with-static-local-accounts), [Single Sign-On with Dynamic Local Accounts](../how-to/workspaces-sessions/server-workspace/windows/authentication.mdx#single-sign-on-with-dynamic-local-accounts), and [Single Sign-On with Active Directory](../how-to/workspaces-sessions/server-workspace/windows/authentication.mdx#single-sign-on-with-static-local-accounts). There are limited UI elements that may appear over the watermark. At this time, the only known UI elements known to appear over the watermark is the start menu and the Task Manager. The following is an example of a valid watermark configuration: ```json { "guac": { "type": "rdp", "settings": { "security": "any", "ignore-cert": true, "enable-font-smoothing": true, "enable-wallpaper": true, "enable-theming": true, "enable-full-window-drag": false, "enable-menu-animations": false, "resize-method": "display-update", "server-layout": "en-us-qwerty", "printer-name": "Kasm" } }, "kasm_svc": { "port": 4902, "watermark": { "text": "${KASM_USER} at %H:%M on %d/%m/%Y", "tint": "255,0,255,255", "repeat-spacing": 100 } } } ``` A break-down of the allowed watermark settings can be found below: | **Setting** | **Default** | **Description** | | --- | --- | --- | | **text** | | The text content of the watermark can include the following session variables: `${KASM_USER}`, `${KASM_USER_ID}`, `${KASM_ID}`, `${WINDOWS_USER}` as well as time formatting using the format %H:%M:%S. | | **timezone** | | The timezone to be used for time formatting, ie. "America/New_York". | | **font** | Arial | The font family to use for the watermark text. | | **font-size** | 20 | The font size in points for the watermark text. | | **tint** | "255,255,255,255" | The color value for the watermark in "r,g,b,a" format where each value is between 0 and 255. | | **opacity** | 1.0 | The opacity of the watermark image in range 0.0 to 1.0. | | **location** | center | The x,y coordinate location for the watermark in "x,y" format. The default value is "center". However, defining `repeat-spacing` will overwrite this default, changing the placement of the watermark accordingly. | | **rotation** | | The rotation in degrees for the watermark text in range -180 to 180. | | **repeat-spacing** | | The spacing in pixels to repeat the watermark text across the session both horizontally and vertically. | | **image** | | The absolute path to the image file to be displayed as the watermark | #### Setting RDP Thick Client Properties All supported RDP file parameters are documented in Microsoft's [RDP file reference](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/rdp-files), The following is an example of a valid `connection_info` JSON object that can be used to set RDP client fields: ```json { "guac": { "type": "rdp", "settings": { "security": "any", "ignore-cert": true, "enable-font-smoothing": true, "enable-wallpaper": true, "enable-theming": true, "enable-full-window-drag": false, "enable-menu-animations": false, "resize-method": "display-update", "server-layout": "en-us-qwerty", "printer-name": "Kasm", "remote-app": "||KasmLauncher", "remote-app-args": "\"C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE\" C:\\Users\\Public\\Documents\\example.xlsx" } }, "rdp_thick_client_properties": { "connection type": 6, "networkautodetect": 1, "bandwidthautodetect": 1, "screen mode id": 2, "singlemoninwindowedmode": 1, "keyboardhook": 2, "disable full window drag": 1, "disable menu anims": 1, "bitmapcachepersistenable": 1, "session bpp": 32, "dynamic resolution": 1, "autoreconnection enabled": 1, "videoplaybackmode": 1, "allow desktop composition": 1, "disable themes": 0, "allow font smoothing": 1, "smart sizing": 1, "desktopscalefactor": 100 }, "kasm_svc": { "port": 4902 } } ``` The `rdp_thick_client_properties` section within `connection_info` allows customization of low-level RDP client parameters to fine-tune performance, display, and user experience. | **Field Name** | **Default** | **Description** | |---|---|---| | connection type | 6 | The type of connection (e.g., 6 for RDP). | | networkautodetect | 1 | Enables automatic network detection. | | bandwidthautodetect | 1 | Enables automatic bandwidth detection. | | screen mode id | 2 | screen mode id setting (1 = windowed, 2 = full screen). | | singlemoninwindowedmode | 1 | Enables single monitor when in windowed mode. | | keyboardhook | 2 | Controls keyboard shortcut handling behavior. | | disable full window drag | 1 | Disables full window drag visuals to improve performance. | | disable menu anims | 1 | Disables menu animations to reduce resource usage. | | bitmapcachepersistenable | 1 | Enables persistent bitmap caching between sessions. | | session bpp | 32 | Bits-per-pixel for session color depth (e.g., 16, 24, 32). | | dynamic resolution | 1 | Enables dynamic adjustment of session resolution. | | autoreconnection enabled | 1 | Automatically reconnects the session if the connection drops. | | videoplaybackmode | 1 | Enables optimized video playback mode. | | allow desktop composition | 1 | Enables desktop composition (Aero effects) if supported. | | disable themes | 0 | If set to 1, disables themes; 0 leaves them enabled. | | allow font smoothing | 1 | Enables font smoothing for better text rendering. | | smart sizing | 1 | Enables the local device scaling the content of the remote session to fit the window size. | | desktopscalefactor | 100 | Specifies the scale factor of the remote session to make the content appear larger. | **Note**: The `desktopscalefactor` property is being deprecated and will soon be unavailable as informed by Microsoft Support. ##### Fields Overridden by Kasm Group Settings Some RDP parameters are automatically overridden by Kasm Group Settings and cannot be set manually in the `connection info` object. These ensure consistent security and policy enforcement across sessions. These include: | **Setting** | **Description** | **Kasm Group Setting Key** | |---|---|---| | full address | Target server address | `connection_proxy_address` | | username | RDP username | Derived from `authenticationtoken` | | domain | RDP domain | Derived from `authenticationtoken` | | use multimon | Multi-monitor support | `control_panel.show_display_manager` | | drivestoredirect | Local drive redirection | `allow_kasm_rdp_map_local_drives` | | redirectsmartcards | Smart card redirection | `allow_kasm_smart_card_passthrough` | | audiocapturemode | Microphone support | `allow_kasm_microphone` | | camerastoredirect | Webcam support | `allow_kasm_webcam` | | redirectclipboard | Clipboard redirection | `allow_kasm_clipboard_up/down` | | redirectprinters | Printer redirection | `allow_kasm_printing` | | redirectwebauthn | WebAuthn redirection | `allow_kasm_rdp_webauthn_passthrough` | ### Default VM VNC Connection Settings This Kasm setting is used to define a series of connection parameters for connecting to external VNC endpoints. It is defined as a single JSON string, a default example is: ```json { "guac": { "type": "vnc", "settings": { "autoretry": 5, "color_depth": 32 } } } ``` A break-down of the [Guacamole](https://guacamole.apache.org/) (guac/vnc) settings can be found below: | **Name** | **Description** | | --- | --- | | **hostname** | The hostname or IP address of the VNC server. | | **port** | The port the VNC server is listening on. | | **autoretry** | The number of times to retry connecting before returning an error. | | **swap-red-blue** | Boolean that will swap red and blue colors to correct display colors being swapped. | | **cursor** | Set to "remote" to have the mouse pointer rendered on the remote server. | | **encodings** | A space-delimited list of VNC encodings to use. | | **read-only** | If set to “true”, the vnc connection made will be read-only, input will not be accepted. | Additional Guacamole connection settings can be found [here](https://guacamole.apache.org/doc/1.5.5/gug/configuring-guacamole.html#vnc). ### Default VM SSH Connection Settings This Kasm setting is used to define a series of connection parameters for connecting to external SSH endpoints. It is defined as a single JSON string, a default example is: ```json { "guac": { "type": "ssh", "settings": { "font-size": "11", "color-scheme": "gray-black", "font-name": "monospace", "scrollback": "1000" } } } ``` A break-down of the [Guacamole](https://guacamole.apache.org/) (guac/ssh) settings can be found below: | **Name** | **Description** | | --- | --- | | **hostname** | The hostname or IP address of the SSH server. | | **port** | The port the SSH server is listening on. | | **host-key** | The known hosts entry for the SSH server. This parameter is optional, and, if not provided, no verification of host identity will be done. | | **server-alive-interval** | By default the SSH client does not send keepalive requests to the server. This parameter allows you to configure the the interval in seconds at which the client connection sends keepalive packets to the server. | | **color-scheme** | The color scheme to use for the terminal emulator used by SSH connections. For details on each option see the Guacamole documentation at the link below. | | **font-name** | The name of the font to use. | | **font-size** | The font size to use in points. | | **scrollback** | The maximum number of rows to allow within the terminal scrollback buffer. | | **command** | The command to execute over the SSH session, if any. This parameter is optional. If not specified, the SSH session will use the user's default shell. | | **locale** | This parameter allows control of the specific locale to request for the SSH session. This parameter is optional and may be any value accepted by the LANG environment variable of the SSH server. Kasm will auto fill in this parameter based on the Kasm Session Language [user profile setting](../tutorials/user-guide/profile.mdx) when not overridden in the [server configuration](../how-to/infra-autoscale/servers.mdx) or this global setting. | | **timezone** | This parameter allows control of the timezone that is sent to the server over the SSH connection, which will change the way local time is displayed on the server. Kasm will auto fill in this parameter based on the Kasm Session Timezone [user profile setting](../tutorials/user-guide/profile.mdx) when not overridden in the [server configuration](../how-to/infra-autoscale/servers.mdx) or this global setting. | Additional Guacamole connection settings can be found [here](https://guacamole.apache.org/doc/1.5.0/gug/configuring-guacamole.html#ssh). ## Egress Plugin The Egress Plugin settings are only applicable when a license has been applied to Kasm Workspaces that includes seats for an Egress Plugin. | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Egress Plugin Update Check** | Allow for Egress Plugins to check in to Update Egress Gateways and Egress Accounts. | None | | **Egress Plugin Update URL** | The URL Used to Update Egress Gateways and Egress Accounts associated with an Egress Plugin. | None | ## Experimental Features By enabling this setting, you will be enabling Experimental Kasm features within your platform. These features have been developed by Kasm but may not be fully productized at the time of addition to the platform. If an experimental feature has a configuration, turning off the experimental features flag will disable those configs. After re-enabling experimental features you would need to re-enable the config as well. | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Enable Experimental Features** | Whether to enable experimental features or not | None | ## Workspaces | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Add Workspaces To Default Group** | Automatically add workspaces to default group when new images are added. | API | | **Default CPU Allocation Method** | Sets the default cpu allocation strategy for container images. Valid options are `Quotas` or `Shares`. See [cpu-resource-allocation](../tutorials/remote-browser-isolation.mdx) for more details. | None | ## Knowledgebase | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Knowledgebase URL** | This is the base URL for the documentation. | None | ## Licensing | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **License Server URL** | The URL to the Kasm Licensing Server. | None | ## Logging Kasm provides centralized logging out of the box, whether you install Kasm all on a single server in a distributed system with redundant API servers and multiple Kasm agents, all logs are collected and aggregated. Kasm provides basic log aggregation, analyses, and storage. The system also support logging directly to Splunk or [File Based Logs](reporting.mdx#file-based-logs) can be ingested by a SIEM solution of choice. | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Debug Log Retention** | Number of debug logs to retain. The default is 300,000 logs. See the section on log retention for more details. | None | | **Splunk HEC Token** | For Splunk logging, this token provides authentication | Manager, API | | **HTTP Method** | The HTTP method to use, POST or PUT are supported. | Manager, API | | **Disable Log Certificate Validation** | If set to true, the remote logging server's certificate is ignored. This is required if using self signed certs. If you use properly signed certs you do not need to enable this. | Manager, API | | **Log Host** | The hostname or IP address of the remote logging system. | Manager, API | | **Log Port** | The port number for the remote logging system. Splunk's default is 8088 other systems may use 443. | Manager, API | | **Log Protocol** | Remote logging protocol. Valid values are https and splunk. | Manager, API | | **Log Retention** | Number of local logs to retain (excluding debug logs). The default is 400,000 logs. See the section on log retention for more details. | None | | **URL Endpoint** | The URI path for the logging system. See the sections below for specific logging solutions like Splunk. | Manager, API | ### Native Kasm Logging By default, logs are stored in the Kasm database. Kasm managers and Kasm API servers write their logs directly to the database. Kasm Agent nodes send logs via HTTPs to their respective Kasm Manager. The Kasm Dashboard relies on the native logging to provide visual statistics. Native logging cannot be disabled, if you enable remote logging the native logging will continue. See the log settings table for details on adjustments to default log settings. ### Splunk Logging Kasm supports Splunk HEC logging over HTTPS. See [Splunk documentation](http://dev.splunk.com/view/event-collector/SP-CAAAE7G) for details on configuring a HEC input. Note that the URI path for a Cloud Splunk instance and a self hosted Splunk instance are different. The example configuration below is for Splunk Cloud SaaS. A cloud instance will have two domain names, the one you access the UI from and one for inputs. Per the linked documentation, the Splunk Cloud SaaS domain name for data input is the same as the UI but with **input-** at the front. - Log Protocol - splunk - Log Host - input-your_cloud_splunk_hostname - Log Port - 8088 - URL Endpoint - /services/collector/event - HTTP Method - POST - Disable Log Certificate Validation - false - Splunk HEC Token - Splunk 12345678-1234-1234-1234-1234567890AB **Note:** Include the "Splunk" prefix manually in the **Splunk HEC Token** field, if required by your HEC endpoint. ### Logging Retention Logging retention applies only to local logging, it does not affect remote logging. Before adjusting the Log Retention or Debug Log Retention you should evaluate your database system. Ensure the database system has adequate storage and processing power to handle the increased logging. If retention beyond 700,000 logs is required, it is highly recommended to use a proper external logging solution. The Debug Log Retention setting should not be adjusted unless needed to troubleshoot issues over a longer period of time. A Kasm system can produce over 10,000 debug logs per hour, therefore, the retention of those logs should be considered very carefully. ## Manager | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Agent Version** | This setting is used to restrict which versions of the Kasm Agent are allowed to communicate with the Manager. | Manager | | **Primary Manager Timeout** | The number of seconds until the primary manager is considered unavailable. If other managers are alive one will take over the primary role. | None | | **Same Zone Reply** | If set to true, a manager will only reply to agent heartbeats with a list of managers in the same zone as itself. Otherwise a list of all managers is given. This allows Agents to failover to managers in other zones. | Manager | | **Token** | An authentication token used in the communication between Kasm Agents and the Manager API server. | Manager | | **Update Check** | This setting will enable/disable the manager checking for Kasm system updates. | None | ## Web Filter | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Web Filter Update URL** | URL used to interface with Kasm's URL category service | API | | **Web Filter Default Category Expiration (Hours)** | URL categorization results will be cached for the specified time, defined in hours. This setting applies to domains that have a category other than Uncategorized. | API | | **Web Filter Uncategorized Expiration (Hours)** | URL categorization results will be cached for the specified time, defined in hours. This setting only applies to domains that are currently categorized as Uncategorized. | API | ## Scale | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Automatically Enable Agents** | Automatically enable agents if disabled every time they check in. | None | | **Guardian Interval** | How often to run the guardian. Guardian handles cleanup of agents and Kasms. As well as provision of autoscale agents. | Manager | | **Guardian Provision Threads** | Number of threads to use for tear down and provision tasks. | Manager | | **Host Dead Expiration** | How long to wait after an agent stops checking in before marking it dead. If it was auto provisioned, it will be cleaned up once marked dead. | Manager | | **Host Missing Expiration** | How long to wait after an agent stops checking in before marking it missing. This value should always be less than the **Host Dead Expiration** | Manager | | **Keep Alive Expiration** | How long the session will stay alive when no client is connected. This is the global setting, can be overridden at the group level. | API | | **Provision Timeout** | How long to wait for an autoscale VM to finish provisioning. | API, Manager | | **Component Missing Expiration** | Change components to a Missing status after they fail to check in within this timeframe. This applies to components such as connection proxies. | None | | **Component Dead Expiration** | Automatically delete components that fail to check in within this timeframe, a value of 0 disables this feature. This applies to components such as connection proxies. | None | ## Theme | **Name** | **Description** | **Services Need Restarted** | | --- | --- | --- | | **Launcher Background URL** | This URL provides the location of a background image to use on the Workspaces launcher. Kasm Workspaces provides several built-in background options that are listed in the "Default Backgrounds" section of [Custom Branding](../how-to/administration/branding.mdx). After changing the setting, please logout and log back in for the setting to take effect. | None | ## Storage | Name | Description | Services Need Restarted | |------|-------------|-------------------------| | Object Storage Key | AWS Access Key ID used to access S3, used for [S3 based persistent profiles](../how-to/data-storage/persistent-profiles.mdx#s3-based-profiles). | API | | Object Storage Secret | AWS Access Key Secret used to access S3, used for [S3 based persistent profiles](../how-to/data-storage/persistent-profiles.mdx#s3-based-profiles). | API | ## Recording | Name | Description | |-----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Session Recording Framerate | The framerate for session recordings. A minimum of 2 frames per second is supported for RDP, VNC and SSH sessions. More frames per second will result in smother video but higher storage and bandwidth usage. | | Session Recording Bitrate | The bitrate for session recordings. A higher bitrate will result in higher quality recordings, but also higher storage and bandwidth usage. It is measured in Mbps. | | Session Recording Width | The width for session recordings. This is the number of pixels in width the video is, a higher number gives higher quality recordings, while increasing storage and bandwidth usage. | | Session Recording Height | The height for session recordings. This is the number of pixels in height the video is, a higher number gives higher quality recordings, while increasing storage and bandwidth usage. | | Session Recording Upload Location | The upload location will be a dynamic URL pointing to an AWS S3 Bucket where the session recording will be stored. This must be the full video path including the filename ending in `.mp4`. | | | Each file will have the epoch added to allow uploading multiple clips per session. | | | The URL can include several templated variables to tailor the storage path. See [Session Recording](../how-to/workspaces-sessions/sessions/session-recording.mdx) for more details. | | | An example of a valid URL is: `s3://session-recordings/{username}/{kasm_id}.mp4` | | Session Recording Queue Length | For RDP, VNC and SSH sessions this is how many recording clips are being processed and uploaded at once on each connection proxy server. For higher concurrent session counts this number should be increased. | | | This will have an effect on the number of CPU cores and memory that are available to handle proxying connections to RDP, VNC and SSH sessions and so resources for the connection proxy server should be | | | adjusted accordingly. Session recording encoding is quite CPU intensive. Refer to the [Kasm sizing guide](../explanations/sizing-operations.mdx) for more information | | Session Recording Retention Period | This value is how long the connection proxy will continue to try and upload recorded clips that have failed to upload. This value is measured in hours and applies to RDP, VNC, and SSH sessions only. | | | Clips that have failed to upload and haven't exceeded the retention period can also be copied out from the folder `/opt/kasm/current/tmp/guac/recordings` on the connection proxy. | | Object Storage Access Key ID | Object storage (S3) access key ID. This ID is specific for session recording purposes. | | Object Storage Access Key Secret | Object Storage Access Key Secret. This secret is specific for session recording purposes. | | Disk Usage Limit for Session Recordings | This is a percentage of the disk space that is allowed to be consumed on the Connection Proxy, before session recording will stop and session creation when session recording is enabled will fail. | | | The default value is 0.90 or otherwise saying when the disk is 90% full session recording stops | ## Setting Properties The following table lists the properties of each setting. | Name | Setting name | | --- | --- | | **Category** | Setting Category | | **Services Restart** | What services need to be restarted on setting change | | **Value** | Settings Actual Value | | **Value Type** | Data Type | | **Description** | Setting Description | ## System Metrics Kasm provides a configurable System Metrics module that periodically collects snapshot logs for essential system components, evaluates their health, and displays the results on the System Metrics dashboard. These settings control whether System Metrics is enabled, how often metrics are collected, and how many metric records are retained for each component. | Name | Description | Services Need Restarted | | --- | --- | --- | | **Enable System Metrics** | When enabled, the backend System Metrics Module periodically collects snapshot logs for all essential components, checks their health, and displays the data on the System Metrics page. | None | | **System Metrics Poll Interval** | Specifies the time interval, in minutes, at which the system collects and evaluates system metrics. A lower value collects metrics more frequently, while a higher value reduces how often checks are performed. | None | | **System Metrics Retention** | Number of system metrics records to retain per component. Increasing this value allows more historical metric snapshots to be reviewed, but may increase the amount of stored metric data. **WARNING**: Review Kasm documentation before adjusting this value. | None | --- ## Kasm: System Metrics # System Metrics Kasm provides a **System Metrics** tool for monitoring the overall health of a Kasm deployment. Since Kasm is made up of multiple components, System Metrics continuously checks the status of those components to help ensure that the system remains healthy and synchronized. The System Metrics dashboard provides a user-friendly interface for identifying warnings, reviewing system health, and troubleshooting critical issues. ## Dashboard The System Metrics dashboard displays a diagnostic summary of the environment, including detected issues, healthy components, and informational alerts. ![System Metrics Dashboard](/img/system-metrics/system-metrics-dashboard.webp) The dashboard helps administrators quickly understand the current health of the system and identify components that may require attention. ## Status Colors The dashboard uses status colors to indicate the severity and condition of each component. 1. **Green — Healthy**: The component is operating normally. 2. **Blue — Info**: General informational messages. For example, a message may indicate that there is no manager in a specific zone. 3. **Yellow — Warning**: An early signal that a component may be unhealthy or requires attention. 4. **Red — Error**: A critical component failure that may significantly impact the overall system. ## System Component Groups System Metrics organizes checks into two main component groups. 1. **Health Monitoring**: Zone-based components. 2. **System Monitoring**: Non-zone-based components. ## System Component Health Checklist The System Metrics dashboard includes checks for both health monitoring and system monitoring components. ### Health Monitoring Health Monitoring includes zone-based component checks such as: 1. **Kasm Managers Health** 2. **Kasm Connection Proxies Health** 3. **Kasm Servers Health** 4. **Kasm Agents Health** ### System Monitoring System Monitoring includes non-zone-based component checks such as: 1. **Database Operational Snapshot** 2. **Kasm License Health** 3. **Kasm Version Health** 4. **Kasm Workspace Health** ## Metrics Overview Each metrics component can be expanded to view performance logs captured within the selected time interval. ![Expanded Metrics Component](/img/system-metrics/expanded-metrics-component.webp) When a component is expanded, the dashboard displays recent checks and a component health summary. This summary provides a quick overview of the component status and helps administrators understand whether the issue is informational, a warning, or an error. Administrators can filter checks by time span and status to investigate issues more easily. ## Viewing Full Metric Data For deeper troubleshooting, select **View full data** on a metric check. ![Full Metric Data](/img/system-metrics/full-metric-data.webp) The full data view displays detailed metric output, including structured diagnostic data. This can help administrators identify the source of a problem and determine the appropriate fix. For example, a database operational snapshot may include information such as: - Database size - Active database connections - Dead tuples - Active queries - Cache hit ratio - Long-running queries - Table-level data - Query details This detailed output can be copied or reviewed directly from the dashboard during troubleshooting. ## Customize the Dashboard The System Metrics dashboard can be customized to better match the administrator's workflow. ![Customize Metrics Dashboard](/img/system-metrics/customize-metrics-dashboard.webp) Administrators can customize the dashboard by rearranging the order of sections and metric components. Unwanted components can also be hidden from the dashboard. To customize the dashboard: 1. Open the **Customize Metrics** option. 2. Drag sections or metrics to reorder them. 3. Hide components that are not needed. 4. Select **Save** to apply the changes. Customization allows administrators to keep the most important system checks visible and organize the dashboard around the components they monitor most frequently. ## System Metrics Checks System Metrics runs a set of default health checks against core Kasm components. These checks are grouped into **System Monitoring** and **Health Monitoring**. Each check can return one of the following statuses: 1. **Healthy**: The component is operating normally. 2. **Info**: The system has detected a condition that is useful to know but does not require immediate action. 3. **Warning**: The system has detected a condition that may require investigation. 4. **Error**: The system has detected a condition that may impact system stability or availability. ### System Monitoring Checks System Monitoring checks non-zone-based system components, including the database, license, Kasm version, and workspace images. #### • Database Operational Snapshot The **Database Operational Snapshot** check reviews database size, connections, replication state, and query behavior. | Condition | Status | Message | | --- | --- | --- | | Database size is greater than 10 GB and less than or equal to 100 GB. | Warning | Database size is above 10 GB. Review growth trends and confirm backups/retention policies are still appropriate. | | Database size is greater than 100 GB. | Warning | Database size is above 100 GB. Investigate rapid growth, check storage capacity, and plan scaling/archival. | | One or more long-running queries are detected. | Warning | One or more long-running queries detected. Investigate slow queries and confirm indexing and workload behavior. | #### • Kasm License Health The **Kasm License Health** check reviews whether a license exists and whether any configured licenses are close to expiration or already expired. | Condition | Status | Message | | --- | --- | --- | | No license is found. | Info | No license found. | | One or more licenses expire within 30 days. | Warning | One or more licenses will expire within 30 days. Please plan to renew. | | One or more licenses have expired. | Error | One or more licenses have expired. Please renew immediately to restore access. | #### • Kasm Version Health The **Kasm Version Health** check reviews whether a Kasm update is available. | Condition | Status | Message | | --- | --- | --- | | A Kasm update is available. | Warning | An update is available for Kasm. Review release notes and schedule an upgrade to stay current on fixes and security updates. | #### • Kasm Container Workspaces Health The **Kasm Container Workspaces Health** check reviews whether workspace images are available and healthy. | Condition | Status | Message | | --- | --- | --- | | No workspace data is available. | Info | No workspaces have been added yet. | | Workspace image data is stale, unavailable, or missing from the agent. | Error | Workspace images are unhealthy: image is stale/unavailable or missing on the agent. Check image sync/pulls, agent connectivity, and registry access. | ### Health Monitoring Checks Health Monitoring checks zone-based components such as Managers, Servers, Agents, and Connection Proxies. #### • Kasm Managers Health The **Kasm Managers Health** check reviews Manager availability, operational status, managed server status, and resource usage. | Condition | Status | Message | | --- | --- | --- | | No Manager data is available. | Info | No Manager data found. | | Manager status is not `running` or `deleting`. | Error | Manager is not in an expected state (running/deleting). Check server health, capacity, and recent failures. | | One or more Manager-managed servers are not `running` or `deleting`. | Error | Manager-managed servers are not in an expected state (running/deleting). Check the affected server(s) and recent events/logs. | | Manager memory usage is above 80%. | Warning | Manager nodes have memory usage above 80%. Investigate memory pressure, workloads, and capacity trends. | | Manager memory usage is above 90%. | Error | Manager nodes have memory usage above 90%. Investigate immediately to prevent instability (check processes, workloads, and capacity). | | Manager CPU usage is above 80%. | Warning | Manager nodes have CPU usage above 80%. Review workloads and investigate sustained CPU pressure. | | Manager CPU usage is above 90%. | Error | Manager nodes have CPU usage above 90%. Investigate immediately to prevent degraded performance. | | Manager disk usage is above 80%. | Warning | Manager nodes have disk usage above 80%. Review storage growth and plan cleanup/expansion. | | Manager disk usage is above 90%. | Error | Manager nodes have disk usage above 90%. Take action immediately (cleanup/expand) to avoid outages. | #### • Kasm Servers Health The **Kasm Servers Health** check reviews Server availability, operational status, and resource usage. | Condition | Status | Message | | --- | --- | --- | | No Server data is available. | Info | No Server data found. | | Server status is not `running` or `deleting`. | Error | Server is not in an expected state (running/deleting). Check server health, capacity, and recent failures. | | Server memory usage is above 80%. | Warning | Server has memory usage above 80%. Investigate memory pressure, workloads, and capacity trends. | | Server memory usage is above 90%. | Error | Server has memory usage above 90%. Investigate immediately to prevent instability. | | Server CPU usage is above 80%. | Warning | Server has CPU usage above 80%. Review workloads and investigate sustained CPU pressure. | | Server CPU usage is above 90%. | Error | Server has CPU usage above 90%. Investigate immediately to prevent degraded performance. | | Server disk usage is above 80%. | Warning | Server has disk usage above 80%. Review storage growth and plan cleanup/expansion. | | Server disk usage is above 90%. | Error | Server has disk usage above 90%. Take action immediately (cleanup/expand) to avoid outages. | #### • Kasm Agents Health The **Kasm Agents Health** check reviews Agent availability, operational status, and resource usage. | Condition | Status | Message | | --- | --- | --- | | No Agent data is available. | Info | No Agents data found. | | Agent status is not `running` or `deleting`. | Error | Agent is not in an expected state (running/deleting). Check server health, capacity, and recent failures. | | Agent memory usage is above 80%. | Warning | Agent has memory usage above 80%. Investigate memory pressure, workloads, and capacity trends. | | Agent memory usage is above 90%. | Error | Agent has memory usage above 90%. Investigate immediately to prevent instability. | | Agent CPU usage is above 80%. | Warning | Agent has CPU usage above 80%. Review workloads and investigate sustained CPU pressure. | | Agent CPU usage is above 90%. | Error | Agent has CPU usage above 90%. Investigate immediately to prevent degraded performance. | | Agent disk usage is above 80%. | Warning | Agent has disk usage above 80%. Review storage growth and plan cleanup/expansion. | | Agent disk usage is above 90%. | Error | Agent has disk usage above 90%. Take action immediately (cleanup/expand) to avoid outages. | #### • Kasm Connection Proxies Health The **Kasm Connection Proxies Health** check reviews Connection Proxy availability, operational status, and resource usage. | Condition | Status | Message | | --- | --- | --- | | No Connection Proxy data is available. | Info | No Connection Proxy data found. | | Connection Proxy status is not `running` or `deleting`. | Error | Connection Proxy is not in an expected state (running/deleting). Verify proxy service status and network reachability. | | Connection Proxy memory usage is above 80%. | Warning | Connection Proxy has memory usage above 80%. Investigate memory pressure, workloads, and capacity trends. | | Connection Proxy memory usage is above 90%. | Error | Connection Proxy has memory usage above 90%. Investigate immediately to prevent instability. | | Connection Proxy CPU usage is above 80%. | Warning | Connection Proxy has CPU usage above 80%. Review workloads and investigate sustained CPU pressure. | | Connection Proxy CPU usage is above 90%. | Error | Connection Proxy has CPU usage above 90%. Investigate immediately to prevent degraded performance. | | Connection Proxy disk usage is above 80%. | Warning | Connection Proxy has disk usage above 80%. Review storage growth and plan cleanup/expansion. | | Connection Proxy disk usage is above 90%. | Error | Connection Proxy has disk usage above 90%. Take action immediately (cleanup/expand) to avoid outages. | ### Resource Usage Thresholds Several Health Monitoring checks use the same resource thresholds across Managers, Servers, Agents, and Connection Proxies. | Resource | Warning Threshold | Error Threshold | | --- | --- | --- | | Memory usage | Above 80% | Above 90% | | CPU usage | Above 80% | Above 90% | | Disk usage | Above 80% | Above 90% | When a warning threshold is reached, administrators should review the affected component and investigate capacity trends. When an error threshold is reached, administrators should take action immediately to prevent degraded performance or outages. ## Diagnosing System Problems The System Metrics dashboard helps administrators quickly identify affected components, review health summaries, and inspect detailed metric data for troubleshooting. ### 1. Review the Diagnostic Summary Start from the **Diagnostic Summary** section at the top of the System Metrics dashboard. This section shows a list of **Affected Components**. Each affected component represents a metric check that has detected an issue, warning, or informational alert. Click an affected component to automatically scroll to the related health check section on the dashboard. ![Diagnostic Summary Affected Components](/img/system-metrics/diagnostic-summary-affected-components.webp) ### 2. Expand the Affected Component and Review the Health Summary After selecting an affected component, expand the related health check by clicking the toggle next to the component name. When expanded, the component displays an overview of the health checks and metrics recorded over time. The first section inside the expanded details is the **Component Health Summary**. The Component Health Summary provides a quick explanation of the issue detected by System Metrics. It may include: - The problem that was found - How many times the problem occurred within the selected time range - The affected zone, when zone data is applicable - The severity of the issue ![Expanded Component Health Summary](/img/system-metrics/expanded-component-health-summary.webp) The text color indicates the type of alert: | Color | Status | Meaning | | --- | --- | --- | | Red | Error | A critical issue was detected and should be investigated immediately. | | Yellow | Warning | A potential issue was detected and may require attention. | | Blue | Info | Informational details are available for review. | ### 3. Filter the Recorded Checks Use the available filters to narrow the results based on the type of issue you want to investigate. For example, you can filter by: - **Status**, such as Error, Warning, Info, or Healthy - **Zone**, when the component is zone-based - **Time range**, to review checks from a specific period Filtering helps reduce noise and makes it easier to focus on the affected checks. ![Filtered Component Checks](/img/system-metrics/filtered-component-checks.webp) Each recorded check provides a snapshot of the component state at that time. The snapshot may include the reason the check failed, related metric values, and additional metadata that can help with troubleshooting. ### 4. View Full Metric Data For deeper troubleshooting, click **View full data** on a recorded check. ![View Full Metric Data](/img/system-metrics/view-full-metric-data.webp) The full data view displays the complete metric payload for that check. This can include detailed system metadata, resource usage, database details, query information, or other component-specific diagnostic data. Use this view when the summary does not provide enough information and you need to inspect the underlying metric data in more detail. ## Global Settings System Metrics can be configured from the **Global Settings** page. These settings control whether System Metrics is enabled, how often metrics are collected, and how many metric records are retained for each component. You can open these settings directly from the **Customize Metrics** modal by clicking the **Global Settings** button. This redirects you to the Global Settings page, where the System Metrics settings can be reviewed and updated. ![System Metrics Global Settings](/img/system-metrics/global-settings-button.webp) ![System Metrics Global Settings](/img/system-metrics/system-metrics-global-settings.webp) The following global settings are available for System Metrics: | Setting | Description | | --- | --- | | `Enable System Metrics` | When enabled, the backend System Metrics Module periodically collects snapshot logs for all essential components, checks their health, and displays the data on the System Metrics page. | | `System Metrics Poll Interval` | Specifies the time interval, in minutes, at which the system collects and evaluates system metrics. | | `System Metrics Retention` | Specifies the number of system metrics records to retain per component. Use caution when adjusting this value, as increasing retention may increase stored metric data. | For more information about configuring global settings, see the [Global Settings](../reference/settings.mdx#system-metrics) documentation. --- ## GCP PostgreSQL Database: Setup & Management # Google Cloud Provider (GCP) PostgreSQL Database Admins may wish to use a Managed Database Service such as Google Cloud Provider (GCP) PostgreSQL Database seperate from their Kasm installation. This guide provides instructions on how to initialize the database server from a remote machine and then install the Kasm WebApp. ## Requirements - Google Cloud Provider (GCP) PostgreSQL server running PostgreSQL version 16. - Google Cloud Provider (GCP) PostgreSQL either already has a User "kasmapp" in the database "kasm" **OR** you have SuperUser credentials on the database. - Machine executing initialization and the Web App server can connect to the Google Cloud Provider (GCP) PostgreSQL Database (default port TCP/5432) ## Sizing | Requirement | CPUs | RAM | |-------------------------|------|-------| | **Minimum Requirements**| 2 | 4 GB | | **Suggested Requirements**| 2 | 16 GB | ## When performing a fresh installation ### Initializing PostgreSQL Database - This can be done from anywhere, but since the script will install docker and other Kasm prerequisites it may be easiest to run the remote DB install from the future Kasm Web App server. - Download latest version of Kasm Workspaces to /tmp - Extract package and initialize the Database. ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz sudo bash kasm_release/install.sh \ --accept-eula \ --role init_remote_db \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --db-master-user [DATABASE_SUPERUSER_USERNAME] \ --db-master-password [DATABASE_SUPERUSER_PASSWORD] ``` If the Database already has the **User** "kasmapp" and **database** "kasm" created you may omit the `-g` and `-G` parameters. The **DATABASE_USERNAME** and **DATABASE_NAME** are optional and only required if not using the default kasm/kasmapp settings. ### Backing up the Google Cloud Provider (GCP) PostgreSQL Server - This script should be run from a Kasm Web App server. If you are backing up a standalone remote database for Kasm Workspaces 1.11.0 or newer then use the existing db_backup script: :::warning Starting in version 1.17.0, the backup destination directory must be readable and writable by the `kasm_db` user (ID 70). When the directory lacks these permissions, the backup fails. ::: ```Bash sudo bash /opt/kasm/bin/utils/db_backup -v --backup-file [DESIRED_BACKUP_FILE_LOCATION] -q [DATABASE_HOSTNAME] --path [PATH_TO_KASM_INSTALL] ``` - The backup will be present at the location specified with **--backup-file** - In Kasm Workspaces [[release]] or newer, use the `--exclude-logs` flag or `-l` to exclude log data from the backup if necessary ### Restoring the Google Cloud Provider (GCP) PostgreSQL server from a backup - This script should be ran from a Kasm Web App server or during a Kasm Workspaces upgrade from the server that ran the database clean install step. - You will need SuperUser credentials on the database. - Make sure that All Kasm Web App and Agent servers have their services stopped. ```bash sudo bash /opt/kasm/[[release]]/bin/utils/db_restore \ --backup-file [LOCATION_OF_BACKUP_FILE] \ --database-hostname [DATABASE_HOSTNAME] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --path /opt/kasm/[[release]] \ --database-master-user [DATABASE_MASTER_USER] \ --database-master-password [DATABASE_MASTER_USER_PASSWORD] ``` - After the restore is complete restart all Kasm Web App and Agent services. ## When performing an upgrade Before performing an upgrade ensure all Kasm Workspaces Containers/Sessions are stopped on all hosts in your deployment. `sudo systemctl stop kasm` Also ensure the "Automatically Enable Agents" is enabled under settings in the Admin Dashboard. These instructions are for upgrading from Kasm Workspaces >= 1.11.0 to [[release]]. #### Database migration The database migration commands should be run once from the Kasm Web App with access to the remote database. Any additional Kasm Web App server does not need to execute database migrations again. * Stop all services: ```Bash sudo systemctl stop kasm ``` * Grab and extract the installer for [[release]]: ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz ``` * Generate a database backup: If necessary, use the `--exclude-logs` flag or `-l` to exclude log data from the backup. Note that this will result in an empty logs interface after the upgrade. ```bash sudo mkdir -p /opt/kasm/backups/ sudo chown 70 /opt/kasm/backups/ sudo bash kasm_release/bin/utils/db_backup \ --backup-file /opt/kasm/backups/[[previous_release]]_backup.tar \ --database-hostname [DATABASE_HOSTNAME] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --path /opt/kasm/current ``` * Log into your PostgreSQL server as the master user and remove the database/user: ```Bash drop database if exists kasm; drop user if exists kasmapp; ``` * Init the empty DB, restore our backup, and upgrade the database: ```bash sudo bash kasm_release/install.sh \ --accept-eula \ --role init_remote_db \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --db-master-user [DATABASE_MASTER_USER] \ --db-master-password [DATABASE_MASTER_USER_PASSWORD] sudo bash /opt/kasm/[[release]]/bin/utils/db_restore \ --backup-file /opt/kasm/backups/[[previous_release]]_backup.tar \ --database-hostname [DATABASE_HOSTNAME] \ --path /opt/kasm/[[release]] \ --database-master-user [DATABASE_MASTER_USER] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --database-master-password [DATABASE_MASTER_USER_PASSWORD] sudo bash /opt/kasm/[[release]]/bin/utils/db_upgrade \ --database-hostname [DATABASE_HOSTNAME] \ --path /opt/kasm/[[release]] ``` * Seed the new images for this installation: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init \ --database-hostname [DATABASE_HOSTNAME] \ --seed-file /opt/kasm/[[release]]/conf/database/seed_data/default_images_amd64.yaml ``` --- ## GPU Acceleration: Setup & Configuration # GPU Acceleration This document outlines our officially supported GPU integration using the Nvidia container runtime. Kasm Workspaces supports passing GPUs through to container sessions. GPUs can be used for development of machine learning, data science, video encoding, graphics acceleration, and a number of other reasons. All uses of GPUs will require special host configurations. This guide will walk through preparing a bare VM with the default installation of Ubuntu 24.04LTS for GPU acceleration within Kasm Workspaces. If Kasm is a multi-server deployment, these steps need to be performed on each Agent component only. If you are installing Kasm Workspaces on a single server, these steps would only need to be performed on that single instance. The security of multi-tenant container GPU acceleration is not well established. This feature should be used with caution and with full understanding of the potential security implications. Kasm Workspaces 1.19.0 and higher supports NVIDIA MIG, which allows you to create multiple instances of a single GPU. This is the only secure way to share a GPU between multiple users. ## Installation video tutorial ## Installation steps **Note**: NVIDIA recommends installing the driver by using the package manager for your distribution and Kasm also recommend the same. 1. Install Kasm Workspaces (if not already installed) 2. NVIDIA CUDA-capable graphics card. For Kasm AI workspaces the minimum required CUDA version is currently `560.28.03`). Please check that your NVIDIA card supports at least this version on the NVIDIA website before continuing. 3. [NVIDIA drivers](https://www.nvidia.com/en-gb/drivers/) 4. [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). **Warning:** Installing NVIDIA drivers via multiple installation methods can result in your system not booting correctly. ## Ubuntu 24.04 LTS For Ubuntu 24.04 systems we provide the following script that will add the Ubuntu graphics-drivers PPA repository, install the latest NVIDIA driver through the `ubuntu-drivers` tool and install the NVIDIA Container Toolkit. The driver installation will require a system reboot and the NVIDIA Container Toolkit will require Docker to be restarted. ```yml #!/bin/bash # Check for NVIDIA cards if ! lspci | grep -i nvidia > /dev/null; then echo "No NVIDIA GPU detected" exit 0 fi add-apt-repository -y ppa:graphics-drivers/ppa curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list apt update apt install -y ubuntu-drivers-common # Run ubuntu-drivers and capture the output DRIVER_OUTPUT=$(ubuntu-drivers list 2>/dev/null) # Extract server driver versions using grep and regex # Pattern looks for nvidia-driver-XXX-server SERVER_VERSIONS=$(echo "$DRIVER_OUTPUT" | grep -o 'nvidia-driver-[0-9]\+-server' | grep -o '[0-9]\+' | sort -n) # Check if any server versions were found if [ -z "$SERVER_VERSIONS" ]; then echo "Error: No NVIDIA server driver versions found." >&2 exit 1 fi # Find the highest version number LATEST_VERSION=$(echo "$SERVER_VERSIONS" | tail -n 1) # Validate that the version is numeric if ! [[ "$LATEST_VERSION" =~ ^[0-9]+$ ]]; then echo "Error: Invalid version number: $LATEST_VERSION" >&2 exit 2 fi # Output only the version number echo "Latest version is: $LATEST_VERSION" ubuntu-drivers install "nvidia:$LATEST_VERSION-server" apt install -y "nvidia-utils-$LATEST_VERSION-server" # Install NVIDIA toolkit + configure for docker apt-get install -y nvidia-container-toolkit nvidia-ctk runtime configure --runtime=docker ``` Reboot your system once the drivers are installed, or if you already had the drivers then restart Docker (`sudo systemctl restart docker`). ## Confirm Kasm GPUs After installing Workspaces, the GPU driver, and GPU container toolkit; confirm Kasm is picking up the GPUs. Log into Kasm as an administrator, navigate to the Agents view under the Admin section. Here you will see a list of agents in the cluster, since this is a single server installation, there will only be one agent listed. Confirm that the agent shows 1 or more GPUs. If the agent lists 0 GPUs, see the [troubleshooting section](../../how-to/troubleshooting/gpu-issues.mdx). ## Verification steps 1. Run `nvidia-smi` on the Agent host to confirm the CUDA driver version (shown in the top-right of the output) is correctly installed. 2. Launch a CUDA-enabled Kasm Workspace, for example, the [Kasm PyTorch](https://ai.registry.kasmweb.com/1.1/new/Q1VEQS1lbmFibGVkIFB5VG9yY2g%3D/) image. Open a Terminal and execute the following commands: ```yml cd torch python import torch torch.cuda.is_available() torch.cuda.device_count() torch.cuda.get_device_name(0) ``` This should confirm that your GPU is successfully configured with CUDA support and that CUDA is available inside a Kasm Workspaces session. ## Managing GPU Resources GPUs are treated similar to CPU cores within Kasm Workspaces. Each agent reports the number of CPUs, RAM, and GPUs available to share between containers. By default, a Workspace set to 1 require 1 GPU will mean that an agent with 1 GPU will only be able to support a single session of that workspace. Kasm can allow a single GPU to be shared between multiple containers, this is known as overriding, see the [ CPU / Memory / GPU Override](../../how-to/infra-autoscale/docker-agent.mdx#cpu--memory--gpu-override) for more details. Overriding the agent to have 4 GPUs would allow up to 4 containers with the GPU passed through, if each were assigned a single GPU. In the context of graphics acceleration, only a single GPU can be passed through. Only non-graphics applications support multiple GPUs per container to be used. ## Assigning GPUs to Workspace images In order for sessions to utilize a GPU, the Workspace must be set to require a GPU. Login as administrator, navigate to Workspaces, in the Workspace list find the target Workspace. Expand the menu by clicking the arrow icon next to the Workspace you want to have a GPU and click Edit. Change the NVIDIA CUDA GPU count to the desired number. ## New GPU and streaming features in 1.19 Kasm Workspaces 1.19 introduces enhanced GPU acceleration, hardware-accelerated video streaming modes, and NVIDIA Multi-Instance GPU (MIG) support. The following video walks through GPU hardware management on the Docker Agent, workspace graphics and streaming configuration, NVIDIA MIG, and the group settings that control encoding preferences. ## GPU Graphics and Video Acceleration Kasm Workspace Images must be on version 1.19.0 or higher to support automatic configuration of graphics and video acceleration covered below. Graphics and video acceleration are separate from passing through GPUs for compute (CUDA). If you select a graphics method supported by the NVIDIA GPU that was passed through for CUDA, the same device will be passed through for graphics. KasmVNC natively supports DRI3 and does not require the use of a translation layer, however, DRI3 is not supported by NVIDIA. Most NVIDIA GPUs support both EGL, which uses VirtualGL, and Vulkan, which uses Zink as a translation layer. Kasm handles the configuration of the container to use the selected method and to pass through the appropriate device. If the agent has multiple compatible GPUs for the selected method, a GPU is selected at random and passed through to the container. If you do not want a specific GPU to be used for graphics, you can disable graphics on that GPU in the Kasm Agent settings. The MESA option means to use the `llvmpipe` software-based GPU. Kasm will attempt to use compatible hardware according to the order of graphics acceleration methods in the `Selected` list, which may be re-ordered by the admin. KasmVNC supports VAAPI for hardware accelerated h.264 and h.265 video encoding of the session stream. Selecting VAAPI for video acceleration will pass through the appropriate DRM device. KasmVNC will automatically detect and use that hardware for encoding if the user selects it. See the Kasm Performance page for more details. KasmVNC does not support NVENC, however it can still be passed through to the container for use by other software. --- ## Deploying on Kubernetes: Installation Guide # Kubernetes Kasm Workspaces core services can be deployed to Kubernetes using the [open-source Kasm Helm chart](https://github.com/kasmtech/kasm-helm), which will be Generally Available as of Kasm version 1.19.0 (the developer preview is available using chart version 1.1190.0). :::tip[Planning your deployment?] Not sure which components you need? The Helm chart does not cover everything — what you provision alongside it depends on your session types (Docker containers, RDP, VNC) and whether you are running multiple zones. See [Kubernetes Deployment Options](../../explanations/kubernetes-deployment-options) for a full breakdown before you start. ::: --- ## Quick Start If you have a running Kubernetes cluster and just want to get Kasm up quickly, here are the minimal steps. See [Installation](#installation) below for the full walkthrough with all options. **Prerequisites:** Kubernetes 1.24+, Helm 3.18.x+, a domain name, and a TLS certificate or cert-manager. Create a namespace and install your TLS certificate as a Kubernetes secret (see [Configure TLS Certificates](../../how-to/kubernetes/configure_tls) for the available methods), then create a minimal values file: ```yaml # my-values.yaml publicAddr: kasm.example.com certificate: secretName: {CERTIFICATE_SECRET_NAME} ``` Install the chart: ```bash kubectl create namespace {NAMESPACE} helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` Wait for pods to be ready, then retrieve the admin password: ```bash kubectl get pods -n {NAMESPACE} --watch kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \ -o jsonpath="{.data.admin-password}" | base64 -d; echo ``` Point your DNS for `publicAddr` to the address shown by `kubectl get ingress -n {NAMESPACE}` and log in at `https://{publicAddr}` with `admin@kasm.local`. :::caution After a successful install, disable the one-time initialization jobs before any future `helm upgrade`: ```yaml dbManagement: initialize: false upgrade: enable: false ``` ::: --- ## Architecture Overview The Kasm Helm chart deploys the core control-plane services inside a Kubernetes cluster. Containerized desktop and application sessions are not run inside the cluster; they are hosted on external Docker Agent servers that you provision separately (either as [static agents](../../how-to/infra-autoscale/autoscale/index.mdx) or via [auto scaling](../../how-to/infra-autoscale/autoscale/index.mdx)). RDP sessions are routed to external Windows or Linux hosts running RDP servers. The following diagram shows the main components and how traffic flows between them: ```mermaid --- title: Kubernetes Architecture config: layout: elk --- flowchart TB subgraph clients ["Client Machines"] Browser(["Browser"]) RDPClient(["Native RDP Client"]) end subgraph cluster ["Kubernetes Cluster"] direction TB Ingress["Ingress Controller\n(LoadBalancer)"] API["Kasm API"] Manager["Kasm Manager"] Guac["Guacamole"] RDPHTTPSGW["RDP HTTPS Gateway"] RDPGW["RDP Gateway"] DB[("PostgreSQL\n(built-in or external)")] Ingress --> API Ingress --> Guac Ingress --> RDPHTTPSGW API --- Manager API --- DB Manager --- DB RDPHTTPSGW --> RDPGW end subgraph external ["External Infrastructure"] Agents["Agents"] Proxies["Dedicated Proxies"] Servers["Servers"] end Browser --> Ingress RDPClient --> Ingress RDPClient -.-> RDPGW Manager --> Agents Manager --> Proxies Guac --> Agents RDPGW --> Servers ``` ### Multi-Zone Architecture Kasm supports multiple deployment zones, which are commonly used to serve users across geographic regions but can also be used to segment groups of users or isolate different workload types across separate pools of compute resources. In a multi-zone deployment, each zone runs its own set of API-layer and proxy-layer services. Additional zones only receive the App role from the Helm chart — their proxy layer is deployed separately using the [multi-zone proxy instructions](../../how-to/kubernetes/multi_zone_proxies). ```mermaid --- title: Multi-Zone Architecture config: layout: elk --- flowchart TB subgraph cluster ["Kubernetes Cluster"] direction TB DB[("DB")] subgraph apiLayerA ["API Layer - Zone A"] direction LR apiSvcA["api\nzone A"] managerSvcA["manager\nzone A"] end subgraph apiLayerB ["API Layer - Zone B"] direction LR apiSvcB["api\nzone B"] managerSvcB["manager\nzone B"] end subgraph proxyLayerA ["Proxy Layer - Zone A"] direction LR proxySvcA["proxy\nzone A"] guacSvcA["guac\nzone A"] rdpgwSvcA["rdp https gateway\nzone A"] redemptionSvcA["rdp gateway\nzone A"] end DB --- apiLayerA DB --- apiLayerB apiLayerA --> proxyLayerA end subgraph separateDeploy ["Zone B - Separate Deployment"] direction LR proxySvcB["proxy\nzone B"] guacSvcB["guac\nzone B"] rdpgwSvcB["rdp https gateway\nzone B"] redemptionSvcB["rdp gateway\nzone B"] end subgraph extA ["Zone A - External Infrastructure"] direction LR serversA["Servers"] agentsA["Agents"] end subgraph extB ["Zone B - External Infrastructure"] direction LR serversB["Servers"] agentsB["Agents"] end apiLayerB --> separateDeploy proxyLayerA --> extA separateDeploy --> extB ``` Key points to note: - **Agents are not included in the Helm chart.** The Kasm Agent, which hosts containerized sessions (desktops, browsers, apps), must be deployed on separate Docker hosts outside the cluster. You can add agents manually as static servers or configure [auto scaling](../../how-to/infra-autoscale/autoscale/index.mdx) to provision them on demand. - **RDP over port 3389 requires extra configuration.** Standard Kubernetes Ingress only handles HTTP/HTTPS traffic on port 443. By default, thick-client RDP connections route through the **RDP HTTPS Gateway** on port 443, which works out of the box. To support direct RDP connections on port 3389, you must expose the RDP Gateway via a NodePort or LoadBalancer service. See [Direct RDP Connections on Kubernetes](../../how-to/kubernetes/rdp_direct_access) for setup instructions. - **Ingress acts as the external load balancer.** All browser and HTTPS-based client traffic enters the cluster through the Ingress controller, which should be backed by a cloud load balancer or similar in production. --- ## Prerequisites Before installing, ensure you have: - **Kubernetes 1.24+** - **Helm 3.18.x+**: install from [helm.sh](https://helm.sh/docs/intro/install/) - **`kubectl`** configured and connected to your target cluster - **A default StorageClass** (or explicit `storageClassName` in your values): required for the built-in PostgreSQL database PVC. Not needed if using a standalone external database. Run `kubectl get storageclass` to verify a default is set. - **A domain name** with DNS control, to use as the `publicAddr` for Kasm - **A TLS certificate** or cert-manager installed in your cluster. See [Configure TLS Certificates for Kasm on Kubernetes](../../how-to/kubernetes/configure_tls) Note that Helm chart versions are based upon Kasm versions, for example chart version `1.1190.0` corresponds to Kasm version `1.19.0`, with the minor (middle) number corresponding to the officially supported Kasm version. :::tip[Using a managed Kubernetes service?] If you are deploying on a managed Kubernetes platform such as **Amazon EKS**, **Google GKE**, or **Azure AKS**, ensure that your cloud provider's CLI tools are installed and configured (e.g., `aws`, `gcloud`, `az`) and that your `kubectl` context is pointed at the correct cluster. Refer to your provider's documentation for cluster setup and authentication: - [Amazon EKS: Getting Started](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) - [Google GKE: Getting Started](https://cloud.google.com/kubernetes-engine/docs/deploy-app-cluster) - [Azure AKS: Getting Started](https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-cli) Cloud-hosted deployments may also benefit from using a managed database service (e.g., Amazon RDS, Cloud SQL, Azure Database for PostgreSQL) instead of the built-in database. See the chart's `database` values for external database configuration. ::: --- ## Installation :::caution[Developer Preview Helm Chart] If you are using a developer preview version of the Kasm Helm chart, be aware that **no clean migration path to future updates is guaranteed**. Review the [Developer Preview Builds](../../reference/builds) warnings before proceeding. ::: ### 0. Verify Your Cluster Before proceeding, confirm that your cluster is reachable and that nodes are healthy: ```bash kubectl cluster-info kubectl get nodes ``` All nodes should show a `Ready` status. If not, resolve any cluster issues before continuing. --- ### 1. Create the Namespace ```bash kubectl create namespace {NAMESPACE} ``` --- ### 2. Configure TLS Install your TLS certificate into the namespace as a Kubernetes secret. See [Configure TLS Certificates for Kasm on Kubernetes](../../how-to/kubernetes/configure_tls) for the available methods. Note the secret name you create, as you will need it as `{CERTIFICATE_SECRET_NAME}` in the next step. --- ### 3. Create Your Values File Create a `my-values.yaml` file. At minimum, include: ```yaml publicAddr: kasm.example.com certificate: secretName: {CERTIFICATE_SECRET_NAME} ``` Refer to the [chart definition](https://github.com/kasmtech/kasm-helm) for a list of all available configuration options (documented in `/charts/kasm/values.yaml`). #### Customizing Component Image Tags By default, each component uses rolling image tags which pull the latest at time of deployment. To pin a specific build, override the `tag` field for each component in your values file: ```yaml components: proxy: image: tag: 1.19.0-rolling-20260215 api: image: tag: 1.19.0-rolling-20260215 manager: image: tag: 1.19.0-rolling-20260215 guac: image: tag: 1.19.0-rolling-20260215 rdpGateway: image: tag: 1.19.0-rolling-20260215 rdpHttpsGateway: image: tag: 1.19.0-rolling-20260215 database: image: tag: 1.19.0-rolling-20260215 ``` You can override any subset of components independently; omitted components continue to use the chart's default tag. :::note To apply tag changes to a running deployment after initial install, see [Applying Changes to a Running Instance](#applying-changes-to-a-running-instance) below. ::: :::caution[`deploymentSize` Variable Value] `deploymentSize` controls resource allocation across all Kasm components. Three values are supported: small, medium, and large. Each value maps to a preset that sets CPU and memory requests/limits and scales the replica count for each component (1/2/3 respectively). The database StatefulSet always runs as a single replica regardless of size. Choose small for evaluation, single-node, or low-concurrency deployments. Use medium or large for production environments where session throughput and availability matter. Any component's resources or replica count can be overridden individually via `components..resources` and `components..replicas` when the preset does not match your workload. ::: --- ### 4. (Optional) Pre-Create Kasm Secrets By default, the Helm chart auto-generates random credentials during installation and stores them in a Kubernetes secret. If you prefer to use your own credentials, create the secret before installing the chart. The secret must be named `{RELEASE_NAME}-secrets`, where `{RELEASE_NAME}` is the name you will pass to `helm install` in the next step. For example, if you plan to run `helm install kasm ...`, the secret must be named `kasm-secrets`. ```yaml apiVersion: v1 kind: Secret metadata: name: {RELEASE_NAME}-secrets namespace: {NAMESPACE} type: Opaque data: admin-password: "" user-password: "" db-password: "" manager-token: "" service-token: "" ``` Apply it with: ```bash kubectl apply -f kasm-secrets.yaml ``` :::tip To base64-encode a value: `echo -n 'my-password' | base64` ::: If the chart finds an existing secret with this name during installation, it will use those values instead of generating new ones. --- ### 5. Install the Chart The Kasm Helm chart is available as an OCI Helm chart and from a classic Helm repository. #### OCI Registry (Recommended) ```bash helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` #### Classic Helm Repository ```bash helm repo add kasm https://helm.kasm.com helm repo update helm install {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` :::caution[After a successful install] Once the installation completes, disable the one-time initialization jobs in your values file before running any future `helm upgrade`. Leaving them enabled will cause them to re-run on every upgrade: ```yaml dbManagement: initialize: false upgrade: enable: false ``` ::: :::tip[Modifying the chart locally] To customize the Helm chart beyond what values allow, clone the [kasm-helm GitHub repository](https://github.com/kasmtech/kasm-helm) and check out the tagged release that corresponds to your Kasm version (e.g., `release/1.1190.0`): ```bash git clone https://github.com/kasmtech/kasm-helm.git cd kasm-helm git checkout release/1.1190.0 ``` Then install from the local chart directory: ```bash helm install {RELEASE_NAME} ./charts/kasm-helm -n {NAMESPACE} -f my-values.yaml ``` ::: --- ### 6. Verify All Pods Are Running ```bash kubectl get pods -n {NAMESPACE} --watch ``` Wait until all pods show `Running` or `Completed`, then press `Ctrl+C`. --- ## Post-Installation ### Configure DNS Retrieve the ingress address assigned to your deployment: ```bash kubectl get ingress -n {NAMESPACE} ``` Update your DNS record for `publicAddr` to point to the value in the `ADDRESS` column. Once DNS has propagated, Kasm will be reachable at `https://{publicAddr}`. ### Retrieve Credentials The quickest way to see all post-install information is: ```bash helm get notes {RELEASE_NAME} -n {NAMESPACE} ``` Or retrieve credentials directly: ```bash # Admin password (login: admin@kasm.local) kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \ -o jsonpath="{.data.admin-password}" | base64 -d; echo # User password (login: user@kasm.local) kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \ -o jsonpath="{.data.user-password}" | base64 -d; echo ``` --- ## Pulling the Latest Build The chart uses rolling image tags which are rebuilt with the latest software updates and patches on a regular schedule. While Kubernetes does not automatically check for newer images for a running service, you can trigger updates by restarting each service and ensuring the `imagePullPolicy` is set to `Always` (which is the chart's default). :::tip[Locking in a specific build] If you need to pin a specific build, you can pin to a timestamped tag such as `1.19.0-rolling-20260215` following the section [Customizing Component Image Tags](#customizing-component-image-tags). Timestamped tags are immutable so a `rollout restart` will not pull a newer build. To advance to a newer timestamped build, update the tag in your values file and run `helm upgrade`. ::: Use the command `kubectl rollout restart` to restart services and pull updates. This type of restart will respect the uptime policies in the chart and minimize disruptions. ```bash kubectl rollout restart deployment/{RELEASE_NAME}-api \ deployment/{RELEASE_NAME}-manager \ deployment/{RELEASE_NAME}-proxy \ deployment/{RELEASE_NAME}-guac \ deployment/{RELEASE_NAME}-rdp-gateway \ deployment/{RELEASE_NAME}-rdp-https-gateway \ -n {NAMESPACE} ``` Monitor rollout progress for any individual deployment: ```bash kubectl rollout status deployment/{RELEASE_NAME}-api -n {NAMESPACE} ``` :::tip[Multi-zone deployments] If you configured `kasmZones`, each zone creates its own set of Deployments with the zone name appended (for example, `{RELEASE_NAME}-api-{ZONE_NAME}`). Run `kubectl get deployments -n {NAMESPACE}` to list all Deployments in your namespace before restarting. ::: --- ## Applying Changes to a Running Instance To apply changes to your values for a running deployment, always set `dbManagement.initialize` to `false`. If left enabled, the one-time initialization job will re-run and fail on an already-initialized database. The value of `dbManagement.upgrade.enable` depends on whether the change includes a database schema migration. If applying a config change or image tag update with no schema migration (typical of rolling updates) you should set `upgrade.enable` to `false` in addition to your other changes: ```yaml dbManagement: initialize: false upgrade: enable: false ``` If an image tag update includes a database schema migration (typical of major/minor version updates, e.g. `1.18.0` -> `1.18.1`), then set the value to `true`: ```yaml dbManagement: initialize: false upgrade: enable: true ``` When `upgrade.enable: true` is set, the upgrade job runs a full database backup and restore cycle on every `helm upgrade`, regardless of whether a schema migration is needed. It will not fail if there is nothing to migrate, but it will perform unnecessary work. Always reset `upgrade.enable` to `false` once the upgrade completes. If you use `false` when a migration was required, pods will fail to start and the API logs will contain an alembic version mismatch error. Rerun the upgrade with `upgrade.enable: true` to recover, then reset it to `false`. Then run: ```bash helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \ --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml ``` --- ## Next Steps - [Configure TLS Certificates](../../how-to/kubernetes/configure_tls): Certificate management options - [Kubernetes How-To Guides](../../how-to/kubernetes): Multi-region proxies, VM migration, and more - [Upgrade Kasm on Kubernetes](../../how-to/upgrade/kubernetes): Upgrade paths - [Kubernetes Troubleshooting](../../how-to/troubleshooting/kubernetes): Diagnose pod, ingress, and storage issues --- ## Kasm Workspaces: Change Listening Port Configuration # Listening Port By default the Kasm Web Application will run on port `443`. Administrators may which to change this for various reasons. If Kasm will be deployed behind an reverse proxy, please consult the [Reverse Proxy Guide](../../how-to/networking/reverse-proxy.mdx) for additional configurations steps. ## Change Port During Installation If you would like to run the Web Application on a different port pass the `-L` flag when calling the installer. ```Bash sudo bash kasm_release/install.sh -L 8443 ``` ## Change Port Post Installation In this example we will update the **Single Server** deployment to utilize port `8443`. Changing the port of an existing installation will make existing sessions inaccessible. Administrators should destroy all existing sessions prior to making this change. - Stop All Kasm services. ```bash sudo systemctl stop kasm ``` - Update the `agent.app.config.yaml` with the desired port. ```bash sudo sed -i "s/public_port.*/public_port: 8443/g" /opt/kasm/current/conf/app/agent/agent.app.config.yaml ``` - (Optional) Verify the changes with the following command. ```bash sudo grep public_port /opt/kasm/current/conf/app/agent/agent.app.config.yaml public_port: 8443 public_port: 8443 ``` - Update the Kasm Nginx proxy configuration to listen on the desired port. ```bash sudo sed -i "s/listen.*/listen 8443 ssl ;/g" /opt/kasm/current/conf/nginx/orchestrator.conf ``` - (Optional) Verify the changes with the following command. ```bash sudo grep listen /opt/kasm/current/conf/nginx/orchestrator.conf listen 8443 ssl ; ``` - Update the `docker-compose.yaml` to export the desired port for `kasm_proxy` container. ```bash sudo sed -i "s/- \"443:443\"/- \"8443:8443\"/g" /opt/kasm/current/docker/docker-compose.yaml ``` - (Optional) Verify the changes with the following command. ```bash sudo grep kasm_proxy -A5 /opt/kasm/current/docker/docker-compose.yaml container_name: kasm_proxy image: "kasmweb/nginx:latest" ports: - "8443:8443" networks: - kasm_default_network ``` - Remove the `kasm_proxy` container so it can be recreated using the updated port mapping. ```bash sudo docker rm -f kasm_proxy ``` - Start All Kasm services. ```bash sudo systemctl start kasm ``` - Log into the Kasm UI. Create a new Kasm Session to verify configurations. - If you are unable to connect to the Kasm session it's possible you may need to change the **Proxy Port** in the Zone settings - The default **Proxy Port** setting of 0 will usually be appropriate (Kasm Workspaces will attempt to automatically determine the correct port from window.location.port) but if you are having issues connecting, or if the port is not already set to 0 you will have to change the **Proxy Port** setting. - Log into the Kasm UI as an administrator. 1. Log into the Kasm UI as an administrator. 2. Select **Infrastructure** -> **Zones**. 3. Select **Edit** next to each Zone. 5) Change the **Proxy Port** setting to the desired value. (e.g `8443`) 6) Click Save. --- ## Configure Intel & AMD GPUs in Kasm Workspaces # Manual Intel or AMD GPU configuration As of Kasm Workspaces version 1.19.0, it is no longer necessary to manually pass through Intel and AMD GPUs; they are detected automatically and managed in the UI. If using an NVIDIA GPU, please see [GPU Acceleration](./gpu.mdx). Intel and AMD GPUs are automatically detected by the Kasm Agent service and will show up in the agent details in the UI. Navigate to **Infrastructure** -> **Docker Agents** and click **Edit** on the target agent. From here you can enable/disable features of each GPU. Disabling a feature means that feature will not be used by user session containers. ![Update Agent](/img/multi_install/agent_gpu_hardware.webp) After confirming that your GPU shows up on the Agent details view, you can test using the GPU on a Workspace. Navigate to **Workspaces** -> **Workspaces** and **Edit** the target workspace. Scroll down to the **GPU Hardware** section. ![File Mappings Table](/img/images/image_gpu_settings.webp) Kasm Workspace Images must be on version 1.19.0 or higher to support automatic configuration of graphics and video acceleration covered below. For graphics acceleration, Intel and AMD GPUs generally support DRI3, EGL, and VULKAN. KasmVNC natively supports DRI3 and does not require the use of a translation layer, therefore, it is the preferred method for Intel and AMD GPUs. EGL uses VirtualGL and Vulkan uses Zink as a translation layer. Regardless of which option you pick, Kasm handles the configuration of the container to use the selected method and passes through the appropriate device. If the agent has multiple compatible GPUs for the selected method, a GPU is selected at random and passed through to the container. If you do not want a specific GPU to be used for graphics, you can disable graphics on that GPU in the Kasm Agent settings covered above. The MESA option means to use the `llvmpipe` software-based GPU. Kasm will attempt to use compatible hardware according to the order of graphics acceleration methods in the **Selected** list, which may be re-ordered by the admin. KasmVNC supports VAAPI for hardware accelerated h.264 and h.265 video encoding of the session stream. Selecting VAAPI for video acceleration will pass through the appropriate DRM device. KasmVNC will automatically detect and use that hardware for encoding if the user selects it. The `SW` option means to use software based encoding and it is recommended to leave that option in the list as a fallback. This **Selected** list of video acceleration methods may also be re-ordered and determines the order in which Kasm attempts to use compatible hardware. See the Kasm Performance page for more details. --- ## Multi-Server Kasm Workspaces Installation: Architecture & Roles # {/* to keep default heading blank */} ## Architecture Roles The following outlines the Role Service in this architecture. The ports and protocols required for communication are listed to allow for firewalls or filtering devices in your environment **Web App Server(s)** > This is the landing point for end users. If end-users access this server from the internet this may be > put in a DMZ enclave. This Server includes the following services: > > - Web Application (kasm_api) > - Manager Service (kasm_manager) > - Proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) **Database Server** > The database server must be accessible by API and Management Services. This Server includes the following services: > > - Database Service (kasm_db) - **Ports / Protocols** - POSTGRESQL (5432) **Agent Server(s)** > Agents are where end-user sessions are created. Depending on the desired architecture these may be placed in various locations. > The agent must be accessible by the Management and Web App Servers. > This server includes the following services: > > - Agent Service (kasm_agent) > - Proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) **Connection Proxy(s)** > Connection proxies are used to broker web native RDP/VNC/SSH and RDP thick client sessions to fixed or autoscaled servers. If this functionality > is not needed, this role does not need to be installed. > Connection proxies need to be accessible from the WebApp servers and to the destination RDP/VNC/SSH servers. If RDP thick client access is desired then the Connection Proxy role must be internet accessible. > This server includes the following services: > > - Guac Service (kasm_guac) > - RDP Gateway Service (kasm_rdp_gateway) > - proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) - RDP (3389) ![Multi Server Install](/img/multi_install/multiple_install.png) --- ## Kasm Workspaces: Multi-Server Proxy Installation Guide # {/* to keep default heading blank */} ## Dedicated Kasm Proxy (optional) In a standard Multi Server installation the Proxy service that handles pointing the client to the correct agent server is included with the Web App role along with all other client UI and routing. The need might arise to have many proxies spread out over different geographic locations while keeping a single web endpoint serving static web content with the Proxy serving the Kasm Workspaces session. To facilitate this there is a `proxy` installation role that installs and configures a web proxy to direct end users to the correct agent to spin up a Kasm Workspaces session. ### Proxy Overview The user follows the same workflow when launching a workspace and on the backend we direct them to the correct Agent/s, but unlike a standard Multi Server Deployment the Workspaces Session is routed through the Proxy in the user's geographic region to reduce latency. ### Proxy installation This guide assumes you have a running Multi Server deployment of Kasm Workspaces and have a basic understanding of domain/SSL management. For help with SSL certificates please see Custom Certificates The following steps can be followed to install the proxy role to a server: - Ensure the Proxy server has a domain name pointed to it and a legitimate SSL certificate. - Download the latest version of Kasm Workspaces to /tmp. - Extract the package and execute the installation. - Post install, configure Kasm Workspaces via the Web UI to use the new Proxy. In this example we assume the proxy domain is **proxy.example.com** and the Web App hosting the API server is located at **workspaces.example.com**. #### Proxy Server installation It is important that the agents in your Multi Server installation can be accessed by this Proxy server deployment ensure connectivity to the Agent server from the Proxy server before installation. In order to install the proxy role you will need to know the URL for the Web App server you plan to have your users connect from. This endpoint will be pointed to for authentication and is needed to enforce strict [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) policies. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release*-latest.tar.gz \ && sudo bash kasm_release/install.sh --role proxy --api-hostname workspaces.kasmweb.com ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release*.tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role proxy --api-hostname workspaces.kasmweb.com ``` #### Post Install Configuration With the proxy running you will need to login to your Kasm Workspaces installation as an administrator and navigate to Admin->Settings->Global->Authentication->Kasm Auth Domain. Change this setting to **example.com** and click Save. Next navigate to Admin->Infrastructure->Zones->Click the arrow next to the zone you want to point to the Proxy->Edit Set **Proxy Hostname** to **proxy.example.com** While in this menu also set **Upstream Auth Address** to **workspaces.example.com** With these setting changed we need to restart the API server container on the Web App server/s: ```Bash sudo docker restart kasm_api ``` When a user now deploys a Kasm Workspace their streaming session will be served up by this new external proxy instead of the default one deployed with the Web App role. --- ## Kasm Workspaces Multi-Server Installation Guide # {/* to keep default heading blank */} ## Installation Guide Follow these steps to setup Kasm on separate servers. ## Install Database Server Role The Database can be configured as a standalone database such as an Amazon RDS instance or an existing Postgres instance, instead of the container provided by Kasm Technologies. For more information, see Standalone Remote Database. The following steps will install the database service on the **Database Server**. - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation. Please note the default login credentials produced during the install. | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] | If you have an activation key it can be passed to the installation script and activation will be completed on your behalf as part of the install. Create a file for the activation key e.g. `activation_key.txt` and paste in the activation key you received in your confirmation email. When running the install.sh use the parameter `-a or --activation-key-file` so your command might look something like this `sudo bash kasm_release/install.sh -a activation_key.txt`. This will not work with an offline air-gapped install, as Kasm Workspaces must contact an activation server to complete licensing your installation. In a multi server install this option only applies to the database role. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz ``` :::note Starting in 1.19.0, the default installation uses rolling images to deliver ongoing security fixes and updates. For static images with manual update control, pass the `-f` or `--use-static-images` argument during the installation or upgrade process. ```Bash sudo bash kasm_release/install.sh -f or sudo bash kasm_release/upgrade.sh -f ``` Refer to Rolling Image Management for more information about rolling images. ::: The **DATABASE_USERNAME** and **DATABASE_NAME** are optional and only required if not using the default kasm/kasmapp settings on an Installation 1.13.0 or newer. ## Install Web App Role The following steps will provision the Web App components on a single server. Repeat these steps on additional servers to add redundancy and scalability. Utilize a single public DNS name with multiple public IPs to have DNS load distribute requests to the Web App Kasm Workspaces server cluster. For the next steps you need the following information - DATABASE_HOSTNAME : The IP, hostname or FQDN of the Database Server that is resolvable and reachable by the Web App server. - DATABASE_PASSWORD : The database password generated during the installation of the database. - DATABASE_USERNAME **Optional** : The database username if using a custom one. This does not need to be included if using a standard Database Server Role installation. - DATABASE_NAME **Optional** : The database name if using a custom one. This does not need to be included if using a standard Database Server Role installation. Before continuing, verify this server can access port \[DATABASE_HOSTNAME\]:5432 Use the `-z` flag to set the Deployment Zone that the components will use. The zone will be created if it does not already exist in the deployment. Unless specified, components will use the "default" zone. Ex: `-z east` Installation is the only time that a new Deployment Zone can be created. - Download the latest version of Kasm Workspaces to /tmp - Extract the package and run execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` - Log into the Web Application running on port 443 at **https://\** - The Default usernames are **admin@kasm.local** and **user@kasm.local**. The passwords will be randomly generated and presented at the end of the install unless the `--admin-password` or/and `--user-password` are specified. ![Default Login Window](/img/login.webp) ## Install Agent Server Role(s) The following steps will install the Agent and Proxy services. Repeat these steps for any additional servers intended to provision end user sessions For the next steps you need the following information - MANAGER_HOSTNAME : The IP, hostname or FQDN of the Web App Server that is resolvable and reachable by the Agent server. - MANAGER_TOKEN : The manger token generated during the db install. This is used for authentication by the Agent. - AGENT_HOSTNAME : This IP, hostname, or FQDN of this Agent Server that is resolvable and reachable by the Web App Server. This value will be reported by the Agent Service during check in routines and used by other services to communicate with it. **Before continuing, verify this server can access port \[MANAGER_HOSTNAME\]:443** - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` - Log into the UI as an Administrator, select **Infrastructure > Docker Agents** and using the arrow menu select edit on the agent you just created. Make sure **Enabled** is selected and click **Save**. ## (Optional) Install Connection Proxy (Guac/rdp-gateway) Role(s) The Connection proxy role is required to support connecting to VMs/Hardware via RDP, VNC, or SSH. Workspace supports connecting to pre-exiting machines or auto provisioning them via Cloud Autoscaling. If these services are not needed, this role does not need to be installed. For the next steps you need the following information - MANAGER_HOSTNAME : The IP, hostname or FQDN of the Web App Server that is resolvable and reachable by the Agent server. - SERVICE_REGISTRATION_TOKEN : The registration token generated during the db install. This is used to register the Connection Proxy with the system. The Service Registration Token (AKA Component Registration Token) can also be found in the global settings in the Kasm Admin UI. - CONNECTION_PROXY_HOSTNAME : This IP, hostname, or FQDN of this Connection Proxy Server that is resolvable and reachable by the Web App Server. This value will be reported by the Connection Proxy Server during registration and used by other services to communicate with it. **Before continuing, verify this server can access port \[MANAGER_HOSTNAME\]:443** Use the `-z` flag to set the Deployment Zone that the components will use. Unless specified, components will use the "default" zone. Ex: `-z east` - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` | Flag | Description | | :--- | :---------- | | `-v, --verbose` | Verbose output | | `-e, --accept-eula` | Accept End User License Agreement | | `-d, --no-db-init` | Skip database initialization | | `-D, --no-start` | Don't start services at the end of installation | | `-W, --default-images` | Seed and Download default Workspaces Images | | `-z, --server-zone` | Server Zone (Deployment Zone for components) | | `-q, --db-hostname` | Database Hostname | | `-Q, --db-password` | Default Database Password | | `-c, --database-user` | Database user | | `-j, --database-name` | Database name | | `-t, --no-db-ssl` | Database, Disable SSL | | `-T, --db-port` | Database port for external DB (default 5432) | | `-U, --user-password` | Default User Password | | `-P, --admin-password` | Default Admin Password | | `-p, --public-hostname` | Agent/Component IP/Hostname used to register with deployment | | `-m, --manager-hostname` | Manager IP/Hostname | | `-M, --manager-token` | Manager Token | | `-i, --agent-server-id` | Set Agent server ID | | `-n, --api-hostname` | Set API server hostname | | `-a, --activation-key-file` | License Activation key file path | | `-w, --offline-workspaces` | Path to the tar.gz workspace images offline installer | | `-s, --offline-service` | Path to the tar.gz service images offline installer | | `-x, --offline-network-plugin` | Path to the tar.gz network plugin images offline installer | | `--offline-logger-plugin` | Path to the tar.gz logger plugin images offline installer | | `-O, --use-rolling-images` | Use rolling Workspaces images | | `-f, --use-static-images` | Use static version Workspaces images | | `-G, --db-master-password` | Database master password for database remote init | | `-g, --db-master-user` | Database master user for database remote init | | `-r, --agent-provider` | Set agent provider | | `-A, --enable-lossless` | Enable lossless streaming option | | `-k, --registration-token` | Register a component with an existing deployment | | `-y, --default-registry-url` | Set the default Workspaces Registry URL | | `-H, --no-swap-check` | Disable check for swapfile | | `-J, --swap-size` | Create swap if none exists in megabytes (e.g., `4096`) | | `-B, --no-check-ports` | Do not check for open ports | | `-b, --no-check-disk` | Do not check disk space | | `-N, --skip-connection-test` | Skip database connection tests | | `-X, --skip-v4l2loopback` | Skip v4l2loopback installation | | `--guac-cluster-size` | Set guac cluster size, 0 for automatic | | `--skip-custom-rclone` | Install the stock Rclone plugin without modification | | `--skip-egress` | Do not install egress network plugin or dependencies | | `--enable-epel` | Enable EPEL repo to install packages not in default RHEL repos. Required for WireGuard on RHEL/Rocky/AlmaLinux/Oracle 8 — pass this flag explicitly or respond `y` to the interactive prompt. | | `--ignore-dep-failures` | Continue installation even if optional dependencies fail to install | | `--install-depends` | Force dependency installation even during offline installs. Has no effect on online installs (deps always run by default). | | `--ssl-public-cert` | Copy the public SSL certificate from this path during install | | `--ssl-private-key` | Copy the private SSL key from this path during install | --- ## Multi-Server Kasm Workspaces Installation Guide # Multi Server Installation In this example, the Kasm services are installed on different servers within the environment. Depending on the desired use case, these servers can be put in separate network enclaves according to your environment and typical security best practices. Please read through the entire process before getting started. Troubleshooting info can be found on the [Troubleshooting Page](../../how-to/troubleshooting) Issues can be reported on the [Kasm Workspaces Issues Page](https://github.com/kasmtech/workspaces-issues/issues) ## Architecture Roles The following outlines the Role Service in this architecture. The ports and protocols required for communication are listed to allow for firewalls or filtering devices in your environment **Web App Server(s)** > This is the landing point for end users. If end-users access this server from the internet this may be > put in a DMZ enclave. This Server includes the following services: > > - Web Application (kasm_api) > - Manager Service (kasm_manager) > - Proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) **Database Server** > The database server must be accessible by API and Management Services. This Server includes the following services: > > - Database Service (kasm_db) - **Ports / Protocols** - POSTGRESQL (5432) **Agent Server(s)** > Agents are where end-user sessions are created. Depending on the desired architecture these may be placed in various locations. > The agent must be accessible by the Management and Web App Servers. > This server includes the following services: > > - Agent Service (kasm_agent) > - Proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) **Connection Proxy(s)** > Connection proxies are used to broker web native RDP/VNC/SSH and RDP thick client sessions to fixed or autoscaled servers. If this functionality > is not needed, this role does not need to be installed. > Connection proxies need to be accessible from the WebApp servers and to the destination RDP/VNC/SSH servers. If RDP thick client access is desired then the Connection Proxy role must be internet accessible. > This server includes the following services: > > - Guac Service (kasm_guac) > - RDP Gateway Service (kasm_rdp_gateway) > - proxy (kasm_proxy) - **Ports / Protocols** - HTTPS (443) - RDP (3389) ![Multi Server Install](/img/multi_install/multiple_install.png) ## Ports and Protocols The ports listed below are defaults. The listening port for agents and web app servers can be customized during installation using the `-L` flag (e.g., `install.sh --role agent -L 5173`). If you change default ports, ensure all firewall rules and autoscale configurations are updated accordingly. | Source | Destination | Port | Notes | | --- | --- | --- | --- | | End User | Web App Server | 443 | Web Application / UI / API | | End User | Connection Proxy (rdp-gateway) | 3389 | RDP Connection | | Web App Server | Database Server | 5432 | Database Access (PostgreSQL) | | Web App Server | Agent Server | 443 | Agent Instructions | | Web App Server | Connection Proxy (Guac) | 443 | Proxied RDP Connections to VMs/Hardware | | Web App Server | VM/Hardware (KasmVNC) | 8443 | Proxied KasmVNC Connections to VMs/Hardware | | Agent Server | Management Server | 443 | Check-in, Request Images, Request Authentication | | Connection Proxy (Guac) | VM/Hardware RDP Systems | 3389 | Converts RDP to Web native rendering via Guac | | Connection Proxy (Guac) | VM/Hardware VNC Systems | 5900 | Converts VNC to Web native rendering via Guac | | Connection Proxy (Guac) | VM/Hardware SSH Systems | 22 | Converts SSH to Web native rendering via Guac | | Connection Proxy (Guac) | Web App Server | 443 | RDP Connection Authorization and Status Checks | | Connection Proxy (rdp-gateway) | VM/Hardware RDP Systems | 3389 | RDP Connection | ## System Requirements Please review the [System Requirements](../../explanations/system-requirements.mdx) before beginning. Kasm provides a Sizing and Deployment Guide to aid in determining hardware specifications for large scale deployments. ## Installation Guide Follow these steps to setup Kasm on separate servers. ## Install Database Server Role The Database can be configured as a standalone database such as an Amazon RDS instance or an existing Postgres instance, instead of the container provided by Kasm Technologies. For more information, see Standalone Remote Database. The following steps will install the database service on the **Database Server**. - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation. Please note the default login credentials produced during the install. | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] | If you have an activation key it can be passed to the installation script and activation will be completed on your behalf as part of the install. Create a file for the activation key e.g. `activation_key.txt` and paste in the activation key you received in your confirmation email. When running the install.sh use the parameter `-a or --activation-key-file` so your command might look something like this `sudo bash kasm_release/install.sh -a activation_key.txt`. This will not work with an offline air-gapped install, as Kasm Workspaces must contact an activation server to complete licensing your installation. In a multi server install this option only applies to the database role. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role db --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz ``` :::note Starting in 1.19.0, the default installation uses rolling images to deliver ongoing security fixes and updates. For static images with manual update control, pass the `-f` or `--use-static-images` argument during the installation or upgrade process. ```Bash sudo bash kasm_release/install.sh -f or sudo bash kasm_release/upgrade.sh -f ``` Refer to Rolling Image Management for more information about rolling images. ::: The **DATABASE_USERNAME** and **DATABASE_NAME** are optional and only required if not using the default kasm/kasmapp settings on an Installation 1.13.0 or newer. ## Install Web App Role The following steps will provision the Web App components on a single server. Repeat these steps on additional servers to add redundancy and scalability. Utilize a single public DNS name with multiple public IPs to have DNS load distribute requests to the Web App Kasm Workspaces server cluster. For the next steps you need the following information - DATABASE_HOSTNAME : The IP, hostname or FQDN of the Database Server that is resolvable and reachable by the Web App server. - DATABASE_PASSWORD : The database password generated during the installation of the database. - DATABASE_USERNAME **Optional** : The database username if using a custom one. This does not need to be included if using a standard Database Server Role installation. - DATABASE_NAME **Optional** : The database name if using a custom one. This does not need to be included if using a standard Database Server Role installation. Before continuing, verify this server can access port \[DATABASE_HOSTNAME\]:5432 Use the `-z` flag to set the Deployment Zone that the components will use. The zone will be created if it does not already exist in the deployment. Unless specified, components will use the "default" zone. Ex: `-z east` Installation is the only time that a new Deployment Zone can be created. - Download the latest version of Kasm Workspaces to /tmp - Extract the package and run execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role app --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role app --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --db-hostname [DATABASE_HOSTNAME] --db-password [DATABASE_PASSWORD] --database-user [DATABASE_USERNAME] --database-name [DATABASE_NAME] ``` - Log into the Web Application running on port 443 at **https://\** - The Default usernames are **admin@kasm.local** and **user@kasm.local**. The passwords will be randomly generated and presented at the end of the install unless the `--admin-password` or/and `--user-password` are specified. ![Default Login Window](/img/login.webp) ## Install Agent Server Role(s) The following steps will install the Agent and Proxy services. Repeat these steps for any additional servers intended to provision end user sessions For the next steps you need the following information - MANAGER_HOSTNAME : The IP, hostname or FQDN of the Web App Server that is resolvable and reachable by the Agent server. - MANAGER_TOKEN : The manger token generated during the db install. This is used for authentication by the Agent. - AGENT_HOSTNAME : This IP, hostname, or FQDN of this Agent Server that is resolvable and reachable by the Web App Server. This value will be reported by the Agent Service during check in routines and used by other services to communicate with it. **Before continuing, verify this server can access port \[MANAGER_HOSTNAME\]:443** - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role agent --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role agent --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz --public-hostname [AGENT_HOSTNAME] --manager-hostname [MANAGER_HOSTNAME] --manager-token [MANAGER_TOKEN] ``` - Log into the UI as an Administrator, select **Infrastructure > Docker Agents** and using the arrow menu select edit on the agent you just created. Make sure **Enabled** is selected and click **Save**. ## (Optional) Install Connection Proxy (Guac/rdp-gateway) Role(s) The Connection proxy role is required to support connecting to VMs/Hardware via RDP, VNC, or SSH. Workspace supports connecting to pre-exiting machines or auto provisioning them via Cloud Autoscaling. If these services are not needed, this role does not need to be installed. For the next steps you need the following information - MANAGER_HOSTNAME : The IP, hostname or FQDN of the Web App Server that is resolvable and reachable by the Agent server. - SERVICE_REGISTRATION_TOKEN : The registration token generated during the db install. This is used to register the Connection Proxy with the system. The Service Registration Token (AKA Component Registration Token) can also be found in the global settings in the Kasm Admin UI. - CONNECTION_PROXY_HOSTNAME : This IP, hostname, or FQDN of this Connection Proxy Server that is resolvable and reachable by the Web App Server. This value will be reported by the Connection Proxy Server during registration and used by other services to communicate with it. **Before continuing, verify this server can access port \[MANAGER_HOSTNAME\]:443** Use the `-z` flag to set the Deployment Zone that the components will use. Unless specified, components will use the "default" zone. Ex: `-z east` - Download the latest version of Kasm Workspaces to /tmp - Extract the package and execute the installation ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --role guac --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role guac --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --api-hostname [MANAGER_HOSTNAME] --public-hostname [CONNECTION_PROXY_HOSTNAME] --registration-token [SERVICE_REGISTRATION_TOKEN] ``` | Flag | Description | | :--- | :---------- | | `-v, --verbose` | Verbose output | | `-e, --accept-eula` | Accept End User License Agreement | | `-d, --no-db-init` | Skip database initialization | | `-D, --no-start` | Don't start services at the end of installation | | `-W, --default-images` | Seed and Download default Workspaces Images | | `-z, --server-zone` | Server Zone (Deployment Zone for components) | | `-q, --db-hostname` | Database Hostname | | `-Q, --db-password` | Default Database Password | | `-c, --database-user` | Database user | | `-j, --database-name` | Database name | | `-t, --no-db-ssl` | Database, Disable SSL | | `-T, --db-port` | Database port for external DB (default 5432) | | `-U, --user-password` | Default User Password | | `-P, --admin-password` | Default Admin Password | | `-p, --public-hostname` | Agent/Component IP/Hostname used to register with deployment | | `-m, --manager-hostname` | Manager IP/Hostname | | `-M, --manager-token` | Manager Token | | `-i, --agent-server-id` | Set Agent server ID | | `-n, --api-hostname` | Set API server hostname | | `-a, --activation-key-file` | License Activation key file path | | `-w, --offline-workspaces` | Path to the tar.gz workspace images offline installer | | `-s, --offline-service` | Path to the tar.gz service images offline installer | | `-x, --offline-network-plugin` | Path to the tar.gz network plugin images offline installer | | `--offline-logger-plugin` | Path to the tar.gz logger plugin images offline installer | | `-O, --use-rolling-images` | Use rolling Workspaces images | | `-f, --use-static-images` | Use static version Workspaces images | | `-G, --db-master-password` | Database master password for database remote init | | `-g, --db-master-user` | Database master user for database remote init | | `-r, --agent-provider` | Set agent provider | | `-A, --enable-lossless` | Enable lossless streaming option | | `-k, --registration-token` | Register a component with an existing deployment | | `-y, --default-registry-url` | Set the default Workspaces Registry URL | | `-H, --no-swap-check` | Disable check for swapfile | | `-J, --swap-size` | Create swap if none exists in megabytes (e.g., `4096`) | | `-B, --no-check-ports` | Do not check for open ports | | `-b, --no-check-disk` | Do not check disk space | | `-N, --skip-connection-test` | Skip database connection tests | | `-X, --skip-v4l2loopback` | Skip v4l2loopback installation | | `--guac-cluster-size` | Set guac cluster size, 0 for automatic | | `--skip-custom-rclone` | Install the stock Rclone plugin without modification | | `--skip-egress` | Do not install egress network plugin or dependencies | | `--enable-epel` | Enable EPEL repo to install packages not in default RHEL repos. Required for WireGuard on RHEL/Rocky/AlmaLinux/Oracle 8 — pass this flag explicitly or respond `y` to the interactive prompt. | | `--ignore-dep-failures` | Continue installation even if optional dependencies fail to install | | `--install-depends` | Force dependency installation even during offline installs. Has no effect on online installs (deps always run by default). | | `--ssl-public-cert` | Copy the public SSL certificate from this path during install | | `--ssl-private-key` | Copy the private SSL key from this path during install | ## Dedicated Kasm Proxy (optional) In a standard Multi Server installation the Proxy service that handles pointing the client to the correct agent server is included with the Web App role along with all other client UI and routing. The need might arise to have many proxies spread out over different geographic locations while keeping a single web endpoint serving static web content with the Proxy serving the Kasm Workspaces session. To facilitate this there is a `proxy` installation role that installs and configures a web proxy to direct end users to the correct agent to spin up a Kasm Workspaces session. ### Proxy Overview The user follows the same workflow when launching a workspace and on the backend we direct them to the correct Agent/s, but unlike a standard Multi Server Deployment the Workspaces Session is routed through the Proxy in the user's geographic region to reduce latency. ### Proxy installation This guide assumes you have a running Multi Server deployment of Kasm Workspaces and have a basic understanding of domain/SSL management. For help with SSL certificates please see Custom Certificates The following steps can be followed to install the proxy role to a server: - Ensure the Proxy server has a domain name pointed to it and a legitimate SSL certificate. - Download the latest version of Kasm Workspaces to /tmp. - Extract the package and execute the installation. - Post install, configure Kasm Workspaces via the Web UI to use the new Proxy. In this example we assume the proxy domain is **proxy.example.com** and the Web App hosting the API server is located at **workspaces.example.com**. #### Proxy Server installation It is important that the agents in your Multi Server installation can be accessed by this Proxy server deployment ensure connectivity to the Agent server from the Proxy server before installation. In order to install the proxy role you will need to know the URL for the Web App server you plan to have your users connect from. This endpoint will be pointed to for authentication and is needed to enforce strict [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) policies. ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release*-latest.tar.gz \ && sudo bash kasm_release/install.sh --role proxy --api-hostname workspaces.kasmweb.com ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release*.tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --role proxy --api-hostname workspaces.kasmweb.com ``` #### Post Install Configuration With the proxy running you will need to login to your Kasm Workspaces installation as an administrator and navigate to Admin->Settings->Global->Authentication->Kasm Auth Domain. Change this setting to **example.com** and click Save. Next navigate to Admin->Infrastructure->Zones->Click the arrow next to the zone you want to point to the Proxy->Edit Set **Proxy Hostname** to **proxy.example.com** While in this menu also set **Upstream Auth Address** to **workspaces.example.com** With these setting changed we need to restart the API server container on the Web App server/s: ```Bash sudo docker restart kasm_api ``` When a user now deploys a Kasm Workspace their streaming session will be served up by this new external proxy instead of the default one deployed with the Web App role. ## Install troubleshooting The install.sh script creates a log file as it runs, this file is removed upon completion of a successful installation. However, if something does go wrong the logfile will be available from the directory the install.sh script was executed from in the format `kasm_install_${TIMESTAMP}.log`. This file will be important for diagnosing the error that caused the installation to fail and will be requested when submitting a support ticket with Kasm Technologies. --- ## Installing on Other Linux Operating Systems # Other Operating Systems The officially supported operating systems that Kasm Workspaces can be installed on can be found on the [System Requirements page](../../explanations/system-requirements.mdx) . However, **Workspaces can be installed on any Linux operating system with bash, openssl, Docker-CE, and docker compose** pre-installed. The installation script checks if docker and docker compose are installed, if all the requirements are met the script will bypass operating system checks. Generally, this means that Workspaces can be installed on any Linux based operating system that Docker supports. ## RedHat 8/9/10 The following instructions show how to install Docker-CE, docker compose, and OpenSSL on RedHat 8, 9 or 10. ```bash # Install dependencies sudo yum install -y yum-utils device-mapper-persistent-data lvm2 nc openssl lsof curl sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # start docker sudo systemctl enable --now docker sudo systemctl start docker ``` **Note:** Docker may fail to start due to missing kernel modules in RHEL 10, as all kernel modules related to the `iptables` utility have been moved to `kernel-modules-extra`. If you see errors like, `iptables failed: addrtype not supported, missing kernel module? xt_addrtype`, install the missing modules and start Docker: ```bash sudo dnf install -y kernel-modules-extra sudo reboot sudo systemctl enable --now docker sudo systemctl start docker ``` ## Optional Dependencies Outside of Docker and Compose, Kasm Workspaces can gain additional functionality through Docker plugins or other system packages being installed. ### Rclone for Cloud Storage Mapping Installing the rclone docker plugin will enable the ability to map [Cloud storage providers](../../how-to/data-storage/storage-mappings/index.mdx) into Workspaces sessions. The following basic steps can be adapted for use on the desired target operating system. ```yml export DOCKER_PLUGIN_DIR=$(sudo docker info | awk -F': ' '/Docker Root Dir/ {print $2}')-plugins #install fuse. Replace this line with something appropriate for the target operating system sudo yum install -y fuse mkdir -p ${DOCKER_PLUGIN_DIR}/rclone/config sudo mkdir -p ${DOCKER_PLUGIN_DIR}/rclone/cache # Arch is either amd64 or arm64 sudo docker plugin install rclone/docker-volume-rclone:${ARCH} args="-v" --alias rclone --grant-all-permissions sudo rm -f ${DOCKER_PLUGIN_DIR}/rclone/cache/docker-plugin.state sudo ln -s /dev/null ${DOCKER_PLUGIN_DIR}/rclone/cache/docker-plugin.state ``` ### v4l2loopback for Webcam support This will allow [Webcam Passthrough](../../how-to/workspaces-sessions/container-workspace/webcam-passthrough.mdx) for Workspaces sessions. *RHEL 8/9/10* ```yml sudo yum install -y --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E %rhel).noarch.rpm sudo yum install -y --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm sudo yum install -y v4l2loopback ``` Using this method the host will be limited to 8 virtual webcam devices, keep this in mind when making deployment decisions. --- ## Standalone Remote Database Setup for Kasm Workspaces # Standalone Remote Database Admins may wish to use a Managed Database Service such as RDS and Elasticache or have a separate PostgreSQL Database server from their Kasm installation. This guide provides instructions on how to initialize the database server from a remote machine and then install the Kasm WebApp. ## Requirements - Remote PostgreSQL server supports PostgreSQL version 16. - Remote PostgreSQL either already has a User "kasmapp" in the database "kasm" **OR** you have SuperUser credentials on the database. - Machine executing initialization and the Web App server can both connect to the PostgreSQL Database (default port TCP/5432) - Remote PostgreSQL must support the UUID-OSSP Extension. The Kasm installer will attempt to create the extension, if it is not already enabled. If you are using the **Azure Database for PosgreSQL** PaaS, you will need to enable the UUID-OSSP extension from the Azure portal prior to following the below steps. In the Azure portal, navigate to your Postgres database, go to Server Parameters, search for `azure.extensions`, hit the drop-down and check th box next to UUID-OSSP. Hit the Save button to apply the change. Wait for the change to apply, this can take a few minutes. ## When performing an installation ### Initializing PostgreSQL Server - This can be done from anywhere, but since the script will install docker and other Kasm prerequisites it may be easiest to run the remote DB install from the future Kasm Web App server. - Download latest version of Kasm Workspaces to /tmp - Extract package and initialize the Database. ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz sudo bash kasm_release/install.sh \ --accept-eula \ --role init_remote_db \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --db-master-user [DATABASE_SUPERUSER_USERNAME] \ --db-master-password [DATABASE_SUPERUSER_PASSWORD] ``` If the Database already has the **User** "kasmapp" and **database** "kasm" created you may omit the `-g` and `-G` parameters. The **DATABASE_USERNAME** and **DATABASE_NAME** are optional and only required if not using the default kasm/kasmapp settings. ### Installing Kasm Web App - Download latest version of Kasm Workspaces to /tmp - Extract package and initialize the Database. ```Bash cd /tmp tar -xf kasm_release*.tar.gz sudo bash kasm_release/install.sh \ --role app \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ ``` ### Backing up the PostgreSQL Server - This script should be run from a Kasm Web App server. If you are backing up a standalone remote database for Kasm Workspaces 1.10.0 we will need to use the backup script that is included with the [[release]] release as the one included with 1.10.0 did not support a remote standalone database: - Download the latest version of Kasm Workspaces to /tmp - Extract package and run the backup script - If necessary, use the `--exclude-logs` flag or `-l` to exclude log data from the backup ```Bash cd /tmp tar -xf kasm_release*.tar.gz sudo bash kasm_release/bin/utils/db_backup \ --backup-file [DESIRED_BACKUP_FILE_LOCATION] \ --database-hostname [DATABASE_HOSTNAME] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --path [PATH_TO_KASM_INSTALL] ``` If you are backing up a standalone remote database for Kasm Workspaces 1.11.0 or newer then use the existing db_backup script: :::warning Starting in version 1.17.0, the backup destination directory must be readable and writable by the `kasm_db` user (ID 70). When the directory lacks these permissions, the backup fails. ::: ```Bash sudo bash /opt/kasm/bin/utils/db_backup -v --backup-file [DESIRED_BACKUP_FILE_LOCATION] -q [DATABASE_HOSTNAME] --path [PATH_TO_KASM_INSTALL] ``` - The backup will be present at the location specified with **--backup-file** ### Restoring the PostgreSQL server from a backup - This script should be ran from a Kasm Web App server or during a Kasm Workspaces upgrade from the server that ran the database clean install step. - You will need SuperUser credentials on the database. - Make sure that All Kasm Web App and Agent servers have their services stopped. ```bash sudo bash /opt/kasm/[[release]]/bin/utils/db_restore \ --backup-file [LOCATION_OF_BACKUP_FILE] \ --database-hostname [DATABASE_HOSTNAME] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --path /opt/kasm/[[release]] \ --database-master-user [DATABASE_MASTER_USER] \ --database-master-password [DATABASE_MASTER_USER_PASSWORD] ``` - After the restore is complete restart all Kasm Web App and Agent services. ## When performing an upgrade Before performing an upgrade ensure all Kasm Workspaces Containers/Sessions are stopped on all hosts in your deployment. `sudo systemctl stop kasm` Also ensure the "Automatically Enable Agents" is enabled under settings in the Admin Dashboard. These instructions are for upgrading from Kasm Workspaces >= 1.11.0 to [[release]]. ### Upgrading Kasm Web App #### Database migration The database migration commands should be run once from the Kasm Web App with access to the remote database. Any additional Kasm Web App server does not need to execute database migrations again. * Stop all services: ```Bash sudo systemctl stop kasm ``` * Grab and extract the installer for [[release]]: ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz ``` * Generate a database backup: If necessary, use the `--exclude-logs` flag or `-l` to exclude log data from the backup. Note that this will result in an empty logs interface after the upgrade. ```bash sudo mkdir -p /opt/kasm/backups/ sudo chown 70 /opt/kasm/backups/ sudo bash kasm_release/bin/utils/db_backup \ --backup-file /opt/kasm/backups/[[previous_release]]_backup.tar \ --database-hostname [DATABASE_HOSTNAME] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --path /opt/kasm/current ``` On systems with a restrictive umask (for example, 0077), the generated backup file may not have sufficient read permissions for the upgrade process, which can cause the restore step to fail. If necessary, adjust the permissions on the backup directory and file (e.g., `chmod 750 /opt/kasm/backups` and `chmod 640 /opt/kasm/backups/.tar`) before proceeding. * Log into your PostgreSQL server as the master user and remove the database/user: ```Bash drop database if exists kasm; drop user if exists kasmapp; ``` * Init the empty DB, restore our backup, and upgrade the database: ```bash sudo bash kasm_release/install.sh \ --accept-eula \ --role init_remote_db \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --db-master-user [DATABASE_MASTER_USER] \ --db-master-password [DATABASE_MASTER_USER_PASSWORD] sudo bash /opt/kasm/[[release]]/bin/utils/db_restore \ --backup-file /opt/kasm/backups/[[previous_release]]_backup.tar \ --database-hostname [DATABASE_HOSTNAME] \ --path /opt/kasm/[[release]] \ --database-master-user [DATABASE_MASTER_USER] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --database-master-password [DATABASE_MASTER_USER_PASSWORD] sudo bash /opt/kasm/[[release]]/bin/utils/db_upgrade \ --database-hostname [DATABASE_HOSTNAME] \ --path /opt/kasm/[[release]] ``` * Seed the new images for this installation: ```bash sudo /opt/kasm/[[release]]/bin/utils/db_init \ --database-hostname [DATABASE_HOSTNAME] \ --seed-file /opt/kasm/[[release]]/conf/database/seed_data/default_images_amd64.yaml ``` #### Kasm Web App upgrade * Run a clean install of [[release]]: ```bash sudo bash kasm_release/install.sh \ --role app \ --no-start \ --db-hostname [DATABASE_HOSTNAME] \ --db-password [DATABASE_KASMAPP_USER_PASSWORD] \ --database-user [DATABASE_USERNAME] \ --database-name [DATABASE_NAME] \ --skip-connection-test ``` * Update config information: ```bash export MANAGER_ID=$(/opt/kasm/bin/utils/yq_$(uname -m) '.manager.manager_id' /opt/kasm/[[previous_release]]/conf/app/api/api.app.config.yaml) sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.manager.manager_id = "'${MANAGER_ID}'"' /opt/kasm/[[release]]/conf/app/api/api.app.config.yaml ``` * **Advanced**: Review the contents of the existing configs to ensure any custom docker settings are migrated to the new configuration. ```Bash diff /opt/kasm/[[previous_release]]/docker/docker-compose.yaml /opt/kasm/[[release]]/docker/docker-compose.yaml ``` * Start the Kasm Web App: ```Bash sudo systemctl start kasm ``` ### Upgrading Kasm Agent * Stop all services: ```Bash sudo systemctl stop kasm ``` * Grab and extract the installer for [[release]]: ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz ``` * Execute a clean install: ```Bash sudo bash kasm_release/install.sh \ --role agent \ --no-start \ --public-hostname [AGENT_HOSTNAME] \ --manager-hostname [MANAGER_HOSTNAME] \ --manager-token [MANAGER_TOKEN] ``` * Update config information: ```bash export SERVER_ID=$(/opt/kasm/bin/utils/yq_$(uname -m) '.agent.server_id' /opt/kasm/[[previous_release]]/conf/app/agent/agent.app.config.yaml) sudo /opt/kasm/bin/utils/yq_$(uname -m) -i '.agent.server_id = "'${SERVER_ID}'"' /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml ``` * Copy the auto-generated nginx configs for any sessions that may exists on the Agent: ```bash /opt/kasm/[[previous_release]]/conf/nginx/containers.d/* /opt/kasm/[[release]]/conf/nginx/containers.d/ ``` * **Advanced**: Review the contents of the existing configs to ensure any custom docker settings are migrated to the new configuration. ```bash diff /opt/kasm/[[previous_release]]/docker/docker-compose.yaml /opt/kasm/[[release]]/docker/docker-compose.yaml diff /opt/kasm/[[previous_release]]/conf/app/agent.app.config.yaml /opt/kasm/[[release]]/conf/app/agent/agent.app.config.yaml ``` * Start the Kasm Agent: ```Bash sudo systemctl start kasm ``` ### Upgrading/Adding the Guac Role This service is used to connect to VM/Hardware running RDP, VNC, or SSH. If these capabilities are not needed, this role does not need to be installed. * On a new server Grab and extract the installer for [[release]]: ```bash cd /tmp curl -O [[storage_url]]kasm_release_[[release]].tar.gz tar -xf kasm_release*.tar.gz ``` * Login to the Workspaces UI as an administrator. Retrieve the value of **Component Registration Token** from the Global Settings. * Execute a clean install: ```Bash sudo bash kasm_release/install.sh \ --role guac \ --api-hostname [API_HOSTNAME] \ --public-hostname [GUAC_SERVER_HOSTNAME] \ --registration-token [COMPONENT_REGISTRATION_TOKEN] ``` --- ## Single Server Kasm Workspaces Installation Guide # Single Server Installation The simplest way to deploy Kasm Workspaces is to install all application services on a single server. End-user sessions will also be provisioned on this server. All interior [docker](../../reference/glossary.mdx#docker) communication occurs within the single server and there are no special configurations required. Please read through the entire process before getting started. For help please see [Help and Support](./support.mdx). In the Single Server configurations all services communicate via internal docker networks. Only access to the Web Application and port 3389 for RDP gateway access (if desired) needs to be exposed. | Source | Destination | Port | Notes | | :--------- | :-------------- | :--- | :---------------------- | | End User | Kasm Workspaces | 443 | Web Application | | End User | Kasm RDP Gateway | 3389 | RDP Thick Client Access | ## Installation Guide Please review the System Requirements before beginning. Kasm provides a Sizing and Deployment Guide to aid in determining hardware specifications for large scale deployments. - Download the latest version of Kasm Workspaces to `/tmp` - Extract the package and run the installation script. | Contents | URL | SHA256 | |:-----------------|:-----------------------------------------------|:-------------------| | Installer Bundle | [[storage_url]]kasm_release_[[release]].tar.gz | [[release_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz | [[amd_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz | [[amd_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz | [[amd_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz | [[amd_logging_plugin_images_sha256]] | | Contents | URL | SHA256 | |:---------------|:------------------------------------------------------------------------------------------|:-------------------------------------| | Services | [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz | [[arm_service_images_sha256]] | | Workspaces | [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz | [[arm_workspace_images_sha256]] | | Network Plugin | [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz | [[arm_network_plugin_images_sha256]] | | Logging Plugin | [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz | [[arm_logging_plugin_images_sha256]] | ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_amd64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --offline-workspaces /tmp/kasm_release_workspace_images_amd64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_amd64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_amd64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_amd64_[[logging_plugin_release]].tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]]-latest.tar.gz \ && sudo bash kasm_release/install.sh --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]]-latest.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]]-latest.tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]]-latest.tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]]-latest.tar.gz ``` ```bash cd /tmp \ && curl --fail-early \ -fO [[storage_url]]kasm_release_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_service_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz \ -fO [[storage_url]]kasm_release_workspace_images_arm64_[[release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz.sha256sum \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz \ -fO [[storage_url]]kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz.sha256sum \ && sha256sum --check *.sha256sum \ && tar -xf kasm_release_[[release]].tar.gz \ && sudo bash kasm_release/install.sh --use-static-images --offline-workspaces /tmp/kasm_release_workspace_images_arm64_[[release]].tar.gz --offline-service /tmp/kasm_release_service_images_arm64_[[release]].tar.gz --offline-network-plugin /tmp/kasm_release_network_plugin_images_arm64_[[network_plugin_release]].tar.gz --offline-logger-plugin /tmp/kasm_release_logging_plugin_images_arm64_[[logging_plugin_release]].tar.gz ``` :::note Starting in 1.19.0, the default installation uses rolling images to deliver ongoing security fixes and updates. For static images with manual update control, pass the `-f` or `--use-static-images` argument during the installation or upgrade process. ```Bash sudo bash kasm_release/install.sh -f or sudo bash kasm_release/upgrade.sh -f ``` Refer to Rolling Image Management for more information about rolling images. ::: - Log into the Web Application running on port 443 at **https://\** - The Default usernames are **admin@kasm.local** and **user@kasm.local**. The passwords will be randomly generated and presented at the end of the install unless the `--admin-password` or/and `--user-password` are specified. ![Default Login Window](/img/login.webp) If you have an activation key it can be passed to the installation script and activation will be completed on your behalf as part of the install. Create a file for the activation key e.g. `activation_key.txt` and paste in the activation key you received in your confirmation email. When running the install.sh use the parameter `-a or --activation-key-file` so your command might look something like this `sudo bash kasm_release/install.sh -a activation_key.txt`. This will not work with an offline air-gapped install, as Kasm Workspaces must contact an activation server to complete licensing your installation. In a multi server install this option only applies to the database role. If you would like to run the Web Application on a different port pass the **-L** flag when calling the installer. e.g `sudo bash kasm_release/install.sh -L 8443` | Flag | Description | | :--- | :---------- | | `-v, --verbose` | Verbose output | | `-e, --accept-eula` | Accept End User License Agreement | | `-D, --no-start` | Don't start services at the end of installation | | `-W, --default-images` | Seed and Download default Workspaces Images | | `-L, --proxy-port` | Default Proxy Listening Port (e.g., `8443` for HTTPS on alternate port) | | `-U, --user-password` | Default User Password | | `-P, --admin-password` | Default Admin Password | | `-a, --activation-key-file` | License Activation key file path | | `-w, --offline-workspaces` | Path to the tar.gz workspace images offline installer | | `-s, --offline-service` | Path to the tar.gz service images offline installer | | `-x, --offline-network-plugin` | Path to the tar.gz network plugin images offline installer | | `--offline-logger-plugin` | Path to the tar.gz logger plugin images offline installer | | `-O, --use-rolling-images` | Use rolling Workspaces images | | `-f, --use-static-images` | Use static version Workspaces images | | `-A, --enable-lossless` | Enable lossless streaming option | | `-H, --no-swap-check` | Disable check for swapfile | | `-J, --swap-size` | Create swap if none exists in megabytes (e.g., `4096`) | | `-B, --no-check-ports` | Do not check for open ports | | `-b, --no-check-disk` | Do not check disk space | | `-X, --skip-v4l2loopback` | Skip v4l2loopback installation | | `--skip-egress` | Do not install egress network plugin or dependencies | | `--enable-epel` | Enable EPEL repo to install packages not in default RHEL repos. Required for WireGuard on RHEL/Rocky/AlmaLinux/Oracle 8 — pass this flag explicitly or respond `y` to the interactive prompt. | | `--ignore-dep-failures` | Continue installation even if optional dependencies fail to install | | `--install-depends` | Force dependency installation even during offline installs. Has no effect on online installs (deps always run by default). | | `--ssl-public-cert` | Copy the public SSL certificate from this path during install | | `--ssl-private-key` | Copy the private SSL key from this path during install | ## Install Video Tutorial This video walks through installing Kasm Workspaces on a single system. ## Install troubleshooting The install.sh script creates a log file as it runs, this file is removed upon completion of a successful installation. However, if something does go wrong the logfile will be available from the directory the install.sh script was executed from in the format `kasm_install_${TIMESTAMP}.log`. This file will be important for diagnosing the error that caused the installation to fail and will be requested when submitting a support ticket with Kasm Technologies. Kasm Technologies. --- ## Get Help: Installation & Support Resources | Comprehensive Guides # Help and Support Resources There is a wealth of self-help, guided and community resources available should you get stuck. Official Kasm Customer Support {" - Get direct assistance from Kasm experts with guaranteed response times."} Knowledge Base {" - In-depth how-to guides and advanced troubleshooting articles."} Troubleshooting Guide {" - Find configuration walkthroughs, implementation guidance, and advanced troubleshooting."} GitHub Community Issue Tracker {" - Submit reproducible bugs, search known issues, or request product enhancements."} Reddit Community (r/kasmweb) {" - Exchange deployment ideas, use cases, and practical lessons with other Kasm users."} YouTube Video Tutorials {" - Watch guided demonstrations, administration, integrations, and end-user workflows."} FAQ {" - Quick answers to the most common installation, configuration, licensing, and architecture questions."} --- ## Uninstall Kasm: Complete Removal Guide for All Components # Uninstall - Stop All Kasm services. ```bash sudo systemctl stop kasm.service sudo systemctl stop kasm-network-plugin.service ``` - Remove the Kasm systemd service units. ```bash sudo systemctl disable kasm.service sudo systemctl disable kasm-network-plugin.service sudo rm /etc/systemd/system/kasm.service sudo rm /etc/systemd/system/kasm-network-plugin.service sudo systemctl daemon-reload ``` - Remove any Kasm session containers. ```bash sudo docker rm -f $(sudo docker container ls -qa --filter="label=kasm.kasmid") ``` If there are no session containers to remove, you will get an error that “docker rm requires at least 1 argument”, which means that the command ran successfully - Remove Kasm service containers. ```bash export KASM_UID=$(id kasm -u) export KASM_GID=$(id kasm -g) sudo -E docker compose -f /opt/kasm/current/docker/docker-compose.yaml rm ``` - Remove the Kasm docker network. ```bash sudo docker network rm kasm_default_network ``` - Remove the Kasm sidecar docker network plugin. ```bash plugin_name=$(sudo docker network inspect kasm_sidecar_network --format '{{.Driver}}') sudo docker network rm kasm_sidecar_network sudo docker plugin disable $plugin_name sudo docker plugin rm $plugin_name sudo rm -rf /var/log/kasm-sidecar sudo rm -rf /var/run/kasm-sidecar ``` - Remove the Kasm database docker volume. ```bash sudo docker volume rm kasm_db_[[release]] ``` - Remove the Kasm docker images. ```bash sudo docker rmi postgres:14-alpine sudo docker rmi kasmweb/nginx:latest sudo docker rmi kasmweb/share:[[release]] sudo docker rmi kasmweb/agent:[[release]] sudo docker rmi kasmweb/manager:[[release]] sudo docker rmi kasmweb/api:[[release]] sudo docker rmi $(sudo docker images --filter "label=com.kasmweb.image=true" -q) ``` - Remove the Kasm installation directory structure. ```bash sudo rm -rf /opt/kasm/ ``` - Remove the Kasm User Accounts. ```bash sudo deluser kasm_db sudo deluser kasm ``` --- ## Open Links in Kasm Isolated Browser Workspaces # Open Untrusted Links in an Isolated Browser The Kasm Open-In Isolation browser extension provides a browser context-menu option for opening a link or selected text in an isolated Kasm Session. Allowing a user that is navigating the web to easily open untrusted links with the malware protection and anonymization that Kasm Isolation provides. ![Right Click Option for Kasm](/img/open_in_extension/right_click.webp) This guide explains how to set up the Kasm Extension to work with an existing Kasm Workspaces deployment. ## Download Links [Chrome Extension](https://chrome.google.com/webstore/detail/kasm-open-in-isolation/pamimfbchojeflegdjgijcgnoghgfemn?hl=en-US) [Firefox Extension](https://addons.mozilla.org/en-US/firefox/addon/kasm-open-in-isolation) ## Setting Kasm User Settings Navigate to the user profile settings on your Kasm deployment by logging into your Kasm Workspaces deployment, and clicking on the profile icon at the top right. ![Edit Profile](/img/open_in_extension/profile.webp) Scroll down and change the Default Workspace Image to the desired browser image. ![Default Workspace Image Setting](/img/open_in_extension/drop_down.webp) Alternatively an Admin may setup a [Casting Config](../how-to/workspaces-sessions/sessions/session-casting.mdx) with the "Allow Resume" and "Allow Dynamic Kasm Url Parameter" settings enabled. The key from the cast config can be entered in the browser extension settings. ## Configuring Extension For **Firefox** the settings for the extension can be accessed by going to `about:addons`, selecting the Kasm Extension and clicking on "Preferences" for. ![Firefox Options](/img/open_in_extension/firefox.webp) For **Chrome** the options can be accessed through the menu shown in the screenshot below. ![Chrome Options](/img/open_in_extension/chrome.webp) ## Configuration Options ![Extension Options](/img/open_in_extension/settings.webp) | Option | Details | | :----: | :----: | | Kasm URL | This is the full URL for Kasm Workspaces, no special paths are needed simply the URL | | Open Method | "Use Go" will open a new Workspace on init, "Use Cast Key" will send the URL to a casting endpoint. Using the casting settings "Allow Dynamic Kasm URL Parameter" and "Allow Resume" can give the user a stateful browser session surviving client restarts [more information for casting](../how-to/workspaces-sessions/sessions/session-casting.mdx) | | Open In | "New Tab" will open the link or text in a new tab while "New Window" will open a new browser window configured without any clutter in the title bar to provide a progressive web application experience | | Search Engine | When opening selected text from a web page if the extension determines the text is not a URL it will be passed to a search engine, select the search engine you prefer here from our list of options or use a custom endpoint | | Replace Text | Allows any number of text strings to be replaced before passing it to the Workspace | ### Text Replacement Text replacement will replace any string in the find field with the string in the replace field. This supports [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) in the find field and the text is processed clientside before deciding how to send it to the Workspace. This can be useful for taking text that is not in standard hyperlink format and converting it into a usable URL and land directly on the URL instead of searching for it. Real world examples: | Find | Replace | Details | | :----: | :----: |--- | | `/your_string/g` | `your_replace` | This will replace all instances of the match inside your selection instead of just the first one | | `/^www/` | `https://www` | This will prepend `https://` to any text selected and if the URL is valid will go directly to that page, IE selecting and opening `www.kasmweb.com` will open `https://www.kasmweb.com` on the Workspace | | `/\[\.\]/g` | `.` | Revert standard URL defanging to change all instances of `[.]` to `.` | | `hxxp` | `http` | Revert standard URL defanging to change `hxxp` to `http` | | `/\[\:\]/g` | `:` | Revert standard URL defanging to change all instances of `[:]` to `:` | | `hXXp` | `http` | Revert standard URL defanging to change `hXXp` to `http` | --- ## Remote Browser Isolation (RBI) # Remote Browser Isolation One of the biggest security risks to organizations is direct internet access to the endpoint. Employees typically need access to the internet to do their jobs, but the proliferation of viruses, malware and phishing attacks pose a significant risk. A single mis-click and the organizations infrastructure can be exposed to viruses and ransomware. Browser Isolation categorically removes this risk, by shifting the paradigm of how this internet is accessed. Users can still access the internet from their endpoint systems, but instead use a remote, containerized browser that is accessed directly from their native browser. Kasm Workspaces provides browser isolation by running a remote, containerized browser that is rendered inside the user's local browser. This allows organizations to cut off direct internet access to the endpoint and tightly control what goes in and out of the network. This is the ultimate protection from viruses, ransomware, and other types of malware. It also enhances data loss prevention programs by allowing administrative control items uploaded , downloaded and copied to the Kasm. ## Seamless Browsing To make browser isolation feel more seamless to the end users, Kasm Workspaces provides additional interfaces that make regular tasks feel the same. For example, when the user attempts to navigate to a website using their local browser, the request is intercepted, A Kasm remote browser is shown, and the remote browser navigates to original website requested. In similar fashion if a user clicks a link in local document or email, the local browser is launched, loads the Kasm remote browser, and navigates to the link that was in the document. ## /go URL Kasm Workspaces exposes a **/go** url that is used to launch or resume as Default Kasm for a user. **kasm_url** can also be passed as a query argument to this URL and exposed as a variable when defining [Docker Exec Config](../how-to/workspaces-sessions/container-workspace/workspaces.mdx#docker-exec-config) to launch a new browser tab. ### go url examples ```bash https:///#/go?kasm_url= https://kasm.company.local/#/go?kasm_url=https%3A%2F%2Fwww.wikipedia.org ``` When resuming an existing session, include the `kasm_url` query parameter if you want the **go** Docker Exec command to open a URL. For desktop images, define the **go** and **assign** commands in [Docker Exec Config](../how-to/workspaces-sessions/container-workspace/workspaces.mdx#docker-exec-config). The Default Kasm can be configured as a [Group Setting](../how-to/security/users-groups-mgmt/groups.mdx#group-settings) or as a [User Setting](../how-to/security/users-groups-mgmt/users.mdx#user-settings) ## Auto Login Kasm offers a group and user setting to automatically launch users into a Kasm after login. The user will have the default Kasm that is configured on either a group or user setting. This is similar to the Go URL but it does not require the user to explicitly go to the /go URL. It pushes them directly after login. This is useful when users want to be abstracted from the image creation and dashboard interface. The User attribute will override the group setting therefore if some users want to still be pushed to the user dashboard after login they may set the auto login to false. ### Workflow Seamless browsing works by intercepting the user's original request and sending the client a redirect to Kasm Workspaces with the original request URL encoded in the **kasm_url** parameter. The client's browser then navigates to Kasm Workspaces and the isolated browser running inside the Kasm sandbox then navigates to the originally requested URL. In order to do this redirection an explicit or implicit forward proxy is needed. Most large organizations will have a forward poxy. In order to do redirection with URL encoding of the original request, the proxy must be capable of configuring custom rules. We have included configuration examples for [F5](//docs/guide/browser_isolation#f5) , [Blue Coat](remote-browser-isolation.mdx#bluecoat) and [Palo Alto](remote-browser-isolation.mdx#palo-alto) vendors. ## Forward Proxy An explicit forward proxy is one that is explicitly configured in the browser or operating system. Most enterprise forward proxies will allow you to create a policy that will properly redirect users request to Kasm. The system needs to redirect, using HTTPS status code 302, to [https://kasm.company.local/#/go](https://kasm.company.local/#/go)?kasm_url=ORIGINAL_URL where kasm.company.local is the hostname of your Kasm installation and ORIGINAL_URL is the user's originally requested URL. This URL needs to be URL encoded. The following sections cover different forward proxy implementations. If your organization already has a compatible proxy in place, then creating a new policy to redirect is all that is needed. If a proxy is not already in place, clients will need the organizations root CA cert trusted by their browser and/or Operating system. If the proxy is an explicit proxy, the browser and/or operating system will need proxy settings configured. ## BlueCoat The BlueCoat proxy can be configured to redirect users to Kasm and encode the orginal request so that Kasm can navigate the isolated browser to the original request. The following link provides a similar example, except this policy redirects users based on URLs that are not categorized. So the rule needs to be modifed to trigger for all URLs, whith the exception of '[https://kasm.company.local](https://kasm.company.local)' (replace with your Kasm installation domain name). The return code needs to be 302 instead of 307, and the destination URL needs to be modified to '[https://kasm.company.local/#/go](https://kasm.company.local/#/go)?kasm_url=\$(1)'. [https://support.symantec.com/en_US/article.TECH241785.html](https://support.symantec.com/en_US/article.TECH241785.html) ## F5 An F5 acting as a forward proxy for an enterprise network can redirect users to Kasm and block direct access to the interent. This is done using an iRule. In he following example, kasm.company.local is the domain name of the Kasm installation. ```none when HTTP_REQUEST { if { ([HTTP::host] != "kasm.company.local") and ([TCP::local_port] == 80) } { HTTP:redirect https://kasm.company.local/#/go?kasm_url=http://[HTTP::host][HTTP::uri] } if { ([HTTP::host] != "kasm.company.local") and ([TCP::local_port] == 443) } { HTTP:redirect https://kasm.company.local/#/go?kasm_url=https://[HTTP::host][HTTP::uri] } } ``` ## Palo Alto The Palo Alto Next Gen Firewall can be configured to redirect users to Kasm by utilizing custom **Response Pages** for URL Filtering block, override or continue actions. Administrators may desire to restrict users from accessing certain URLs or categories directly, and instead present users with a special Response Page with the option to visit the link in isolation via Kasm, or even automatically redirect them. Please consult the following vendor documentation for configuration steps. [https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-admin/url-filtering/url-filtering-concepts/url-filtering-response-pages.html](https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-admin/url-filtering/url-filtering-concepts/url-filtering-response-pages.html) Below are example block pages that may be used to redirect users. Block Page to automatically redirect the user to Kasm ```html // highlight-next-line ``` [Default Palo Alto Block Page with a link to open the blocked site in Kasm](https://www.kasmweb.com/docs/latest/guide/browser_isolation.html#id7) ```html Web Page Blocked

Web Page Blocked

Access to the web page you were trying to visit has been blocked in accordance with company policy. Please contact your system administrator if you believe this is in error.

User:

URL:

Category:

// highlight-next-line
Open Site in Kasm

If you feel this page has been incorrectly blocked, you may click Continue to proceed to the page. However, this action will be logged.

Return to previous page
``` ## Kasm Squid Squid is an open source forward proxy. We have developed a containerized version of Squid for proxy redirection. This project is open source and located at [https://bitbucket.org/kasmtech/kasm_squid/src/master/](https://bitbucket.org/kasmtech/kasm_squid/src/master/) ## Installation - Clone the repository at [https://bitbucket.org/kasmtech/kasm_squid/src/master/](https://bitbucket.org/kasmtech/kasm_squid/src/master/) - Run the install redirector script with the Kasm Workspaces url after the -k argument ```Bash sudo ./install_redirector.sh -k https://kasm.company.internal ``` - Download myCA.der from /srv/kasm_squid/ssl_cert/myCA.der For most browsers, windows settings can be used for the proxy settings. ## Setup Root CA Trust - Use the windows key + r shortcut to open the run prompt - Type in secpol.msc and click OK - Select public Key Policies from the Security Settings - Open the Certificate Path Validation Settings window ![Certificate Validation](/img/browser_isolation/certificate_validation.png) - Check Define these policy settings - Make sure to select all of these > - Allow user trusted root CAs to be used to validate certificates > - Allow users to trust peer trust certificates > - Third-Party Root CAs and Enterprise Root CAs - Select apply - Use the windows key + r shortcut to pen the run prompt - Type in certmgr.msc and click OK - Expand Trusted Root Certification Authorities - Right click certificates -> all tasks -> import ![Certificate Import](/img/browser_isolation/certificate_import.png) - Browse to the certificate and select open - Click next, next and finish ## Setup proxy in windows settings - Open Windows settings and select Network and Internet - Select proxy at the bottom left - Under manual proxy setup select Use a proxy server ![Proxy Settings](/img/browser_isolation/proxy_settings.jpg) - Enter the Kasm proxy server address and port 3122 - Enter the Kasm domain into the excluded proxy addresses - Select save For browsers like Edge, Chrome and Internet Explorer the proxy should be up and working. Firefox will need to be configured separately. ## Setup Firefox - In the Firefox options select privacy and security - Scroll to the bottom and click View Certificates - Import myCA.der from the Kasm Proxy - Check all boxes and click OK ![Import to Firefox](/img/browser_isolation/firefox_import.jpg) - Navigate to the General tab - Scroll to the bottom for Network Settings - Select Manual proxy configuration - Input the IP address of the squid server and port 3122 - Select Use proxy for all protocols - Add in the Kasm Workspaces domain name under no proxy for - Select OK ![Firefox Proxy Config](/img/browser_isolation/firefox_proxy.jpg) Firefox will now redirect all traffic through the secure Kasm. ## Troubleshooting If the browser is not connecting to the proxy make sure to open port 3122 on the proxy server. If the Kasm seems to be reconnecting make sure the browser is configured to not use the proxy settings for the Kasm Workspaces server as Squid does not handle websockets. If HTTPS or security warning errors are occurring, ensure the root certificate is installed on the browser. Ensure that the proxy was installed using the domain name for the actual Kasm Workspaces server. --- ## Protected Web Apps: Secure Access Setup # Secure Web Based Applications Protected Web Apps are browser based applications that are either hosted internally on protected enclaves or are other SaaS based web applications that administrators wish to publish to end user while employing the robust authentication and DLP controls of Kasm. ## Configuring a Browser-based Workspace 1. Log into the Kasm UI as an administrator. 2. From the Admin panel, expand **Workspaces**, and select **Registry** 3. The Kasm Workspace Registry entries should be visible. Select the Chrome Workspaces from the list, then select **Edit** 4. Update the name description of the workspace to something helpful. In this example we will use `Gitlab`. 5. In the **Docker Run Config Override** section enter the following data to configure the chrome browser to open to a specified URL (e.g `https://gitlab.com/users/sign_in`). ```json { "environment": { "LAUNCH_URL": "https://gitlab.com/users/sign_in" } } ``` 6. Adding a URL to a thumbnail of the target application will help user's quickly identify the workspace (e.g `https://gitlab.com/favicon.png`). Once done, click **Save** ## Launching the Workspace 1. Back on the Workspace dashboard, the new `Gitlab` workspace should be visible. 2. Launch the workspace and confirm the browser navigates to the desired web app. ## (Optional) Kiosk Mode In the last example, you will notice that the containerized chrome browser fully loads within the end user's browser. This will give a "browser in browser" effect that may or may not be desirable. If you'd like to remove the navigation bar from within the Chrome workspace, change the Docker Run Config Override setting for the `Gitlab` (Chrome) Workspace to include the `--kiosk` argument for the `LAUNCH_URL` environment variable. ```json { "environment": { "LAUNCH_URL": "--kiosk https://gitlab.com/users/sign_in" } } ``` The difference between the default behavior and kiosk mode can be seen below. ## (Optional) Managed Browser Policies Administrators may wish to add and/or enforce certain capabilities within the containerized browsers such as pre-defining bookmarks, adding extensions or disabling features like developer tools. The best way to do this is via the [Chrome's Managed Policies Guide](../how-to/workspaces-sessions/container-workspace/chrome-managed-policies.mdx). ## (Optional) Web Filter Administrators my wish to employ the Web Filter to restrict users from accessing web content outside of the approved web app. 1. Log into the Kasm UI as an administrator. 2. From the Admin panel, expand **Settings**, and select **Web Filter** 3. Select Add Policy 4. Give the Policy a name (e.g `Gitlab Policy`) and select **Deny by Default**. 5. In this example we want to block all access except for the gitlab domain ad any other required domains needed (e.g for authentication with google). Add the approved domains to the **Whitelist**. 6. Click Save. 7. Edit the previously defined workspace, update the Web Filter Policy to the use the `Gitlab Policy`. 8. Test access to the Protected Web App. Ensure proper functionality is allowed. Navigating to an unapproved site should result in a blockage. ## (Optional) Watermarking Administrators may wish to apply a graphic or text based watermark to be displayed during the session. Utilize the following File Mapping example, to apply a watermark to the [Using File Mapping to Apply a Custom KasmVNC Watermark](../how-to/workspaces-sessions/file-mappings.mdx#using-file-mapping-to-apply-a-custom-kasmvnc-watermark) Workspace. ## (Optional) DLP Controls Administrators may wish to apply additional data loss prevention settings such as restricting the user's ability to upload/download files, copy and paste text/image via the clipboard etc. Most of these items can be applied via Group Settings and are explained in the [Data Loss Prevention Guide](../how-to/security/data-loss-prevention.mdx) It may be helpful to review how Group Settings can be applied and layered. A walkthrough is available in the video below --- ## Control Panel The in-session control panel serves as a centralized hub for accessing various tools and features that enhance your interaction with the remote desktop environment. It provides you with convenient options to customize your session, manage audio settings, transfer files, control streaming quality, and more. This documentation will guide you through the different functionalities of the control panel, empowering you to make the most out of your remote desktop experience. ![Control Panel](/img/user_guide/new_control_panel.webp) ## Sound Audio produced within the session can be toggled on and off via the **Sound** item. Depending on certain browser settings, users may need to click inside the session at least once in order for audio to start playing ## Webcam Access to a local webcam can be toggled on and off via the **Webcam** item. ## Webcam Pass-through The local webcam can be used within the Kasm session by enabling this option. Depending on browser settings, the user may be asked to grant permission to the microphone. ![Webcam Permission Pop-Up Box](/img/user_guide/webcam_permission.png) ## Webcam Settings In addition to the basic on/off toggle, there are more nuanced settings that the user can control to optimize their webcam usage within a Kasm session. These include: * Quality * FPS (frames per second) * Webcam Device ### Quality The quality setting allows you to control the video feed's compression level from your webcam. While selecting a higher quality setting can result in a more detailed and sharp image, it will lead to an increased consumption of bandwidth. ### FPS The FPS, or frames per second, refers to the frame rate of the webcam video feed. The higher the rate, the more responsive the feed will be. Yet, it's important to note that higher frame rates will lead to increased badwidth consumption. ### Webcam Device This setting allows you to select which webcam device you want to use within the session, especially beneficial if your setup includes multiple webcams. The change in the webcam device will be instantaneous. However, please note that showing the webcam settings might require you to grant permissions to access your devices. This is standard procedure to protect your privacy and to ensure the software can find all connected webcam devices. You may be prompted with a permission pop-up box, like the one shown below: ![Webcam Permission Pop-Up Box](/img/user_guide/webcam_permission.png) For more detailed information about webcam pass-through, please refer to [../../how-to/webcam_passthrough](../../how-to/workspaces-sessions/container-workspace/webcam-passthrough.mdx). ## Microphone Pass-through The local microphone can be used within the Kasm session by enabling this option. Depending on browser settings, the user may be asked to grant permission to the microphone. ![Microphone Permission Pop-Up Box](/img/user_guide/mic_permission.webp) ## Clipboard The clipboard option in the control panel allows you interact with the clipboard of the remote host. If you are using a Chromium based browser on your local system, such as: Chrome, Chromium, Brave, or Edge, there is no need to use the manual clipboard control. Kasm supports seamless clipboard for Chromium based browsers. For non-Chromium based browsers, such as Firefox, Safari, and Internet Explorer, you will need to use the control panel to transfer text to and from the remote session's clipboard. ## Download The download option in the control panel gives you a list of files that are in the remote session's download folder. You can then download any file in this folder to your local computer. The Downloads folder is located at `/home/kasm-user/Downloads`. The downloads can be sorted by Name, Date and Size. ![Sorting Downloads](/img/user_guide/downloads.webp) ## Upload The upload option in the control panel gives you the ability to upload files on your local computer to the remote session. Files uploaded will be placed at `/home/kasm-user/Uploads`. ## Displays If your local computer has multiple monitors, you can use the Kasm display manager to add additional displays and manage their location. The `Auto Placement` option is available for supported browsers. With this option enabled, Kasm will automatically detect your local monitors and arrange new windows appropriately. For devices with high DPI monitors, you may see a `Native Resolution` option in the display manager. By default, Kasm will try to adjust the remote display resolution to provide an optimal experience. Users may wish to override this behavior by enabling the `Native Resolution`, which will force the remote resolution of the session to match the physical resolution of local monitors. ![Display Manager](/img/user_guide/display_manager.webp) ## Streaming quality Kasm Workspaces allows users to control settings that affect streaming quality which have direct impact not only on the image quality but also server performance and network bandwidth usage. The settings can be found in the `Control Panel` under the `Streaming Quality` section. ### Guac based workspaces Guac based workspaces have less options than container based workspaces. #### Scaling Mode | Name | Description | |----------------------|-----------------------------| | Remote Resize | This will resize the workspace to use the full space available in the browser window | | Local Scaling | This will resize the workspace to fit within the broswer window while keeping the resolution specified | | Off | No scaling will apply, the size will be as set in the resolution with scrollbars added if needed | ### Container based workspaces #### Quality presets In order to simplify settings Kasm Workspaces provides a range of preset qualities that can be used to easily control the rendering quality. | Name | Description | |----------------------|-----------------------------| | Static | A fixed resolution of 1280x720. The image is scaled client side to fit as much screen as possible while preserving the aspect ratio. The frame rate is limited at 24fps.| | Low | A dynamic resolution with a maximum width of 1280. The height is scaled accordingly while preserving the aspect ratio. The image is scaled client side to fill the screen. The frame rate is limited at 24fps. | | Medium | A dynamic resolution matching client's resolution, resized automatically. The frame rate is limited at 60ps. | | High | Same as the medium quality but with a much higher image quality. The frame rate is limited at 60ps. | | Extreme | Same as the high quality but with the video mode disabled. The frame rate is limited at 60ps. | #### Advanced settings Users that require a finer control over streaming quality can use the advanced settings that can be found by toggling the `Advanced` dropdown available when a medium or higher quality is chosen. ![Where to Find Advanced Quality Settings](/img/user_guide/new_advanced.webp) The following settings can be adjusted: | Name | Description | |----------------------|-----------------------------| | Scaling mode | Controls where the image scaling is applied. | | Set Resolution | Forces the server to use a given resolution. | | Max FPS | Limits the frame rate at which the server can stream. | | Performance Stats | Toggles showing of performance related statistics (CPU, Network, FPS) | ## Fullscreen Kasm Workspaces allows users to enter into a fullscreen session. When in fullscreen users should enjoy a better experience. Unfortunately this feature is not available on all mobile platforms, most notably on iOS as we use the [requestFullScreen function](https://caniuse.com/?search=requestfullscreen). If you want to use fullscreen on iOS you will need to install our [PWA](./pwa.mdx). ## Share The Share option in the control panel allows you to put your session in to sharing mode. The Session Sharing feature in Kasm allows users to place an existing session in “sharing mode”. This generates a unique URL that can be shared with other authenticated users, granting them the ability to view or interact with the session. When session sharing is enabled, the shared session is framed within a user interface that allows participants to see who is also viewing the shared session and to interact with each other using chat communications. Click here to [Learn more about session sharing](../../how-to/workspaces-sessions/sessions/session-sharing.mdx) ## Gamepads Users may pass up to 4 local gamepads into the session. Press any button on the connected Bluetooth or USB gamepad(s). If the browser detects the gamepad(s), an entry will be listed for each device. A dropdown will be visible next to each device representing the virtual device port/index ( 0 - 3 ) mapped within the session. These can be changed as desired. ![Gamepad Connection](/img/gamepad/new_connection.webp) Please see [../../how-to/gamepad_passthrough](../../how-to/workspaces-sessions/container-workspace/gamepad-passthrough.mdx) for more details. ## Advanced ### Show Keyboard Controls This option allows you to show or hide the pop keyboard button, which appears in the lower right of the screen. The pop keyboard button is used on mobile devices to pop open your native on-screen keyboard of your mobile device. Kasm automatically detects if you are on a mobile device with an on-screen keyboard and should display the pop keyboard button, however, there may be some devices where detection fails. This option allows you to forcefully display or hide the button if auto detection fails. ### IME Input Mode The IME input mode allows for different input methods required for languages with large symbol sets such as Japanese or Hindi. ### Game Mode Game mode locks the cursor center screen and provides the remote environment relative cursor movements. This is necessary for some games, such as first-person shooters. Press the escape key to break from game mode. You can also use Ctrl+Shift+2 to enable and disable game mode. ### Pointer Lock Pointer lock keeps your cursor from going outside of your local browser window. This can be used in combination with fullscreen to provide a better user experience that is closer to working on a local system. Press escape to break from pointer lock mode. You can also use Ctrl+Shift+3 to enable or disable pointer lock mode. ![Advanced Settings](/img/user_guide/new_advanced_settings.webp) --- ## User Guide: Navigating Workspaces # User Guide The User Guide walks through the end-user features of Kasm Workspaces. Learn how to navigate the launcher, interact with workspaces using the control panel, manage sessions, and use the browser extension. --- ## Launcher: Launching & Managing Sessions # Workspaces Launcher The Workspaces launcher is the main hub for all your activities in Kasm Workspaces. From this panel, you can create and connect to Workspace sessions. ![Main Workspaces Launcher Screen](/img/user_guide/launcher/launcher.webp) ## Browsing Workspaces When you open the Workspaces launcher, you will see a list of Workspaces published by the administrator. To find a specific Workspace, you have the following options: * **Workspace Search:** To search for a Workspace, type its name or relevant keywords in the search bar. You can also use search operators or advanced search options to refine your search. * **Filtering by Tags:** Workspaces can be tagged to categorize them based on their purpose or functionality. To narrow down the Workspace list, select one or more tags from the available options. Only Workspaces matching the selected tags will be displayed. ![Workspace Searching Tools](/img/user_guide/launcher/search_tools.webp) ## Launching a Workspace To launch a Workspace, follow these steps: 1. Select the Workspace you want to launch from the list. ![Launching a Session](/img/user_guide/launcher/running_sessions.webp) 2. If the Workspace is container-based, you will see additional options controlled by your administrator: * **Resume** - Reconnect to an existing session. If the session is stopped or paused , it will be started before connecting. * **Stop** - Stop a session. All file changes are preserved for stopped sessions, but any running programs will be closed. This option is only available for container-based Workspaces. * **Pause** - Pause a session. All file changes and running programs are preserved when paused. This option is only available for container-based Workspaces. * **Delete** - Delete a session. ![Session Actions](/img/user_guide/launcher/session_actions.webp) The availability of these options may vary depending on the permissions granted by your administrator. Not all options will always be available for every Workspace session. ## Managing Workspace Sessions Once you have launched a Workspace session, you can manage it using the following actions: * **Open in New Tab:** When you launch a session and choose to open it in a new tab, the Workspace session will load in a separate tab of your web browser. This allows you to switch between multiple Workspaces easily by selecting the desired tab. * **Open in Current Tab:** When you choose to open a session in the current tab, the current content of the tab will be replaced with the Workspace session. This means that any existing web page or application in the tab will be closed and replaced by the Workspace session. * **Open in New Window:** If you prefer to have the Workspace session in a separate browser window, you can choose the option to open it in a new window. This provides a dedicated window for the Workspace session, independent of your other browser tabs. * **Collapsing and Docking:** Additionally, you can manage your Workspace sessions by collapsing and docking them. By clicking the minus icon in the top right-hand corner of a session, you can collapse it and move it to the lower dock. Hovering over a docked session reveals additional actions, and clicking on it pops it back into the visible list on the left. ![Open Session Options](/img/user_guide/launcher/open_session.webp) ![Docked Sessions](/img/user_guide/launcher/docked_sessions.webp) The availability of these options may vary depending on the permissions granted by your administrator. Not all options will always be available for every Workspace session. ## Additional Features ### Usage Limits If usage limits are configured for your account, you can view the remaining time available on your user dashboard. Please note that paused and stopped sessions still count toward your allowance. ![Session Time Usage](/img/user_guide/launcher/usage_limit.webp) Clicking on the usage limit icon will provide a more detailed display. ![Detailed Session Time Usage](/img/user_guide/launcher/usage_limit_details.webp) ### Persistent Profiles Kasm Workspaces supports persistent profiles, which allow you to save your preferred settings, configurations, and files across multiple sessions. Your administrator can provide more information on how to utilize this feature and any limitations or considerations associated with using persistent profiles. To learn more about Persistent Profiles, visit the [Persistent Profiles Page](../../how-to/data-storage/persistent-profiles.mdx). ![Persistent Profiles](/img/user_guide/launcher/persistent_profiles.webp) ### Deployment Zones Kasm Workspaces offers deployment zones to optimize your workspace environment based on location or other requirements. Your administrator can guide you on the different deployment zones available, their purpose, and how to select or switch between deployment zones. To learn more about Deployment Zones, visit the [Deployment Zones Page](../../how-to/infra-autoscale/deployment-zones.mdx). ### Assigned Servers Workspaces can be created that allow you to access specific servers within a pool. If you see the following when trying to access a workspace, you do not have any available assigned servers and should contact an Administrator for further assistance. ![No Assigned Servers](/img/sessions/server_pool_none.png) --- ## User Guide: Peripheral Support # Peripheral Support Kasm Workspaces support a variety of peripherals. The following table shows where various options are supported across different configurations: Peripheral Web-Based ContainerLinux Container Web-Based Windows · RDP (KDS)Windows VM Web-Based Linux · VNCLinux VM · non-container Web-Based Linux · RDP (KDS) 4Linux VM Thick-Client Windows · RDP (KDS)Windows VM Thick-Client Linux · RDP (KDS) 4Linux VM Microphone Yes Yes No Yes Yes Yes Webcam Yes No No No Yes No Gamepad Yes No No No Yes No Yubikey (webauthn) No No No No Yes 3 No SmartCard Yes 1 Yes 1, 2 No No Yes No Generic USB No No No No Yes No Printer Redirection Yes Yes Yes No Yes No Multi-Monitor Yes No Yes No Yes Yes Local Drive No No No No Yes Yes 1. SmartCard support is available for web-based container and Windows workspaces using the Kasm Native Smartcard Client and Chrome extension 2. SmartCard support is also available for web-based Windows workspaces when using ChromeOS as your client 3. Yubikey (WebAuthn) passthrough only works with Windows 11 based clients connecting through the Microsoft Remote Desktop client (mstsc.exe) 4. On Linux RDP sessions (web-based and thick client), Smart Card, Generic USB, Printer Redirection, and Yubikey (WebAuthn) passthrough are not available because they are not implemented in xrdp. KDS = Kasm Desktop Service. --- ## User Profile: Settings, SSH Keys & Storage # User Profile In the Edit User Profile screen you can manage various aspects of your Kasm Workspaces account. Let's explore the available options and settings. ![Edit Profile Screen](/img/user_guide/profile/profile_details.webp) ## Accessing Your Profile To access your user profile, click on the round icon in the top right corner of the dashboard. and then select `Edit Profile`. You can also sign out of your account by clicking the `Sign Out` button. ![Edit Profile Button Location](/img/user_guide/profile/edit_profile.webp) The list provided represents a set of actions or options available within the user profile section of Kasm Workspaces. Here's what each item in the list refers to: * **View Profile Details:** This option allows users to access and view their profile details, which typically include information such as username, first name, last name, organization, phone number, and last session details. * **Change your password:** Users can select this option to modify their current password and set a new one for their Kasm Workspaces account. It usually involves entering the current password, followed by the desired new password and confirmation. * **Change Settings:** This option enables users to customize various settings related to their Kasm Workspaces experience. It typically includes preferences such as auto-launching sessions, chat sound effects, default workspace image, session tips display, control panel behavior, and theme selection. * **Change or add SSH Keys:** Users can manage their SSH keys through this option. It allows them to add new SSH key pairs or update the existing ones. SSH keys are used for secure authentication and access to Kasm Workspaces sessions. * **View session history:** This option provides users with access to their session history, displaying details about their past sessions, including the workspace image used, session creation time, session stop time, the user who stopped the session, and the duration of each session. These options give users control over their profile details, security settings, SSH keys, and provide insights into their session history within Kasm Workspaces. ## Profile Details In the profile details section, you can view and update your personal information, including: * User Name * First Name * Last Name * Organization * Phone * Last Session ![Profile Details Section](/img/user_guide/profile/profile_details_2.webp) ### Resetting Your Password If you need to change your password, follow these steps: 1. Click on the `Reset Password` button located in the top right corner. 2. Enter your current password, followed by your new password and confirmation. 3. Click `Save` to update your password. ![Resetting Password Options](/img/user_guide/profile/reset_password.webp) ### Group Membership Under the `Last Session` tab, you'll find the groups you are a member of. To learn more about groups, visit the [Groups Section](../../how-to/security/users-groups-mgmt/groups.mdx). ![Groups](/img/user_guide/profile/groups.webp) ## Settings The settings section allows you to customize various aspects of your Kasm Workspaces experience. ![Settings Section](/img/user_guide/profile/settings.webp) ### Auto Launch Session By enabling this setting **(default: off)**, Kasm Workspaces will automatically launch a session for you upon login. The default workspace image will be used. ### Chat Sound Effects You can enable sound effects for chat during shared sessions with this option. Click here for more info on [Shared Sessions](../../how-to/workspaces-sessions/sessions/session-sharing.mdx). ### Default Workspace Image The default Workspace image is used in two scenarios. 1. If you have the `Auto Launch Session` setting enabled, this default image will be used. 2. If you have the Kasm Browser Extension installed, you can right-click on a link and select `Open Link in Kasm` to open the link using the default workspace image. To learn more about Kasm Open In Isolation Browser Extension , visit the [Open In Isolation Browser Extension Section](../kasm-extension.mdx). ![Default Images Section](/img/user_guide/profile/default_image.webp) ### Show Tips During Session Enabling this setting **(default: off)** will display helpful tips when launching a Kasm session. ### Toggle Control Panel By enabling this setting **(default: off)**, you can open and close the control panel within a Kasm session by double-clicking the CTRL key. ![Settings Section Continued](/img/user_guide/profile/settings_2.webp) ### Theme You can adjust the app theme to your preference. The options include: * **Auto:** Automatically follows your system's OS theme settings. * **Dark:** Switches to a dark theme. * **Light:** Switches to a light theme. ![Theme Section](/img/user_guide/profile/theme.webp) ### Kasm UI Language The user can adjust their preferred language for the UI, this is seperate from the language inside a Kasm session, which is modified in the dropdown below. ![Changing Kasm UI Language](/img/user_guide/profile/ui_language_dropdown.webp) ### Kasm Session Language The user can adjust their preferred language for Kasm sessions. For container based sessions this language will be used unless the administrator has set the LC_ALL environment variable in the run_config setting for one of the user's groups or the workspace configuration. For Kasm connection proxy SSH sessions the language will be used unless the administrator has set the locale setting in connection_info on the server or modified the default global setting. This dropdown has an 'Auto' setting that will autodetect the user's language set in the browser and use that for the Kasm session. In Kasm Workspaces 1.14.0 many locales were added to the Kasm containerized workspaces in the official Workspaces Registry. ![Changing Kasm Session Language](/img/user_guide/profile/session_language_dropdown.webp) ### Kasm Session Timezone The user can adjust their preferred timezone for Kasm sessions. For container based sessions this timezone will be used unless the administrator has set the TZ environment variable in the run_config setting for one of the user's groups or the workspace configuration. For Kasm connection proxy RDP and SSH sessions the timezone will be used unless the administrator has set the timezone setting in connection_info on the server or modified the default global setting. This dropdown has an 'Auto' setting that will autodetect the user's timezone set in the browser and use that for the Kasm session. ![Changing Kasm Session Timezone](/img/user_guide/profile/session_timezone_dropdown.webp) ## SSH Keys Manage your SSH keys in this section. You have the following options: ### SSH Public Key The SSH public key is automatically injected into each new Kasm session, provided it's allowed by the administrator's policies. ![SSH Section](/img/user_guide/profile/ssh.webp) ### New Key Pair Update the SSH key pair that gets automatically injected into each new Kasm session, subject to the administrator's policies. ![Changing Key Pair Section](/img/user_guide/profile/ssh_upload.webp) ## Session Usage The session Usage displays your usage data for the past 30 days. You can customize the number of rows per page to improve readability. Available options include: * 5 * 10 * 25 * 50 * 100 The session usage details include the following information: * **Image:** The workspace image used. * **Created:** The timestamp when the session was created. * **Stopped On:** The timestamp when the session was stopped. * **Stopped By:** The user who stopped the session. * **Usage (hours):** The total duration of the session in hours. ![Session Usage Section](/img/user_guide/profile/usage.webp) ## Cloud Storage If enabled by the administrator, a **Cloud Storage** section will be visible in the profile. This panel allows users to register accounts for popular cloud storage providers that will then be automatically attached to new container-based sessions. The following services are available if enabled by the administrator - **Google Drive** - **Microsoft OneDrive** - **Dropbox** - **Nextcloud** - **AWS S3** - **Custom** (Administrators only) The **Custom** storage provider is an additional Storage Provider that is only able to be added by users that are members of the Administrators group. Clicking **Add Storage Mapping**, will bring up a form to begin configuring access to the cloud storage providers offered by the administrator. ![Add Storage Mapping](/img/storage_mapping/profile_add_storage_mapping.png) Configure the details as desired. Authentication for some storage providers (Google Drive, OneDrive, Dropbox) will be handled by the providers themselves. - **Enabled** : When enabled the Cloud Storage Mapping will be used on all new sessions. - **Read Only**: When enabled the Cloud Storage Mapping will be accessible in a read only fashion. Adding , modifying or deleting files will not be allowed. Administrators may force cloud storage mappings to be Read Only, regardless of the setting specified here. ![Configure Storage Mapping](/img/storage_mapping/dropbox/configure_storage.webp) Once configured, the storage mappings are available to be updated or deleted from the Cloud Storage section of the profile. ![Storage Mapping](/img/storage_mapping/dropbox/storage_mapping.png) Once inside a new session, the files will be available at the specified location. ![Personal Dropbox mapped into the container's file system](/img/storage_mapping/dropbox/files.png) ### Storage Provider Configuration Examples: - [Dropbox](../../how-to/data-storage/storage-mappings/dropbox.mdx) - [Google Drive](../../how-to/data-storage/storage-mappings/gdrive.mdx) - [Nextcloud](../../how-to/data-storage/storage-mappings/nextcloud.mdx) - [OneDrive](../../how-to/data-storage/storage-mappings/onedrive.mdx) - [S3](../../how-to/data-storage/storage-mappings/s3.mdx) - [Custom](../../how-to/data-storage/storage-mappings/custom.mdx) --- ## Kasm Workspaces PWA: User Guide | Installation & Removal # Progressive Web App (PWA) Welcome to the Kasm Workspaces Progressive Web App (PWA)! A PWA provides a similar experience to that of a mobile app installed from an App Store, with some key benefits for users: **Benefits for the user:** * **Small size** - You aren't installing a full application, which saves storage space on your device. * **Instant updates** - The PWA is still a website, so updates to the site are immediately available to the PWA. * **Add to homescreen** - You can add the PWA to your homescreen, making it easily accessible like any other application. * **Tables window** - Enjoy a clutter-free experience without the distraction of browser bars, maximizing the useful space available. Configuring and using PWAs requires certain administrative configurations. Refer to the [PWA Admin Guide](../../how-to/workspaces-sessions/pwa/index.mdx) for details. ## Installation PWA installation methods vary across platforms and even devices within platforms. Unfortunately PWA installation isn't universal across platforms or even devices on platforms. Some platforms prompt you to install the app when you visit a site that has PWA functionality, some just show it in the browser bar, and some don't show anything at all (iOS). Here are the installation instructions for different platforms: ### Android Using Chrome on Android tends to give the best PWA experience, When using Chrome on Android, you will be prompted to install the PWA when you visit the site. For Firefox, click on the three dots next to the browser bar and select "Install App." This also works with Chrome if you close the prompt and decide to install it later. ### iOS Unfortunately, iOS does not provide a direct indication that a PWA is available. You can only install a PWA using Safari on iOS by following these steps: 1. Open Safari and navigate to the site. 2. Tap the Share icon. 3. Scroll down until you find the option "Add to Home Screen" and tap on it. 4. Finally, tap the "Add" button to install the PWA. ### Desktop Browsers Currently, Safari on MacOS does not offer an option to install a PWA. However, other browsers support PWA installation: Most desktop browsers show the option to install the PWA either in the browser URL bar or when you click the three dots menu. ## Removing Removing a PWA can vary on Android, iOS, and desktop platforms. Here are the steps to remove the PWA from each platform: ### Android Android doesn't have a universal system for removing PWAs, as it can vary based on the phone, launcher, browser, or even the specific version of the browser. Here are three different options you can try: 1. From your app drawer or home screen, open **Settings**. 2. Tap **Apps & notifications** and then select **See all apps**. 3. Find the PWA that you want to remove and tap the icon. 4. Tap **Uninstall**. --- Alternatively: 1. Find the app on your homescreen. 2. Long press until extra information pops up. 3. Click on the Remove icon --- Or: 1. Find the app on your homescreen. 2. Long press until extra information pops up. 3. Start dragging until an option to remove appears. 4. Drop the app into the Remove area. ### iOS Removing a PWA on iOS can be done by following these steps: 1. Find the app on your home screen 2. Either long press on the background until the icons start wiggling and a minus icon appears in the top left corner on the apps, then click the minus icon, or long press on the app and click the **Delete Bookmark** option. 3. Confirm you want to delete the bookmark. ### Desktop 1. Open the Workspaces PWA. 2. At the top of the application find the three dots menu at the top right and click it. 3. Click the **Uninstall** option. 4. Click on the subsequent **Remove** button. ## Standalone PWA Apps Kasm now allows individual workspaces and casting links to be installed as standalone PWAs. To do this, launch the workspace then open the control panel. If the workspace is available to be installed as a PWA there should be an install button. What happens next will depend on the browser / device. On chromium based browsers you will be directed to the install button, on ios devices you will be directed to a page with an animation explaining how to install on safari. Safari and firefox do not currently support installing PWAs on desktop browsers. --- ## Configure Dropbox as a Storage Provider in Workspaces # ### Dropbox storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Dropbox** from the drop-down, then select **Next**. ![Configure the Dropbox storage mapping](/img/storage_mapping/dropbox/configure_storage.webp) 4. The Dropbox login page appears. Log in with the desired account. ![Log in to Dropbox](/img/storage_mapping/dropbox/login.png) 5. Dropbox asks for consent to provide access to the account. Approve the request. ![Approve Kasm access to Dropbox](/img/storage_mapping/dropbox/approve.png) 6. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The Dropbox storage mapping in the profile](/img/storage_mapping/dropbox/storage_mapping.png) 7. Launch a new container-based session. Confirm that Dropbox is mapped inside the session at the `/dropbox` location. ![Dropbox files mapped inside a session](/img/storage_mapping/dropbox/files.png) --- ## Gdrive Integration: Connecting Google Drive to Workspaces # ### Google Drive storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Google Drive** from the drop-down, then select **Next**. ![Configure the Google Drive storage mapping](/img/storage_mapping/gdrive/configure_storage.png) 4. The Google login page appears. Log in with the desired account. This account must be a test user from the OAuth app creation process. ![Log in to Google](/img/storage_mapping/gdrive/login.png) 5. When the Google OAuth app is not yet approved, a warning appears. Click **Continue**. ![Approve Kasm access to Google Drive](/img/storage_mapping/gdrive/approve.png) 6. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The Google Drive storage mapping in the profile](/img/storage_mapping/gdrive/storage_mapping.png) 7. Launch a new container-based session. Confirm that Google Drive is mapped inside the session at the `/gdrive` location. ![Google Drive files mapped inside a session](/img/storage_mapping/gdrive/files.png) --- ## Configure Nextcloud Storage Mapping in Paperspace # ### Nextcloud storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **Nextcloud** from the drop-down. Enter the **Nextcloud Username** and **Nextcloud Password**, then select **Next**. ![Configure the Nextcloud storage mapping](/img/storage_mapping/nextcloud/configure_storage.png) 4. The new storage mapping appears in the Cloud Storage section of the profile. ![The Nextcloud storage mapping in the profile](/img/storage_mapping/nextcloud/storage_mapping.png) 5. Launch a new container-based session. Confirm that the Nextcloud files are mapped inside the session at the `/nextcloud` location. ![Nextcloud files mapped inside a session](/img/storage_mapping/nextcloud/files.png) --- ## Connect OneDrive to Workspaces for Cloud Storage # ### OneDrive storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **OneDrive** from the drop-down, then select **Next**. ![Configure the OneDrive storage mapping](/img/storage_mapping/onedrive/configure_storage.png) 4. The Microsoft login page appears. Log in with the desired account. ![Log in to Microsoft](/img/storage_mapping/onedrive/login.png) 5. A consent screen appears that requests the permissions needed to access OneDrive. Approve the request. ![Approve Kasm access to OneDrive](/img/storage_mapping/onedrive/approve.png) 6. Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The OneDrive storage mapping in the profile](/img/storage_mapping/onedrive/storage_mapping.png) 7. Launch a new container-based session. Confirm that OneDrive is mapped inside the session at the `/onedrive` location. ![OneDrive files mapped inside a session](/img/storage_mapping/onedrive/files.png) --- ## Configure S3 Storage Provider for Cloud Workspaces # ### S3 storage mapping configuration 1. From any page, select the profile icon at the top right. ![Edit the user profile](/img/storage_mapping/edit_profile.png) 2. Select the **Cloud Storage** section, then **Add Storage Mapping**. ![Add a storage mapping from the profile](/img/storage_mapping/profile_add_storage_mapping.png) 3. Select **S3** from the drop-down. Enter the **S3 Access Key ID**, **S3 Secret Access Key**, and **S3 Bucket**, then select **Next**. ![Configure the S3 storage mapping](/img/storage_mapping/s3/configure_storage.png) 4. On success, Kasm redirects you to the Workspaces dashboard. The new storage mapping appears in the Cloud Storage section of the profile. ![The S3 storage mapping in the profile](/img/storage_mapping/s3/storage_mapping.png) 5. Launch a new container-based session. Confirm that the S3 buckets are mapped inside the session at the `/s3` location. ![S3 files mapped inside a session](/img/storage_mapping/s3/files.png) --- ## Translations & Language Settings # Translations Kasm Workspaces has been machine translated into 91 languages. When a user hits Workspaces it will automatically set the language to match what the user has set in their browser preferences. If you want to manually change the language that can be done by going to your **User Profile / Settings** and updating the Kasm UI Language dropdown. ![Changing Kasm UI Language](/img/user_guide/profile/ui_language_dropdown.webp) Alternatively adding `?lng=` before the # in the url, for example `https://server_or_ip/?lng=en#/dashboard` will also work. Please understand that machine translations are never perfect, if you want to help with the translations the top languages are managed at [crowdin](https://crowdin.com/project/kasm) --- ## Valid Locale Codes for Docker Run Configuration The language codes below are valid for the docker run_config setting at the group and workspace level. See [group settings](how-to/security/users-groups-mgmt/groups.mdx#group-settings) and [workspaces](how-to/workspaces-sessions/container-workspace/workspaces.mdx) for more information. Every workspace may not have every language below available. aa_DJ.UTF-8 aa_ER.UTF-8 aa_ET.UTF-8 af_ZA.UTF-8 am_ET.UTF-8 an_ES.UTF-8 ar_AE.UTF-8 ar_BH.UTF-8 ar_DZ.UTF-8 ar_EG.UTF-8 ar_IN.UTF-8 ar_IQ.UTF-8 ar_JO.UTF-8 ar_KW.UTF-8 ar_LB.UTF-8 ar_LY.UTF-8 ar_MA.UTF-8 ar_OM.UTF-8 ar_QA.UTF-8 ar_SA.UTF-8 ar_SD.UTF-8 ar_SY.UTF-8 ar_TN.UTF-8 ar_YE.UTF-8 as_IN.UTF-8 ast_ES.UTF-8 ayc_PE.UTF-8 az_AZ.UTF-8 be_BY.UTF-8 bem_ZM.UTF-8 ber_DZ.UTF-8 ber_MA.UTF-8 bg_BG.UTF-8 bho_IN.UTF-8 bn_BD.UTF-8 bn_IN.UTF-8 bo_CN.UTF-8 bo_IN.UTF-8 br_FR.UTF-8 brx_IN.UTF-8 bs_BA.UTF-8 byn_ER.UTF-8 ca_AD.UTF-8 ca_ES.UTF-8 ca_FR.UTF-8 ca_IT.UTF-8 crh_UA.UTF-8 csb_PL.UTF-8 cs_CZ.UTF-8 cv_RU.UTF-8 cy_GB.UTF-8 da_DK.UTF-8 de_AT.UTF-8 de_BE.UTF-8 de_CH.UTF-8 de_DE.UTF-8 de_LU.UTF-8 doi_IN.UTF-8 dv_MV.UTF-8 dz_BT.UTF-8 el_CY.UTF-8 el_GR.UTF-8 en_AG.UTF-8 en_AU.UTF-8 en_BW.UTF-8 en_CA.UTF-8 en_DK.UTF-8 en_GB.UTF-8 en_HK.UTF-8 en_IE.UTF-8 en_IN.UTF-8 en_NG.UTF-8 en_NZ.UTF-8 en_PH.UTF-8 en_SG.UTF-8 en_US.UTF-8 en_ZA.UTF-8 en_ZM.UTF-8 en_ZW.UTF-8 es_AR.UTF-8 es_BO.UTF-8 es_CL.UTF-8 es_CO.UTF-8 es_CR.UTF-8 es_CU.UTF-8 es_DO.UTF-8 es_EC.UTF-8 es_ES.UTF-8 es_GT.UTF-8 es_HN.UTF-8 es_MX.UTF-8 es_NI.UTF-8 es_PA.UTF-8 es_PE.UTF-8 es_PR.UTF-8 es_PY.UTF-8 es_SV.UTF-8 es_US.UTF-8 es_UY.UTF-8 es_VE.UTF-8 et_EE.UTF-8 eu_ES.UTF-8 fa_IR.UTF-8 ff_SN.UTF-8 fi_FI.UTF-8 fil_PH.UTF-8 fo_FO.UTF-8 fr_BE.UTF-8 fr_CA.UTF-8 fr_CH.UTF-8 fr_FR.UTF-8 fr_LU.UTF-8 fur_IT.UTF-8 fy_DE.UTF-8 fy_NL.UTF-8 ga_IE.UTF-8 gd_GB.UTF-8 gez_ER.UTF-8 gez_ET.UTF-8 gl_ES.UTF-8 gu_IN.UTF-8 gv_GB.UTF-8 ha_NG.UTF-8 he_IL.UTF-8 hi_IN.UTF-8 hne_IN.UTF-8 hr_HR.UTF-8 hsb_DE.UTF-8 ht_HT.UTF-8 hu_HU.UTF-8 hy_AM.UTF-8 ia_FR.UTF-8 id_ID.UTF-8 ig_NG.UTF-8 ik_CA.UTF-8 is_IS.UTF-8 it_CH.UTF-8 it_IT.UTF-8 iu_CA.UTF-8 ja_JP.UTF-8 ka_GE.UTF-8 kk_KZ.UTF-8 kl_GL.UTF-8 km_KH.UTF-8 kn_IN.UTF-8 kok_IN.UTF-8 ko_KR.UTF-8 ks_IN.UTF-8 ku_TR.UTF-8 kw_GB.UTF-8 ky_KG.UTF-8 lb_LU.UTF-8 lg_UG.UTF-8 li_BE.UTF-8 lij_IT.UTF-8 li_NL.UTF-8 lo_LA.UTF-8 lt_LT.UTF-8 lv_LV.UTF-8 mag_IN.UTF-8 mai_IN.UTF-8 mg_MG.UTF-8 mhr_RU.UTF-8 mi_NZ.UTF-8 mk_MK.UTF-8 ml_IN.UTF-8 mni_IN.UTF-8 mn_MN.UTF-8 mr_IN.UTF-8 ms_MY.UTF-8 mt_MT.UTF-8 my_MM.UTF-8 nb_NO.UTF-8 nds_DE.UTF-8 nds_NL.UTF-8 ne_NP.UTF-8 nhn_MX.UTF-8 niu_NU.UTF-8 niu_NZ.UTF-8 nl_AW.UTF-8 nl_BE.UTF-8 nl_NL.UTF-8 nn_NO.UTF-8 nr_ZA.UTF-8 nso_ZA.UTF-8 oc_FR.UTF-8 om_ET.UTF-8 om_KE.UTF-8 or_IN.UTF-8 os_RU.UTF-8 pa_IN.UTF-8 pa_PK.UTF-8 pl_PL.UTF-8 ps_AF.UTF-8 pt_BR.UTF-8 pt_PT.UTF-8 ro_RO.UTF-8 ru_RU.UTF-8 ru_UA.UTF-8 rw_RW.UTF-8 sa_IN.UTF-8 sat_IN.UTF-8 sc_IT.UTF-8 sd_IN.UTF-8 se_NO.UTF-8 shs_CA.UTF-8 sid_ET.UTF-8 si_LK.UTF-8 sk_SK.UTF-8 sl_SI.UTF-8 so_DJ.UTF-8 so_ET.UTF-8 so_KE.UTF-8 so_SO.UTF-8 sq_AL.UTF-8 sq_MK.UTF-8 sr_ME.UTF-8 sr_RS.UTF-8 ss_ZA.UTF-8 st_ZA.UTF-8 sv_FI.UTF-8 sv_SE.UTF-8 sw_KE.UTF-8 sw_TZ.UTF-8 szl_PL.UTF-8 ta_IN.UTF-8 ta_LK.UTF-8 te_IN.UTF-8 tg_TJ.UTF-8 th_TH.UTF-8 ti_ER.UTF-8 ti_ET.UTF-8 tig_ER.UTF-8 tk_TM.UTF-8 tl_PH.UTF-8 tn_ZA.UTF-8 tr_CY.UTF-8 tr_TR.UTF-8 ts_ZA.UTF-8 tt_RU.UTF-8 ug_CN.UTF-8 uk_UA.UTF-8 unm_US.UTF-8 ur_IN.UTF-8 ur_PK.UTF-8 uz_UZ.UTF-8 ve_ZA.UTF-8 vi_VN.UTF-8 wa_BE.UTF-8 wae_CH.UTF-8 wal_ET.UTF-8 wo_SN.UTF-8 xh_ZA.UTF-8 yi_US.UTF-8 yo_NG.UTF-8 yue_HK.UTF-8 zh_CN.UTF-8 zh_HK.UTF-8 zh_SG.UTF-8 zh_TW.UTF-8 zu_ZA.UTF-8 --- ## Valid Timezone List for Docker Run Config The timezones below are valid for the docker run_config setting at the group and workspace level. See [group settings](how-to/security/users-groups-mgmt/groups.mdx#group-settings) and [workspaces](how-to/workspaces-sessions/container-workspace/workspaces.mdx) for more information. Europe/Andorra Asia/Dubai Asia/Kabul Europe/Tirane Asia/Yerevan Antarctica/Casey Antarctica/Davis Antarctica/DumontDUrville Antarctica/Mawson Antarctica/Palmer Antarctica/Rothera Antarctica/Syowa Antarctica/Troll Antarctica/Vostok America/Argentina/Buenos_Aires America/Argentina/Cordoba America/Argentina/Salta America/Argentina/Jujuy America/Argentina/Tucuman America/Argentina/Catamarca America/Argentina/La_Rioja America/Argentina/San_Juan America/Argentina/Mendoza America/Argentina/San_Luis America/Argentina/Rio_Gallegos America/Argentina/Ushuaia Pacific/Pago_Pago Europe/Vienna Australia/Lord_Howe Antarctica/Macquarie Australia/Hobart Australia/Melbourne Australia/Sydney Australia/Broken_Hill Australia/Brisbane Australia/Lindeman Australia/Adelaide Australia/Darwin Australia/Perth Australia/Eucla Asia/Baku America/Barbados Asia/Dhaka Europe/Brussels Europe/Sofia Atlantic/Bermuda Asia/Brunei America/La_Paz America/Noronha America/Belem America/Fortaleza America/Recife America/Araguaina America/Maceio America/Bahia America/Sao_Paulo America/Campo_Grande America/Cuiaba America/Santarem America/Porto_Velho America/Boa_Vista America/Manaus America/Eirunepe America/Rio_Branco America/Nassau Asia/Thimphu Europe/Minsk America/Belize America/St_Johns America/Halifax America/Glace_Bay America/Moncton America/Goose_Bay America/Blanc-Sablon America/Toronto America/Nipigon America/Thunder_Bay America/Iqaluit America/Pangnirtung America/Atikokan America/Winnipeg America/Rainy_River America/Resolute America/Rankin_Inlet America/Regina America/Swift_Current America/Edmonton America/Cambridge_Bay America/Yellowknife America/Inuvik America/Creston America/Dawson_Creek America/Fort_Nelson America/Whitehorse America/Dawson America/Vancouver Indian/Cocos Europe/Zurich Africa/Abidjan Pacific/Rarotonga America/Santiago America/Punta_Arenas Pacific/Easter Asia/Shanghai Asia/Urumqi America/Bogota America/Costa_Rica America/Havana Atlantic/Cape_Verde America/Curacao Indian/Christmas Asia/Nicosia Asia/Famagusta Europe/Prague Europe/Berlin Europe/Copenhagen America/Santo_Domingo Africa/Algiers America/Guayaquil Pacific/Galapagos Europe/Tallinn Africa/Cairo Africa/El_Aaiun Europe/Madrid Africa/Ceuta Atlantic/Canary Europe/Helsinki Pacific/Fiji Atlantic/Stanley Pacific/Chuuk Pacific/Pohnpei Pacific/Kosrae Atlantic/Faroe Europe/Paris Europe/London Asia/Tbilisi America/Cayenne Africa/Accra Europe/Gibraltar America/Nuuk America/Danmarkshavn America/Scoresbysund America/Thule Europe/Athens Atlantic/South_Georgia America/Guatemala Pacific/Guam Africa/Bissau America/Guyana Asia/Hong_Kong America/Tegucigalpa America/Port-au-Prince Europe/Budapest Asia/Jakarta Asia/Pontianak Asia/Makassar Asia/Jayapura Europe/Dublin Asia/Jerusalem Asia/Kolkata Indian/Chagos Asia/Baghdad Asia/Tehran Atlantic/Reykjavik Europe/Rome America/Jamaica Asia/Amman Asia/Tokyo Africa/Nairobi Asia/Bishkek Pacific/Tarawa Pacific/Enderbury Pacific/Kiritimati Asia/Pyongyang Asia/Seoul Asia/Almaty Asia/Qyzylorda Asia/Qostanay Asia/Aqtobe Asia/Aqtau Asia/Atyrau Asia/Oral Asia/Beirut Asia/Colombo Africa/Monrovia Europe/Vilnius Europe/Luxembourg Europe/Riga Africa/Tripoli Africa/Casablanca Europe/Monaco Europe/Chisinau Pacific/Majuro Pacific/Kwajalein Asia/Yangon Asia/Ulaanbaatar Asia/Hovd Asia/Choibalsan Asia/Macau America/Martinique Europe/Malta Indian/Mauritius Indian/Maldives America/Mexico_City America/Cancun America/Merida America/Monterrey America/Matamoros America/Mazatlan America/Chihuahua America/Ojinaga America/Hermosillo America/Tijuana America/Bahia_Banderas Asia/Kuala_Lumpur Asia/Kuching Africa/Maputo Africa/Windhoek Pacific/Noumea Pacific/Norfolk Africa/Lagos America/Managua Europe/Amsterdam Europe/Oslo Asia/Kathmandu Pacific/Nauru Pacific/Niue Pacific/Auckland Pacific/Chatham America/Panama America/Lima Pacific/Tahiti Pacific/Marquesas Pacific/Gambier Pacific/Port_Moresby Pacific/Bougainville Asia/Manila Asia/Karachi Europe/Warsaw America/Miquelon Pacific/Pitcairn America/Puerto_Rico Asia/Gaza Asia/Hebron Europe/Lisbon Atlantic/Madeira Atlantic/Azores Pacific/Palau America/Asuncion Asia/Qatar Indian/Reunion Europe/Bucharest Europe/Belgrade Europe/Kaliningrad Europe/Moscow Europe/Simferopol Europe/Kirov Europe/Volgograd Europe/Astrakhan Europe/Saratov Europe/Ulyanovsk Europe/Samara Asia/Yekaterinburg Asia/Omsk Asia/Novosibirsk Asia/Barnaul Asia/Tomsk Asia/Novokuznetsk Asia/Krasnoyarsk Asia/Irkutsk Asia/Chita Asia/Yakutsk Asia/Khandyga Asia/Vladivostok Asia/Ust-Nera Asia/Magadan Asia/Sakhalin Asia/Srednekolymsk Asia/Kamchatka Asia/Anadyr Asia/Riyadh Pacific/Guadalcanal Indian/Mahe Africa/Khartoum Europe/Stockholm Asia/Singapore America/Paramaribo Africa/Juba Africa/Sao_Tome America/El_Salvador Asia/Damascus America/Grand_Turk Africa/Ndjamena Indian/Kerguelen Asia/Bangkok Asia/Dushanbe Pacific/Fakaofo Asia/Dili Asia/Ashgabat Africa/Tunis Pacific/Tongatapu Europe/Istanbul America/Port_of_Spain Pacific/Funafuti Asia/Taipei Europe/Kiev Europe/Uzhgorod Europe/Zaporozhye Pacific/Wake America/New_York America/Detroit America/Kentucky/Louisville America/Kentucky/Monticello America/Indiana/Indianapolis America/Indiana/Vincennes America/Indiana/Winamac America/Indiana/Marengo America/Indiana/Petersburg America/Indiana/Vevay America/Chicago America/Indiana/Tell_City America/Indiana/Knox America/Menominee America/North_Dakota/Center America/North_Dakota/New_Salem America/North_Dakota/Beulah America/Denver America/Boise America/Phoenix America/Los_Angeles America/Anchorage America/Juneau America/Sitka America/Metlakatla America/Yakutat America/Nome America/Adak Pacific/Honolulu America/Montevideo Asia/Samarkand Asia/Tashkent America/Caracas Asia/Ho_Chi_Minh Pacific/Efate Pacific/Wallis Pacific/Apia Africa/Johannesburg --- ## How Document a Good Support Ticket {/* truncate */} # How to document a Good Support Ticket When reporting an issue or asking for help with **Kasm Workspaces** — whether through a **support ticket**, a **Reddit post**, or a **GitHub issue** — providing complete and accurate information helps our team and the community resolve your issue faster. This guide walks you through how to collect and export logs, version details, and other key system information to create a well-documented support request. ## Index - Basic System Information to Include - Host Environment Details - Network Activity Logs (HAR files) - Kasm Logs - Kasm Logs with Context - Container logs ## Basic System Information to Include When reaching out for help, always include the following basic details to help our team quickly understand your environment and Kasm version. On your Kasm Admin panel, go to **“Diagnostics” → “System Info”**. Extract the following information from this page: - Web UI version - Database Version - API Server Build If you’re a licensed user and you have questions about a licensed feature, please also include: - Installation ID (found the the same System Info page) - License ID (go to the “Licenses” tab in System Info page to find this) Please **do not** include your Installation ID and License ID if you’re making a support request on a public platform (like Reddit or GitHub). Instead, only include these details when creating a support ticket directly through our portal. Please also include your web browser version in the support ticket. ## Host Environment Details It is also very helpful to include details about your host environment like your OS, Kernel, Docker version, Kasm service image versions. Please execute the following commands on your Kasm host to extract these details: ```yaml # Show kernel and system info uname -a # Show OS details cat /etc/os-release # Show Docker info sudo docker info # List running Kasm containers sudo docker ps | grep kasm # List Docker plugins sudo docker plugin ls ``` ## Network Activity Logs (HAR files) If you're facing **connectivity issues** with sessions or failed **API requests**, exporting **network logs (HAR files)** can be extremely helpful. > **Security Reminder:** HAR files may contain sensitive data such as tokens or session information. > Only share them through **official support tickets**, never on public forums. > After submitting your HAR logs, **log out and change your password** for security. #### To export your HAR logs: 1. Open your browser’s **Developer Tools** (usually `F12` or `Ctrl + Shift + I`). 2. Go to the **Network** tab. 3. Enable **Preserve Log**. 4. Reproduce the issue on your Kasm deployment. 5. Once done, click the **Download/Export** button to save the log as a `.har` file. 6. Attach this file when submitting your ticket. ## Kasm Logs If Kasm is producing **errors**, **timeouts**, or **unexpected behavior**, include system logs from your deployment. - Go to **Diagnostics → Logging**. - Set: - **Level:** `error` - **Limit:** `1000` - **Time:** `1440` (minutes) - Click **Export** to download logs as a `.json` file. - Attach this file in your support request. ## Kasm Logs with Context For targeted troubleshooting, you can export logs surrounding a specific event or error. For example, if you notice an error related to an *Autoscale configuration*: - Locate the relevant log entry in **Diagnostics → Logging**. - Select the entry and click **Export**. - Specify: - **Context Window Before** (example: 300 seconds) - **Context Window After** (example: 60 seconds) - **Set a Password** for the exported log file. - Click **Export** and attach both the file and password in your support ticket. ## Container Logs If your containers fail to start, container logs are critical for diagnosing startup failures. - SSH into your Kasm Host. - Stop Kasm services: ```bash sudo /opt/kasm/bin/stop ``` - Edit the agent configuration file (`/opt/kasm/current/conf/app/agent.app.config.yaml`) Change ***remove_failed_containers*** to ***false***: ```yaml remove_failed_containers: false ``` - Restart Kasm services: ```bash sudo /opt/kasm/bin/start ``` - Try launching a workspace on Kasm – if it fails, list all containers: ```bash sudo docker ps -a ``` - Copy the **Container ID** of the failed container, then view logs: ```bash sudo docker logs ``` - Save and attach the output in your support ticket. After exporting logs, revert the cleanup setting: - Stop Kasm services: ```bash sudo /opt/kasm/bin/stop ``` - Edit the agent configuration file (`/opt/kasm/current/conf/app/agent.app.config.yaml`) Change ***remove_failed_containers*** back to ***true***: ```yaml remove_failed_containers: true ``` - Remove the nginx configs of existing containers (please note that this will delete all existing Kasm sessions) ```bash sudo rm -rf /opt/kasm/current/www/nginx/conf.d/* ``` - Start Kasm services ```bash sudo /opt/kasm/bin/start ``` That’s it! By including accurate version information, host details, HAR logs, and Kasm logs, you make it much easier for the team to identify and resolve issues quickly. --- ## Kasm Customer Support Portal Guide {/* truncate */} # Kasm Customer Support Portal Guide The **Kasm Customer Support Portal** ([support.kasm.com](https://support.kasm.com)) is where customers can submit support requests and access self-help resources. An active support package is required for engineer support. Support packages are available for enterprise customers with 25+ licenses. The following self-help resources are freely available without an account: - [Documentation](/docs/develop/) - [Knowledge Base](https://kasmweb.atlassian.net/servicedesk/customer/user/forbidden) - [KasmGPT AI Chatbot](/docs/kasmgpt) - Community Channels: - [YouTube](https://www.youtube.com/@KasmWorkspaces) - [Subreddit](https://www.reddit.com/r/kasmweb) - [GitHub Issue Tracker](https://github.com/kasmtech/workspaces-issues/issues) ## Before You Begin Before starting registration, have the following ready: - Your email address - An authenticator app on your mobile device (e.g., Google Authenticator, Microsoft Authenticator) — MFA setup is required - A hardware security key (optional alternative to an authenticator app) ## Part 1: Registering for the Support Portal #### Step 1 – Go to support.kasm.com Navigate to [support.kasm.com](https://support.kasm.com). Self-help resources are accessible directly from this page without an account. {/* # */} #### Step 2 – Enter your email and click Next Enter your email address and click **Next**. {/* # */} #### Step 3 – Click “Continue with single sign-on” On the next screen, click **Continue with single sign-on**. #### Step 4 – Register on Kasm Passport You will be redirected to **Kasm Passport**, the Kasm SSO system. If you do not already have an account: - Click **Sign up** - Or use **Google** or **Microsoft** sign-in #### Step 5 – Enter your email and create a password Password must be at least 8 characters and meet the complexity requirements shown. Click **Continue**. {/* # */} #### Step 6 – Verify your email A verification email will arrive from `no-reply@kasm.com`. Click Verify Your Account in the email, then click **Continue** on the confirmation screen. {/* # */} #### Step 7 – Complete your profile Enter your First Name, Last Name, Company Name, and Job Title. Click **Continue**. {/* # */} #### Step 8 – Set up multi-factor authentication Choose an authenticator app or hardware security key and follow the on-screen instructions. This step is required. Have your authenticator app open and ready on your mobile device before this step. #### Step 9 – Trust this device (optional) Choose whether to enable faster future logins via fingerprint or face recognition on this device. #### Step 10 – Registration complete You are now logged in. Future logins will be faster, especially if you trusted your device. ## Part 2: Navigating the Support Portal #### Your Account Click the profile icon in the upper-right corner to access: - **Requests** – View all open and closed tickets linked to your email, including tickets submitted before registration - **Profile** – Update your name and account details {/* # */} #### Self-Help Resources The portal includes the following self-help resources: - **How-to & Troubleshooting Articles** – Guides for common tasks and known issues - **Security Notices** – Security announcements for Kasm Workspaces - **How to Document a Good Support Ticket** – Guide and video for collecting logs and system information before submitting a ticket - **KasmGPT AI Chatbot** – AI chatbot trained on Kasm documentation and knowledge base that answers questions and cites official sources - **Product Maintenance Lifecycle** – Supported Kasm versions and maintenance status - **Official Documentation** ## Part 3: Submitting a Support Ticket #### Step 1 – Click “Need to raise a request? Contact us.” To begin, click **Need to raise a request? Contact us.** #### Step 2 – Select a request type Choose the request type that best matches your issue: - Report a bug - Technical support - Licensing and billing questions - Suggest an improvement or new feature - Other questions #### Step 3 – Fill out the ticket form Complete the support ticket form with the required details. {/* # */} Do not include personal, confidential, classified, or proprietary information. You are responsible for anonymizing data per your organization's policies. ##### Business Impact Select the option that best describes how the issue affects your organization. ##### Current Kasm Version Select your version. Versions outside the maintenance window may only receive an upgrade recommendation. ##### Summary Enter a brief title. The portal will suggest related knowledge base articles — review them before continuing. ##### Description Include: what you're experiencing, expected behavior, and troubleshooting steps already taken (and results). The more detail you provide, the faster we can help. Review the [How to Document a Good Support Ticket guide](/hc/document-support-ticket) and include the relevant logs before submitting. ##### Components or Products Select the relevant Kasm product or component, if applicable. ##### Attachments Attach screenshots, logs, or other relevant files by dragging and dropping or clicking Browse. #### Step 4 – Click Send Your ticket will appear under Requests in your account. Our support team will respond within Eastern Standard business hours per your support package SLAs. See [kasm.com/support-subscriptions](https://kasm.com/support-subscriptions) for details.