Skip to content

Commit 5a9d3fd

Browse files
feat: Change how analytics proxy works (backport release-3.5.x) (#19854)
Co-authored-by: Dylan Guedes <[email protected]>
1 parent 232fa6c commit 5a9d3fd

File tree

1 file changed

+67
-14
lines changed

1 file changed

+67
-14
lines changed

pkg/analytics/reporter.go

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ package analytics
33
import (
44
"bytes"
55
"context"
6+
"crypto/tls"
67
"errors"
78
"flag"
9+
"fmt"
810
"io"
911
"math"
12+
"net"
1013
"net/http"
1114
"net/url"
1215
"os"
@@ -16,7 +19,7 @@ import (
1619
"github.com/go-kit/log/level"
1720
"github.com/google/uuid"
1821
"github.com/grafana/dskit/backoff"
19-
"github.com/grafana/dskit/crypto/tls"
22+
dskittls "github.com/grafana/dskit/crypto/tls"
2023
"github.com/grafana/dskit/kv"
2124
"github.com/grafana/dskit/multierror"
2225
"github.com/grafana/dskit/services"
@@ -46,11 +49,11 @@ var (
4649
)
4750

4851
type Config struct {
49-
Enabled bool `yaml:"reporting_enabled"`
50-
Leader bool `yaml:"-"`
51-
UsageStatsURL string `yaml:"usage_stats_url"`
52-
ProxyURL string `yaml:"proxy_url"`
53-
TLSConfig tls.ClientConfig `yaml:"tls_config"`
52+
Enabled bool `yaml:"reporting_enabled"`
53+
Leader bool `yaml:"-"`
54+
UsageStatsURL string `yaml:"usage_stats_url"`
55+
ProxyURL string `yaml:"proxy_url"`
56+
TLSConfig dskittls.ClientConfig `yaml:"tls_config"`
5457
}
5558

5659
// RegisterFlags adds the flags required to config this to the given FlagSet
@@ -83,19 +86,22 @@ func NewReporter(config Config, kvConfig kv.Config, objectClient client.ObjectCl
8386

8487
originalDefaultTransport := http.DefaultTransport.(*http.Transport)
8588
tr := originalDefaultTransport.Clone()
86-
if config.TLSConfig.CertPath != "" || config.TLSConfig.KeyPath != "" {
87-
var err error
88-
tr.TLSClientConfig, err = config.TLSConfig.GetTLSConfig()
89-
if err != nil {
90-
return nil, err
91-
}
92-
}
89+
9390
if config.ProxyURL != "" {
9491
proxyURL, err := url.ParseRequestURI(config.ProxyURL)
9592
if err != nil {
9693
return nil, err
9794
}
98-
tr.Proxy = http.ProxyURL(proxyURL)
95+
96+
if proxyURL.Scheme == "https" {
97+
// For HTTPS proxies, create a custom transport that handles different TLS configs
98+
tr, err = createCustomTransportForHTTPSProxy(tr, proxyURL, config.TLSConfig)
99+
if err != nil {
100+
return nil, err
101+
}
102+
} else {
103+
tr.Proxy = http.ProxyURL(proxyURL)
104+
}
99105
}
100106
r := &Reporter{
101107
logger: logger,
@@ -320,6 +326,7 @@ func (rep *Reporter) running(ctx context.Context) error {
320326
continue
321327
}
322328
rep.lastReport = next
329+
level.Debug(rep.logger).Log("msg", "reported cluster stats", "date", time.Now())
323330
next = next.Add(reportInterval)
324331
case <-ctx.Done():
325332
if err := ctx.Err(); !errors.Is(err, context.Canceled) {
@@ -386,3 +393,49 @@ func nextReport(interval time.Duration, createdAt, now time.Time) time.Time {
386393
// createdAt * (x * interval ) >= now
387394
return createdAt.Add(time.Duration(math.Ceil(float64(now.Sub(createdAt))/float64(interval))) * interval)
388395
}
396+
397+
// createCustomTransportForHTTPSProxy creates a transport that validates the HTTPS proxy certificate
398+
// while maintaining system CA trust for the final destination.
399+
func createCustomTransportForHTTPSProxy(tr *http.Transport, proxyURL *url.URL, tlsConfig dskittls.ClientConfig) (*http.Transport, error) {
400+
// Create the proxy TLS config for connecting to the proxy
401+
var proxyTLSConfig *tls.Config
402+
if tlsConfig.CertPath != "" || tlsConfig.KeyPath != "" || tlsConfig.CAPath != "" ||
403+
tlsConfig.ServerName != "" || tlsConfig.InsecureSkipVerify {
404+
var err error
405+
proxyTLSConfig, err = tlsConfig.GetTLSConfig()
406+
if err != nil {
407+
return nil, fmt.Errorf("error getting proxy TLS config: %w", err)
408+
}
409+
}
410+
411+
// function that handles proxy connections differently.
412+
tr.DialTLSContext = func(_ context.Context, network, addr string) (net.Conn, error) {
413+
// Parse the address to determine if this is a proxy connection
414+
host, _, err := net.SplitHostPort(addr)
415+
if err != nil {
416+
host = addr
417+
}
418+
419+
// If this is a connection to our proxy, use the proxy TLS config
420+
if host == proxyURL.Hostname() {
421+
conn, err := tls.Dial(network, addr, proxyTLSConfig)
422+
if err != nil {
423+
return nil, err
424+
}
425+
return conn, nil
426+
}
427+
428+
// For all other connections (to final destinations), use system CAs
429+
defaultConfig := &tls.Config{}
430+
conn, err := tls.Dial(network, addr, defaultConfig)
431+
if err != nil {
432+
return nil, err
433+
}
434+
return conn, nil
435+
}
436+
437+
// Set up the proxy
438+
tr.Proxy = http.ProxyURL(proxyURL)
439+
440+
return tr, nil
441+
}

0 commit comments

Comments
 (0)