Skip to content

Commit

Permalink
Update grpc/http proxy protocol validation
Browse files Browse the repository at this point in the history
  • Loading branch information
AlessandroPatti committed Aug 17, 2023
1 parent d3afb83 commit 555a06c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ OPTIONS:
[$BAZEL_REMOTE_NUM_UPLOADERS]
--grpc_proxy.url value The base URL to use for a grpc proxy backend, e.g.
localhost:9090 or example.com:7070.
grpc://localhost:9090 or grpcs://example.com:7070.
[$BAZEL_REMOTE_GRPC_PROXY_URL]
--grpc_proxy.key_file value Path to a key used to authenticate with the
Expand Down
43 changes: 34 additions & 9 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"math"
"net"
"net/url"
"os"
"sort"
"strconv"
Expand All @@ -24,9 +25,9 @@ import (

// GRPCBackendConfig stores the configuration of a GRPC proxy backend.
type GRPCBackendConfig struct {
BaseUrl string `yaml:"url"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
BaseURL *url.URL `yaml:"url"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
}

// GoogleCloudStorageConfig stores the configuration of a GCS proxy backend.
Expand All @@ -38,9 +39,9 @@ type GoogleCloudStorageConfig struct {

// HTTPBackendConfig stores the configuration for a HTTP proxy backend.
type HTTPBackendConfig struct {
BaseURL string `yaml:"url"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
BaseURL *url.URL `yaml:"url"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
}

// Config holds the top-level configuration for bazel-remote.
Expand Down Expand Up @@ -351,21 +352,36 @@ func validateConfig(c *Config) error {
}

if c.HTTPBackend != nil {
if c.HTTPBackend.BaseURL == "" {
if c.HTTPBackend.BaseURL == nil {
return errors.New("The 'url' field is required for 'http_proxy'")
}
if c.HTTPBackend.BaseURL.Scheme != "http" && c.HTTPBackend.BaseURL.Scheme != "https" {
return errors.New("The http proxy backend protocol must be either http or https")
}
if c.HTTPBackend.KeyFile != "" || c.HTTPBackend.CertFile != "" {
if c.HTTPBackend.KeyFile == "" || c.HTTPBackend.CertFile == "" {
return errors.New("To use mTLS with the http proxy, both a key and a certificate must be provided")
}
if c.HTTPBackend.BaseURL.Scheme != "https" {
return errors.New("When mTLS is enabled, the grpc proxy backend protocol must be grpcs")
}
}
}

if c.GRPCBackend != nil {
if c.GRPCBackend.BaseURL == nil {
return errors.New("The 'url' field is required for 'http_proxy'")
}
if c.GRPCBackend.BaseURL.Scheme != "grpc" && c.GRPCBackend.BaseURL.Scheme != "grpcs" {
return errors.New("The grpc proxy backend protocol must be either grpc or grpcs")
}
if c.GRPCBackend.KeyFile != "" || c.GRPCBackend.CertFile != "" {
if c.GRPCBackend.KeyFile == "" || c.GRPCBackend.CertFile == "" {
return errors.New("To use mTLS with the grpc proxy, both a key and a certificate must be provided")
}
if c.GRPCBackend.BaseURL.Scheme != "grpcs" {
return errors.New("When mTLS is enabled, the grpc proxy backend protocol must be grpcs")
}
}
}

Expand Down Expand Up @@ -497,17 +513,26 @@ func get(ctx *cli.Context) (*Config, error) {

var hc *HTTPBackendConfig
if ctx.String("http_proxy.url") != "" {
u, err := url.Parse(ctx.String("http_proxy.url"))
if err != nil {
return nil, err
}
hc = &HTTPBackendConfig{
BaseURL: ctx.String("http_proxy.url"),
BaseURL: u,
KeyFile: ctx.String("http_proxy.key_file"),
CertFile: ctx.String("http_proxy.cert_file"),
}
}

var grpcb *GRPCBackendConfig
if ctx.String("grpc_proxy.url") != "" {
u, err := url.Parse(ctx.String("grpc_proxy.url"))
if err != nil {
return nil, err
}

grpcb = &GRPCBackendConfig{
BaseUrl: ctx.String("grpc_proxy.url"),
BaseURL: u,
KeyFile: ctx.String("grpc_proxy.key_file"),
CertFile: ctx.String("grpc_proxy.cert_file"),
}
Expand Down
7 changes: 6 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"math"
"net/url"
"reflect"
"regexp"
"strings"
Expand Down Expand Up @@ -122,6 +123,10 @@ http_proxy:
t.Fatal(err)
}

url, err := url.Parse("https://remote-cache.com:8080/cache")
if err != nil {
t.Fatal(err)
}
expectedConfig := &Config{
HTTPAddress: "localhost:8080",
GRPCAddress: "localhost:9092",
Expand All @@ -130,7 +135,7 @@ http_proxy:
StorageMode: "zstd",
ZstdImplementation: "go",
HTTPBackend: &HTTPBackendConfig{
BaseURL: "https://remote-cache.com:8080/cache",
BaseURL: url,
},
NumUploaders: 100,
MaxQueuedUploads: 1000000,
Expand Down
47 changes: 19 additions & 28 deletions config/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"crypto/tls"
"fmt"
"net/http"
"net/url"

"github.com/buchgr/bazel-remote/v2/cache/azblobproxy"
"github.com/buchgr/bazel-remote/v2/cache/gcsproxy"
Expand All @@ -20,6 +19,19 @@ import (
prom "github.com/prometheus/client_golang/prometheus"
)

func getTLSConfig(certFile, keyFile string) (*tls.Config, error) {
config := &tls.Config{}
if certFile != "" && keyFile != "" {
readCert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}

config.Certificates = []tls.Certificate{readCert}
}
return config, nil
}

func (c *Config) setProxy() error {
if c.GoogleCloudStorage != nil {
proxyCache, err := gcsproxy.New(c.GoogleCloudStorage.Bucket,
Expand All @@ -35,18 +47,11 @@ func (c *Config) setProxy() error {

if c.GRPCBackend != nil {
var opts []grpc.DialOption
if c.GRPCBackend.CertFile != "" && c.GRPCBackend.KeyFile != "" {
readCert, err := tls.LoadX509KeyPair(
c.GRPCBackend.CertFile,
c.GRPCBackend.KeyFile,
)
if c.GRPCBackend.BaseURL.Scheme == "grpcs" {
config, err := getTLSConfig(c.GRPCBackend.CertFile, c.GRPCBackend.KeyFile)
if err != nil {
return err
}

config := &tls.Config{
Certificates: []tls.Certificate{readCert},
}
creds := credentials.NewTLS(config)
opts = append(opts, grpc.WithTransportCredentials(creds))
} else {
Expand All @@ -61,7 +66,7 @@ func (c *Config) setProxy() error {
opts = append(opts, grpc.WithChainStreamInterceptor(metrics.StreamClientInterceptor()))
opts = append(opts, grpc.WithChainUnaryInterceptor(metrics.UnaryClientInterceptor()))

conn, err := grpc.Dial(c.GRPCBackend.BaseUrl, opts...)
conn, err := grpc.Dial(c.GRPCBackend.BaseURL.Host, opts...)
if err != nil {
return err
}
Expand All @@ -78,30 +83,16 @@ func (c *Config) setProxy() error {

if c.HTTPBackend != nil {
httpClient := &http.Client{}
var baseURL *url.URL
baseURL, err := url.Parse(c.HTTPBackend.BaseURL)
if err != nil {
return err
}

if c.HTTPBackend.CertFile != "" && c.HTTPBackend.KeyFile != "" {
readCert, err := tls.LoadX509KeyPair(
c.HTTPBackend.CertFile,
c.HTTPBackend.KeyFile,
)
if c.HTTPBackend.BaseURL.Scheme == "https" {
config, err := getTLSConfig(c.HTTPBackend.CertFile, c.HTTPBackend.KeyFile)
if err != nil {
return err
}

config := &tls.Config{
Certificates: []tls.Certificate{readCert},
}

tr := &http.Transport{TLSClientConfig: config}
httpClient.Transport = tr
}

proxyCache, err := httpproxy.New(baseURL, c.StorageMode,
proxyCache, err := httpproxy.New(c.HTTPBackend.BaseURL, c.StorageMode,
httpClient, c.AccessLogger, c.ErrorLogger, c.NumUploaders, c.MaxQueuedUploads)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion utils/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func GetCliFlags() []cli.Flag {
&cli.StringFlag{
Name: "grpc_proxy.url",
Value: "",
Usage: "The base URL to use for a grpc proxy backend, e.g. localhost:9090 or example.com:7070.",
Usage: "The base URL to use for a grpc proxy backend, e.g. grpc://localhost:9090 or grpcs://example.com:7070.",
EnvVars: []string{"BAZEL_REMOTE_GRPC_PROXY_URL"},
},
&cli.StringFlag{
Expand Down

0 comments on commit 555a06c

Please sign in to comment.