Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ type tlsConfig struct {
cipherSuites []string
curvePreferences []string
clientAuthType string
clientCAFile string
reloadInterval time.Duration

serverCertFile string
Expand Down Expand Up @@ -894,6 +895,7 @@ func main() {
cfg.tls.minVersion,
cfg.tls.maxVersion,
cfg.tls.clientAuthType,
cfg.tls.clientCAFile,
cfg.tls.cipherSuites,
cfg.tls.curvePreferences,
)
Expand Down Expand Up @@ -1005,6 +1007,7 @@ func main() {
cfg.tls.minVersion,
cfg.tls.maxVersion,
cfg.tls.clientAuthType,
cfg.tls.clientCAFile,
cfg.tls.cipherSuites,
cfg.tls.curvePreferences,
)
Expand Down Expand Up @@ -1289,6 +1292,8 @@ func parseFlags() (config, error) {
" The list is a filter of allowed groups; crypto/tls chooses the preference order.")
flag.StringVar(&cfg.tls.clientAuthType, "tls.client-auth-type", "RequestClientCert",
"Policy for TLS client-side authentication. Values are from ClientAuthType constants in https://pkg.go.dev/crypto/tls#ClientAuthType")
flag.StringVar(&cfg.tls.clientCAFile, "tls.client-ca-file", "",
"File containing the CA certificate for verifying client certificates. Required when using RequireAndVerifyClientCert or VerifyClientCertIfGiven.")
flag.DurationVar(&cfg.tls.reloadInterval, "tls.reload-interval", time.Minute,
"The interval at which to watch for TLS certificate changes.")
flag.StringVar(&cfg.middleware.grpcRateLimiterAddress, "middleware.rate-limiter.grpc-address", "",
Expand Down Expand Up @@ -1630,6 +1635,7 @@ func newGRPCServer(cfg *config, tenantHeader string, tenantIDs map[string]string
cfg.tls.minVersion,
cfg.tls.maxVersion,
cfg.tls.clientAuthType,
cfg.tls.clientCAFile,
cfg.tls.cipherSuites,
cfg.tls.curvePreferences,
)
Expand Down
31 changes: 30 additions & 1 deletion tls/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package tls

import (
"crypto/tls"
"crypto/x509"
"fmt"
"os"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
Expand All @@ -27,7 +29,7 @@ var curveIDs = map[string]tls.CurveID{
}

// NewServerConfig provides new server TLS configuration.
func NewServerConfig(logger log.Logger, certFile, keyFile, minVersion, maxVersion, clientAuthType string, cipherSuites, curvePreferences []string) (*tls.Config, error) {
func NewServerConfig(logger log.Logger, certFile, keyFile, minVersion, maxVersion, clientAuthType, clientCAFile string, cipherSuites, curvePreferences []string) (*tls.Config, error) {
if certFile == "" && keyFile == "" {
level.Info(logger).Log("msg", "TLS disabled; key and cert must be set to enable")

Expand Down Expand Up @@ -70,6 +72,32 @@ func NewServerConfig(logger log.Logger, certFile, keyFile, minVersion, maxVersio
return nil, fmt.Errorf("can not parse TLS Client authentication policy: %w", err)
}

// Load client CA certificate pool for verifying client certificates
var clientCAs *x509.CertPool
if clientCAFile != "" {
// Only load client CA if client authentication requires verification
if tlsClientAuthType == tls.RequireAndVerifyClientCert || tlsClientAuthType == tls.VerifyClientCertIfGiven {
caCert, err := os.ReadFile(clientCAFile)
if err != nil {
return nil, fmt.Errorf("failed to read client CA file: %w", err)
}

clientCAs = x509.NewCertPool()
if !clientCAs.AppendCertsFromPEM(caCert) {
return nil, fmt.Errorf("failed to parse client CA certificate from %s", clientCAFile)
}

level.Info(logger).Log("msg", "loaded client CA certificate for mTLS verification", "file", clientCAFile)
} else {
level.Warn(logger).Log("msg", "client CA file provided but client auth type does not require verification", "clientAuthType", clientAuthType)
}
} else if tlsClientAuthType == tls.RequireAndVerifyClientCert || tlsClientAuthType == tls.VerifyClientCertIfGiven {
level.Warn(logger).Log(
"msg", "client authentication requires verification but no client CA file provided, will use system CA pool",
"clientAuthType", clientAuthType,
)
}

tlsCfg := &tls.Config{
Certificates: []tls.Certificate{tlsCert},
// A list of supported cipher suites for TLS versions up to TLS 1.2.
Expand All @@ -78,6 +106,7 @@ func NewServerConfig(logger log.Logger, certFile, keyFile, minVersion, maxVersio
CipherSuites: cipherSuiteIDs,
// If CurvePreferences is nil, a default list of secure curves is used.
CurvePreferences: curvePreferenceIDs,
ClientCAs: clientCAs,
ClientAuth: tlsClientAuthType,
MinVersion: tlsMinVersion,
MaxVersion: tlsMaxVersion,
Expand Down
1 change: 1 addition & 0 deletions tls/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ func TestNewServerConfigCurvePreferences(t *testing.T) {
"VersionTLS13",
"VersionTLS13",
"RequestClientCert",
"",
nil,
tc.curves,
)
Expand Down
Loading