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 }