Revision c0473f492c256c77d3d5ab010158dc52aeccec85 authored by Grot (@grafanabot) on 12 May 2023, 08:49:54 UTC, committed by GitHub on 12 May 2023, 08:49:54 UTC
Pyroscope: Add authentication when calling backendType resource API (#67667)

(cherry picked from commit 8da90f624dd0c0b09432b9fd9a324f08c82314f8)

Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
1 parent b811e9c
Raw File
secure_socks_proxy.go
package proxy

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net/http"
	"os"
	"strings"

	"github.com/grafana/grafana-plugin-sdk-go/backend"
	sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
	"github.com/grafana/grafana/pkg/setting"
	"golang.org/x/net/proxy"
)

// NewSecureSocksHTTPProxy takes a http.DefaultTransport and wraps it in a socks5 proxy with TLS
func NewSecureSocksHTTPProxy(cfg *setting.SecureSocksDSProxySettings, transport *http.Transport) error {
	dialSocksProxy, err := NewSecureSocksProxyContextDialer(cfg)
	if err != nil {
		return err
	}

	contextDialer, ok := dialSocksProxy.(proxy.ContextDialer)
	if !ok {
		return errors.New("unable to cast socks proxy dialer to context proxy dialer")
	}

	transport.DialContext = contextDialer.DialContext
	return nil
}

// NewSecureSocksProxyContextDialer returns a proxy context dialer that will wrap connections in a secure socks proxy
func NewSecureSocksProxyContextDialer(cfg *setting.SecureSocksDSProxySettings) (proxy.Dialer, error) {
	certPool := x509.NewCertPool()
	for _, rootCAFile := range strings.Split(cfg.RootCA, " ") {
		// nolint:gosec
		// The gosec G304 warning can be ignored because `rootCAFile` comes from config ini.
		pem, err := os.ReadFile(rootCAFile)
		if err != nil {
			return nil, err
		}
		if !certPool.AppendCertsFromPEM(pem) {
			return nil, errors.New("failed to append CA certificate " + rootCAFile)
		}
	}

	cert, err := tls.LoadX509KeyPair(cfg.ClientCert, cfg.ClientKey)
	if err != nil {
		return nil, err
	}

	tlsDialer := &tls.Dialer{
		Config: &tls.Config{
			Certificates: []tls.Certificate{cert},
			ServerName:   cfg.ServerName,
			RootCAs:      certPool,
		},
	}
	dialSocksProxy, err := proxy.SOCKS5("tcp", cfg.ProxyAddress, nil, tlsDialer)
	if err != nil {
		return nil, err
	}

	return dialSocksProxy, nil
}

// SecureSocksProxyEnabledOnDS checks the datasource json data to see if the secure socks proxy is enabled on it
func SecureSocksProxyEnabledOnDS(opts sdkhttpclient.Options) bool {
	jsonData := backend.JSONDataFromHTTPClientOptions(opts)
	res, enabled := jsonData["enableSecureSocksProxy"]
	if !enabled {
		return false
	}

	if val, ok := res.(bool); ok {
		return val
	}

	return false
}
back to top