Skip to content

[code] serve each webview from own origin #4738

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

Merged
merged 1 commit into from
Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions chart/templates/ws-manager-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ data:
},
"heartbeatInterval": "30s",
"hostURL": "https://{{ $.Values.hostname }}",
"workspaceClusterHost": "ws{{- if $gp.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}",
"initProbe": {
"timeout": "1s"
},
Expand Down
2 changes: 1 addition & 1 deletion components/ide/code/leeway.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ RUN curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh |
&& npm install -g yarn node-gyp
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH

ENV GP_CODE_COMMIT a17670ba5af14e0faf3a6927983468d28fda235b
ENV GP_CODE_COMMIT 6cf68cedd9ab62af8e426a364d97ed206bbe0a02
RUN mkdir gp-code \
&& cd gp-code \
&& git init \
Expand Down
13 changes: 13 additions & 0 deletions components/proxy/conf/Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ https://*.*.{$GITPOD_DOMAIN} {
}
}

# remove (webview-|browser-|extensions-) after Theia removed and new VS Code is used by all workspaces
@workspace_port header_regexp host Host ^(webview-|browser-|extensions-)?(?P<workspacePort>[0-9]{2,5})-(?P<workspaceID>[a-z0-9][0-9a-z\-]+).ws(?P<location>-[a-z0-9]+)?.{$GITPOD_DOMAIN}
handle @workspace_port {
reverse_proxy https://ws-proxy.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:9090 {
Expand All @@ -255,6 +256,7 @@ https://*.*.{$GITPOD_DOMAIN} {
}
}

# remove (webview-|browser-|extensions-) after Theia removed and new VS Code is used by all workspaces
@workspace header_regexp host Host ^(webview-|browser-|extensions-)?(?P<workspaceID>[a-z0-9][0-9a-z\-]+).ws(?P<location>-[a-z0-9]+)?.{$GITPOD_DOMAIN}
handle @workspace {
reverse_proxy https://ws-proxy.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:9090 {
Expand All @@ -266,6 +268,17 @@ https://*.*.{$GITPOD_DOMAIN} {
}
}

# foreign content origin should be decoupled from the workspace (port) origin but the workspace (port) prefix should be the path root for routing
@foreign_content header_regexp host Host ^(.*)(foreign).ws(-[a-z0-9]+)?.{$GITPOD_DOMAIN}
handle @foreign_content {
reverse_proxy https://ws-proxy.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:9090 {
import workspace_transport
import upstream_headers

header_up X-WSProxy-Host {http.request.host}
}
}

respond "Not found" 404
}

Expand Down
57 changes: 35 additions & 22 deletions components/supervisor-api/go/info.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions components/supervisor-api/info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,7 @@ message WorkspaceInfoResponse {
}
// repository is a repository from which this workspace was created
Repository repository = 10;

// workspace_cluster_host provides the cluster host under which this workspace is served, e.g. ws-eu11.gitpod.io
string workspace_cluster_host = 11;
}
3 changes: 3 additions & 0 deletions components/supervisor/pkg/supervisor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ type WorkspaceConfig struct {

// WorkspaceContext is a context for this workspace
WorkspaceContext string `env:"GITPOD_WORKSPACE_CONTEXT"`

// WorkspaceClusterHost is a host under which this workspace is served, e.g. ws-eu11.gitpod.io
WorkspaceClusterHost string `env:"GITPOD_WORKSPACE_CLUSTER_HOST"`
}

