From 05b138cc6b0bc0a80a5aacb0691118e337ff9613 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Thu, 15 Feb 2024 23:49:24 +0000 Subject: [PATCH] fix: add `--block-direct-connections` to wsproxies --- codersdk/deployment.go | 3 +- enterprise/cli/proxyserver.go | 1 + enterprise/cli/proxyserver_test.go | 2 +- enterprise/coderd/coderdenttest/proxytest.go | 2 + enterprise/wsproxy/wsproxy.go | 5 +- enterprise/wsproxy/wsproxy_test.go | 70 ++++++++++++++++++++ 6 files changed, 80 insertions(+), 3 deletions(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index fc13d53c2629a..ef4feeab06372 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -880,7 +880,8 @@ when required by your organization's security policy.`, Env: "CODER_BLOCK_DIRECT", Value: &c.DERP.Config.BlockDirect, Group: &deploymentGroupNetworkingDERP, - YAML: "blockDirect", + YAML: "blockDirect", Annotations: clibase.Annotations{}. + Mark(annotationExternalProxies, "true"), }, { Name: "DERP Force WebSockets", diff --git a/enterprise/cli/proxyserver.go b/enterprise/cli/proxyserver.go index 59b650ffc26cb..fd672a913e65d 100644 --- a/enterprise/cli/proxyserver.go +++ b/enterprise/cli/proxyserver.go @@ -262,6 +262,7 @@ func (r *RootCmd) proxyServer() *clibase.Cmd { AllowAllCors: cfg.Dangerous.AllowAllCors.Value(), DERPEnabled: cfg.DERP.Server.Enable.Value(), DERPOnly: derpOnly.Value(), + BlockDirect: cfg.DERP.Config.BlockDirect.Value(), DERPServerRelayAddress: cfg.DERP.Server.RelayURL.String(), }) if err != nil { diff --git a/enterprise/cli/proxyserver_test.go b/enterprise/cli/proxyserver_test.go index 688075bf1f105..71aa4e02941fb 100644 --- a/enterprise/cli/proxyserver_test.go +++ b/enterprise/cli/proxyserver_test.go @@ -20,7 +20,7 @@ import ( "github.com/coder/coder/v2/testutil" ) -func Test_Headers(t *testing.T) { +func Test_ProxyServer_Headers(t *testing.T) { t.Parallel() const ( diff --git a/enterprise/coderd/coderdenttest/proxytest.go b/enterprise/coderd/coderdenttest/proxytest.go index 831c4be86f640..96e6593e8ed44 100644 --- a/enterprise/coderd/coderdenttest/proxytest.go +++ b/enterprise/coderd/coderdenttest/proxytest.go @@ -34,6 +34,7 @@ type ProxyOptions struct { DisablePathApps bool DerpDisabled bool DerpOnly bool + BlockDirect bool // ProxyURL is optional ProxyURL *url.URL @@ -158,6 +159,7 @@ func NewWorkspaceProxyReplica(t *testing.T, coderdAPI *coderd.API, owner *coders DERPOnly: options.DerpOnly, DERPServerRelayAddress: serverURL.String(), StatsCollectorOptions: statsCollectorOptions, + BlockDirect: options.BlockDirect, }) require.NoError(t, err) t.Cleanup(func() { diff --git a/enterprise/wsproxy/wsproxy.go b/enterprise/wsproxy/wsproxy.go index 14f9f5f002f26..6edd6d55420ca 100644 --- a/enterprise/wsproxy/wsproxy.go +++ b/enterprise/wsproxy/wsproxy.go @@ -75,6 +75,9 @@ type Options struct { // DERPOnly determines whether this proxy only provides DERP and does not // provide access to workspace apps/terminal. DERPOnly bool + // BlockDirect controls the servertailnet of the proxy, forcing it from + // negotiating direct connections. + BlockDirect bool ProxySessionToken string // AllowAllCors will set all CORs headers to '*'. @@ -251,7 +254,7 @@ func New(ctx context.Context, opts *Options) (*Server, error) { }, regResp.DERPForceWebSockets, s.DialCoordinator, - false, // TODO: this will be covered in a subsequent pr. + opts.BlockDirect, s.TracerProvider, ) if err != nil { diff --git a/enterprise/wsproxy/wsproxy_test.go b/enterprise/wsproxy/wsproxy_test.go index 13d908c07c8e2..f974247467ba4 100644 --- a/enterprise/wsproxy/wsproxy_test.go +++ b/enterprise/wsproxy/wsproxy_test.go @@ -615,6 +615,76 @@ func TestWorkspaceProxyWorkspaceApps(t *testing.T) { }) } +func TestWorkspaceProxyWorkspaceApps_BlockDirect(t *testing.T) { + t.Parallel() + + apptest.Run(t, false, func(t *testing.T, opts *apptest.DeploymentOptions) *apptest.Deployment { + deploymentValues := coderdtest.DeploymentValues(t) + deploymentValues.DisablePathApps = clibase.Bool(opts.DisablePathApps) + deploymentValues.Dangerous.AllowPathAppSharing = clibase.Bool(opts.DangerousAllowPathAppSharing) + deploymentValues.Dangerous.AllowPathAppSiteOwnerAccess = clibase.Bool(opts.DangerousAllowPathAppSiteOwnerAccess) + deploymentValues.Experiments = []string{ + "*", + } + + proxyStatsCollectorFlushCh := make(chan chan<- struct{}, 1) + flushStats := func() { + proxyStatsCollectorFlushDone := make(chan struct{}, 1) + proxyStatsCollectorFlushCh <- proxyStatsCollectorFlushDone + <-proxyStatsCollectorFlushDone + } + + if opts.PrimaryAppHost == "" { + opts.PrimaryAppHost = "*.primary.test.coder.com" + } + client, closer, api, user := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + DeploymentValues: deploymentValues, + AppHostname: opts.PrimaryAppHost, + IncludeProvisionerDaemon: true, + RealIPConfig: &httpmw.RealIPConfig{ + TrustedOrigins: []*net.IPNet{{ + IP: net.ParseIP("127.0.0.1"), + Mask: net.CIDRMask(8, 32), + }}, + TrustedHeaders: []string{ + "CF-Connecting-IP", + }, + }, + WorkspaceAppsStatsCollectorOptions: opts.StatsCollectorOptions, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureWorkspaceProxy: 1, + }, + }, + }) + t.Cleanup(func() { + _ = closer.Close() + }) + + // Create the external proxy + if opts.DisableSubdomainApps { + opts.AppHost = "" + } + proxyAPI := coderdenttest.NewWorkspaceProxyReplica(t, api, client, &coderdenttest.ProxyOptions{ + Name: "best-proxy", + AppHostname: opts.AppHost, + DisablePathApps: opts.DisablePathApps, + FlushStats: proxyStatsCollectorFlushCh, + BlockDirect: true, + }) + + return &apptest.Deployment{ + Options: opts, + SDKClient: client, + FirstUser: user, + PathAppBaseURL: proxyAPI.Options.AccessURL, + FlushStats: flushStats, + } + }) +} + // createDERPClient creates a DERP client and spawns a goroutine that reads from // the client and sends the received packets to a channel. //