* Track active ssh sessions established via the web
Adds open session tracking in `web.Handler` and introduces a new
`web.Server` to prevent closing the web `http.Server` during
a graceful shutdown if there are still open sessions. From the
`http.Server/Shutdown` docs:
> Shutdown does not attempt to close nor wait for hijacked
> connections such as WebSockets. The caller of Shutdown should
> separately notify such long-lived connections of shutdown and wait
> for them to close, if desired.
Because the web sessions use WebSockets, `Shutdown` will not
wait for them to be idle before terminating. This used to work due
to the fact that web sessions dialed the Proxy SSH Port to establish the
SSH session. Which meant that all accounting of active user connections
by `sshutils/server.go` was accurate. But now that sessions are
established directly via the `proxy.Router` the web sessions were
unaccounted for.
The `web.Server` now mimics the behavior of `sshutils/server.go` for
Shutdown. Only once all the active web sessions have been terminated
will the underlying http.Server be shutdown.
Fixes#20227
* Prevent race from causing remote clients from being closed
`web.SessionContext` was susceptible to races retrieving `auth.ClientI`
for remote sites. The mutex on the remote client cache was not held for
the duration of the `GetUserClient` which meant two simultaneous requests
could find no client existed in the cache, create one and then add it to
the cache. When the second client is added to the cache it would close the
first client created, which results in the `use of closed network connection`
error displaying on the web UI as described in #17173.
To remedy this the portion of `GetUserClient` that retrieves the remote client
is now protected by a `singleflight.Group`. This ensures that races on creating
a client no longer happen.
`web.SessionContext` was slightly refactored to make it easier to test, to
remove some unnecessary operations, and to provide `context.Context` to `GetUserClient`.
Additionally, all `web.SessionContext` variables which were named `ctx` in `lib/web`
have been renamed to avoid confusion as that often refers to a `context.Context`.
Fixes#17173
Uses site (trusted-cluster) specific auth client when getting windows desktop and connecting to w_d_s, which allows trusted clusters to work as expected.
Attempt to upgrade the connection between browser/proxy to websockets
first. This way, we have a mechanism to send errors to the browser for
anything else that might go wrong.
This includes 3 optimizations to improve performance of desktop sessions:
1. Reuse the same image object when encoding PNGs. This prevents us from making
a 16KB allocation for every single bitmap that comes through.
2. Introduce a new PNG frame message that has a length as part of the header.
The original message had no length, which required a costly decode operation
just to find the message boundary. This fixes a performance regression in the
proxy for v10.2.x.
3. Eliminate the use of binary.Write when encoding the most common message types.
While convenient, binary.Write uses reflection to detect the type of the input, which slows encoding down.
Co-authored-by: Isaiah Becker-Mayer <isaiah@goteleport.com>
Primary Changes:
- Remove reliance on Private Key PEM:
- Update native and keygen packages to return PrivateKey instead of PEM key
- Add new PrivateKey interface which implements crypto.Signer
- Replace PEM encoded private key usage where possible
- Replace calls to tls.(Load)X509KeyPair with keys.(Load)X509KeyPair in
client packages
Minor Changes:
- Remove unused agent.AddedKey return from LoadKey
- Simplify sshutils and removed unused code paths
- Add ecdsa and ed25519 key support
Websockets are a message-based protocol, but our combination of
an io.Writer wrapper and io.Copy means some TDP messages may
get broken up and emitted as separate message events in the browser.
Our UI assumes that each 'message' event is a single TDP message,
so we make sure that each TDP message we send corresponds to a
single WriteMessage call.
This adds proxy peering support. A configurable setting that allows for agents
to connect to a subset of proxies and be reachable through any proxy in the
cluster. This is achieved by creating grpc connections between each proxy
server. Client connections can then be passed between proxies to the desired
agent.
* add hostlogin to proxy config for windows
* Set ProxyClient's HostLogin to the Windows username
Also convert a few TLS handshakes to a context-aware version
for better timeout/cancelation behavior.
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Add support for windows desktop services proxying different desktops
* Add filter to GetWindowsDesktops, remove GetWindowsDesktop and GetWindowsDesktopByName
* Cache cleanup
* Fix cache deletes for Windows desktops
For deletes, the cache only gets the backend key, not the entire
resource. Do what database access does, which is to extract the
host ID from the path, and stuff it in the description field of
the resource header.
* Godoc cleanup
* Fix lint
* Address review comments
* Send error message if no desktop found
* Revert to x/net/websocket
This got converted to gorilla/websocket as part of moderated sessions.
We'll do a more intentional conversion post-release.
* fix lint
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Prior to this change, Teleport would always emit errors to the logs
when a desktop session is closed (for example, when the user closes
their browser tab).
This change ensures that:
- the input and output writing goroutines in the proxy don't race
to close connections (we use a sync.Once here)
- EOF and other "connection closed" errors are not logged as errors
Fixes#8661
- Ensure that the dial request uses proper "server ID" format,
which is <uuid>.<cluster_name>
- Update reverse tunnel agent to handle tunnel connections
to desktops
* Adds username and initial screen size to the websocket parameter string and sends over tdp during the connection process
* simplifications from CR
* fixes // //
* updates endpoints
* Exposes an endpoint for fetching a single desktop by name
* Apply suggestions from code review
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* changes inaccurate desktopUUID to desktopName
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Connect proxy <-> windows_desktop_service <-> RDP server
Link together the proxy (websocket), service (mTPS) and RDP client. Pass
target desktop UUID via SNI on the TLS connection from the proxy.
* Use client CAs to validate incoming desktop_service connections
* Send binary frames on desktop websocket