Skip to content

Commit 0cc4263

Browse files
committed
Fix DERP mesh with TLS
1 parent c1aa3d2 commit 0cc4263

File tree

6 files changed

+53
-49
lines changed

6 files changed

+53
-49
lines changed

enterprise/coderd/coderd.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/ed25519"
66
"crypto/tls"
7+
"crypto/x509"
78
"net/http"
89
"sync"
910
"time"
@@ -138,10 +139,22 @@ func New(ctx context.Context, options *Options) (*API, error) {
138139
if err != nil {
139140
return nil, xerrors.Errorf("initialize replica: %w", err)
140141
}
142+
143+
rootCA := x509.NewCertPool()
144+
for _, certificate := range options.TLSCertificates {
145+
for _, certificatePart := range certificate.Certificate {
146+
certificate, err := x509.ParseCertificate(certificatePart)
147+
if err != nil {
148+
return nil, xerrors.Errorf("parse certificate %s: %w", certificate.Subject.CommonName, err)
149+
}
150+
rootCA.AddCert(certificate)
151+
}
152+
}
153+
141154
// nolint:gosec
142155
api.derpMesh = derpmesh.New(options.Logger.Named("derpmesh"), api.DERPServer, &tls.Config{
143-
Certificates: options.TLSCertificates,
144-
ServerName: options.AccessURL.Host,
156+
ServerName: options.AccessURL.Host,
157+
RootCAs: rootCA,
145158
})
146159

147160
err = api.updateEntitlements(ctx)

enterprise/derpmesh/derpmesh_test.go

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -37,44 +37,27 @@ func TestMain(m *testing.M) {
3737

3838
func TestDERPMesh(t *testing.T) {
3939
t.Parallel()
40-
t.Run("ExchangeMessages", func(t *testing.T) {
41-
// This tests messages passing through multiple DERP servers.
42-
t.Parallel()
43-
firstServer, firstServerURL, firstTLSName := startDERP(t)
44-
defer firstServer.Close()
45-
secondServer, secondServerURL, secondTLSName := startDERP(t)
46-
firstMesh := derpmesh.New(slogtest.Make(t, nil).Named("first").Leveled(slog.LevelDebug), firstServer, firstTLSName)
47-
firstMesh.SetAddresses([]string{secondServerURL})
48-
secondMesh := derpmesh.New(slogtest.Make(t, nil).Named("second").Leveled(slog.LevelDebug), secondServer, secondTLSName)
49-
secondMesh.SetAddresses([]string{firstServerURL})
50-
defer firstMesh.Close()
51-
defer secondMesh.Close()
52-
53-
first := key.NewNode()
54-
second := key.NewNode()
55-
firstClient, err := derphttp.NewClient(first, secondServerURL, tailnet.Logger(slogtest.Make(t, nil)))
56-
require.NoError(t, err)
57-
secondClient, err := derphttp.NewClient(second, firstServerURL, tailnet.Logger(slogtest.Make(t, nil)))
58-
require.NoError(t, err)
59-
err = secondClient.Connect(context.Background())
60-
require.NoError(t, err)
61-
62-
sent := []byte("hello world")
63-
err = firstClient.Send(second.Public(), sent)
64-
require.NoError(t, err)
40+
commonName := "something.org"
41+
rawCert := generateTLSCertificate(t, commonName)
42+
certificate, err := x509.ParseCertificate(rawCert.Certificate[0])
43+
require.NoError(t, err)
44+
pool := x509.NewCertPool()
45+
pool.AddCert(certificate)
46+
tlsConfig := &tls.Config{
47+
ServerName: commonName,
48+
RootCAs: pool,
49+
Certificates: []tls.Certificate{rawCert},
50+
}
6551

66-
got := recvData(t, secondClient)
67-
require.Equal(t, sent, got)
68-
})
6952
t.Run("ExchangeMessages", func(t *testing.T) {
7053
// This tests messages passing through multiple DERP servers.
7154
t.Parallel()
72-
firstServer, firstServerURL, firstTLSName := startDERP(t)
55+
firstServer, firstServerURL := startDERP(t, tlsConfig)
7356
defer firstServer.Close()
74-
secondServer, secondServerURL, secondTLSName := startDERP(t)
75-
firstMesh := derpmesh.New(slogtest.Make(t, nil).Named("first").Leveled(slog.LevelDebug), firstServer, firstTLSName)
57+
secondServer, secondServerURL := startDERP(t, tlsConfig)
58+
firstMesh := derpmesh.New(slogtest.Make(t, nil).Named("first").Leveled(slog.LevelDebug), firstServer, tlsConfig)
7659
firstMesh.SetAddresses([]string{secondServerURL})
77-
secondMesh := derpmesh.New(slogtest.Make(t, nil).Named("second").Leveled(slog.LevelDebug), secondServer, secondTLSName)
60+
secondMesh := derpmesh.New(slogtest.Make(t, nil).Named("second").Leveled(slog.LevelDebug), secondServer, tlsConfig)
7861
secondMesh.SetAddresses([]string{firstServerURL})
7962
defer firstMesh.Close()
8063
defer secondMesh.Close()
@@ -83,8 +66,10 @@ func TestDERPMesh(t *testing.T) {
8366
second := key.NewNode()
8467
firstClient, err := derphttp.NewClient(first, secondServerURL, tailnet.Logger(slogtest.Make(t, nil)))
8568
require.NoError(t, err)
69+
firstClient.TLSConfig = tlsConfig
8670
secondClient, err := derphttp.NewClient(second, firstServerURL, tailnet.Logger(slogtest.Make(t, nil)))
8771
require.NoError(t, err)
72+
secondClient.TLSConfig = tlsConfig
8873
err = secondClient.Connect(context.Background())
8974
require.NoError(t, err)
9075

@@ -98,8 +83,8 @@ func TestDERPMesh(t *testing.T) {
9883
t.Run("RemoveAddress", func(t *testing.T) {
9984
// This tests messages passing through multiple DERP servers.
10085
t.Parallel()
101-
server, serverURL, tlsName := startDERP(t)
102-
mesh := derpmesh.New(slogtest.Make(t, nil).Named("first").Leveled(slog.LevelDebug), server, tlsName)
86+
server, serverURL := startDERP(t, tlsConfig)
87+
mesh := derpmesh.New(slogtest.Make(t, nil).Named("first").Leveled(slog.LevelDebug), server, tlsConfig)
10388
mesh.SetAddresses([]string{"http://fake.com"})
10489
// This should trigger a removal...
10590
mesh.SetAddresses([]string{})
@@ -109,8 +94,10 @@ func TestDERPMesh(t *testing.T) {
10994
second := key.NewNode()
11095
firstClient, err := derphttp.NewClient(first, serverURL, tailnet.Logger(slogtest.Make(t, nil)))
11196
require.NoError(t, err)
97+
firstClient.TLSConfig = tlsConfig
11298
secondClient, err := derphttp.NewClient(second, serverURL, tailnet.Logger(slogtest.Make(t, nil)))
11399
require.NoError(t, err)
100+
secondClient.TLSConfig = tlsConfig
114101
err = secondClient.Connect(context.Background())
115102
require.NoError(t, err)
116103
sent := []byte("hello world")
@@ -124,8 +111,8 @@ func TestDERPMesh(t *testing.T) {
124111
meshes := make([]*derpmesh.Mesh, 0, 20)
125112
serverURLs := make([]string, 0, 20)
126113
for i := 0; i < 20; i++ {
127-
server, url, tlsName := startDERP(t)
128-
mesh := derpmesh.New(slogtest.Make(t, nil).Named("mesh").Leveled(slog.LevelDebug), server, tlsName)
114+
server, url := startDERP(t, tlsConfig)
115+
mesh := derpmesh.New(slogtest.Make(t, nil).Named("mesh").Leveled(slog.LevelDebug), server, tlsConfig)
129116
t.Cleanup(func() {
130117
_ = server.Close()
131118
_ = mesh.Close()
@@ -141,8 +128,10 @@ func TestDERPMesh(t *testing.T) {
141128
second := key.NewNode()
142129
firstClient, err := derphttp.NewClient(first, serverURLs[9], tailnet.Logger(slogtest.Make(t, nil)))
143130
require.NoError(t, err)
131+
firstClient.TLSConfig = tlsConfig
144132
secondClient, err := derphttp.NewClient(second, serverURLs[16], tailnet.Logger(slogtest.Make(t, nil)))
145133
require.NoError(t, err)
134+
secondClient.TLSConfig = tlsConfig
146135
err = secondClient.Connect(context.Background())
147136
require.NoError(t, err)
148137

@@ -172,21 +161,18 @@ func recvData(t *testing.T, client *derphttp.Client) []byte {
172161
}
173162
}
174163

175-
func startDERP(t *testing.T) (*derp.Server, string, *tls.Config) {
164+
func startDERP(t *testing.T, tlsConfig *tls.Config) (*derp.Server, string) {
176165
logf := tailnet.Logger(slogtest.Make(t, nil))
177166
d := derp.NewServer(key.NewNode(), logf)
178167
d.SetMeshKey("some-key")
179168
server := httptest.NewUnstartedServer(derphttp.Handler(d))
180-
commonName := "something.org"
181-
server.TLS = &tls.Config{
182-
Certificates: []tls.Certificate{generateTLSCertificate(t, commonName)},
183-
}
184-
server.Start()
169+
server.TLS = tlsConfig
170+
server.StartTLS()
185171
t.Cleanup(func() {
186172
_ = d.Close()
187173
})
188174
t.Cleanup(server.Close)
189-
return d, server.URL, server.TLS
175+
return d, server.URL
190176
}
191177

192178
func generateTLSCertificate(t testing.TB, commonName string) tls.Certificate {

enterprise/tailnet/coordinator.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,11 @@ func (c *haCoordinator) hangleAgentUpdate(id uuid.UUID, decoder *json.Decoder) (
294294
func (c *haCoordinator) Close() error {
295295
c.mutex.Lock()
296296
defer c.mutex.Unlock()
297-
297+
select {
298+
case <-c.close:
299+
return nil
300+
default:
301+
}
298302
close(c.close)
299303

300304
wg := sync.WaitGroup{}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ replace github.com/tcnksm/go-httpstat => github.com/kylecarbs/go-httpstat v0.0.0
4040

4141
// There are a few minor changes we make to Tailscale that we're slowly upstreaming. Compare here:
4242
// https://github.com/tailscale/tailscale/compare/main...coder:tailscale:main
43-
replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20221014173742-9f1da7795630
43+
replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20221015033036-5861cbbf7bf5
4444

4545
// Switch to our fork that imports fixes from http://github.com/tailscale/ssh.
4646
// See: https://github.com/coder/coder/issues/3371

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,8 @@ github.com/coder/retry v1.3.0 h1:5lAAwt/2Cm6lVmnfBY7sOMXcBOwcwJhmV5QGSELIVWY=
351351
github.com/coder/retry v1.3.0/go.mod h1:tXuRgZgWjUnU5LZPT4lJh4ew2elUhexhlnXzrJWdyFY=
352352
github.com/coder/ssh v0.0.0-20220811105153-fcea99919338 h1:tN5GKFT68YLVzJoA8AHuiMNJ0qlhoD3pGN3JY9gxSko=
353353
github.com/coder/ssh v0.0.0-20220811105153-fcea99919338/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914=
354-
github.com/coder/tailscale v1.1.1-0.20221014173742-9f1da7795630 h1:FgWWdu0fnFEpUNjW0vOaCuOxOZ/GQzn6oo7p5IMlSA0=
355-
github.com/coder/tailscale v1.1.1-0.20221014173742-9f1da7795630/go.mod h1:5amxy08qijEa8bcTW2SeIy4MIqcmd7LMsuOxqOlj2Ak=
354+
github.com/coder/tailscale v1.1.1-0.20221015033036-5861cbbf7bf5 h1:WVH6e/qK3Wpl0wbmpORD2oQ1qLJborF3fsFHyO1ps0Y=
355+
github.com/coder/tailscale v1.1.1-0.20221015033036-5861cbbf7bf5/go.mod h1:5amxy08qijEa8bcTW2SeIy4MIqcmd7LMsuOxqOlj2Ak=
356356
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
357357
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
358358
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ export interface Replica {
538538
readonly relay_address: string
539539
readonly region_id: number
540540
readonly error: string
541+
readonly database_latency: number
541542
}
542543

543544
// From codersdk/error.go

0 commit comments

Comments
 (0)