From 46578990b6df892e224e914ef4715336a698a1a4 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Fri, 9 Jun 2023 13:28:59 +0000 Subject: [PATCH 1/8] feat: add flag to disable all direct connections --- agent/agent.go | 16 ++++---- cli/server.go | 1 + cli/testdata/coder_server_--help.golden | 8 ++++ cli/testdata/server-config.yaml.golden | 7 ++++ coderd/apidoc/docs.go | 9 +++++ coderd/apidoc/swagger.json | 9 +++++ coderd/workspaceagents.go | 28 +++++++------ codersdk/agentsdk/agentsdk.go | 25 ++++++------ codersdk/deployment.go | 14 ++++++- codersdk/workspaceagents.go | 6 ++- docs/api/agents.md | 2 + docs/api/general.md | 1 + docs/api/schemas.md | 53 ++++++++++++++---------- docs/cli/server.md | 10 +++++ site/src/api/typesGenerated.ts | 1 + tailnet/conn.go | 8 ++++ tailnet/derpmap.go | 16 +++++++- tailnet/derpmap_test.go | 54 +++++++++++++++++++++++-- 18 files changed, 206 insertions(+), 62 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 165c73598939c..75235c38722e1 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -587,7 +587,7 @@ func (a *agent) run(ctx context.Context) error { network := a.network a.closeMutex.Unlock() if network == nil { - network, err = a.createTailnet(ctx, manifest.DERPMap) + network, err = a.createTailnet(ctx, manifest.DERPMap, manifest.AllowDirectConnections) if err != nil { return xerrors.Errorf("create tailnet: %w", err) } @@ -605,8 +605,9 @@ func (a *agent) run(ctx context.Context) error { a.startReportingConnectionStats(ctx) } else { - // Update the DERP map! + // Update the DERP map and allow/disallow direct connections. network.SetDERPMap(manifest.DERPMap) + network.SetBlockEndpoints(!manifest.AllowDirectConnections) } a.logger.Debug(ctx, "running tailnet connection coordinator") @@ -631,12 +632,13 @@ func (a *agent) trackConnGoroutine(fn func()) error { return nil } -func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (_ *tailnet.Conn, err error) { +func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap, allowDirectConnections bool) (_ *tailnet.Conn, err error) { network, err := tailnet.NewConn(&tailnet.Options{ - Addresses: []netip.Prefix{netip.PrefixFrom(codersdk.WorkspaceAgentIP, 128)}, - DERPMap: derpMap, - Logger: a.logger.Named("tailnet"), - ListenPort: a.tailnetListenPort, + Addresses: []netip.Prefix{netip.PrefixFrom(codersdk.WorkspaceAgentIP, 128)}, + DERPMap: derpMap, + Logger: a.logger.Named("tailnet"), + ListenPort: a.tailnetListenPort, + BlockEndpoints: !allowDirectConnections, }) if err != nil { return nil, xerrors.Errorf("create tailnet: %w", err) diff --git a/cli/server.go b/cli/server.go index d7dea720978e9..94ea759a2992a 100644 --- a/cli/server.go +++ b/cli/server.go @@ -412,6 +412,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. derpMap, err := tailnet.NewDERPMap( ctx, defaultRegion, cfg.DERP.Server.STUNAddresses, cfg.DERP.Config.URL.String(), cfg.DERP.Config.Path.String(), + cfg.DERP.Config.DisableDirect.Value(), ) if err != nil { return xerrors.Errorf("create derp map: %w", err) diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index f8f45b138d7fd..661d5422789f1 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -171,6 +171,14 @@ backed by Tailscale and WireGuard. Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. + --disable-direct bool, $CODER_DISABLE_DIRECT + Disable peer-to-peer (aka. direct) workspace connections. All + workspace connections from the CLI will be proxied through Coder (or + custom configured DERP servers) and will never be peer-to-peer when + enabled. Workspaces may still reach out to STUN servers to get their + address until they are restarted after this change has been made, but + new connections will still be proxied regardless. + Networking / HTTP Options --disable-password-auth bool, $CODER_DISABLE_PASSWORD_AUTH Disable password authentication. This is recommended for security diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index 4755939392dd1..5d61d13386c43 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -117,6 +117,13 @@ networking: # for high availability. # (default: , type: url) relayURL: + # Disable peer-to-peer (aka. direct) workspace connections. All workspace + # connections from the CLI will be proxied through Coder (or custom configured + # DERP servers) and will never be peer-to-peer when enabled. Workspaces may still + # reach out to STUN servers to get their address until they are restarted after + # this change has been made, but new connections will still be proxied regardless. + # (default: , type: bool) + disableDirect: false # URL to fetch a DERP mapping on startup. See: # https://tailscale.com/kb/1118/custom-derp-servers/. # (default: , type: string) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index fcc08069ab70a..dc04584f35279 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5732,6 +5732,9 @@ const docTemplate = `{ "agentsdk.Manifest": { "type": "object", "properties": { + "allow_direct_connections": { + "type": "boolean" + }, "apps": { "type": "array", "items": { @@ -7011,6 +7014,9 @@ const docTemplate = `{ "codersdk.DERPConfig": { "type": "object", "properties": { + "disable_direct": { + "type": "boolean" + }, "path": { "type": "string" }, @@ -9275,6 +9281,9 @@ const docTemplate = `{ "codersdk.WorkspaceAgentConnectionInfo": { "type": "object", "properties": { + "allow_direct_connections": { + "type": "boolean" + }, "derp_map": { "$ref": "#/definitions/tailcfg.DERPMap" } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index f97718458a847..5b6cab0969ee4 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5047,6 +5047,9 @@ "agentsdk.Manifest": { "type": "object", "properties": { + "allow_direct_connections": { + "type": "boolean" + }, "apps": { "type": "array", "items": { @@ -6243,6 +6246,9 @@ "codersdk.DERPConfig": { "type": "object", "properties": { + "disable_direct": { + "type": "boolean" + }, "path": { "type": "string" }, @@ -8371,6 +8377,9 @@ "codersdk.WorkspaceAgentConnectionInfo": { "type": "object", "properties": { + "allow_direct_connections": { + "type": "boolean" + }, "derp_map": { "$ref": "#/definitions/tailcfg.DERPMap" } diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index cc05ecc73d3ef..3ec18b8a6ce7b 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -161,18 +161,19 @@ func (api *API) workspaceAgentManifest(rw http.ResponseWriter, r *http.Request) } httpapi.Write(ctx, rw, http.StatusOK, agentsdk.Manifest{ - Apps: convertApps(dbApps), - DERPMap: api.DERPMap, - GitAuthConfigs: len(api.GitAuthConfigs), - EnvironmentVariables: apiAgent.EnvironmentVariables, - StartupScript: apiAgent.StartupScript, - Directory: apiAgent.Directory, - VSCodePortProxyURI: vscodeProxyURI, - MOTDFile: workspaceAgent.MOTDFile, - StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second, - ShutdownScript: apiAgent.ShutdownScript, - ShutdownScriptTimeout: time.Duration(apiAgent.ShutdownScriptTimeoutSeconds) * time.Second, - Metadata: convertWorkspaceAgentMetadataDesc(metadata), + Apps: convertApps(dbApps), + DERPMap: api.DERPMap, + GitAuthConfigs: len(api.GitAuthConfigs), + EnvironmentVariables: apiAgent.EnvironmentVariables, + StartupScript: apiAgent.StartupScript, + Directory: apiAgent.Directory, + VSCodePortProxyURI: vscodeProxyURI, + MOTDFile: workspaceAgent.MOTDFile, + StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second, + ShutdownScript: apiAgent.ShutdownScript, + ShutdownScriptTimeout: time.Duration(apiAgent.ShutdownScriptTimeoutSeconds) * time.Second, + AllowDirectConnections: api.DeploymentValues.DERP.Config.DisableDirect.Value(), + Metadata: convertWorkspaceAgentMetadataDesc(metadata), }) } @@ -733,7 +734,8 @@ func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request ctx := r.Context() httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceAgentConnectionInfo{ - DERPMap: api.DERPMap, + DERPMap: api.DERPMap, + AllowDirectConnections: api.DeploymentValues.DERP.Config.DisableDirect.Value(), }) } diff --git a/codersdk/agentsdk/agentsdk.go b/codersdk/agentsdk/agentsdk.go index a14dbb54ccccc..dd8b5a854daa7 100644 --- a/codersdk/agentsdk/agentsdk.go +++ b/codersdk/agentsdk/agentsdk.go @@ -87,18 +87,19 @@ type Manifest struct { // GitAuthConfigs stores the number of Git configurations // the Coder deployment has. If this number is >0, we // set up special configuration in the workspace. - GitAuthConfigs int `json:"git_auth_configs"` - VSCodePortProxyURI string `json:"vscode_port_proxy_uri"` - Apps []codersdk.WorkspaceApp `json:"apps"` - DERPMap *tailcfg.DERPMap `json:"derpmap"` - EnvironmentVariables map[string]string `json:"environment_variables"` - StartupScript string `json:"startup_script"` - StartupScriptTimeout time.Duration `json:"startup_script_timeout"` - Directory string `json:"directory"` - MOTDFile string `json:"motd_file"` - ShutdownScript string `json:"shutdown_script"` - ShutdownScriptTimeout time.Duration `json:"shutdown_script_timeout"` - Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"` + GitAuthConfigs int `json:"git_auth_configs"` + VSCodePortProxyURI string `json:"vscode_port_proxy_uri"` + Apps []codersdk.WorkspaceApp `json:"apps"` + DERPMap *tailcfg.DERPMap `json:"derpmap"` + EnvironmentVariables map[string]string `json:"environment_variables"` + StartupScript string `json:"startup_script"` + StartupScriptTimeout time.Duration `json:"startup_script_timeout"` + Directory string `json:"directory"` + MOTDFile string `json:"motd_file"` + ShutdownScript string `json:"shutdown_script"` + ShutdownScriptTimeout time.Duration `json:"shutdown_script_timeout"` + AllowDirectConnections bool `json:"allow_direct_connections"` + Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"` } // Manifest fetches manifest for the currently authenticated workspace agent. diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 6972e94e3a338..1b01b16d7e348 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -221,8 +221,9 @@ type DERPServerConfig struct { } type DERPConfig struct { - URL clibase.String `json:"url" typescript:",notnull"` - Path clibase.String `json:"path" typescript:",notnull"` + DisableDirect clibase.Bool `json:"disable_direct" typescript:",notnull"` + URL clibase.String `json:"url" typescript:",notnull"` + Path clibase.String `json:"path" typescript:",notnull"` } type PrometheusConfig struct { @@ -710,6 +711,15 @@ when required by your organization's security policy.`, Group: &deploymentGroupNetworkingDERP, YAML: "relayURL", }, + { + Name: "Disable Direct Connections", + Description: "Disable peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless.", + Flag: "disable-direct", + Env: "CODER_DISABLE_DIRECT", + Value: &c.DERP.Config.DisableDirect, + Group: &deploymentGroupNetworkingDERP, + YAML: "disableDirect", + }, { Name: "DERP Config URL", Description: "URL to fetch a DERP mapping on startup. See: https://tailscale.com/kb/1118/custom-derp-servers/.", diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index dcede6a069f4f..5135498b395bd 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -160,7 +160,8 @@ type DERPRegion struct { // a connection with a workspace. // @typescript-ignore WorkspaceAgentConnectionInfo type WorkspaceAgentConnectionInfo struct { - DERPMap *tailcfg.DERPMap `json:"derp_map"` + DERPMap *tailcfg.DERPMap `json:"derp_map"` + AllowDirectConnections bool `json:"allow_direct_connections"` } // @typescript-ignore DialWorkspaceAgentOptions @@ -187,6 +188,9 @@ func (c *Client) DialWorkspaceAgent(ctx context.Context, agentID uuid.UUID, opti if err != nil { return nil, xerrors.Errorf("decode conn info: %w", err) } + if !connInfo.AllowDirectConnections { + options.BlockEndpoints = true + } ip := tailnet.IP() var header http.Header diff --git a/docs/api/agents.md b/docs/api/agents.md index b748a2b299dfb..03782747b280d 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -292,6 +292,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/manifest \ ```json { + "allow_direct_connections": true, "apps": [ { "command": "string", @@ -515,6 +516,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/con ```json { + "allow_direct_connections": true, "derp_map": { "omitDefaultRegions": true, "regions": { diff --git a/docs/api/general.md b/docs/api/general.md index 57fe3716efc22..1bf1159307388 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -167,6 +167,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ }, "derp": { "config": { + "disable_direct": true, "path": "string", "url": "string" }, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index e4fd03c5cd0b7..6b88714423308 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -161,6 +161,7 @@ ```json { + "allow_direct_connections": true, "apps": [ { "command": "string", @@ -257,21 +258,22 @@ ### Properties -| Name | Type | Required | Restrictions | Description | -| ------------------------- | ------------------------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | -| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | -| `directory` | string | false | | | -| `environment_variables` | object | false | | | -| » `[any property]` | string | false | | | -| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | -| `metadata` | array of [codersdk.WorkspaceAgentMetadataDescription](#codersdkworkspaceagentmetadatadescription) | false | | | -| `motd_file` | string | false | | | -| `shutdown_script` | string | false | | | -| `shutdown_script_timeout` | integer | false | | | -| `startup_script` | string | false | | | -| `startup_script_timeout` | integer | false | | | -| `vscode_port_proxy_uri` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `allow_direct_connections` | boolean | false | | | +| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | +| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| `directory` | string | false | | | +| `environment_variables` | object | false | | | +| » `[any property]` | string | false | | | +| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | +| `metadata` | array of [codersdk.WorkspaceAgentMetadataDescription](#codersdkworkspaceagentmetadatadescription) | false | | | +| `motd_file` | string | false | | | +| `shutdown_script` | string | false | | | +| `shutdown_script_timeout` | integer | false | | | +| `startup_script` | string | false | | | +| `startup_script_timeout` | integer | false | | | +| `vscode_port_proxy_uri` | string | false | | | ## agentsdk.PatchStartupLogs @@ -1661,6 +1663,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { "config": { + "disable_direct": true, "path": "string", "url": "string" }, @@ -1698,6 +1701,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { + "disable_direct": true, "path": "string", "url": "string" } @@ -1705,10 +1709,11 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ### Properties -| Name | Type | Required | Restrictions | Description | -| ------ | ------ | -------- | ------------ | ----------- | -| `path` | string | false | | | -| `url` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ---------------- | ------- | -------- | ------------ | ----------- | +| `disable_direct` | boolean | false | | | +| `path` | string | false | | | +| `url` | string | false | | | ## codersdk.DERPRegion @@ -1831,6 +1836,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in }, "derp": { "config": { + "disable_direct": true, "path": "string", "url": "string" }, @@ -2158,6 +2164,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in }, "derp": { "config": { + "disable_direct": true, "path": "string", "url": "string" }, @@ -4685,6 +4692,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { + "allow_direct_connections": true, "derp_map": { "omitDefaultRegions": true, "regions": { @@ -4741,9 +4749,10 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ### Properties -| Name | Type | Required | Restrictions | Description | -| ---------- | ---------------------------------- | -------- | ------------ | ----------- | -| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------------- | ---------------------------------- | -------- | ------------ | ----------- | +| `allow_direct_connections` | boolean | false | | | +| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | ## codersdk.WorkspaceAgentLifecycle diff --git a/docs/cli/server.md b/docs/cli/server.md index 9dcd9e8d9cdeb..7fa8d292c4d89 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -173,6 +173,16 @@ An HTTP URL that is accessible by other replicas to relay DERP traffic. Required Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. +### --disable-direct + +| | | +| ----------- | ------------------------------------------ | +| Type | bool | +| Environment | $CODER_DISABLE_DIRECT | +| YAML | networking.derp.disableDirect | + +Disable peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless. + ### --disable-owner-workspace-access | | | diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index dea9dd74080ff..c50900cd725d2 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -278,6 +278,7 @@ export interface DERP { // From codersdk/deployment.go export interface DERPConfig { + readonly disable_direct: boolean readonly url: string readonly path: string } diff --git a/tailnet/conn.go b/tailnet/conn.go index 20a00d94d6804..d68c41a8b15ed 100644 --- a/tailnet/conn.go +++ b/tailnet/conn.go @@ -353,6 +353,14 @@ func (c *Conn) SetDERPMap(derpMap *tailcfg.DERPMap) { c.wireguardEngine.SetNetworkMap(&netMapCopy) } +// SetBlockEndpoints sets whether or not to block P2P endpoints. This setting +// will only apply to new peers. +func (c *Conn) SetBlockEndpoints(blockEndpoints bool) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.blockEndpoints = blockEndpoints +} + // SetDERPRegionDialer updates the dialer to use for connecting to DERP regions. func (c *Conn) SetDERPRegionDialer(dialer func(ctx context.Context, region *tailcfg.DERPRegion) net.Conn) { c.magicConn.SetDERPRegionDialer(dialer) diff --git a/tailnet/derpmap.go b/tailnet/derpmap.go index 13a998177c24f..b41041df1edd6 100644 --- a/tailnet/derpmap.go +++ b/tailnet/derpmap.go @@ -15,10 +15,16 @@ import ( // NewDERPMap constructs a DERPMap from a set of STUN addresses and optionally a remote // URL to fetch a mapping from e.g. https://controlplane.tailscale.com/derpmap/default. -func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []string, remoteURL, localPath string) (*tailcfg.DERPMap, error) { +// +//nolint:revive +func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []string, remoteURL, localPath string, allowSTUN bool) (*tailcfg.DERPMap, error) { if remoteURL != "" && localPath != "" { return nil, xerrors.New("a remote URL or local path must be specified, not both") } + if !allowSTUN { + stunAddrs = nil + } + if region != nil { for index, stunAddr := range stunAddrs { host, rawPort, err := net.SplitHostPort(stunAddr) @@ -74,5 +80,13 @@ func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []str } derpMap.Regions[region.RegionID] = region } + if !allowSTUN { + for _, region := range derpMap.Regions { + for _, node := range region.Nodes { + node.STUNPort = -1 + } + } + } + return derpMap, nil } diff --git a/tailnet/derpmap_test.go b/tailnet/derpmap_test.go index 71f0da1fcc8cd..b9cb559b44a8c 100644 --- a/tailnet/derpmap_test.go +++ b/tailnet/derpmap_test.go @@ -22,7 +22,7 @@ func TestNewDERPMap(t *testing.T) { derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 1, Nodes: []*tailcfg.DERPNode{{}}, - }, []string{"stun.google.com:2345"}, "", "") + }, []string{"stun.google.com:2345"}, "", "", true) require.NoError(t, err) require.Len(t, derpMap.Regions[1].Nodes, 2) }) @@ -39,7 +39,7 @@ func TestNewDERPMap(t *testing.T) { t.Cleanup(server.Close) derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 2, - }, []string{}, server.URL, "") + }, []string{}, server.URL, "", true) require.NoError(t, err) require.Len(t, derpMap.Regions, 2) }) @@ -56,7 +56,7 @@ func TestNewDERPMap(t *testing.T) { t.Cleanup(server.Close) _, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 1, - }, []string{}, server.URL, "") + }, []string{}, server.URL, "", true) require.Error(t, err) }) t.Run("LocalPath", func(t *testing.T) { @@ -72,8 +72,54 @@ func TestNewDERPMap(t *testing.T) { require.NoError(t, err) derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 2, - }, []string{}, "", localPath) + }, []string{}, "", localPath, true) require.NoError(t, err) require.Len(t, derpMap.Regions, 2) }) + t.Run("DisableSTUN", func(t *testing.T) { + t.Parallel() + localPath := filepath.Join(t.TempDir(), "derp.json") + content, err := json.Marshal(&tailcfg.DERPMap{ + Regions: map[int]*tailcfg.DERPRegion{ + 1: { + Nodes: []*tailcfg.DERPNode{{ + STUNPort: 1234, + }}, + }, + 2: { + Nodes: []*tailcfg.DERPNode{ + { + STUNPort: 1234, + }, + { + STUNPort: 12345, + }, + }, + }, + }, + }) + require.NoError(t, err) + err = os.WriteFile(localPath, content, 0o600) + require.NoError(t, err) + region := &tailcfg.DERPRegion{ + RegionID: 3, + Nodes: []*tailcfg.DERPNode{{ + STUNPort: 1234, + }}, + } + derpMap, err := tailnet.NewDERPMap(context.Background(), region, []string{"127.0.0.1:54321"}, "", localPath, false) + require.NoError(t, err) + require.Len(t, derpMap.Regions, 3) + + require.Len(t, derpMap.Regions[1].Nodes, 1) + require.EqualValues(t, -1, derpMap.Regions[1].Nodes[0].STUNPort) + require.Len(t, derpMap.Regions[2].Nodes, 2) + require.EqualValues(t, -1, derpMap.Regions[2].Nodes[0].STUNPort) + require.EqualValues(t, -1, derpMap.Regions[2].Nodes[1].STUNPort) + // We don't add any nodes ourselves if STUN is disabled. + require.Len(t, derpMap.Regions[3].Nodes, 1) + // ... but we still remove the STUN port from existing nodes in the + // region. + require.EqualValues(t, -1, derpMap.Regions[3].Nodes[0].STUNPort) + }) } From f17bee74595f1b8c999e561e119d5df010d0fa94 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Fri, 9 Jun 2023 13:36:29 +0000 Subject: [PATCH 2/8] block coderd -> workspace direct too --- coderd/workspaceagents.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 3ec18b8a6ce7b..729dfaf7693c9 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -664,9 +664,10 @@ func (api *API) workspaceAgentListeningPorts(rw http.ResponseWriter, r *http.Req func (api *API) dialWorkspaceAgentTailnet(agentID uuid.UUID) (*codersdk.WorkspaceAgentConn, error) { clientConn, serverConn := net.Pipe() conn, err := tailnet.NewConn(&tailnet.Options{ - Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)}, - DERPMap: api.DERPMap, - Logger: api.Logger.Named("tailnet"), + Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)}, + DERPMap: api.DERPMap, + Logger: api.Logger.Named("tailnet"), + BlockEndpoints: api.DeploymentValues.DERP.Config.DisableDirect.Value(), }) if err != nil { _ = clientConn.Close() From 76e2200af3d8165260e77f1a8e82f0da0def0954 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Sat, 10 Jun 2023 03:42:20 +0000 Subject: [PATCH 3/8] z --- coderd/coderdtest/coderdtest.go | 78 ++++++++++++++++++--------------- coderd/workspaceagents.go | 4 +- coderd/workspaceagents_test.go | 77 ++++++++++++++++++++++++++++++++ tailnet/conn.go | 7 +++ tailnet/derpmap.go | 5 +++ tailnet/derpmap_test.go | 7 +++ 6 files changed, 140 insertions(+), 38 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index f0c57552087cf..ec3663430ff32 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -289,6 +289,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can } stunAddr, stunCleanup := stuntest.ServeWithPacketListener(t, nettype.Std{}) + stunAddr.IP = net.ParseIP("127.0.0.1") t.Cleanup(stunCleanup) derpServer := derp.NewServer(key.NewNode(), tailnet.Logger(slogtest.Make(t, nil).Named("derp").Leveled(slog.LevelDebug))) @@ -306,6 +307,29 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can require.NoError(t, err) } + region := &tailcfg.DERPRegion{ + EmbeddedRelay: true, + RegionID: int(options.DeploymentValues.DERP.Server.RegionID.Value()), + RegionCode: options.DeploymentValues.DERP.Server.RegionCode.String(), + RegionName: options.DeploymentValues.DERP.Server.RegionName.String(), + Nodes: []*tailcfg.DERPNode{{ + Name: fmt.Sprintf("%db", options.DeploymentValues.DERP.Server.RegionID), + RegionID: int(options.DeploymentValues.DERP.Server.RegionID.Value()), + IPv4: "127.0.0.1", + DERPPort: derpPort, + // STUN port is added as a separate node by tailnet.NewDERPMap() if + // direct connections are enabled. + STUNPort: -1, + InsecureForTests: true, + ForceHTTP: options.TLSCertificates == nil, + }}, + } + if !options.DeploymentValues.DERP.Server.Enable.Value() { + region = nil + } + derpMap, err := tailnet.NewDERPMap(ctx, region, []string{stunAddr.String()}, "", "", !options.DeploymentValues.DERP.Config.DisableDirect.Value()) + require.NoError(t, err) + return func(h http.Handler) { mutex.Lock() defer mutex.Unlock() @@ -324,42 +348,24 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can Pubsub: options.Pubsub, GitAuthConfigs: options.GitAuthConfigs, - Auditor: options.Auditor, - AWSCertificates: options.AWSCertificates, - AzureCertificates: options.AzureCertificates, - GithubOAuth2Config: options.GithubOAuth2Config, - RealIPConfig: options.RealIPConfig, - OIDCConfig: options.OIDCConfig, - GoogleTokenValidator: options.GoogleTokenValidator, - SSHKeygenAlgorithm: options.SSHKeygenAlgorithm, - DERPServer: derpServer, - APIRateLimit: options.APIRateLimit, - LoginRateLimit: options.LoginRateLimit, - FilesRateLimit: options.FilesRateLimit, - Authorizer: options.Authorizer, - Telemetry: telemetry.NewNoop(), - TemplateScheduleStore: &templateScheduleStore, - TLSCertificates: options.TLSCertificates, - TrialGenerator: options.TrialGenerator, - DERPMap: &tailcfg.DERPMap{ - Regions: map[int]*tailcfg.DERPRegion{ - 1: { - EmbeddedRelay: true, - RegionID: 1, - RegionCode: "coder", - RegionName: "Coder", - Nodes: []*tailcfg.DERPNode{{ - Name: "1a", - RegionID: 1, - IPv4: "127.0.0.1", - DERPPort: derpPort, - STUNPort: stunAddr.Port, - InsecureForTests: true, - ForceHTTP: options.TLSCertificates == nil, - }}, - }, - }, - }, + Auditor: options.Auditor, + AWSCertificates: options.AWSCertificates, + AzureCertificates: options.AzureCertificates, + GithubOAuth2Config: options.GithubOAuth2Config, + RealIPConfig: options.RealIPConfig, + OIDCConfig: options.OIDCConfig, + GoogleTokenValidator: options.GoogleTokenValidator, + SSHKeygenAlgorithm: options.SSHKeygenAlgorithm, + DERPServer: derpServer, + APIRateLimit: options.APIRateLimit, + LoginRateLimit: options.LoginRateLimit, + FilesRateLimit: options.FilesRateLimit, + Authorizer: options.Authorizer, + Telemetry: telemetry.NewNoop(), + TemplateScheduleStore: &templateScheduleStore, + TLSCertificates: options.TLSCertificates, + TrialGenerator: options.TrialGenerator, + DERPMap: derpMap, MetricsCacheRefreshInterval: options.MetricsCacheRefreshInterval, AgentStatsRefreshInterval: options.AgentStatsRefreshInterval, DeploymentValues: options.DeploymentValues, diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 729dfaf7693c9..b9b7ea2bdc183 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -172,7 +172,7 @@ func (api *API) workspaceAgentManifest(rw http.ResponseWriter, r *http.Request) StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second, ShutdownScript: apiAgent.ShutdownScript, ShutdownScriptTimeout: time.Duration(apiAgent.ShutdownScriptTimeoutSeconds) * time.Second, - AllowDirectConnections: api.DeploymentValues.DERP.Config.DisableDirect.Value(), + AllowDirectConnections: !api.DeploymentValues.DERP.Config.DisableDirect.Value(), Metadata: convertWorkspaceAgentMetadataDesc(metadata), }) } @@ -736,7 +736,7 @@ func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceAgentConnectionInfo{ DERPMap: api.DERPMap, - AllowDirectConnections: api.DeploymentValues.DERP.Config.DisableDirect.Value(), + AllowDirectConnections: !api.DeploymentValues.DERP.Config.DisableDirect.Value(), }) } diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 73b540ea5ac68..76d80ddba3f7d 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -2,6 +2,7 @@ package coderd_test import ( "context" + "encoding/json" "fmt" "net" "net/http" @@ -444,6 +445,82 @@ func TestWorkspaceAgentTailnet(t *testing.T) { require.Equal(t, "test", strings.TrimSpace(string(output))) } +func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { + t.Parallel() + + dv := coderdtest.DeploymentValues(t) + err := dv.DERP.Config.DisableDirect.Set("true") + require.NoError(t, err) + require.True(t, dv.DERP.Config.DisableDirect.Value()) + + client, daemonCloser := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{ + DeploymentValues: dv, + }) + user := coderdtest.CreateFirstUser(t, client) + authToken := uuid.NewString() + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: echo.ProvisionComplete, + ProvisionApply: echo.ProvisionApplyWithAgent(authToken), + }) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + daemonCloser.Close() + + ctx := testutil.Context(t, testutil.WaitLong) + + // Verify that the manifest has AllowDirectConnections set to false. + agentClient := agentsdk.New(client.URL) + agentClient.SetSessionToken(authToken) + manifest, err := agentClient.Manifest(ctx) + require.NoError(t, err) + require.False(t, manifest.AllowDirectConnections) + + agentCloser := agent.New(agent.Options{ + Client: agentClient, + Logger: slogtest.Make(t, nil).Named("agent").Leveled(slog.LevelDebug), + }) + defer agentCloser.Close() + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) + agentID := resources[0].Agents[0].ID + + // Verify that the connection data has no STUN ports and + // AllowDirectConnections set to false. + res, err := client.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceagents/%s/connection", agentID), nil) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusOK, res.StatusCode) + var connInfo codersdk.WorkspaceAgentConnectionInfo + err = json.NewDecoder(res.Body).Decode(&connInfo) + require.NoError(t, err) + require.False(t, connInfo.AllowDirectConnections) + for _, region := range connInfo.DERPMap.Regions { + t.Logf("region %s (%v)", region.RegionCode, region.EmbeddedRelay) + for _, node := range region.Nodes { + t.Logf(" node %s (stun %d)", node.Name, node.STUNPort) + require.EqualValues(t, -1, node.STUNPort) + // tailnet.NewDERPMap() will create nodes with "stun" in the name, + // but not if direct is disabled. + require.NotContains(t, node.Name, "stun") + require.False(t, node.STUNOnly) + } + } + + conn, err := client.DialWorkspaceAgent(ctx, resources[0].Agents[0].ID, &codersdk.DialWorkspaceAgentOptions{ + Logger: slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug), + }) + require.NoError(t, err) + defer conn.Close() + require.True(t, conn.BlockEndpoints()) + + require.True(t, conn.AwaitReachable(ctx)) + _, p2p, _, err := conn.Ping(ctx) + require.NoError(t, err) + require.False(t, p2p) +} + func TestWorkspaceAgentListeningPorts(t *testing.T) { t.Parallel() diff --git a/tailnet/conn.go b/tailnet/conn.go index d68c41a8b15ed..844dc89c7c904 100644 --- a/tailnet/conn.go +++ b/tailnet/conn.go @@ -524,6 +524,13 @@ func (c *Conn) DERPMap() *tailcfg.DERPMap { return c.netMap.DERPMap } +// BlockEndpoints returns whether or not P2P is blocked. +func (c *Conn) BlockEndpoints() bool { + c.mutex.Lock() + defer c.mutex.Unlock() + return c.blockEndpoints +} + // AwaitReachable pings the provided IP continually until the // address is reachable. It's the callers responsibility to provide // a timeout, otherwise this function will block forever. diff --git a/tailnet/derpmap.go b/tailnet/derpmap.go index b41041df1edd6..f7a5cb47ef82e 100644 --- a/tailnet/derpmap.go +++ b/tailnet/derpmap.go @@ -82,9 +82,14 @@ func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []str } if !allowSTUN { for _, region := range derpMap.Regions { + newNodes := make([]*tailcfg.DERPNode, 0, len(region.Nodes)) for _, node := range region.Nodes { node.STUNPort = -1 + if !node.STUNOnly { + newNodes = append(newNodes, node) + } } + region.Nodes = newNodes } } diff --git a/tailnet/derpmap_test.go b/tailnet/derpmap_test.go index b9cb559b44a8c..0108f739ac90c 100644 --- a/tailnet/derpmap_test.go +++ b/tailnet/derpmap_test.go @@ -94,6 +94,10 @@ func TestNewDERPMap(t *testing.T) { { STUNPort: 12345, }, + { + STUNOnly: true, + STUNPort: 54321, + }, }, }, }, @@ -113,9 +117,12 @@ func TestNewDERPMap(t *testing.T) { require.Len(t, derpMap.Regions[1].Nodes, 1) require.EqualValues(t, -1, derpMap.Regions[1].Nodes[0].STUNPort) + // The STUNOnly node should get removed. require.Len(t, derpMap.Regions[2].Nodes, 2) require.EqualValues(t, -1, derpMap.Regions[2].Nodes[0].STUNPort) + require.False(t, derpMap.Regions[2].Nodes[0].STUNOnly) require.EqualValues(t, -1, derpMap.Regions[2].Nodes[1].STUNPort) + require.False(t, derpMap.Regions[2].Nodes[1].STUNOnly) // We don't add any nodes ourselves if STUN is disabled. require.Len(t, derpMap.Regions[3].Nodes, 1) // ... but we still remove the STUN port from existing nodes in the From 43f12cdf33a3e0098cf871cb8fdb7eba6f4c7ac3 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Sat, 10 Jun 2023 03:46:02 +0000 Subject: [PATCH 4/8] fixup! z --- tailnet/derpmap.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tailnet/derpmap.go b/tailnet/derpmap.go index f7a5cb47ef82e..1b1eebc9a9df8 100644 --- a/tailnet/derpmap.go +++ b/tailnet/derpmap.go @@ -80,6 +80,8 @@ func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []str } derpMap.Regions[region.RegionID] = region } + // Remove all STUNPorts from DERPy nodes, and fully remove all STUNOnly + // nodes. if !allowSTUN { for _, region := range derpMap.Regions { newNodes := make([]*tailcfg.DERPNode, 0, len(region.Nodes)) From aa3cdda366bde09b6126b673fc77b632c9a882b4 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Sat, 10 Jun 2023 03:58:04 +0000 Subject: [PATCH 5/8] fixup! Merge branch 'main' into dean/disable-direct --- enterprise/cli/root_internal_test.go | 3 ++- enterprise/cli/testdata/coder_server_--help.golden | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/root_internal_test.go b/enterprise/cli/root_internal_test.go index cc7b803698442..abaa9cc53d020 100644 --- a/enterprise/cli/root_internal_test.go +++ b/enterprise/cli/root_internal_test.go @@ -3,9 +3,10 @@ package cli import ( "testing" - "github.com/coder/coder/cli" "github.com/stretchr/testify/require" + "github.com/coder/coder/cli" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/clitest" diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index f8f45b138d7fd..661d5422789f1 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -171,6 +171,14 @@ backed by Tailscale and WireGuard. Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. + --disable-direct bool, $CODER_DISABLE_DIRECT + Disable peer-to-peer (aka. direct) workspace connections. All + workspace connections from the CLI will be proxied through Coder (or + custom configured DERP servers) and will never be peer-to-peer when + enabled. Workspaces may still reach out to STUN servers to get their + address until they are restarted after this change has been made, but + new connections will still be proxied regardless. + Networking / HTTP Options --disable-password-auth bool, $CODER_DISABLE_PASSWORD_AUTH Disable password authentication. This is recommended for security From bd107bc4709906b7feebba4f00b3304ea7f4ad20 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 21 Jun 2023 19:31:20 +0000 Subject: [PATCH 6/8] rename flag and fields --- agent/agent.go | 8 ++--- cli/server.go | 2 +- cli/testdata/coder_server_--help.golden | 16 +++++----- cli/testdata/server-config.yaml.golden | 4 +-- coderd/coderdtest/coderdtest.go | 2 +- coderd/workspaceagents.go | 32 +++++++++---------- coderd/workspaceagents_test.go | 12 +++---- codersdk/agentsdk/agentsdk.go | 26 +++++++-------- codersdk/deployment.go | 23 +++++++------ codersdk/workspaceagents.go | 6 ++-- .../cli/testdata/coder_server_--help.golden | 16 +++++----- tailnet/derpmap.go | 6 ++-- tailnet/derpmap_test.go | 10 +++--- 13 files changed, 83 insertions(+), 80 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 75235c38722e1..93b3040c23489 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -587,7 +587,7 @@ func (a *agent) run(ctx context.Context) error { network := a.network a.closeMutex.Unlock() if network == nil { - network, err = a.createTailnet(ctx, manifest.DERPMap, manifest.AllowDirectConnections) + network, err = a.createTailnet(ctx, manifest.DERPMap, manifest.DisableDirectConnections) if err != nil { return xerrors.Errorf("create tailnet: %w", err) } @@ -607,7 +607,7 @@ func (a *agent) run(ctx context.Context) error { } else { // Update the DERP map and allow/disallow direct connections. network.SetDERPMap(manifest.DERPMap) - network.SetBlockEndpoints(!manifest.AllowDirectConnections) + network.SetBlockEndpoints(manifest.DisableDirectConnections) } a.logger.Debug(ctx, "running tailnet connection coordinator") @@ -632,13 +632,13 @@ func (a *agent) trackConnGoroutine(fn func()) error { return nil } -func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap, allowDirectConnections bool) (_ *tailnet.Conn, err error) { +func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap, disableDirectConnections bool) (_ *tailnet.Conn, err error) { network, err := tailnet.NewConn(&tailnet.Options{ Addresses: []netip.Prefix{netip.PrefixFrom(codersdk.WorkspaceAgentIP, 128)}, DERPMap: derpMap, Logger: a.logger.Named("tailnet"), ListenPort: a.tailnetListenPort, - BlockEndpoints: !allowDirectConnections, + BlockEndpoints: disableDirectConnections, }) if err != nil { return nil, xerrors.Errorf("create tailnet: %w", err) diff --git a/cli/server.go b/cli/server.go index 94ea759a2992a..3bdbd4fc1428c 100644 --- a/cli/server.go +++ b/cli/server.go @@ -412,7 +412,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. derpMap, err := tailnet.NewDERPMap( ctx, defaultRegion, cfg.DERP.Server.STUNAddresses, cfg.DERP.Config.URL.String(), cfg.DERP.Config.Path.String(), - cfg.DERP.Config.DisableDirect.Value(), + cfg.DERP.Config.BlockDirect.Value(), ) if err != nil { return xerrors.Errorf("create derp map: %w", err) diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 661d5422789f1..13acf8dc293cb 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -147,6 +147,14 @@ between workspaces and users are peer-to-peer. However, when Coder cannot establish a peer to peer connection, Coder uses a distributed relay network backed by Tailscale and WireGuard. + --block-direct-connections bool, $CODER_BLOCK_DIRECT + Block peer-to-peer (aka. direct) workspace connections. All workspace + connections from the CLI will be proxied through Coder (or custom + configured DERP servers) and will never be peer-to-peer when enabled. + Workspaces may still reach out to STUN servers to get their address + until they are restarted after this change has been made, but new + connections will still be proxied regardless. + --derp-config-path string, $CODER_DERP_CONFIG_PATH Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp-servers/. @@ -171,14 +179,6 @@ backed by Tailscale and WireGuard. Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. - --disable-direct bool, $CODER_DISABLE_DIRECT - Disable peer-to-peer (aka. direct) workspace connections. All - workspace connections from the CLI will be proxied through Coder (or - custom configured DERP servers) and will never be peer-to-peer when - enabled. Workspaces may still reach out to STUN servers to get their - address until they are restarted after this change has been made, but - new connections will still be proxied regardless. - Networking / HTTP Options --disable-password-auth bool, $CODER_DISABLE_PASSWORD_AUTH Disable password authentication. This is recommended for security diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index 5d61d13386c43..cfe5915c14b89 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -117,13 +117,13 @@ networking: # for high availability. # (default: , type: url) relayURL: - # Disable peer-to-peer (aka. direct) workspace connections. All workspace + # Block peer-to-peer (aka. direct) workspace connections. All workspace # connections from the CLI will be proxied through Coder (or custom configured # DERP servers) and will never be peer-to-peer when enabled. Workspaces may still # reach out to STUN servers to get their address until they are restarted after # this change has been made, but new connections will still be proxied regardless. # (default: , type: bool) - disableDirect: false + blockDirect: false # URL to fetch a DERP mapping on startup. See: # https://tailscale.com/kb/1118/custom-derp-servers/. # (default: , type: string) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index ec3663430ff32..21974f5e81627 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -327,7 +327,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can if !options.DeploymentValues.DERP.Server.Enable.Value() { region = nil } - derpMap, err := tailnet.NewDERPMap(ctx, region, []string{stunAddr.String()}, "", "", !options.DeploymentValues.DERP.Config.DisableDirect.Value()) + derpMap, err := tailnet.NewDERPMap(ctx, region, []string{stunAddr.String()}, "", "", options.DeploymentValues.DERP.Config.BlockDirect.Value()) require.NoError(t, err) return func(h http.Handler) { diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index b11592e5b7d5f..17269d12e4bc0 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -161,19 +161,19 @@ func (api *API) workspaceAgentManifest(rw http.ResponseWriter, r *http.Request) } httpapi.Write(ctx, rw, http.StatusOK, agentsdk.Manifest{ - Apps: convertApps(dbApps), - DERPMap: api.DERPMap, - GitAuthConfigs: len(api.GitAuthConfigs), - EnvironmentVariables: apiAgent.EnvironmentVariables, - StartupScript: apiAgent.StartupScript, - Directory: apiAgent.Directory, - VSCodePortProxyURI: vscodeProxyURI, - MOTDFile: workspaceAgent.MOTDFile, - StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second, - ShutdownScript: apiAgent.ShutdownScript, - ShutdownScriptTimeout: time.Duration(apiAgent.ShutdownScriptTimeoutSeconds) * time.Second, - AllowDirectConnections: !api.DeploymentValues.DERP.Config.DisableDirect.Value(), - Metadata: convertWorkspaceAgentMetadataDesc(metadata), + Apps: convertApps(dbApps), + DERPMap: api.DERPMap, + GitAuthConfigs: len(api.GitAuthConfigs), + EnvironmentVariables: apiAgent.EnvironmentVariables, + StartupScript: apiAgent.StartupScript, + Directory: apiAgent.Directory, + VSCodePortProxyURI: vscodeProxyURI, + MOTDFile: workspaceAgent.MOTDFile, + StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second, + ShutdownScript: apiAgent.ShutdownScript, + ShutdownScriptTimeout: time.Duration(apiAgent.ShutdownScriptTimeoutSeconds) * time.Second, + DisableDirectConnections: api.DeploymentValues.DERP.Config.BlockDirect.Value(), + Metadata: convertWorkspaceAgentMetadataDesc(metadata), }) } @@ -667,7 +667,7 @@ func (api *API) dialWorkspaceAgentTailnet(agentID uuid.UUID) (*codersdk.Workspac Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)}, DERPMap: api.DERPMap, Logger: api.Logger.Named("tailnet"), - BlockEndpoints: api.DeploymentValues.DERP.Config.DisableDirect.Value(), + BlockEndpoints: api.DeploymentValues.DERP.Config.BlockDirect.Value(), }) if err != nil { _ = clientConn.Close() @@ -735,8 +735,8 @@ func (api *API) workspaceAgentConnection(rw http.ResponseWriter, r *http.Request ctx := r.Context() httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceAgentConnectionInfo{ - DERPMap: api.DERPMap, - AllowDirectConnections: !api.DeploymentValues.DERP.Config.DisableDirect.Value(), + DERPMap: api.DERPMap, + DisableDirectConnections: api.DeploymentValues.DERP.Config.BlockDirect.Value(), }) } diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 53da2f09aa55b..4febe96610291 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -449,9 +449,9 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) - err := dv.DERP.Config.DisableDirect.Set("true") + err := dv.DERP.Config.BlockDirect.Set("true") require.NoError(t, err) - require.True(t, dv.DERP.Config.DisableDirect.Value()) + require.True(t, dv.DERP.Config.BlockDirect.Value()) client, daemonCloser := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{ DeploymentValues: dv, @@ -471,12 +471,12 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { ctx := testutil.Context(t, testutil.WaitLong) - // Verify that the manifest has AllowDirectConnections set to false. + // Verify that the manifest has DisableDirectConnections set to true. agentClient := agentsdk.New(client.URL) agentClient.SetSessionToken(authToken) manifest, err := agentClient.Manifest(ctx) require.NoError(t, err) - require.False(t, manifest.AllowDirectConnections) + require.True(t, manifest.DisableDirectConnections) agentCloser := agent.New(agent.Options{ Client: agentClient, @@ -487,7 +487,7 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { agentID := resources[0].Agents[0].ID // Verify that the connection data has no STUN ports and - // AllowDirectConnections set to false. + // DisableDirectConnections set to true. res, err := client.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceagents/%s/connection", agentID), nil) require.NoError(t, err) defer res.Body.Close() @@ -495,7 +495,7 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { var connInfo codersdk.WorkspaceAgentConnectionInfo err = json.NewDecoder(res.Body).Decode(&connInfo) require.NoError(t, err) - require.False(t, connInfo.AllowDirectConnections) + require.True(t, connInfo.DisableDirectConnections) for _, region := range connInfo.DERPMap.Regions { t.Logf("region %s (%v)", region.RegionCode, region.EmbeddedRelay) for _, node := range region.Nodes { diff --git a/codersdk/agentsdk/agentsdk.go b/codersdk/agentsdk/agentsdk.go index dd8b5a854daa7..b5c26b265ef35 100644 --- a/codersdk/agentsdk/agentsdk.go +++ b/codersdk/agentsdk/agentsdk.go @@ -87,19 +87,19 @@ type Manifest struct { // GitAuthConfigs stores the number of Git configurations // the Coder deployment has. If this number is >0, we // set up special configuration in the workspace. - GitAuthConfigs int `json:"git_auth_configs"` - VSCodePortProxyURI string `json:"vscode_port_proxy_uri"` - Apps []codersdk.WorkspaceApp `json:"apps"` - DERPMap *tailcfg.DERPMap `json:"derpmap"` - EnvironmentVariables map[string]string `json:"environment_variables"` - StartupScript string `json:"startup_script"` - StartupScriptTimeout time.Duration `json:"startup_script_timeout"` - Directory string `json:"directory"` - MOTDFile string `json:"motd_file"` - ShutdownScript string `json:"shutdown_script"` - ShutdownScriptTimeout time.Duration `json:"shutdown_script_timeout"` - AllowDirectConnections bool `json:"allow_direct_connections"` - Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"` + GitAuthConfigs int `json:"git_auth_configs"` + VSCodePortProxyURI string `json:"vscode_port_proxy_uri"` + Apps []codersdk.WorkspaceApp `json:"apps"` + DERPMap *tailcfg.DERPMap `json:"derpmap"` + EnvironmentVariables map[string]string `json:"environment_variables"` + StartupScript string `json:"startup_script"` + StartupScriptTimeout time.Duration `json:"startup_script_timeout"` + Directory string `json:"directory"` + MOTDFile string `json:"motd_file"` + ShutdownScript string `json:"shutdown_script"` + ShutdownScriptTimeout time.Duration `json:"shutdown_script_timeout"` + DisableDirectConnections bool `json:"disable_direct_connections"` + Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"` } // Manifest fetches manifest for the currently authenticated workspace agent. diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 1b01b16d7e348..59e4fac98c3bb 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -221,9 +221,9 @@ type DERPServerConfig struct { } type DERPConfig struct { - DisableDirect clibase.Bool `json:"disable_direct" typescript:",notnull"` - URL clibase.String `json:"url" typescript:",notnull"` - Path clibase.String `json:"path" typescript:",notnull"` + BlockDirect clibase.Bool `json:"block_direct" typescript:",notnull"` + URL clibase.String `json:"url" typescript:",notnull"` + Path clibase.String `json:"path" typescript:",notnull"` } type PrometheusConfig struct { @@ -712,13 +712,16 @@ when required by your organization's security policy.`, YAML: "relayURL", }, { - Name: "Disable Direct Connections", - Description: "Disable peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless.", - Flag: "disable-direct", - Env: "CODER_DISABLE_DIRECT", - Value: &c.DERP.Config.DisableDirect, - Group: &deploymentGroupNetworkingDERP, - YAML: "disableDirect", + Name: "Block Direct Connections", + Description: "Block peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless.", + // This cannot be called `disable-direct-connections` because that's + // already a global CLI flag for CLI connections. This is a + // deployment-wide flag. + Flag: "block-direct-connections", + Env: "CODER_BLOCK_DIRECT", + Value: &c.DERP.Config.BlockDirect, + Group: &deploymentGroupNetworkingDERP, + YAML: "blockDirect", }, { Name: "DERP Config URL", diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index e642b28167fbb..4b9d4b7512c02 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -160,8 +160,8 @@ type DERPRegion struct { // a connection with a workspace. // @typescript-ignore WorkspaceAgentConnectionInfo type WorkspaceAgentConnectionInfo struct { - DERPMap *tailcfg.DERPMap `json:"derp_map"` - AllowDirectConnections bool `json:"allow_direct_connections"` + DERPMap *tailcfg.DERPMap `json:"derp_map"` + DisableDirectConnections bool `json:"disable_direct_connections"` } // @typescript-ignore DialWorkspaceAgentOptions @@ -188,7 +188,7 @@ func (c *Client) DialWorkspaceAgent(ctx context.Context, agentID uuid.UUID, opti if err != nil { return nil, xerrors.Errorf("decode conn info: %w", err) } - if !connInfo.AllowDirectConnections { + if connInfo.DisableDirectConnections { options.BlockEndpoints = true } diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index 661d5422789f1..13acf8dc293cb 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -147,6 +147,14 @@ between workspaces and users are peer-to-peer. However, when Coder cannot establish a peer to peer connection, Coder uses a distributed relay network backed by Tailscale and WireGuard. + --block-direct-connections bool, $CODER_BLOCK_DIRECT + Block peer-to-peer (aka. direct) workspace connections. All workspace + connections from the CLI will be proxied through Coder (or custom + configured DERP servers) and will never be peer-to-peer when enabled. + Workspaces may still reach out to STUN servers to get their address + until they are restarted after this change has been made, but new + connections will still be proxied regardless. + --derp-config-path string, $CODER_DERP_CONFIG_PATH Path to read a DERP mapping from. See: https://tailscale.com/kb/1118/custom-derp-servers/. @@ -171,14 +179,6 @@ backed by Tailscale and WireGuard. Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. - --disable-direct bool, $CODER_DISABLE_DIRECT - Disable peer-to-peer (aka. direct) workspace connections. All - workspace connections from the CLI will be proxied through Coder (or - custom configured DERP servers) and will never be peer-to-peer when - enabled. Workspaces may still reach out to STUN servers to get their - address until they are restarted after this change has been made, but - new connections will still be proxied regardless. - Networking / HTTP Options --disable-password-auth bool, $CODER_DISABLE_PASSWORD_AUTH Disable password authentication. This is recommended for security diff --git a/tailnet/derpmap.go b/tailnet/derpmap.go index 1b1eebc9a9df8..37092886540dd 100644 --- a/tailnet/derpmap.go +++ b/tailnet/derpmap.go @@ -17,11 +17,11 @@ import ( // URL to fetch a mapping from e.g. https://controlplane.tailscale.com/derpmap/default. // //nolint:revive -func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []string, remoteURL, localPath string, allowSTUN bool) (*tailcfg.DERPMap, error) { +func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []string, remoteURL, localPath string, disableSTUN bool) (*tailcfg.DERPMap, error) { if remoteURL != "" && localPath != "" { return nil, xerrors.New("a remote URL or local path must be specified, not both") } - if !allowSTUN { + if disableSTUN { stunAddrs = nil } @@ -82,7 +82,7 @@ func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []str } // Remove all STUNPorts from DERPy nodes, and fully remove all STUNOnly // nodes. - if !allowSTUN { + if disableSTUN { for _, region := range derpMap.Regions { newNodes := make([]*tailcfg.DERPNode, 0, len(region.Nodes)) for _, node := range region.Nodes { diff --git a/tailnet/derpmap_test.go b/tailnet/derpmap_test.go index 0108f739ac90c..bc5205cc45cf4 100644 --- a/tailnet/derpmap_test.go +++ b/tailnet/derpmap_test.go @@ -22,7 +22,7 @@ func TestNewDERPMap(t *testing.T) { derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 1, Nodes: []*tailcfg.DERPNode{{}}, - }, []string{"stun.google.com:2345"}, "", "", true) + }, []string{"stun.google.com:2345"}, "", "", false) require.NoError(t, err) require.Len(t, derpMap.Regions[1].Nodes, 2) }) @@ -39,7 +39,7 @@ func TestNewDERPMap(t *testing.T) { t.Cleanup(server.Close) derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 2, - }, []string{}, server.URL, "", true) + }, []string{}, server.URL, "", false) require.NoError(t, err) require.Len(t, derpMap.Regions, 2) }) @@ -56,7 +56,7 @@ func TestNewDERPMap(t *testing.T) { t.Cleanup(server.Close) _, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 1, - }, []string{}, server.URL, "", true) + }, []string{}, server.URL, "", false) require.Error(t, err) }) t.Run("LocalPath", func(t *testing.T) { @@ -72,7 +72,7 @@ func TestNewDERPMap(t *testing.T) { require.NoError(t, err) derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{ RegionID: 2, - }, []string{}, "", localPath, true) + }, []string{}, "", localPath, false) require.NoError(t, err) require.Len(t, derpMap.Regions, 2) }) @@ -111,7 +111,7 @@ func TestNewDERPMap(t *testing.T) { STUNPort: 1234, }}, } - derpMap, err := tailnet.NewDERPMap(context.Background(), region, []string{"127.0.0.1:54321"}, "", localPath, false) + derpMap, err := tailnet.NewDERPMap(context.Background(), region, []string{"127.0.0.1:54321"}, "", localPath, true) require.NoError(t, err) require.Len(t, derpMap.Regions, 3) From 9e7c5e17ca297bc05bc45cd891494056a4953b5e Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 21 Jun 2023 20:02:47 +0000 Subject: [PATCH 7/8] fixup! rename flag and fields --- coderd/apidoc/docs.go | 14 ++++---- coderd/apidoc/swagger.json | 14 ++++---- docs/api/agents.md | 6 ++-- docs/api/general.md | 2 +- docs/api/schemas.md | 64 +++++++++++++++++----------------- docs/cli/server.md | 20 +++++------ site/src/api/typesGenerated.ts | 2 +- 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 8c1ae672bc4fe..5ede78d185420 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5738,9 +5738,6 @@ const docTemplate = `{ "agentsdk.Manifest": { "type": "object", "properties": { - "allow_direct_connections": { - "type": "boolean" - }, "apps": { "type": "array", "items": { @@ -5753,6 +5750,9 @@ const docTemplate = `{ "directory": { "type": "string" }, + "disable_direct_connections": { + "type": "boolean" + }, "environment_variables": { "type": "object", "additionalProperties": { @@ -7020,7 +7020,7 @@ const docTemplate = `{ "codersdk.DERPConfig": { "type": "object", "properties": { - "disable_direct": { + "block_direct": { "type": "boolean" }, "path": { @@ -9287,11 +9287,11 @@ const docTemplate = `{ "codersdk.WorkspaceAgentConnectionInfo": { "type": "object", "properties": { - "allow_direct_connections": { - "type": "boolean" - }, "derp_map": { "$ref": "#/definitions/tailcfg.DERPMap" + }, + "disable_direct_connections": { + "type": "boolean" } } }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 25a4be09e935b..8b915d8c356d9 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5053,9 +5053,6 @@ "agentsdk.Manifest": { "type": "object", "properties": { - "allow_direct_connections": { - "type": "boolean" - }, "apps": { "type": "array", "items": { @@ -5068,6 +5065,9 @@ "directory": { "type": "string" }, + "disable_direct_connections": { + "type": "boolean" + }, "environment_variables": { "type": "object", "additionalProperties": { @@ -6252,7 +6252,7 @@ "codersdk.DERPConfig": { "type": "object", "properties": { - "disable_direct": { + "block_direct": { "type": "boolean" }, "path": { @@ -8383,11 +8383,11 @@ "codersdk.WorkspaceAgentConnectionInfo": { "type": "object", "properties": { - "allow_direct_connections": { - "type": "boolean" - }, "derp_map": { "$ref": "#/definitions/tailcfg.DERPMap" + }, + "disable_direct_connections": { + "type": "boolean" } } }, diff --git a/docs/api/agents.md b/docs/api/agents.md index 03782747b280d..bb973baff4381 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -292,7 +292,6 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/manifest \ ```json { - "allow_direct_connections": true, "apps": [ { "command": "string", @@ -364,6 +363,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/manifest \ } }, "directory": "string", + "disable_direct_connections": true, "environment_variables": { "property1": "string", "property2": "string" @@ -516,7 +516,6 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/con ```json { - "allow_direct_connections": true, "derp_map": { "omitDefaultRegions": true, "regions": { @@ -567,7 +566,8 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent}/con "regionName": "string" } } - } + }, + "disable_direct_connections": true } ``` diff --git a/docs/api/general.md b/docs/api/general.md index 1bf1159307388..a9acfd9b230ad 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -167,7 +167,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ }, "derp": { "config": { - "disable_direct": true, + "block_direct": true, "path": "string", "url": "string" }, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 6b88714423308..e6b95eac949ae 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -161,7 +161,6 @@ ```json { - "allow_direct_connections": true, "apps": [ { "command": "string", @@ -233,6 +232,7 @@ } }, "directory": "string", + "disable_direct_connections": true, "environment_variables": { "property1": "string", "property2": "string" @@ -258,22 +258,22 @@ ### Properties -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ------------------------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `allow_direct_connections` | boolean | false | | | -| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | -| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | -| `directory` | string | false | | | -| `environment_variables` | object | false | | | -| » `[any property]` | string | false | | | -| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | -| `metadata` | array of [codersdk.WorkspaceAgentMetadataDescription](#codersdkworkspaceagentmetadatadescription) | false | | | -| `motd_file` | string | false | | | -| `shutdown_script` | string | false | | | -| `shutdown_script_timeout` | integer | false | | | -| `startup_script` | string | false | | | -| `startup_script_timeout` | integer | false | | | -| `vscode_port_proxy_uri` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ---------------------------- | ------------------------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | +| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| `directory` | string | false | | | +| `disable_direct_connections` | boolean | false | | | +| `environment_variables` | object | false | | | +| » `[any property]` | string | false | | | +| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | +| `metadata` | array of [codersdk.WorkspaceAgentMetadataDescription](#codersdkworkspaceagentmetadatadescription) | false | | | +| `motd_file` | string | false | | | +| `shutdown_script` | string | false | | | +| `shutdown_script_timeout` | integer | false | | | +| `startup_script` | string | false | | | +| `startup_script_timeout` | integer | false | | | +| `vscode_port_proxy_uri` | string | false | | | ## agentsdk.PatchStartupLogs @@ -1663,7 +1663,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { "config": { - "disable_direct": true, + "block_direct": true, "path": "string", "url": "string" }, @@ -1701,7 +1701,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { - "disable_direct": true, + "block_direct": true, "path": "string", "url": "string" } @@ -1709,11 +1709,11 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ### Properties -| Name | Type | Required | Restrictions | Description | -| ---------------- | ------- | -------- | ------------ | ----------- | -| `disable_direct` | boolean | false | | | -| `path` | string | false | | | -| `url` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------- | ------- | -------- | ------------ | ----------- | +| `block_direct` | boolean | false | | | +| `path` | string | false | | | +| `url` | string | false | | | ## codersdk.DERPRegion @@ -1836,7 +1836,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in }, "derp": { "config": { - "disable_direct": true, + "block_direct": true, "path": "string", "url": "string" }, @@ -2164,7 +2164,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in }, "derp": { "config": { - "disable_direct": true, + "block_direct": true, "path": "string", "url": "string" }, @@ -4692,7 +4692,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { - "allow_direct_connections": true, "derp_map": { "omitDefaultRegions": true, "regions": { @@ -4743,16 +4742,17 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "regionName": "string" } } - } + }, + "disable_direct_connections": true } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ---------------------------------- | -------- | ------------ | ----------- | -| `allow_direct_connections` | boolean | false | | | -| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| Name | Type | Required | Restrictions | Description | +| ---------------------------- | ---------------------------------- | -------- | ------------ | ----------- | +| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| `disable_direct_connections` | boolean | false | | | ## codersdk.WorkspaceAgentLifecycle diff --git a/docs/cli/server.md b/docs/cli/server.md index 7fa8d292c4d89..2911d704e1a90 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -30,6 +30,16 @@ coder server [flags] The URL that users will use to access the Coder deployment. +### --block-direct-connections + +| | | +| ----------- | ---------------------------------------- | +| Type | bool | +| Environment | $CODER_BLOCK_DIRECT | +| YAML | networking.derp.blockDirect | + +Block peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless. + ### --browser-only | | | @@ -173,16 +183,6 @@ An HTTP URL that is accessible by other replicas to relay DERP traffic. Required Addresses for STUN servers to establish P2P connections. Use special value 'disable' to turn off STUN. -### --disable-direct - -| | | -| ----------- | ------------------------------------------ | -| Type | bool | -| Environment | $CODER_DISABLE_DIRECT | -| YAML | networking.derp.disableDirect | - -Disable peer-to-peer (aka. direct) workspace connections. All workspace connections from the CLI will be proxied through Coder (or custom configured DERP servers) and will never be peer-to-peer when enabled. Workspaces may still reach out to STUN servers to get their address until they are restarted after this change has been made, but new connections will still be proxied regardless. - ### --disable-owner-workspace-access | | | diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index c50900cd725d2..cf3d0d7891283 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -278,7 +278,7 @@ export interface DERP { // From codersdk/deployment.go export interface DERPConfig { - readonly disable_direct: boolean + readonly block_direct: boolean readonly url: string readonly path: string } From 92fdc5edaeeee3fcf53aff572d7d8cfd486fd6f6 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 21 Jun 2023 21:50:59 +0000 Subject: [PATCH 8/8] fixup! Merge branch 'main' into dean/disable-direct --- cli/netcheck_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/netcheck_test.go b/cli/netcheck_test.go index a9b346554facf..890260c1a704e 100644 --- a/cli/netcheck_test.go +++ b/cli/netcheck_test.go @@ -25,10 +25,14 @@ func TestNetcheck(t *testing.T) { clitest.StartWithWaiter(t, inv).RequireSuccess() + b := out.Bytes() + t.Log(string(b)) var report healthcheck.DERPReport - require.NoError(t, json.Unmarshal(out.Bytes(), &report)) + require.NoError(t, json.Unmarshal(b, &report)) assert.True(t, report.Healthy) require.Len(t, report.Regions, 1) - require.Len(t, report.Regions[1].NodeReports, 1) + for _, v := range report.Regions { + require.Len(t, v.NodeReports, len(v.Region.Nodes)) + } }