Skip to content

Commit 0f8c2f5

Browse files
feat: Use Tailscale networking by default (#4003)
* feat: Use Tailscale networking by default Removal of WebRTC code will happen in another PR, but it felt dangerious to default and remove in a single commit. Ideally, we can release this version and collect final thoughts and feedback before a full commitment. * Remove UNIX forwarding Tailscale doesn't support this, and adding support for it shouldn't block our rollout. Customers can always forward over SSH. * Update cli/portforward_test.go Co-authored-by: Dean Sheather <dean@deansheather.com> Co-authored-by: Dean Sheather <dean@deansheather.com>
1 parent 478d49c commit 0f8c2f5

File tree

8 files changed

+28
-183
lines changed

8 files changed

+28
-183
lines changed

agent/agent_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ func TestAgent(t *testing.T) {
559559
DERPMap: derpMap,
560560
}, 0)
561561
defer conn.Close()
562-
res, err := conn.Speedtest(speedtest.Upload, speedtest.MinDuration)
562+
res, err := conn.Speedtest(speedtest.Upload, 250*time.Millisecond)
563563
require.NoError(t, err)
564564
t.Logf("%.2f MBits/s", res[len(res)-1].MBitsPerSecond())
565565
})

cli/agent_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestWorkspaceAgent(t *testing.T) {
4747
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
4848
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
4949

50-
cmd, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String(), "--wireguard=false")
50+
cmd, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String())
5151
ctx, cancelFunc := context.WithCancel(context.Background())
5252
defer cancelFunc()
5353
errC := make(chan error)
@@ -105,7 +105,7 @@ func TestWorkspaceAgent(t *testing.T) {
105105
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
106106
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
107107

108-
cmd, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String(), "--wireguard=false")
108+
cmd, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String())
109109
ctx, cancelFunc := context.WithCancel(context.Background())
110110
defer cancelFunc()
111111
errC := make(chan error)
@@ -163,7 +163,7 @@ func TestWorkspaceAgent(t *testing.T) {
163163
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
164164
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
165165

166-
cmd, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String(), "--wireguard=false")
166+
cmd, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String())
167167
ctx, cancelFunc := context.WithCancel(context.Background())
168168
defer cancelFunc()
169169
errC := make(chan error)

