From 7ccb3057a403403b7d1c04daf45a86de9d158e79 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 8 Nov 2024 07:17:41 +1100 Subject: [PATCH] chore: RBAC investigations, do not merge --- internal/rpc/rpc.go | 102 +++++++++++--------------------------------- 1 file changed, 26 insertions(+), 76 deletions(-) diff --git a/internal/rpc/rpc.go b/internal/rpc/rpc.go index f1af32ffa5..7cd9d55a2e 100644 --- a/internal/rpc/rpc.go +++ b/internal/rpc/rpc.go @@ -7,7 +7,6 @@ import ( "fmt" "net" "net/http" - "os" "strings" "syscall" "time" @@ -21,91 +20,42 @@ import ( "github.com/TBD54566975/ftl/internal/log" ) -// InitialiseClients initialises global HTTP clients used by the RPC system. -// -// "authenticators" are authenticator executables to use for each endpoint. The key is the URL of the endpoint, the -// value is the path to the authenticator executable. -// -// "allowInsecure" skips certificate verification, making TLS susceptible to machine-in-the-middle attacks. -func InitialiseClients(authenticators map[string]string, allowInsecure bool) { - // We can't have a client-wide timeout because it also applies to - // streaming RPCs, timing them out. - h2cClient = &http.Client{ - Transport: authn.Transport(&http2.Transport{ - AllowHTTP: true, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: allowInsecure, // #nosec G402 - }, - DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { - conn, err := dialer.Dial(network, addr) - return conn, err - }, - }, authenticators), - } - tlsClient = &http.Client{ - Transport: authn.Transport(&http2.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: allowInsecure, // #nosec G402 - }, - DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { - tlsDialer := tls.Dialer{Config: config, NetDialer: dialer} - conn, err := tlsDialer.DialContext(ctx, network, addr) - return conn, err - }, - }, authenticators), - } - - // Use a separate client for HTTP/1.1 with TLS. - http1TLSClient = &http.Client{ - Transport: authn.Transport(&http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: allowInsecure, // #nosec G402 - }, - DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - logger := log.FromContext(ctx) - logger.Debugf("HTTP/1.1 connecting to %s %s", network, addr) - - tlsDialer := tls.Dialer{NetDialer: dialer} - conn, err := tlsDialer.DialContext(ctx, network, addr) - return conn, fmt.Errorf("HTTP/1.1 TLS dial failed: %w", err) - }, - }, authenticators), - } -} - -func init() { - InitialiseClients(map[string]string{}, false) -} - -var ( - dialer = &net.Dialer{ - Timeout: time.Second * 10, - } - h2cClient *http.Client - tlsClient *http.Client - // Temporary client for HTTP/1.1 with TLS to help with debugging. - http1TLSClient *http.Client -) - type Pingable interface { Ping(ctx context.Context, req *connect.Request[ftlv1.PingRequest]) (*connect.Response[ftlv1.PingResponse], error) } // GetHTTPClient returns a HTTP client usable for the given URL. func GetHTTPClient(url string) *http.Client { - if h2cClient == nil { - panic("rpc.InitialiseClients() must be called before GetHTTPClient()") - } - - // TEMP_GRPC_HTTP1_ONLY set to non blank will use http1TLSClient - if os.Getenv("TEMP_GRPC_HTTP1_ONLY") != "" { - return http1TLSClient + dialer := &net.Dialer{ + Timeout: time.Second * 15, } if strings.HasPrefix(url, "http://") { - return h2cClient + return &http.Client{ + Transport: authn.Transport(&http2.Transport{ + AllowHTTP: true, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, // #nosec G402 + }, + DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { + conn, err := dialer.Dial(network, addr) + return conn, err + }, + }, make(map[string]string)), + } + } + return &http.Client{ + Transport: authn.Transport(&http2.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, // #nosec G402 + }, + DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { + tlsDialer := tls.Dialer{Config: config, NetDialer: dialer} + conn, err := tlsDialer.DialContext(ctx, network, addr) + return conn, err + }, + }, make(map[string]string)), } - return tlsClient } // ClientFactory is a function that creates a new client and is typically one of