Project: Teleport (Provisioning / Security & Compliance)
File: 0034-desktop-access-windows.md

authors: Andrew Lytvynov (andrew@goteleport.com) state: implemented RFD 33 defines the high-level goals and architecture for Teleport Desktop Access. This RFD specifies how Teleport Desktop Access integrates with Windows hosts, including Microsoft Active Directory domains. Windows Desktop Access is implemented using `windowsdesktopservice` that translates the Teleport desktop protocol into RDP: ``` +--+ | web UI | +--+ ^ | desktop protocol over websocket v +--+ | proxy | +--+ ^ | desktop protocol over mTLS v +-+ | windowsdesktopservice |--\ +-+-\ | ^ | | | RDP | RDP | LDAP v v | ++ +--+ +-+ | windows server 2012 | | windows 7 | | domain controller | ++ +--+ +-+ ``` `windowsdesktopservice` can talk to any number of remote Windows RDP hosts. It can also talk to `localhost` RDP service, if installed on a Windows machine in agent mode (described below). `windowsdesktopservice` has the ability to automatically discover available Windows hosts from Active Directory by performing an LDAP search. In addition, `windowsdesktopservice` can use a static list of Windows hosts provided in `teleport.yaml`. Windows Desktop Access supports Windows Server 2012 R2, Windows 7 and newer versions. However, it should also work with any server that implements RDP and supports Smart Card authentication. Windows Desktop Access uses Remote Desktop Protocol (RDP). RDP service is built into Windows and requires no additional software to be installed on the hosts. RDP is a very complex protocol, with cruft accumulated over its long history and frequent vulnerability discoveries (see [Security Concerns](#security-concerns) below). It was not my first choice for this implementation. However, it is the only option for supporting concurrent sessions and allows easier customer rollout without per-host agents. `windowsdesktopservice` implements an RDP client. There are no existing Go libraries implementing enough of the RDP spec for a basic desktop session. There are a few options, in order of preference: use via FFI from Go, assuming it supports smart cards use via CGO, assuming it supports smart cards and concurrent outbound connections implement RDP protocol in Go from scratch; last resort due to the amount of work needed `windowsdesktopservice` can run in two modes: gateway and agent. Gateway mode is for connecting to multiple remote Windows hosts, similar to Kubernetes Access. This mode is shown in the [Architecture diagram](#architecture) above. This mode is easy for admins to set up and has minimal resource overhead. However, this requires the Windows hosts to expose RDP ports to the `windowsdesktopservice`, which is more risky (see [Security Concerns](#security-concerns) below). Agent mode is for running a `windowsdesktopservice` instance on the Windows host as a system service. In this mode, connection is made over `localhost` and the RDP port does not need to be exposed on the network. `windowsdesktopservice` can reverse-tunnel to the Teleport proxy, allowing the Windows host to completely block all inbound connections. In the future, `windowsdesktopservice` could also collect more session information (like eBPF on Linux) and enforce extra restrictions. ``` +--+ | web UI | +--+ ^ | desktop protocol over websocket v +--+ | proxy | +--+ ^ | desktop protocol over mTLS over reverse tunnel | +|+ | v | | +-+ | | | windowsdesktopservice | | | +-+ | | ^ | | | RDP over localhost | | v | | +-+ | | | RDP service | | | +-+ Windows host | +-+ ``` In Windows, authentication is handled differently for standalone and Active Directory-enrolled machines. Standalone machines validate credentials using the local user database (SAM). Active Directory-enrolled machines send credentials to the domain controller for validation. Teleport Desktop Access will support both

Windows generally exposes 3 authentication mechanisms: smart cards username/password kerberos tickets Smart cards implement asymmetric cert-based authn, using PKI configured on the server/AD side. Since this is the only known way for us to support cert-based authn, Teleport will implement a smart card emulator to authenticate over RDP. This will be the primary authentication method. Smart card authentication and emulator are described in more detail in RFD 35. Although username and password are the most universal, a major part of Teleport's value is to provide strong authentication using short-lived certificates. Supporting username and password authentication would weaken the overall security of the system and as such will not be implemented. When a user is already authenticated against Kerberos (using one of the above methods), they get a Ticket-granting ticket (TGT) which can be used to get other tickets for specific services, such as an RDP host. Since Teleport has no exposure to Kerberos tickets (even when using AAD as SSO provider) and we can't assume that all clients use Windows machines, Teleport will not use TGTs for RDP authentication. When a user starts a new desktop session, they must specify the Windows host to connect to. Internally, Teleport tracks known Windows hosts using `WindowsDesktop` objects. There are 3 ways that `windowsdesktopservice` discovers Windows hosts to register: hardcoded list of hosts provided in the config file (see ) list of Active Directory-enrolled hosts obtained from AD via LDAPS (LDAP over SSL) LDAP library: https://pkg.go.dev/github.com/go-ldap/ldap/v3 local host, when running on a Windows machine in agent mode By default, Teleport will only register hosts that are provided in the configuration file. To enable host discovery over LDAP, additional configuration is necessary (see ). Teleport will automatically apply the following host labels to hosts which are discovered from Active Directory. | Label | LDAP Attribute | Example | | -- | -- | - | | `teleport.dev/computer_name` | `name` | `WIN-I5G06B8RT33` | `teleport.dev/dnshostname` | | `WIN-I5G06B8RT33.example.com` | `teleport.dev/os` | | `Windows Server 2012` | `teleport.dev/os_version`| | `4.0` | `teleport.dev/windows_domain`| Sourced from config | `example.com` RDP supports concurrent user sessions on the same host. It allocates a virtual desktop for each user to isolate their activities. However, it only allows a single session per user per host. If a user starts a new session on the host that they are already logged into, they will log out the other session. This is RDP behavior we cannot change. All the usual controls on Teleport sessions apply to Desktop Access, like user locking, concurrent session limits and idle timeouts. New `teleport.yaml` section for `windowsdesktopservice`: ```yaml windowsdesktopservice: enabled: yes # default false listen_addr: 0.0.0.0:3080 public_addr: [rdp.example.com:3080] mode: "gateway" # or "agent" ldap: host: ldap.example.com username: "ldap_user" password: "ldap_pass" cacert: "/var/lib/teleport/ldapca.pem" hosts: win1.example.com win2.example.com ... discovery: base_dn: '*' # wildcard searches from the root, leave empty to disable discovery filters: # additional LDAP filters: https://ldap.com/ldap-filters/ filter1 # note: multiple filters are combined into an AND filter filter2 host_labels: match: ".*" labels: env: prod match: "^db.*" labels: type: database kind: postgres match: "^dc\.example\.com$" labels: type: domain_controller ``` RDP is a very complex protocol with a history of vulnerabilities. Using a memory-safe client that we fully control and not exposing raw RDP publicly is essential. Running Teleport in agent mode is and extra hardening step to avoid exposing RDP even on private networks. Generally, admins are still responsible for patching their Windows hosts to pick up any RDP server fixes that come out. The RDP client implementation in Teleport should be reasonably paranoid, verify the identity of the target RDP host and treat it as potentially malicious.