Skip to content
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

Merged
merged 7 commits into from
Apr 26, 2021

Conversation

andrejtokarcik
Copy link
Contributor

@andrejtokarcik andrejtokarcik commented Apr 14, 2021

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.
@andrejtokarcik andrejtokarcik marked this pull request as ready for review April 14, 2021 14:47
Copy link
Contributor

@awly awly left a 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.

Comment on lines 355 to 356
h.GET("/webapi/apps/:fqdn", h.WithAuth(h.getAppFQDN))
h.GET("/webapi/apps/:fqdn/:clusterName/:publicAddr", h.WithAuth(h.getAppFQDN))
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Contributor Author

@andrejtokarcik andrejtokarcik Apr 16, 2021

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:

  1. The user opens an app via the Web UI.
  2. 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).
  3. 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 case getAppFQDN would return the same app.proxy.example.com which is expected since the web UI populates the app launcher params based on the same data as those used by getAppFQDN.
  4. 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 a state value etc. etc.

Now, there is another way to invoke the app launcher instead of going directly through Teleport Web UI:

  1. The user opens whatever.proxy.example.com in his browser.
  2. 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).
  3. 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 say app.proxy-example.org), it could be completely unrelated to the FQDN input.
  4. 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, ...).

Copy link
Contributor

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?

lib/web/apiserver.go Outdated Show resolved Hide resolved
@awly
Copy link
Contributor

awly commented Apr 21, 2021

@andrejtokarcik could you create an issue for this PR?
Also, please sync with @r0mant on your overall solution so he's aware.

@andrejtokarcik
Copy link
Contributor Author

@awly Created issue #6551 to track this.

lib/web/apiserver.go Show resolved Hide resolved
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 {
Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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 {
Copy link
Collaborator

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 Show resolved Hide resolved
lib/web/apps.go Outdated Show resolved Hide resolved
lib/web/apps.go Show resolved Hide resolved
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 {
Copy link
Contributor

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)

@andrejtokarcik andrejtokarcik force-pushed the andrej/fix/double-CreateAppSession branch from d913088 to 24c23a2 Compare April 26, 2021 20:03
@andrejtokarcik andrejtokarcik enabled auto-merge (squash) April 26, 2021 20:22
@andrejtokarcik andrejtokarcik merged commit 8e5ff95 into master Apr 26, 2021
@andrejtokarcik andrejtokarcik deleted the andrej/fix/double-CreateAppSession branch April 26, 2021 20:31
andrejtokarcik added a commit that referenced this pull request Apr 28, 2021
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants