Skip to content
This repository was archived by the owner on Jul 13, 2025. It is now read-only.

Commit a3dac5a

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents dc20eb1 + a64ca7a commit a3dac5a

File tree

109 files changed

+3857
-835
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+3857
-835
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ buildmultiarchimage: ## Build (and optionally push) multiarch docker image
6464
check: staticcheck vet depaware buildwindows build386 buildlinuxarm buildwasm ## Perform basic checks and compilation tests
6565

6666
staticcheck: ## Run staticcheck.io checks
67-
./tool/go run honnef.co/go/tools/cmd/staticcheck -- $$(./tool/go list ./... | grep -v tempfork)
67+
./tool/go run honnef.co/go/tools/cmd/staticcheck -- $$(./tool/go run ./tool/listpkgs --ignore-3p ./...)
6868

6969
kube-generate-all: kube-generate-deepcopy ## Refresh generated files for Tailscale Kubernetes Operator
7070
./tool/go generate ./cmd/k8s-operator

chirp/chirp_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Tailscale Inc & AUTHORS
22
// SPDX-License-Identifier: BSD-3-Clause
3+
34
package chirp
45

56
import (

client/local/local.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
// Copyright (c) Tailscale Inc & AUTHORS
22
// SPDX-License-Identifier: BSD-3-Clause
33

4-
//go:build go1.22
5-
64
// Package local contains a Go client for the Tailscale LocalAPI.
75
package local
86

97
import (
8+
"bufio"
109
"bytes"
1110
"cmp"
1211
"context"
@@ -16,6 +15,7 @@ import (
1615
"errors"
1716
"fmt"
1817
"io"
18+
"iter"
1919
"net"
2020
"net/http"
2121
"net/http/httptrace"
@@ -42,6 +42,7 @@ import (
4242
"tailscale.com/types/dnstype"
4343
"tailscale.com/types/key"
4444
"tailscale.com/types/tkatype"
45+
"tailscale.com/util/eventbus"
4546
"tailscale.com/util/syspolicy/setting"
4647
)
4748

@@ -414,6 +415,44 @@ func (lc *Client) TailDaemonLogs(ctx context.Context) (io.Reader, error) {
414415
return res.Body, nil
415416
}
416417

418+
// StreamBusEvents returns an iterator of Tailscale bus events as they arrive.
419+
// Each pair is a valid event and a nil error, or a zero event a non-nil error.
420+
// In case of error, the iterator ends after the pair reporting the error.
421+
// Iteration stops if ctx ends.
422+
func (lc *Client) StreamBusEvents(ctx context.Context) iter.Seq2[eventbus.DebugEvent, error] {
423+
return func(yield func(eventbus.DebugEvent, error) bool) {
424+
req, err := http.NewRequestWithContext(ctx, "GET",
425+
"http://"+apitype.LocalAPIHost+"/localapi/v0/debug-bus-events", nil)
426+
if err != nil {
427+
yield(eventbus.DebugEvent{}, err)
428+
return
429+
}
430+
res, err := lc.doLocalRequestNiceError(req)
431+
if err != nil {
432+
yield(eventbus.DebugEvent{}, err)
433+
return
434+
}
435+
if res.StatusCode != http.StatusOK {
436+
yield(eventbus.DebugEvent{}, errors.New(res.Status))
437+
return
438+
}
439+
defer res.Body.Close()
440+
dec := json.NewDecoder(bufio.NewReader(res.Body))
441+
for {
442+
var evt eventbus.DebugEvent
443+
if err := dec.Decode(&evt); err == io.EOF {
444+
return
445+
} else if err != nil {
446+
yield(eventbus.DebugEvent{}, err)
447+
return
448+
}
449+
if !yield(evt, nil) {
450+
return
451+
}
452+
}
453+
}
454+
}
455+
417456
// Pprof returns a pprof profile of the Tailscale daemon.
418457
func (lc *Client) Pprof(ctx context.Context, pprofType string, sec int) ([]byte, error) {
419458
var secArg string

cmd/cloner/cloner_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Tailscale Inc & AUTHORS
22
// SPDX-License-Identifier: BSD-3-Clause
3+
34
package main
45

56
import (

cmd/derper/depaware.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
157157
💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting
158158
L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics
159159
tailscale.com/util/dnsname from tailscale.com/hostinfo+
160-
tailscale.com/util/eventbus from tailscale.com/net/netmon
160+
tailscale.com/util/eventbus from tailscale.com/net/netmon+
161161
💣 tailscale.com/util/hashx from tailscale.com/util/deephash
162162
tailscale.com/util/httpm from tailscale.com/client/tailscale
163163
tailscale.com/util/lineiter from tailscale.com/hostinfo+

cmd/derper/derper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ var (
6868
runDERP = flag.Bool("derp", true, "whether to run a DERP server. The only reason to set this false is if you're decommissioning a server but want to keep its bootstrap DNS functionality still running.")
6969
flagHome = flag.String("home", "", "what to serve at the root path. It may be left empty (the default, for a default homepage), \"blank\" for a blank page, or a URL to redirect to")
7070

71-
meshPSKFile = flag.String("mesh-psk-file", defaultMeshPSKFile(), "if non-empty, path to file containing the mesh pre-shared key file. It should contain some hex string; whitespace is trimmed.")
71+
meshPSKFile = flag.String("mesh-psk-file", defaultMeshPSKFile(), "if non-empty, path to file containing the mesh pre-shared key file. It must be 64 lowercase hexadecimal characters; whitespace is trimmed.")
7272
meshWith = flag.String("mesh-with", "", "optional comma-separated list of hostnames to mesh with; the server's own hostname can be in the list. If an entry contains a slash, the second part names a hostname to be used when dialing the target.")
7373
secretsURL = flag.String("secrets-url", "", "SETEC server URL for secrets retrieval of mesh key")
7474
secretPrefix = flag.String("secrets-path-prefix", "prod/derp", "setec path prefix for \""+setecMeshKeyName+"\" secret for DERP mesh key")

cmd/derper/mesh.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func startMeshWithHost(s *derp.Server, hostTuple string) error {
7272

7373
add := func(m derp.PeerPresentMessage) { s.AddPacketForwarder(m.Key, c) }
7474
remove := func(m derp.PeerGoneMessage) { s.RemovePacketForwarder(m.Peer, c) }
75-
go c.RunWatchConnectionLoop(context.Background(), s.PublicKey(), logf, add, remove)
75+
notifyError := func(err error) {}
76+
go c.RunWatchConnectionLoop(context.Background(), s.PublicKey(), logf, add, remove, notifyError)
7677
return nil
7778
}

cmd/derpprobe/derpprobe.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,36 @@
55
package main
66

77
import (
8+
"context"
89
"flag"
910
"fmt"
1011
"log"
1112
"net/http"
1213
"os"
14+
"path"
15+
"path/filepath"
1316
"sort"
1417
"time"
1518

19+
"github.com/tailscale/setec/client/setec"
1620
"tailscale.com/prober"
1721
"tailscale.com/tsweb"
22+
"tailscale.com/types/key"
1823
"tailscale.com/version"
1924

2025
// Support for prometheus varz in tsweb
2126
_ "tailscale.com/tsweb/promvarz"
2227
)
2328

29+
const meshKeyEnvVar = "TAILSCALE_DERPER_MESH_KEY"
30+
const setecMeshKeyName = "meshkey"
31+
32+
func defaultSetecCacheDir() string {
33+
return filepath.Join(os.Getenv("HOME"), ".cache", "derper-secrets")
34+
}
35+
2436
var (
37+
dev = flag.Bool("dev", false, "run in localhost development mode")
2538
derpMapURL = flag.String("derp-map", "https://login.tailscale.com/derpmap/default", "URL to DERP map (https:// or file://) or 'local' to use the local tailscaled's DERP map")
2639
versionFlag = flag.Bool("version", false, "print version and exit")
2740
listen = flag.String("listen", ":8030", "HTTP listen address")
@@ -37,6 +50,10 @@ var (
3750
qdPacketsPerSecond = flag.Int("qd-packets-per-second", 0, "if greater than 0, queuing delay will be measured continuously using 260 byte packets (approximate size of a CallMeMaybe packet) sent at this rate per second")
3851
qdPacketTimeout = flag.Duration("qd-packet-timeout", 5*time.Second, "queuing delay packets arriving after this period of time from being sent are treated like dropped packets and don't count toward queuing delay timings")
3952
regionCodeOrID = flag.String("region-code", "", "probe only this region (e.g. 'lax' or '17'); if left blank, all regions will be probed")
53+
meshPSKFile = flag.String("mesh-psk-file", "", "if non-empty, path to file containing the mesh pre-shared key file. It must be 64 lowercase hexadecimal characters; whitespace is trimmed.")
54+
secretsURL = flag.String("secrets-url", "", "SETEC server URL for secrets retrieval of mesh key")
55+
secretPrefix = flag.String("secrets-path-prefix", "prod/derp", fmt.Sprintf("setec path prefix for \"%s\" secret for DERP mesh key", setecMeshKeyName))
56+
secretsCacheDir = flag.String("secrets-cache-dir", defaultSetecCacheDir(), "directory to cache setec secrets in (required if --secrets-url is set)")
4057
)
4158

4259
func main() {
@@ -47,11 +64,16 @@ func main() {
4764
}
4865

4966
p := prober.New().WithSpread(*spread).WithOnce(*probeOnce).WithMetricNamespace("derpprobe")
67+
meshKey, err := getMeshKey()
68+
if err != nil {
69+
log.Fatalf("failed to get mesh key: %v", err)
70+
}
5071
opts := []prober.DERPOpt{
5172
prober.WithMeshProbing(*meshInterval),
5273
prober.WithSTUNProbing(*stunInterval),
5374
prober.WithTLSProbing(*tlsInterval),
5475
prober.WithQueuingDelayProbing(*qdPacketsPerSecond, *qdPacketTimeout),
76+
prober.WithMeshKey(meshKey),
5577
}
5678
if *bwInterval > 0 {
5779
opts = append(opts, prober.WithBandwidthProbing(*bwInterval, *bwSize, *bwTUNIPv4Address))
@@ -99,6 +121,53 @@ func main() {
99121
log.Fatal(http.ListenAndServe(*listen, mux))
100122
}
101123

124+
func getMeshKey() (key.DERPMesh, error) {
125+
var meshKey string
126+
127+
if *dev {
128+
meshKey = os.Getenv(meshKeyEnvVar)
129+
if meshKey == "" {
130+
log.Printf("No mesh key specified for dev via %s\n", meshKeyEnvVar)
131+
} else {
132+
log.Printf("Set mesh key from %s\n", meshKeyEnvVar)
133+
}
134+
} else if *secretsURL != "" {
135+
meshKeySecret := path.Join(*secretPrefix, setecMeshKeyName)
136+
fc, err := setec.NewFileCache(*secretsCacheDir)
137+
if err != nil {
138+
log.Fatalf("NewFileCache: %v", err)
139+
}
140+
log.Printf("Setting up setec store from %q", *secretsURL)
141+
st, err := setec.NewStore(context.Background(),
142+
setec.StoreConfig{
143+
Client: setec.Client{Server: *secretsURL},
144+
Secrets: []string{
145+
meshKeySecret,
146+
},
147+
Cache: fc,
148+
})
149+
if err != nil {
150+
log.Fatalf("NewStore: %v", err)
151+
}
152+
meshKey = st.Secret(meshKeySecret).GetString()
153+
log.Println("Got mesh key from setec store")
154+
st.Close()
155+
} else if *meshPSKFile != "" {
156+
b, err := setec.StaticFile(*meshPSKFile)
157+
if err != nil {
158+
log.Fatalf("StaticFile failed to get key: %v", err)
159+
}
160+
log.Println("Got mesh key from static file")
161+
meshKey = b.GetString()
162+
}
163+
if meshKey == "" {
164+
log.Printf("No mesh key found, mesh key is empty")
165+
return key.DERPMesh{}, nil
166+
}
167+
168+
return key.ParseDERPMesh(meshKey)
169+
}
170+
102171
type overallStatus struct {
103172
good, bad []string
104173
}

cmd/gitops-pusher/gitops-pusher_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Tailscale Inc & AUTHORS
22
// SPDX-License-Identifier: BSD-3-Clause
3+
34
package main
45

56
import (

cmd/k8s-operator/ingress-for-pg.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
252252
return false, fmt.Errorf("error determining DNS name base: %w", err)
253253
}
254254
dnsName := hostname + "." + tcd
255-
if err := r.ensureCertResources(ctx, pgName, dnsName, ing); err != nil {
255+
if err := r.ensureCertResources(ctx, pg, dnsName, ing); err != nil {
256256
return false, fmt.Errorf("error ensuring cert resources: %w", err)
257257
}
258258

@@ -931,18 +931,31 @@ func ownersAreSetAndEqual(a, b *tailscale.VIPService) bool {
931931
// (domain) is a valid Kubernetes resource name.
932932
// https://github.com/tailscale/tailscale/blob/8b1e7f646ee4730ad06c9b70c13e7861b964949b/util/dnsname/dnsname.go#L99
933933
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names
934-
func (r *HAIngressReconciler) ensureCertResources(ctx context.Context, pgName, domain string, ing *networkingv1.Ingress) error {
935-
secret := certSecret(pgName, r.tsNamespace, domain, ing)
936-
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, secret, nil); err != nil {
934+
func (r *HAIngressReconciler) ensureCertResources(ctx context.Context, pg *tsapi.ProxyGroup, domain string, ing *networkingv1.Ingress) error {
935+
secret := certSecret(pg.Name, r.tsNamespace, domain, ing)
936+
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, secret, func(s *corev1.Secret) {
937+
// Labels might have changed if the Ingress has been updated to use a
938+
// different ProxyGroup.
939+
s.Labels = secret.Labels
940+
}); err != nil {
937941
return fmt.Errorf("failed to create or update Secret %s: %w", secret.Name, err)
938942
}
939-
role := certSecretRole(pgName, r.tsNamespace, domain)
940-
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, role, nil); err != nil {
943+
role := certSecretRole(pg.Name, r.tsNamespace, domain)
944+
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, role, func(r *rbacv1.Role) {
945+
// Labels might have changed if the Ingress has been updated to use a
946+
// different ProxyGroup.
947+
r.Labels = role.Labels
948+
}); err != nil {
941949
return fmt.Errorf("failed to create or update Role %s: %w", role.Name, err)
942950
}
943-
rb := certSecretRoleBinding(pgName, r.tsNamespace, domain)
944-
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, rb, nil); err != nil {
945-
return fmt.Errorf("failed to create or update RoleBinding %s: %w", rb.Name, err)
951+
rolebinding := certSecretRoleBinding(pg.Name, r.tsNamespace, domain)
952+
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, rolebinding, func(rb *rbacv1.RoleBinding) {
953+
// Labels and subjects might have changed if the Ingress has been updated to use a
954+
// different ProxyGroup.
955+
rb.Labels = rolebinding.Labels
956+
rb.Subjects = rolebinding.Subjects
957+
}); err != nil {
958+
return fmt.Errorf("failed to create or update RoleBinding %s: %w", rolebinding.Name, err)
946959
}
947960
return nil
948961
}

0 commit comments

Comments
 (0)