cli/configssh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ func configSSH() *cobra.Command {
374374
cmd.Flags().BoolVarP(&skipProxyCommand, "skip-proxy-command", "", false, "Specifies whether the ProxyCommand option should be skipped. Useful for testing.")
375375
_ = cmd.Flags().MarkHidden("skip-proxy-command")
376376
cliflag.BoolVarP(cmd.Flags(), &usePreviousOpts, "use-previous-options", "", "CODER_SSH_USE_PREVIOUS_OPTIONS", false, "Specifies whether or not to keep options from previous run of config-ssh.")
377-
cliflag.BoolVarP(cmd.Flags(), &wireguard, "wireguard", "", "CODER_CONFIG_SSH_WIREGUARD", false, "Whether to use Wireguard for SSH tunneling.")
377+
cliflag.BoolVarP(cmd.Flags(), &wireguard, "wireguard", "", "CODER_CONFIG_SSH_WIREGUARD", true, "Whether to use Wireguard for SSH tunneling.")
378378
_ = cmd.Flags().MarkHidden("wireguard")
379379

380380
cliui.AllowSkipPrompt(cmd)

cli/portforward.go

Lines changed: 8 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"net"
77
"os"
88
"os/signal"
9-
"runtime"
109
"strconv"
1110
"strings"
1211
"sync"
@@ -24,10 +23,9 @@ import (
2423

2524
func portForward() *cobra.Command {
2625
var (
27-
tcpForwards []string // <port>:<port>
28-
udpForwards []string // <port>:<port>
29-
unixForwards []string // <path>:<path> OR <port>:<path>
30-
wireguard bool
26+
tcpForwards []string // <port>:<port>
27+
udpForwards []string // <port>:<port>
28+
wireguard bool
3129
)
3230
cmd := &cobra.Command{
3331
Use: "port-forward <workspace>",
@@ -43,14 +41,6 @@ func portForward() *cobra.Command {
4341
Description: "Port forward a single UDP port from port 9000 to port 9000 on your local machine",
4442
Command: "coder port-forward <workspace> --udp 9000",
4543
},
46-
example{
47-
Description: "Forward a Unix socket in the workspace to a local Unix socket",
48-
Command: "coder port-forward <workspace> --unix ./local.sock:~/remote.sock",
49-
},
50-
example{
51-
Description: "Forward a Unix socket in the workspace to a local TCP port",
52-
Command: "coder port-forward <workspace> --unix 8080:~/remote.sock",
53-
},
5444
example{
5545
Description: "Port forward multiple TCP ports and a UDP port",
5646
Command: "coder port-forward <workspace> --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53",
@@ -60,7 +50,7 @@ func portForward() *cobra.Command {
6050
ctx, cancel := context.WithCancel(cmd.Context())
6151
defer cancel()
6252

63-
specs, err := parsePortForwards(tcpForwards, udpForwards, unixForwards)
53+
specs, err := parsePortForwards(tcpForwards, udpForwards)
6454
if err != nil {
6555
return xerrors.Errorf("parse port-forward specs: %w", err)
6656
}
@@ -165,8 +155,7 @@ func portForward() *cobra.Command {
165155

166156
cmd.Flags().StringArrayVarP(&tcpForwards, "tcp", "p", []string{}, "Forward a TCP port from the workspace to the local machine")
167157
cmd.Flags().StringArrayVar(&udpForwards, "udp", []string{}, "Forward a UDP port from the workspace to the local machine. The UDP connection has TCP-like semantics to support stateful UDP protocols")
168-
cmd.Flags().StringArrayVar(&unixForwards, "unix", []string{}, "Forward a Unix socket in the workspace to a local Unix socket or TCP port")
169-
cmd.Flags().BoolVarP(&wireguard, "wireguard", "", false, "Specifies whether to use wireguard networking or not.")
158+
cmd.Flags().BoolVarP(&wireguard, "wireguard", "", true, "Specifies whether to use wireguard networking or not.")
170159
_ = cmd.Flags().MarkHidden("wireguard")
171160
return cmd
172161
}
@@ -198,8 +187,6 @@ func listenAndPortForward(ctx context.Context, cmd *cobra.Command, conn agent.Co
198187
IP: net.ParseIP(host),
199188
Port: portInt,
200189
})
201-
case "unix":
202-
l, err = net.Listen(spec.listenNetwork, spec.listenAddress)
203190
default:
204191
return nil, xerrors.Errorf("unknown listen network %q", spec.listenNetwork)
205192
}
@@ -236,14 +223,14 @@ func listenAndPortForward(ctx context.Context, cmd *cobra.Command, conn agent.Co
236223
}
237224

238225
type portForwardSpec struct {
239-
listenNetwork string // tcp, udp, unix
226+
listenNetwork string // tcp, udp
240227
listenAddress string // <ip>:<port> or path
241228

242-
dialNetwork string // tcp, udp, unix
229+
dialNetwork string // tcp, udp
243230
dialAddress string // <ip>:<port> or path
244231
}
245232

246-
func parsePortForwards(tcpSpecs, udpSpecs, unixSpecs []string) ([]portForwardSpec, error) {
233+
func parsePortForwards(tcpSpecs, udpSpecs []string) ([]portForwardSpec, error) {
247234
specs := []portForwardSpec{}
248235

249236
for _, spec := range tcpSpecs {
@@ -274,29 +261,6 @@ func parsePortForwards(tcpSpecs, udpSpecs, unixSpecs []string) ([]portForwardSpe
274261
})
275262
}
276263

277-
for _, specStr := range unixSpecs {
278-
localPath, localTCP, remotePath, err := parseUnixUnix(specStr)
279-
if err != nil {
280-
return nil, xerrors.Errorf("failed to parse Unix port-forward specification %q: %w", specStr, err)
281-
}
282-
283-
spec := portForwardSpec{
284-
dialNetwork: "unix",
285-
dialAddress: remotePath,
286-
}
287-
if localPath == "" {
288-
spec.listenNetwork = "tcp"
289-
spec.listenAddress = fmt.Sprintf("127.0.0.1:%v", localTCP)
290-
} else {
291-
if runtime.GOOS == "windows" {
292-
return nil, xerrors.Errorf("Unix port-forwarding is not supported on Windows")
293-
}
294-
spec.listenNetwork = "unix"
295-
spec.listenAddress = localPath
296-
}
297-
specs = append(specs, spec)
298-
}
299-
300264
// Check for duplicate entries.
301265
locals := map[string]struct{}{}
302266
for _, spec := range specs {
@@ -322,15 +286,6 @@ func parsePort(in string) (uint16, error) {
322286
return uint16(port), nil
323287
}
324288

325-
func parseUnixPath(in string) (string, error) {
326-
path, err := agent.ExpandRelativeHomePath(strings.TrimSpace(in))
327-
if err != nil {
328-
return "", xerrors.Errorf("tidy path %q: %w", in, err)
329-
}
330-
331-
return path, nil
332-
}
333-
334289
func parsePortPort(in string) (local uint16, remote uint16, err error) {
335290
parts := strings.Split(in, ":")
336291
if len(parts) > 2 {
@@ -352,37 +307,3 @@ func parsePortPort(in string) (local uint16, remote uint16, err error) {
352307

353308
return local, remote, nil
354309
}
355-
356-
func parsePortOrUnixPath(in string) (string, uint16, error) {
357-
port, err := parsePort(in)
358-
if err == nil {
359-
return "", port, nil
360-
}
361-
362-
path, err := parseUnixPath(in)
363-
if err != nil {
364-
return "", 0, xerrors.Errorf("could not parse port or unix path %q: %w", in, err)
365-
}
366-
367-
return path, 0, nil
368-
}
369-
370-
func parseUnixUnix(in string) (string, uint16, string, error) {
371-
parts := strings.Split(in, ":")
372-
if len(parts) > 2 {
373-
return "", 0, "", xerrors.Errorf("invalid port-forward specification %q", in)
374-
}
375-
if len(parts) == 1 {
376-
// Duplicate the single part
377-
parts = append(parts, parts[0])
378-
}
379-
380-
localPath, localPort, err := parsePortOrUnixPath(parts[0])
381-
if err != nil {
382-
return "", 0, "", xerrors.Errorf("parse local part of spec %q: %w", in, err)
383-
}
384-
385-
// We don't really touch the remote path at all since it gets cleaned
386-
// up/expanded on the remote.
387-
return localPath, localPort, parts[1], nil
388-
}

cli/portforward_test.go

Lines changed: 7 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import (
66
"fmt"
77
"io"
88
"net"
9-
"path/filepath"
10-
"runtime"
119
"strings"
1210
"sync"
1311
"testing"
@@ -58,7 +56,7 @@ func TestPortForward(t *testing.T) {
5856
// setupRemote creates a "remote" listener to emulate a service in the
5957
// workspace.
6058
setupRemote func(t *testing.T) net.Listener
61-
// setupLocal returns an available port or Unix socket path that the
59+
// setupLocal returns an available port that the
6260
// port-forward command will listen on "locally". Returns the address
6361
// you pass to net.Dial, and the port/path you pass to `coder
6462
// port-forward`.
@@ -110,26 +108,6 @@ func TestPortForward(t *testing.T) {
110108
return l.Addr().String(), port
111109
},
112110
},
113-
{
114-
name: "Unix",
115-
network: "unix",
116-
flag: "--unix=%v:%v",
117-
setupRemote: func(t *testing.T) net.Listener {
118-
if runtime.GOOS == "windows" {
119-
t.Skip("Unix socket forwarding isn't supported on Windows")
120-
}
121-
122-
tmpDir := t.TempDir()
123-
l, err := net.Listen("unix", filepath.Join(tmpDir, "test.sock"))
124-
require.NoError(t, err, "create UDP listener")
125-
return l
126-
},
127-
setupLocal: func(t *testing.T) (string, string) {
128-
tmpDir := t.TempDir()
129-
path := filepath.Join(tmpDir, "test.sock")
130-
return path, path
131-
},
132-
},
133111
}
134112

135113
// Setup agent once to be shared between test-cases (avoid expensive
@@ -234,74 +212,16 @@ func TestPortForward(t *testing.T) {
234212
})
235213
}
236214

237-
// Test doing a TCP -> Unix forward.
238-
//nolint:paralleltest
239-
t.Run("TCP2Unix", func(t *testing.T) {
240-
var (
241-
// Find the TCP and Unix cases so we can use their setupLocal and
242-
// setupRemote methods respectively.
243-
tcpCase = cases[0]
244-
unixCase = cases[2]
245-
246-
// Setup remote Unix listener.
247-
p1 = setupTestListener(t, unixCase.setupRemote(t))
248-
)
249-
250-
// Create a flag that forwards from local TCP to Unix listener 1.
251-
// Notably this is a --unix flag.
252-
localAddress, localFlag := tcpCase.setupLocal(t)
253-
flag := fmt.Sprintf(unixCase.flag, localFlag, p1)
254-
255-
// Launch port-forward in a goroutine so we can start dialing
256-
// the "local" listener.
257-
cmd, root := clitest.New(t, "port-forward", workspace.Name, flag)
258-
clitest.SetupConfig(t, client, root)
259-
buf := newThreadSafeBuffer()
260-
cmd.SetOut(buf)
261-
ctx, cancel := context.WithCancel(context.Background())
262-
defer cancel()
263-
errC := make(chan error)
264-
go func() {
265-
errC <- cmd.ExecuteContext(ctx)
266-
}()
267-
waitForPortForwardReady(t, buf)
268-
269-
t.Parallel() // Port is reserved, enable parallel execution.
270-
271-
// Open two connections simultaneously and test them out of
272-
// sync.
273-
d := net.Dialer{Timeout: testutil.WaitShort}
274-
c1, err := d.DialContext(ctx, tcpCase.network, localAddress)
275-
require.NoError(t, err, "open connection 1 to 'local' listener")
276-
defer c1.Close()
277-
c2, err := d.DialContext(ctx, tcpCase.network, localAddress)
278-
require.NoError(t, err, "open connection 2 to 'local' listener")
279-
defer c2.Close()
280-
testDial(t, c2)
281-
testDial(t, c1)
282-
283-
cancel()
284-
err = <-errC
285-
require.ErrorIs(t, err, context.Canceled)
286-
})
287-
288-
// Test doing TCP, UDP and Unix at the same time.
215+
// Test doing TCP and UDP at the same time.
289216
//nolint:paralleltest
290217
t.Run("All", func(t *testing.T) {
291218
var (
292-
// These aren't fixed size because we exclude Unix on Windows.
293219
dials = []addr{}
294220
flags = []string{}
295221
)
296222

297223
// Start listeners and populate arrays with the cases.
298224
for _, c := range cases {
299-
if strings.HasPrefix(c.network, "unix") && runtime.GOOS == "windows" {
300-
// Unix isn't supported on Windows, but we can still
301-
// test other protocols together.
302-
continue
303-
}
304-
305225
p := setupTestListener(t, c.setupRemote(t))
306226

307227
localAddress, localFlag := c.setupLocal(t)
@@ -391,7 +311,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) ([]coders
391311
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
392312

393313
// Start workspace agent in a goroutine
394-
cmd, root := clitest.New(t, "agent", "--agent-token", agentToken, "--agent-url", client.URL.String(), "--wireguard=false")
314+
cmd, root := clitest.New(t, "agent", "--agent-token", agentToken, "--agent-url", client.URL.String())
395315
clitest.SetupConfig(t, client, root)
396316
errC := make(chan error)
397317
agentCtx, agentCancel := context.WithCancel(ctx)
@@ -412,7 +332,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) ([]coders
412332
}
413333

414334
// setupTestListener starts accepting connections and echoing a single packet.
415-
// Returns the listener and the listen port or Unix path.
335+
// Returns the listener and the listen port.
416336
func setupTestListener(t *testing.T, l net.Listener) string {
417337
t.Helper()
418338

@@ -444,11 +364,9 @@ func setupTestListener(t *testing.T, l net.Listener) string {
444364
}()
445365

446366
addr := l.Addr().String()
447-
if !strings.HasPrefix(l.Addr().Network(), "unix") {
448-
_, port, err := net.SplitHostPort(addr)
449-
require.NoErrorf(t, err, "split non-Unix listen path %q", addr)
450-
addr = port
451-
}
367+
_, port, err := net.SplitHostPort(addr)
368+
require.NoErrorf(t, err, "split listen path %q", addr)
369+
addr = port
452370

453371
return addr
454372
}

cli/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ func Server(newAPI func(*coderd.Options) *coderd.API) *cobra.Command {
812812
"Specifies an issuer URL to use for OIDC.")
813813
cliflag.StringArrayVarP(root.Flags(), &oidcScopes, "oidc-scopes", "", "CODER_OIDC_SCOPES", []string{oidc.ScopeOpenID, "profile", "email"},
814814
"Specifies scopes to grant when authenticating with OIDC.")
815-
cliflag.BoolVarP(root.Flags(), &tailscaleEnable, "tailscale", "", "CODER_TAILSCALE", false,
815+
cliflag.BoolVarP(root.Flags(), &tailscaleEnable, "tailscale", "", "CODER_TAILSCALE", true,
816816
"Specifies whether Tailscale networking is used for web applications and terminals.")
817817
_ = root.Flags().MarkHidden("tailscale")
818818
enableTelemetryByDefault := !isTest()

cli/ssh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func ssh() *cobra.Command {
221221
cliflag.BoolVarP(cmd.Flags(), &forwardAgent, "forward-agent", "A", "CODER_SSH_FORWARD_AGENT", false, "Specifies whether to forward the SSH agent specified in $SSH_AUTH_SOCK")
222222
cliflag.StringVarP(cmd.Flags(), &identityAgent, "identity-agent", "", "CODER_SSH_IDENTITY_AGENT", "", "Specifies which identity agent to use (overrides $SSH_AUTH_SOCK), forward agent must also be enabled")
223223
cliflag.DurationVarP(cmd.Flags(), &wsPollInterval, "workspace-poll-interval", "", "CODER_WORKSPACE_POLL_INTERVAL", workspacePollInterval, "Specifies how often to poll for workspace automated shutdown.")
224-
cliflag.BoolVarP(cmd.Flags(), &wireguard, "wireguard", "", "CODER_SSH_WIREGUARD", false, "Whether to use Wireguard for SSH tunneling.")
224+
cliflag.BoolVarP(cmd.Flags(), &wireguard, "wireguard", "", "CODER_SSH_WIREGUARD", true, "Whether to use Wireguard for SSH tunneling.")
225225
_ = cmd.Flags().MarkHidden("wireguard")
226226

227227
return cmd

coderd/coderd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ func New(options *Options) *API {
9595
if options.APIRateLimit == 0 {
9696
options.APIRateLimit = 512
9797
}
98+
if options.AgentStatsRefreshInterval == 0 {
99+
options.AgentStatsRefreshInterval = 10 * time.Minute
100+
}
101+
if options.MetricsCacheRefreshInterval == 0 {
102+
options.MetricsCacheRefreshInterval = time.Hour
103+
}
98104
if options.Authorizer == nil {
99105
var err error
100106
options.Authorizer, err = rbac.NewAuthorizer()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy