go.temporal.io/server@v1.23.0/common/rpc/encryption/tls_factory.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package encryption
    26  
    27  import (
    28  	"crypto/tls"
    29  	"crypto/x509"
    30  	"fmt"
    31  	"strings"
    32  	"time"
    33  
    34  	"go.temporal.io/server/common/log"
    35  	"go.temporal.io/server/common/metrics"
    36  
    37  	"go.temporal.io/server/common/config"
    38  )
    39  
    40  type (
    41  	// TLSConfigProvider serves as a common interface to read server and client configuration for TLS.
    42  	TLSConfigProvider interface {
    43  		GetInternodeServerConfig() (*tls.Config, error)
    44  		GetInternodeClientConfig() (*tls.Config, error)
    45  		GetFrontendServerConfig() (*tls.Config, error)
    46  		GetFrontendClientConfig() (*tls.Config, error)
    47  		GetRemoteClusterClientConfig(hostname string) (*tls.Config, error)
    48  		GetExpiringCerts(timeWindow time.Duration) (expiring CertExpirationMap, expired CertExpirationMap, err error)
    49  	}
    50  
    51  	// CertProvider is a common interface to load raw TLS/X509 primitives.
    52  	CertProvider interface {
    53  		FetchServerCertificate() (*tls.Certificate, error)
    54  		FetchClientCAs() (*x509.CertPool, error)
    55  		FetchClientCertificate(isWorker bool) (*tls.Certificate, error)
    56  		FetchServerRootCAsForClient(isWorker bool) (*x509.CertPool, error)
    57  		GetExpiringCerts(timeWindow time.Duration) (expiring CertExpirationMap, expired CertExpirationMap, err error)
    58  	}
    59  
    60  	// PerHostCertProviderMap returns a CertProvider for a given host name.
    61  	PerHostCertProviderMap interface {
    62  		GetCertProvider(hostName string) (provider CertProvider, clientAuthRequired bool, err error)
    63  		GetExpiringCerts(timeWindow time.Duration) (expiring CertExpirationMap, expired CertExpirationMap, err error)
    64  		NumberOfHosts() int
    65  	}
    66  
    67  	CertThumbprint [16]byte
    68  
    69  	CertExpirationData struct {
    70  		Thumbprint CertThumbprint
    71  		IsCA       bool
    72  		DNSNames   []string
    73  		Expiration time.Time
    74  	}
    75  
    76  	CertExpirationMap map[CertThumbprint]CertExpirationData
    77  
    78  	CertExpirationChecker interface {
    79  		GetExpiringCerts(timeWindow time.Duration) (expiring CertExpirationMap, expired CertExpirationMap, err error)
    80  	}
    81  
    82  	tlsConfigConstructor func() (*tls.Config, error)
    83  )
    84  
    85  // NewTLSConfigProviderFromConfig creates a new TLS Config provider from RootTLS config.
    86  // A custom cert provider factory can be optionally injected via certProviderFactory argument.
    87  // Otherwise, it defaults to using localStoreCertProvider
    88  func NewTLSConfigProviderFromConfig(
    89  	encryptionSettings config.RootTLS,
    90  	metricsHandler metrics.Handler,
    91  	logger log.Logger,
    92  	certProviderFactory CertProviderFactory,
    93  ) (TLSConfigProvider, error) {
    94  	if err := validateRootTLS(&encryptionSettings); err != nil {
    95  		return nil, err
    96  	}
    97  	if certProviderFactory == nil {
    98  		certProviderFactory = NewLocalStoreCertProvider
    99  	}
   100  	return NewLocalStoreTlsProvider(&encryptionSettings, metricsHandler.WithTags(metrics.OperationTag(metrics.ServerTlsScope)), logger, certProviderFactory)
   101  }
   102  
   103  func validateRootTLS(cfg *config.RootTLS) error {
   104  	if err := validateGroupTLS(&cfg.Internode); err != nil {
   105  		return err
   106  	}
   107  	if err := validateGroupTLS(&cfg.Frontend); err != nil {
   108  		return err
   109  	}
   110  	return validateWorkerTLS(&cfg.SystemWorker)
   111  }
   112  
   113  func validateGroupTLS(cfg *config.GroupTLS) error {
   114  	if err := validateServerTLS(&cfg.Server); err != nil {
   115  		return err
   116  	}
   117  	if err := validateClientTLS(&cfg.Client); err != nil {
   118  		return err
   119  	}
   120  	for host, hostConfig := range cfg.PerHostOverrides {
   121  
   122  		if strings.TrimSpace(host) == "" {
   123  			return fmt.Errorf("host name cannot be empty string")
   124  		}
   125  		if err := validateServerTLS(&hostConfig); err != nil {
   126  			return err
   127  		}
   128  	}
   129  	return nil
   130  }
   131  
   132  func validateWorkerTLS(cfg *config.WorkerTLS) error {
   133  	if cfg.CertFile != "" && cfg.CertData != "" {
   134  		return fmt.Errorf("cannot specify CertFile and CertData at the same time")
   135  	}
   136  	if cfg.KeyFile != "" && cfg.KeyData != "" {
   137  		return fmt.Errorf("cannot specify KeyFile and KeyData at the same time")
   138  	}
   139  	return validateClientTLS(&cfg.Client)
   140  }
   141  
   142  func validateServerTLS(cfg *config.ServerTLS) error {
   143  	if cfg.CertFile != "" && cfg.CertData != "" {
   144  		return fmt.Errorf("cannot specify CertFile and CertData at the same time")
   145  	}
   146  	if cfg.KeyFile != "" && cfg.KeyData != "" {
   147  		return fmt.Errorf("cannot specify KeyFile and KeyData at the same time")
   148  	}
   149  	if err := validateCAs(cfg.ClientCAData); err != nil {
   150  		return fmt.Errorf("invalid ServerTLS.ClientCAData: %w", err)
   151  	}
   152  	if err := validateCAs(cfg.ClientCAFiles); err != nil {
   153  		return fmt.Errorf("invalid ServerTLS.ClientCAFiles: %w", err)
   154  	}
   155  	if len(cfg.ClientCAFiles) > 0 && len(cfg.ClientCAData) > 0 {
   156  		return fmt.Errorf("cannot specify ClientCAFiles and ClientCAData at the same time")
   157  	}
   158  	return nil
   159  }
   160  
   161  func validateClientTLS(cfg *config.ClientTLS) error {
   162  	if err := validateCAs(cfg.RootCAData); err != nil {
   163  		return fmt.Errorf("invalid ClientTLS.RootCAData: %w", err)
   164  	}
   165  	if err := validateCAs(cfg.RootCAFiles); err != nil {
   166  		return fmt.Errorf("invalid ClientTLS.RootCAFiles: %w", err)
   167  	}
   168  	if len(cfg.RootCAData) > 0 && len(cfg.RootCAFiles) > 0 {
   169  		return fmt.Errorf("cannot specify RootCAFiles and RootCAData at the same time")
   170  	}
   171  	return nil
   172  }
   173  
   174  func validateCAs(cas []string) error {
   175  	for _, ca := range cas {
   176  		if strings.TrimSpace(ca) == "" {
   177  			return fmt.Errorf("CA cannot be empty string")
   178  		}
   179  	}
   180  	return nil
   181  }