// WorkspaceGitpodToken is a list of tokens that should be added to supervisor's token service
Expand Down
11 changes: 6 additions & 5 deletions components/supervisor/pkg/supervisor/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,12 @@ func (is *InfoService) RegisterREST(mux *runtime.ServeMux, grpcEndpoint string)
// WorkspaceInfo provides information about the workspace
func (is *InfoService) WorkspaceInfo(context.Context, *api.WorkspaceInfoRequest) (*api.WorkspaceInfoResponse, error) {
resp := &api.WorkspaceInfoResponse{
CheckoutLocation: is.cfg.RepoRoot,
InstanceId: is.cfg.WorkspaceInstanceID,
WorkspaceId: is.cfg.WorkspaceID,
GitpodHost: is.cfg.GitpodHost,
WorkspaceContextUrl: is.cfg.WorkspaceContextURL,
CheckoutLocation: is.cfg.RepoRoot,
InstanceId: is.cfg.WorkspaceInstanceID,
WorkspaceId: is.cfg.WorkspaceID,
GitpodHost: is.cfg.GitpodHost,
WorkspaceContextUrl: is.cfg.WorkspaceContextURL,
WorkspaceClusterHost: is.cfg.WorkspaceClusterHost,
}

commit, err := is.cfg.getCommit()
Expand Down
2 changes: 2 additions & 0 deletions components/ws-manager/pkg/manager/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ type Configuration struct {
WorkspaceDaemon WorkspaceDaemonConfiguration `json:"wsdaemon"`
// RegistryFacadeHost is the host (possibly including port) on which the registry facade resolves
RegistryFacadeHost string `json:"registryFacadeHost"`
// Cluster host under which workspaces are served, e.g. ws-eu11.gitpod.io
WorkspaceClusterHost string `json:"workspaceClusterHost"`
}

// AllContainerConfiguration contains the configuration for all container in a workspace pod
Expand Down
2 changes: 2 additions & 0 deletions components/ws-manager/pkg/manager/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,9 @@ func (m *Manager) createWorkspaceEnvironment(startContext *startWorkspaceContext
result = append(result, corev1.EnvVar{Name: "THEIA_WORKSPACE_ROOT", Value: getWorkspaceRelativePath(spec.WorkspaceLocation)})
result = append(result, corev1.EnvVar{Name: "GITPOD_HOST", Value: m.Config.GitpodHostURL})
result = append(result, corev1.EnvVar{Name: "GITPOD_WORKSPACE_URL", Value: startContext.WorkspaceURL})
result = append(result, corev1.EnvVar{Name: "GITPOD_WORKSPACE_CLUSTER_HOST", Value: m.Config.WorkspaceClusterHost})
result = append(result, corev1.EnvVar{Name: "THEIA_SUPERVISOR_ENDPOINT", Value: fmt.Sprintf(":%d", startContext.SupervisorPort)})
// TODO(ak) remove THEIA_WEBVIEW_EXTERNAL_ENDPOINT and THEIA_MINI_BROWSER_HOST_PATTERN when Theia is removed
result = append(result, corev1.EnvVar{Name: "THEIA_WEBVIEW_EXTERNAL_ENDPOINT", Value: "webview-{{hostname}}"})
result = append(result, corev1.EnvVar{Name: "THEIA_MINI_BROWSER_HOST_PATTERN", Value: "browser-{{hostname}}"})

Expand Down
20 changes: 20 additions & 0 deletions components/ws-proxy/pkg/proxy/pass.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"syscall"
"time"

"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -187,3 +188,22 @@ func withXFrameOptionsFilter() proxyPassOpt {
})
}
}

type workspaceTransport struct {
transport http.RoundTripper
}

func (t *workspaceTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
vars := mux.Vars(req)
if vars[foreignPathIdentifier] != "" {
req = req.Clone(req.Context())
req.URL.Path = vars[foreignPathIdentifier]
}
return t.transport.RoundTrip(req)
}

func withWorkspaceTransport() proxyPassOpt {
return func(h *proxyPassConfig) {
h.Transport = &workspaceTransport{h.Transport}
}
}
6 changes: 4 additions & 2 deletions components/ws-proxy/pkg/proxy/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ func installWorkspaceRoutes(r *mux.Router, config *RouteHandlerConfig, ip Worksp
routes.HandleDirectSupervisorRoute(r.PathPrefix("/_supervisor"), true)

routes.HandleDirectIDERoute(r.MatcherFunc(func(req *http.Request, m *mux.RouteMatch) bool {
return m.Vars != nil && m.Vars[foreignOriginPrefix] != ""
// this handles all foreign (none-IDE) content
return m.Vars != nil && m.Vars[foreignOriginIdentifier] != ""
}))

routes.HandleRoot(r.NewRoute())
Expand Down Expand Up @@ -132,7 +133,7 @@ func (ir *ideRoutes) HandleDirectIDERoute(route *mux.Route) {
r.Use(ir.Config.WorkspaceAuthHandler)
r.Use(ir.workspaceMustExistHandler)

r.NewRoute().HandlerFunc(proxyPass(ir.Config, workspacePodResolver))
r.NewRoute().HandlerFunc(proxyPass(ir.Config, workspacePodResolver, withWorkspaceTransport()))
}

func (ir *ideRoutes) HandleDirectSupervisorRoute(route *mux.Route, authenticated bool) {
Expand Down Expand Up @@ -323,6 +324,7 @@ func installWorkspacePortRoutes(r *mux.Router, config *RouteHandlerConfig) error
workspacePodPortResolver,
withHTTPErrorHandler(showPortNotFoundPage),
withXFrameOptionsFilter(),
withWorkspaceTransport(),
)(rw, r)
},
)
Expand Down
20 changes: 20 additions & 0 deletions components/ws-proxy/pkg/proxy/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,26 @@ func TestRoutes(t *testing.T) {
Body: "blobserve hit: /blobserve/gitpod-io/supervisor:latest/main.js\nreadOnly: true\n",
},
},
{
Desc: "extensions route GET",
Request: modifyRequest(httptest.NewRequest("GET", "https://extensions-foreign.test-domain.com/"+workspaces[0].WorkspaceID+"/extensions.js", nil),
addHostHeader,
addHeader("Origin", config.GitpodInstallation.HostName),
addOwnerToken(workspaces[0].InstanceID, workspaces[0].Auth.OwnerToken),
),
Expectation: Expectation{
Status: http.StatusOK,
Header: http.Header{
"Access-Control-Allow-Credentials": {"true"},
"Access-Control-Allow-Origin": {"test-domain.com"},
"Access-Control-Expose-Headers": {"Authorization"},
"Content-Length": {"30"},
"Content-Type": {"text/plain; charset=utf-8"},
"Vary": {"Accept-Encoding"},
},
Body: "workspace hit: /extensions.js\n",
},
},
}

log.Init("ws-proxy-test", "", false, true)
Expand Down
Loading