github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/nomad/structs/config/tls.go (about) 1 package config 2 3 import ( 4 "crypto/tls" 5 "fmt" 6 "sync" 7 ) 8 9 // TLSConfig provides TLS related configuration 10 type TLSConfig struct { 11 12 // EnableHTTP enabled TLS for http traffic to the Nomad server and clients 13 EnableHTTP bool `mapstructure:"http"` 14 15 // EnableRPC enables TLS for RPC and Raft traffic to the Nomad servers 16 EnableRPC bool `mapstructure:"rpc"` 17 18 // VerifyServerHostname is used to enable hostname verification of servers. This 19 // ensures that the certificate presented is valid for server.<region>.nomad 20 // This prevents a compromised client from being restarted as a server, and then 21 // intercepting request traffic as well as being added as a raft peer. This should be 22 // enabled by default with VerifyOutgoing, but for legacy reasons we cannot break 23 // existing clients. 24 VerifyServerHostname bool `mapstructure:"verify_server_hostname"` 25 26 // CAFile is a path to a certificate authority file. This is used with VerifyIncoming 27 // or VerifyOutgoing to verify the TLS connection. 28 CAFile string `mapstructure:"ca_file"` 29 30 // CertFile is used to provide a TLS certificate that is used for serving TLS connections. 31 // Must be provided to serve TLS connections. 32 CertFile string `mapstructure:"cert_file"` 33 34 // KeyLoader is a helper to dynamically reload TLS configuration 35 KeyLoader *KeyLoader 36 37 keyloaderLock sync.Mutex 38 39 // KeyFile is used to provide a TLS key that is used for serving TLS connections. 40 // Must be provided to serve TLS connections. 41 KeyFile string `mapstructure:"key_file"` 42 43 // RPCUpgradeMode should be enabled when a cluster is being upgraded 44 // to TLS. Allows servers to accept both plaintext and TLS connections and 45 // should only be a temporary state. 46 RPCUpgradeMode bool `mapstructure:"rpc_upgrade_mode"` 47 48 // Verify connections to the HTTPS API 49 VerifyHTTPSClient bool `mapstructure:"verify_https_client"` 50 } 51 52 type KeyLoader struct { 53 cacheLock sync.Mutex 54 certificate *tls.Certificate 55 } 56 57 // LoadKeyPair reloads the TLS certificate based on the specified certificate 58 // and key file. If successful, stores the certificate for further use. 59 func (k *KeyLoader) LoadKeyPair(certFile, keyFile string) (*tls.Certificate, error) { 60 k.cacheLock.Lock() 61 defer k.cacheLock.Unlock() 62 63 // Allow downgrading 64 if certFile == "" && keyFile == "" { 65 k.certificate = nil 66 return nil, nil 67 } 68 69 cert, err := tls.LoadX509KeyPair(certFile, keyFile) 70 if err != nil { 71 return nil, fmt.Errorf("Failed to load cert/key pair: %v", err) 72 } 73 74 k.certificate = &cert 75 return k.certificate, nil 76 } 77 78 // GetOutgoingCertificate fetches the currently-loaded certificate when 79 // accepting a TLS connection. This currently does not consider information in 80 // the ClientHello and only returns the certificate that was last loaded. 81 func (k *KeyLoader) GetOutgoingCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) { 82 k.cacheLock.Lock() 83 defer k.cacheLock.Unlock() 84 return k.certificate, nil 85 } 86 87 // GetClientCertificate fetches the currently-loaded certificate when the Server 88 // requests a certificate from the caller. This currently does not consider 89 // information in the ClientHello and only returns the certificate that was last 90 // loaded. 91 func (k *KeyLoader) GetClientCertificate(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 92 k.cacheLock.Lock() 93 defer k.cacheLock.Unlock() 94 return k.certificate, nil 95 } 96 97 func (k *KeyLoader) Copy() *KeyLoader { 98 if k == nil { 99 return nil 100 } 101 102 new := KeyLoader{} 103 new.certificate = k.certificate 104 return &new 105 } 106 107 // GetKeyLoader returns the keyloader for a TLSConfig object. If the keyloader 108 // has not been initialized, it will first do so. 109 func (t *TLSConfig) GetKeyLoader() *KeyLoader { 110 t.keyloaderLock.Lock() 111 defer t.keyloaderLock.Unlock() 112 113 // If the keyloader has not yet been initialized, do it here 114 if t.KeyLoader == nil { 115 t.KeyLoader = &KeyLoader{} 116 } 117 return t.KeyLoader 118 } 119 120 // Copy copies the fields of TLSConfig to another TLSConfig object. Required as 121 // to not copy mutexes between objects. 122 func (t *TLSConfig) Copy() *TLSConfig { 123 if t == nil { 124 return t 125 } 126 127 new := &TLSConfig{} 128 new.EnableHTTP = t.EnableHTTP 129 new.EnableRPC = t.EnableRPC 130 new.VerifyServerHostname = t.VerifyServerHostname 131 new.CAFile = t.CAFile 132 new.CertFile = t.CertFile 133 134 t.keyloaderLock.Lock() 135 new.KeyLoader = t.KeyLoader.Copy() 136 t.keyloaderLock.Unlock() 137 138 new.KeyFile = t.KeyFile 139 new.RPCUpgradeMode = t.RPCUpgradeMode 140 new.VerifyHTTPSClient = t.VerifyHTTPSClient 141 return new 142 } 143 144 func (t *TLSConfig) IsEmpty() bool { 145 if t == nil { 146 return true 147 } 148 149 return t.EnableHTTP == false && 150 t.EnableRPC == false && 151 t.VerifyServerHostname == false && 152 t.CAFile == "" && 153 t.CertFile == "" && 154 t.KeyFile == "" && 155 t.VerifyHTTPSClient == false 156 } 157 158 // Merge is used to merge two TLS configs together 159 func (t *TLSConfig) Merge(b *TLSConfig) *TLSConfig { 160 result := t.Copy() 161 162 if b.EnableHTTP { 163 result.EnableHTTP = true 164 } 165 if b.EnableRPC { 166 result.EnableRPC = true 167 } 168 if b.VerifyServerHostname { 169 result.VerifyServerHostname = true 170 } 171 if b.CAFile != "" { 172 result.CAFile = b.CAFile 173 } 174 if b.CertFile != "" { 175 result.CertFile = b.CertFile 176 } 177 if b.KeyFile != "" { 178 result.KeyFile = b.KeyFile 179 } 180 if b.VerifyHTTPSClient { 181 result.VerifyHTTPSClient = true 182 } 183 if b.RPCUpgradeMode { 184 result.RPCUpgradeMode = true 185 } 186 return result 187 } 188 189 // Equals compares the fields of two TLS configuration objects, returning a 190 // boolean indicating if they are the same. 191 // It is possible for either the calling TLSConfig to be nil, or the TLSConfig 192 // that it is being compared against, so we need to handle both places. See 193 // server.go Reload for example. 194 func (t *TLSConfig) Equals(newConfig *TLSConfig) bool { 195 if t == nil || newConfig == nil { 196 return t == newConfig 197 } 198 199 return t.EnableRPC == newConfig.EnableRPC && 200 t.CAFile == newConfig.CAFile && 201 t.CertFile == newConfig.CertFile && 202 t.KeyFile == newConfig.KeyFile && 203 t.RPCUpgradeMode == newConfig.RPCUpgradeMode && 204 t.VerifyHTTPSClient == newConfig.VerifyHTTPSClient 205 }