-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a dedicated API endpoint for app FQDN resolving #6449
Conversation
Currently, an app's target FQDN can be obtained only using the endpoint for creating new app sessions. The OAuth-style back-and-forth redirects between the app launcher and the app itself are therefore forced to generate an unnecessary additional app session just to resolve the FQDN. The new endpoint introduced here allows to resolve such FQDNs by invoking a dedicated endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's an issue filed for this, please link it.
lib/web/apiserver.go
Outdated
h.GET("/webapi/apps/:fqdn", h.WithAuth(h.getAppFQDN)) | ||
h.GET("/webapi/apps/:fqdn/:clusterName/:publicAddr", h.WithAuth(h.getAppFQDN)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this endpoint is for resolving FQDN, drop the fqdn
parameter
also, the first endpoint here seems redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fqdn
parameter is needed, serves as a hint to resolve the actual/safe FQDN. It's the same logic as in the original createAppSession
handler.
No, both endpoints may get used from the webapps
app launcher.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you show an example usage of this endpoint (example URL and response)?
I'm not familiar with how this FQDN resolution works, it just seems odd that it takes an FQDN and returns one too. Maybe the parameter should be named differently, like appName
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say there is a Teleport proxy running at proxy.example.com
.
With the new getAppFQDN
endpoint, the following would happen in an ordinary, best-case scenario:
- The user opens an app via the Web UI.
- A new tab is opened with the app launcher
https://proxy.example.com/web/launch/app.proxy.example.com/cluster-name/app.proxy.example.com
(matching this URL pattern). - Since the user-provided FQDN shouldn't be blindly trusted, the app launcher invokes
getAppFQDN
to get a known/safe FQDN for the app. In this casegetAppFQDN
would return the sameapp.proxy.example.com
which is expected since the web UI populates the app launcher params based on the same data as those used bygetAppFQDN
. - The app launcher would then redirect the user to
https://app.proxy.example.com/x-teleport-auth
which in turn redirects back to the app launcher with astate
value etc. etc.
Now, there is another way to invoke the app launcher instead of going directly through Teleport Web UI:
- The user opens
whatever.proxy.example.com
in his browser. - This triggers the app launcher
https://proxy.example.com/web/launch/whatever.proxy.example.com
(only the FQDN param is now present, since the target cluster and the app's public address aren't known at this point). getAppFQDN
guesses the intended app (from among those running in the root as well as the leaf clusters) on a best-effort basis and either fails or returns the found FQDN. If the app is configured with a public address (here let's sayapp.proxy-example.org
), it could be completely unrelated to the FQDN input.- Etc.
From the robustness/security standpoint, getAppFQDN
serves to prevent infinite redirects and block malicious FQDN inputs (e.g., stealing valid app sessions, phishing). This was already achieved with CreateAppSession
which also returns the FQDN as part of its output but with the undesirable side effect of creating a new valid app session (confusing audit log entries, a potential attack vector, ...).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I think I understand.
Can you change the URL parameter name here from :fqdn
to :untrustedFQDN
or :userFQDN
to hint that it's different from the return FQDN?
@andrejtokarcik could you create an issue for this PR? |
lib/web/apps.go
Outdated
type CreateAppSessionRequest struct { | ||
// FQDN is the fully qualified domain name of the application. | ||
FQDN string `json:"fqdn"` | ||
type AppResolveParams struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename this to AppResolveRequest
for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this since these AppResolveParams
are populated in the course of both getAppFQDN
and createAppSession
. Renaming this to AppResolveRequest
would misleadingly indicate this is just the input part of a single request-response pair.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, please make wrapper types for individual endpoints, like:
type GetAppFQDNRequest AppResolveRequest
(or ember a struct, whichever is cleaner)
@@ -66,15 +66,58 @@ type CreateAppSessionRequest struct { | |||
ClusterName string `json:"cluster_name"` | |||
} | |||
|
|||
type GetAppFQDNResponse struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AppResolveResponse
for consistency?
lib/web/apps.go
Outdated
type CreateAppSessionRequest struct { | ||
// FQDN is the fully qualified domain name of the application. | ||
FQDN string `json:"fqdn"` | ||
type AppResolveParams struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, please make wrapper types for individual endpoints, like:
type GetAppFQDNRequest AppResolveRequest
(or ember a struct, whichever is cleaner)
d913088
to
24c23a2
Compare
Currently, an app's target FQDN can be obtained only using the endpoint for creating new app sessions. The OAuth-style back-and-forth redirects between the app launcher and the app itself are therefore forced to generate an unnecessary additional app session just to resolve the FQDN. The new endpoint introduced here allows to resolve such FQDNs by invoking a dedicated endpoint.
Currently, an app's target FQDN can be obtained only using the endpoint
for creating new app sessions. The OAuth-style back-and-forth redirects
between the app launcher and the app itself are therefore forced to
generate an unnecessary additional app session just to resolve the FQDN.
The new endpoint introduced here allows to resolve such FQDNs by
invoking a dedicated endpoint.