github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/security/certificate_manager.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package security 12 13 import ( 14 "context" 15 "crypto/tls" 16 "fmt" 17 "os" 18 "path/filepath" 19 20 "github.com/cockroachdb/cockroach/pkg/util/log" 21 "github.com/cockroachdb/cockroach/pkg/util/metric" 22 "github.com/cockroachdb/cockroach/pkg/util/stop" 23 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 24 "github.com/cockroachdb/cockroach/pkg/util/sysutil" 25 "github.com/cockroachdb/errors" 26 ) 27 28 var ( 29 metaCAExpiration = metric.Metadata{ 30 Name: "security.certificate.expiration.ca", 31 Help: "Expiration for the CA certificate. 0 means no certificate or error.", 32 Measurement: "Certificate Expiration", 33 Unit: metric.Unit_TIMESTAMP_SEC, 34 } 35 metaClientCAExpiration = metric.Metadata{ 36 Name: "security.certificate.expiration.client-ca", 37 Help: "Expiration for the client CA certificate. 0 means no certificate or error.", 38 Measurement: "Certificate Expiration", 39 Unit: metric.Unit_TIMESTAMP_SEC, 40 } 41 metaUICAExpiration = metric.Metadata{ 42 Name: "security.certificate.expiration.ui-ca", 43 Help: "Expiration for the UI CA certificate. 0 means no certificate or error.", 44 Measurement: "Certificate Expiration", 45 Unit: metric.Unit_TIMESTAMP_SEC, 46 } 47 metaNodeExpiration = metric.Metadata{ 48 Name: "security.certificate.expiration.node", 49 Help: "Expiration for the node certificate. 0 means no certificate or error.", 50 Measurement: "Certificate Expiration", 51 Unit: metric.Unit_TIMESTAMP_SEC, 52 } 53 metaNodeClientExpiration = metric.Metadata{ 54 Name: "security.certificate.expiration.node-client", 55 Help: "Expiration for the node's client certificate. 0 means no certificate or error.", 56 Measurement: "Certificate Expiration", 57 Unit: metric.Unit_TIMESTAMP_SEC, 58 } 59 metaUIExpiration = metric.Metadata{ 60 Name: "security.certificate.expiration.ui", 61 Help: "Expiration for the UI certificate. 0 means no certificate or error.", 62 Measurement: "Certificate Expiration", 63 Unit: metric.Unit_TIMESTAMP_SEC, 64 } 65 ) 66 67 // CertificateManager lives for the duration of the process and manages certificates and keys. 68 // It reloads all certificates when triggered and construct tls.Config objects for 69 // servers or clients. 70 // 71 // Important note: Load() performs some sanity checks (file pairs match, CA certs don't disappear), 72 // but these are by no means complete. Completeness is not required as nodes restarting have 73 // no fallback if invalid certs/keys are present. 74 // 75 // The nomenclature for certificates is as follows, all within the certs-dir. 76 // - ca.crt main CA certificate. 77 // Used to verify everything unless overridden by more specifica CAs. 78 // - ca-client.crt CA certificate to verify client certificates. If it does not exist, 79 // fall back on 'ca.crt'. 80 // - node.crt node certificate. 81 // Server-side certificate (always) and client-side certificate unless 82 // client.node.crt is found. 83 // Verified using 'ca.crt'. 84 // - client.<user>.crt client certificate for 'user'. Verified using 'ca.crt', or 'ca-client.crt'. 85 // - client.node.crt client certificate for the 'node' user. If it does not exist, 86 // fall back on 'node.crt'. 87 type CertificateManager struct { 88 // Certificate directory is not modified after initialization. 89 certsDir string 90 // The metrics struct is initialized at init time and metrics do their 91 // own locking. 92 certMetrics CertificateMetrics 93 94 // mu protects all remaining fields. 95 mu syncutil.RWMutex 96 97 // If false, this is the first load. Needed to ensure we do not drop certain certs. 98 initialized bool 99 100 // Set of certs. These are swapped in during Load(), and never mutated afterwards. 101 caCert *CertInfo // default CA certificate 102 clientCACert *CertInfo // optional: certificate to verify client certificates 103 uiCACert *CertInfo // optional: certificate to verify UI certficates 104 nodeCert *CertInfo // certificate for nodes (always server cert, sometimes client cert) 105 nodeClientCert *CertInfo // optional: client certificate for 'node' user. Also included in 'clientCerts' 106 uiCert *CertInfo // optional: server certificate for the admin UI. 107 clientCerts map[string]*CertInfo 108 109 // TLS configs. Initialized lazily. Wiped on every successful Load(). 110 // Server-side config. 111 serverConfig *tls.Config 112 // Server-side config for the Admin UI. 113 uiServerConfig *tls.Config 114 // Client-side config for the cockroach node. 115 // All other client tls.Config objects are built as requested and not cached. 116 clientConfig *tls.Config 117 } 118 119 // CertificateMetrics holds metrics about the various certificates. 120 // These are initialized when the certificate manager is created and updated 121 // on reload. 122 type CertificateMetrics struct { 123 CAExpiration *metric.Gauge 124 ClientCAExpiration *metric.Gauge 125 UICAExpiration *metric.Gauge 126 NodeExpiration *metric.Gauge 127 NodeClientExpiration *metric.Gauge 128 UIExpiration *metric.Gauge 129 } 130 131 func makeCertificateManager(certsDir string) *CertificateManager { 132 cm := &CertificateManager{certsDir: os.ExpandEnv(certsDir)} 133 // Initialize metrics: 134 cm.certMetrics = CertificateMetrics{ 135 CAExpiration: metric.NewGauge(metaCAExpiration), 136 ClientCAExpiration: metric.NewGauge(metaClientCAExpiration), 137 UICAExpiration: metric.NewGauge(metaUICAExpiration), 138 NodeExpiration: metric.NewGauge(metaNodeExpiration), 139 NodeClientExpiration: metric.NewGauge(metaNodeClientExpiration), 140 UIExpiration: metric.NewGauge(metaUIExpiration), 141 } 142 return cm 143 } 144 145 // NewCertificateManager creates a new certificate manager. 146 func NewCertificateManager(certsDir string) (*CertificateManager, error) { 147 cm := makeCertificateManager(certsDir) 148 return cm, cm.LoadCertificates() 149 } 150 151 // NewCertificateManagerFirstRun creates a new certificate manager. 152 // The certsDir is created if it does not exist. 153 // This should only be called when generating certificates, the server has 154 // no business creating the certs directory. 155 func NewCertificateManagerFirstRun(certsDir string) (*CertificateManager, error) { 156 cm := makeCertificateManager(certsDir) 157 if err := NewCertificateLoader(cm.certsDir).MaybeCreateCertsDir(); err != nil { 158 return nil, err 159 } 160 161 return cm, cm.LoadCertificates() 162 } 163 164 // Metrics returns the metrics struct. 165 func (cm *CertificateManager) Metrics() CertificateMetrics { 166 return cm.certMetrics 167 } 168 169 // RegisterSignalHandler registers a signal handler for SIGHUP, triggering a 170 // refresh of the certificates directory on notification. 171 func (cm *CertificateManager) RegisterSignalHandler(stopper *stop.Stopper) { 172 go func() { 173 ch := sysutil.RefreshSignaledChan() 174 for { 175 select { 176 case <-stopper.ShouldStop(): 177 return 178 case sig := <-ch: 179 log.Infof(context.Background(), "received signal %q, triggering certificate reload", sig) 180 if err := cm.LoadCertificates(); err != nil { 181 log.Warningf(context.Background(), "could not reload certificates: %v", err) 182 } else { 183 log.Info(context.Background(), "successfully reloaded certificates") 184 } 185 } 186 } 187 }() 188 } 189 190 // CACertPath returns the expected file path for the CA certificate. 191 func (cm *CertificateManager) CACertPath() string { 192 return filepath.Join(cm.certsDir, CACertFilename()) 193 } 194 195 // CACertFilename returns the expected file name for the CA certificate. 196 func CACertFilename() string { return "ca" + certExtension } 197 198 // ClientCACertPath returns the expected file path for the CA certificate 199 // used to verify client certificates. 200 func (cm *CertificateManager) ClientCACertPath() string { 201 return filepath.Join(cm.certsDir, "ca-client"+certExtension) 202 } 203 204 // UICACertPath returns the expected file path for the CA certificate 205 // used to verify Admin UI certificates. 206 func (cm *CertificateManager) UICACertPath() string { 207 return filepath.Join(cm.certsDir, "ca-ui"+certExtension) 208 } 209 210 // NodeCertPath returns the expected file path for the node certificate. 211 func (cm *CertificateManager) NodeCertPath() string { 212 return filepath.Join(cm.certsDir, "node"+certExtension) 213 } 214 215 // NodeKeyPath returns the expected file path for the node key. 216 func (cm *CertificateManager) NodeKeyPath() string { 217 return filepath.Join(cm.certsDir, "node"+keyExtension) 218 } 219 220 // UICertPath returns the expected file path for the UI certificate. 221 func (cm *CertificateManager) UICertPath() string { 222 return filepath.Join(cm.certsDir, "ui"+certExtension) 223 } 224 225 // UIKeyPath returns the expected file path for the UI key. 226 func (cm *CertificateManager) UIKeyPath() string { 227 return filepath.Join(cm.certsDir, "ui"+keyExtension) 228 } 229 230 // ClientCertPath returns the expected file path for the user's certificate. 231 func (cm *CertificateManager) ClientCertPath(user string) string { 232 return filepath.Join(cm.certsDir, ClientCertFilename(user)) 233 } 234 235 // ClientCertFilename returns the expected file name for the user's certificate. 236 func ClientCertFilename(user string) string { return "client." + user + certExtension } 237 238 // ClientKeyPath returns the expected file path for the user's key. 239 func (cm *CertificateManager) ClientKeyPath(user string) string { 240 return filepath.Join(cm.certsDir, ClientKeyFilename(user)) 241 } 242 243 // ClientKeyFilename returns the expected file name for the user's key. 244 func ClientKeyFilename(user string) string { return "client." + user + keyExtension } 245 246 // CACert returns the CA cert. May be nil. 247 // Callers should check for an internal Error field. 248 func (cm *CertificateManager) CACert() *CertInfo { 249 cm.mu.RLock() 250 defer cm.mu.RUnlock() 251 return cm.caCert 252 } 253 254 // ClientCACert returns the CA cert used to verify client certificates. May be nil. 255 // Callers should check for an internal Error field. 256 func (cm *CertificateManager) ClientCACert() *CertInfo { 257 cm.mu.RLock() 258 defer cm.mu.RUnlock() 259 return cm.clientCACert 260 } 261 262 // UICACert returns the CA cert used to verify the Admin UI certificate. May be nil. 263 // Callers should check for an internal Error field. 264 func (cm *CertificateManager) UICACert() *CertInfo { 265 cm.mu.RLock() 266 defer cm.mu.RUnlock() 267 return cm.uiCACert 268 } 269 270 // UICert returns the certificate used by the Admin UI. May be nil. 271 // Callers should check for an internal Error field. 272 func (cm *CertificateManager) UICert() *CertInfo { 273 cm.mu.RLock() 274 defer cm.mu.RUnlock() 275 return cm.uiCert 276 } 277 278 // checkCertIsValid returns an error if the passed cert is missing or has an error. 279 func checkCertIsValid(cert *CertInfo) error { 280 if cert == nil { 281 return errors.New("not found") 282 } 283 return cert.Error 284 } 285 286 // NodeCert returns the Node cert. May be nil. 287 // Callers should check for an internal Error field. 288 func (cm *CertificateManager) NodeCert() *CertInfo { 289 cm.mu.RLock() 290 defer cm.mu.RUnlock() 291 return cm.nodeCert 292 } 293 294 // ClientCerts returns the Client certs. 295 // Callers should check for internal Error fields. 296 func (cm *CertificateManager) ClientCerts() map[string]*CertInfo { 297 cm.mu.RLock() 298 defer cm.mu.RUnlock() 299 return cm.clientCerts 300 } 301 302 // Error is the error type for this package. 303 // TODO(knz): make this an error wrapper. 304 type Error struct { 305 Message string 306 Err error 307 } 308 309 // Error implements the error interface. 310 func (e *Error) Error() string { 311 return fmt.Sprintf("%s: %v", e.Message, e.Err) 312 } 313 314 // makeErrorf constructs an Error and returns it. 315 func makeErrorf(err error, format string, args ...interface{}) *Error { 316 return &Error{ 317 Message: fmt.Sprintf(format, args...), 318 Err: err, 319 } 320 } 321 322 // makeError constructs an Error with just a string. 323 func makeError(err error, s string) *Error { return makeErrorf(err, "%s", s) } 324 325 // LoadCertificates creates a CertificateLoader to load all certs and keys. 326 // Upon success, it swaps the existing certificates for the new ones. 327 func (cm *CertificateManager) LoadCertificates() error { 328 cl := NewCertificateLoader(cm.certsDir) 329 if err := cl.Load(); err != nil { 330 return makeErrorf(err, "problem loading certs directory %s", cm.certsDir) 331 } 332 333 var caCert, clientCACert, uiCACert, nodeCert, uiCert, nodeClientCert *CertInfo 334 clientCerts := make(map[string]*CertInfo) 335 for _, ci := range cl.Certificates() { 336 switch ci.FileUsage { 337 case CAPem: 338 caCert = ci 339 case ClientCAPem: 340 clientCACert = ci 341 case UICAPem: 342 uiCACert = ci 343 case NodePem: 344 nodeCert = ci 345 case UIPem: 346 uiCert = ci 347 case ClientPem: 348 clientCerts[ci.Name] = ci 349 if ci.Name == NodeUser { 350 nodeClientCert = ci 351 } 352 } 353 } 354 355 cm.mu.Lock() 356 defer cm.mu.Unlock() 357 if cm.initialized { 358 // If we ran before, make sure we don't reload with missing/bad certificates. 359 if err := checkCertIsValid(caCert); checkCertIsValid(cm.caCert) == nil && err != nil { 360 return makeError(err, "reload would lose valid CA cert") 361 } 362 if err := checkCertIsValid(nodeCert); checkCertIsValid(cm.nodeCert) == nil && err != nil { 363 return makeError(err, "reload would lose valid node cert") 364 } 365 if err := checkCertIsValid(nodeClientCert); checkCertIsValid(cm.nodeClientCert) == nil && err != nil { 366 return makeErrorf(err, "reload would lose valid client cert for '%s'", NodeUser) 367 } 368 if err := checkCertIsValid(clientCACert); checkCertIsValid(cm.clientCACert) == nil && err != nil { 369 return makeError(err, "reload would lose valid CA certificate for client verification") 370 } 371 if err := checkCertIsValid(uiCACert); checkCertIsValid(cm.uiCACert) == nil && err != nil { 372 return makeError(err, "reload would lose valid CA certificate for UI") 373 } 374 if err := checkCertIsValid(uiCert); checkCertIsValid(cm.uiCert) == nil && err != nil { 375 return makeError(err, "reload would lose valid UI certificate") 376 } 377 } 378 379 if nodeClientCert == nil && nodeCert != nil { 380 // No client certificate for node, but we have a node certificate. Check that 381 // it contains the required client fields. 382 if err := validateDualPurposeNodeCert(nodeCert); err != nil { 383 return err 384 } 385 } 386 387 // Swap everything. 388 cm.caCert = caCert 389 cm.clientCACert = clientCACert 390 cm.uiCACert = uiCACert 391 392 cm.nodeCert = nodeCert 393 cm.nodeClientCert = nodeClientCert 394 cm.uiCert = uiCert 395 cm.clientCerts = clientCerts 396 397 cm.initialized = true 398 399 cm.serverConfig = nil 400 cm.uiServerConfig = nil 401 cm.clientConfig = nil 402 403 cm.updateMetricsLocked() 404 return nil 405 } 406 407 // updateMetricsLocked updates the values on the certificate metrics. 408 // The metrics may not exist (eg: in tests that build their own CertificateManager). 409 // If the corresponding certificate is missing or invalid (Error != nil), we reset the 410 // metric to zero. 411 // cm.mu must be held to protect the certificates. Metrics do their own atomicity. 412 func (cm *CertificateManager) updateMetricsLocked() { 413 maybeSetMetric := func(m *metric.Gauge, ci *CertInfo) { 414 if m == nil { 415 return 416 } 417 if ci != nil && ci.Error == nil { 418 m.Update(ci.ExpirationTime.Unix()) 419 } else { 420 m.Update(0) 421 } 422 } 423 424 // CA certificate expiration. 425 maybeSetMetric(cm.certMetrics.CAExpiration, cm.caCert) 426 427 // Client CA certificate expiration. 428 maybeSetMetric(cm.certMetrics.ClientCAExpiration, cm.clientCACert) 429 430 // UI CA certificate expiration. 431 maybeSetMetric(cm.certMetrics.UICAExpiration, cm.uiCACert) 432 433 // Node certificate expiration. 434 // TODO(marc): we need to examine the entire certificate chain here, if the CA cert 435 // used to sign the node cert expires sooner, then that is the expiration time to report. 436 maybeSetMetric(cm.certMetrics.NodeExpiration, cm.nodeCert) 437 438 // Node client certificate expiration. 439 maybeSetMetric(cm.certMetrics.NodeClientExpiration, cm.nodeClientCert) 440 441 // UI certificate expiration. 442 maybeSetMetric(cm.certMetrics.UIExpiration, cm.uiCert) 443 } 444 445 // GetServerTLSConfig returns a server TLS config with a callback to fetch the 446 // latest TLS config. We still attempt to get the config to make sure 447 // the initial call has a valid config loaded. 448 func (cm *CertificateManager) GetServerTLSConfig() (*tls.Config, error) { 449 if _, err := cm.getEmbeddedServerTLSConfig(nil); err != nil { 450 return nil, err 451 } 452 return &tls.Config{ 453 GetConfigForClient: cm.getEmbeddedServerTLSConfig, 454 }, nil 455 } 456 457 // getEmbeddedServerTLSConfig returns the most up-to-date server tls.Config. 458 // This is the callback set in tls.Config.GetConfigForClient. We currently 459 // ignore the ClientHelloInfo object. 460 func (cm *CertificateManager) getEmbeddedServerTLSConfig( 461 _ *tls.ClientHelloInfo, 462 ) (*tls.Config, error) { 463 cm.mu.Lock() 464 defer cm.mu.Unlock() 465 466 if cm.serverConfig != nil { 467 return cm.serverConfig, nil 468 } 469 470 ca, err := cm.getCACertLocked() 471 if err != nil { 472 return nil, err 473 } 474 475 nodeCert, err := cm.getNodeCertLocked() 476 if err != nil { 477 return nil, err 478 } 479 480 clientCA, err := cm.getClientCACertLocked() 481 if err != nil { 482 return nil, err 483 } 484 485 cfg, err := newServerTLSConfig( 486 nodeCert.FileContents, 487 nodeCert.KeyFileContents, 488 ca.FileContents, 489 clientCA.FileContents) 490 if err != nil { 491 return nil, err 492 } 493 494 cm.serverConfig = cfg 495 return cfg, nil 496 } 497 498 // GetUIServerTLSConfig returns a server TLS config for the Admin UI with a 499 // callback to fetch the latest TLS config. We still attempt to get the config to make sure 500 // the initial call has a valid config loaded. 501 func (cm *CertificateManager) GetUIServerTLSConfig() (*tls.Config, error) { 502 if _, err := cm.getEmbeddedUIServerTLSConfig(nil); err != nil { 503 return nil, err 504 } 505 return &tls.Config{ 506 GetConfigForClient: cm.getEmbeddedUIServerTLSConfig, 507 }, nil 508 } 509 510 // getEmbeddedUIServerTLSConfig returns the most up-to-date server tls.Config for the Admin UI. 511 // This is the callback set in tls.Config.GetConfigForClient. We currently 512 // ignore the ClientHelloInfo object. 513 func (cm *CertificateManager) getEmbeddedUIServerTLSConfig( 514 _ *tls.ClientHelloInfo, 515 ) (*tls.Config, error) { 516 cm.mu.Lock() 517 defer cm.mu.Unlock() 518 519 if cm.uiServerConfig != nil { 520 return cm.uiServerConfig, nil 521 } 522 523 uiCert, err := cm.getUICertLocked() 524 if err != nil { 525 return nil, err 526 } 527 528 cfg, err := newUIServerTLSConfig( 529 uiCert.FileContents, 530 uiCert.KeyFileContents) 531 if err != nil { 532 return nil, err 533 } 534 535 cm.uiServerConfig = cfg 536 return cfg, nil 537 } 538 539 // getCACertLocked returns the general CA cert. 540 // cm.mu must be held. 541 func (cm *CertificateManager) getCACertLocked() (*CertInfo, error) { 542 if err := checkCertIsValid(cm.caCert); err != nil { 543 return nil, makeError(err, "problem with CA certificate") 544 } 545 return cm.caCert, nil 546 } 547 548 // getClientCACertLocked returns the CA cert used to verify client certificates. 549 // Use the client CA if it exists, otherwise fall back on the general CA. 550 // cm.mu must be held. 551 func (cm *CertificateManager) getClientCACertLocked() (*CertInfo, error) { 552 if cm.clientCACert == nil { 553 // No client CA: use general CA. 554 return cm.getCACertLocked() 555 } 556 557 if err := checkCertIsValid(cm.clientCACert); err != nil { 558 return nil, makeError(err, "problem with client CA certificate") 559 } 560 return cm.clientCACert, nil 561 } 562 563 // getUICACertLocked returns the CA cert for the Admin UI. 564 // Use the UI CA if it exists, otherwise fall back on the general CA. 565 // cm.mu must be held. 566 func (cm *CertificateManager) getUICACertLocked() (*CertInfo, error) { 567 if cm.uiCACert == nil { 568 // No UI CA: use general CA. 569 return cm.getCACertLocked() 570 } 571 572 if err := checkCertIsValid(cm.uiCACert); err != nil { 573 return nil, makeError(err, "problem with UI CA certificate") 574 } 575 return cm.uiCACert, nil 576 } 577 578 // getNodeCertLocked returns the node certificate. 579 // cm.mu must be held. 580 func (cm *CertificateManager) getNodeCertLocked() (*CertInfo, error) { 581 if err := checkCertIsValid(cm.nodeCert); err != nil { 582 return nil, makeError(err, "problem with node certificate") 583 } 584 return cm.nodeCert, nil 585 } 586 587 // getUICertLocked returns the UI certificate if present, otherwise returns 588 // the node certificate. 589 // cm.mu must be held. 590 func (cm *CertificateManager) getUICertLocked() (*CertInfo, error) { 591 if cm.uiCert == nil { 592 // No UI certificate: use node certificate. 593 return cm.getNodeCertLocked() 594 } 595 if err := checkCertIsValid(cm.uiCert); err != nil { 596 return nil, makeError(err, "problem with UI certificate") 597 } 598 return cm.uiCert, nil 599 } 600 601 // getClientCertLocked returns the client cert/key for the specified user, 602 // or an error if not found. 603 // cm.mu must be held. 604 func (cm *CertificateManager) getClientCertLocked(user string) (*CertInfo, error) { 605 ci := cm.clientCerts[user] 606 if err := checkCertIsValid(ci); err != nil { 607 return nil, makeErrorf(err, "problem with client cert for user %s", user) 608 } 609 610 return ci, nil 611 } 612 613 // getNodeClientCertLocked returns the client cert/key for the node user. 614 // Use the client certificate for 'node' if it exists, otherwise use 615 // the node certificate which should be a combined client/server certificate. 616 // cm.mu must be held. 617 func (cm *CertificateManager) getNodeClientCertLocked() (*CertInfo, error) { 618 if cm.nodeClientCert == nil { 619 // No specific client cert for 'node': use multi-purpose node cert. 620 return cm.getNodeCertLocked() 621 } 622 623 if err := checkCertIsValid(cm.nodeClientCert); err != nil { 624 return nil, makeError(err, "problem with node client certificate") 625 } 626 return cm.nodeClientCert, nil 627 } 628 629 // GetClientTLSConfig returns the most up-to-date client tls.Config. 630 // Returns the dual-purpose node certs if user == NodeUser and there is no 631 // separate client cert for 'node'. 632 func (cm *CertificateManager) GetClientTLSConfig(user string) (*tls.Config, error) { 633 cm.mu.Lock() 634 defer cm.mu.Unlock() 635 636 // We always need the CA cert. 637 ca, err := cm.getCACertLocked() 638 if err != nil { 639 return nil, err 640 } 641 642 if user != NodeUser { 643 clientCert, err := cm.getClientCertLocked(user) 644 if err != nil { 645 return nil, err 646 } 647 648 cfg, err := newClientTLSConfig( 649 clientCert.FileContents, 650 clientCert.KeyFileContents, 651 ca.FileContents) 652 if err != nil { 653 return nil, err 654 } 655 656 return cfg, nil 657 } 658 659 // We're the node user: 660 // Return the cached config if we have one. 661 if cm.clientConfig != nil { 662 return cm.clientConfig, nil 663 } 664 665 clientCert, err := cm.getNodeClientCertLocked() 666 if err != nil { 667 return nil, err 668 } 669 670 cfg, err := newClientTLSConfig( 671 clientCert.FileContents, 672 clientCert.KeyFileContents, 673 ca.FileContents) 674 if err != nil { 675 return nil, err 676 } 677 678 // Cache the config. 679 cm.clientConfig = cfg 680 return cfg, nil 681 } 682 683 // GetUIClientTLSConfig returns the most up-to-date client tls.Config for Admin UI clients. 684 // It does not include a client certificate and uses the UI CA certificate if present. 685 func (cm *CertificateManager) GetUIClientTLSConfig() (*tls.Config, error) { 686 cm.mu.Lock() 687 defer cm.mu.Unlock() 688 689 // We always need the CA cert. 690 uiCA, err := cm.getUICACertLocked() 691 if err != nil { 692 return nil, err 693 } 694 695 cfg, err := newUIClientTLSConfig(uiCA.FileContents) 696 if err != nil { 697 return nil, err 698 } 699 700 return cfg, nil 701 } 702 703 // GetClientCertPaths returns the paths to the client cert and key. 704 // Returns the node cert and key if user == NodeUser. 705 func (cm *CertificateManager) GetClientCertPaths(user string) (string, string, error) { 706 var clientCert *CertInfo 707 var err error 708 709 cm.mu.RLock() 710 defer cm.mu.RUnlock() 711 712 if user == NodeUser { 713 clientCert, err = cm.getNodeClientCertLocked() 714 } else { 715 clientCert, err = cm.getClientCertLocked(user) 716 } 717 if err != nil { 718 return "", "", err 719 } 720 721 return filepath.Join(cm.certsDir, clientCert.Filename), 722 filepath.Join(cm.certsDir, clientCert.KeyFilename), 723 nil 724 } 725 726 // GetCACertPath returns the path to the CA certificate. 727 func (cm *CertificateManager) GetCACertPath() (string, error) { 728 cm.mu.RLock() 729 defer cm.mu.RUnlock() 730 731 ca, err := cm.getCACertLocked() 732 if err != nil { 733 return "", err 734 } 735 736 return filepath.Join(cm.certsDir, ca.Filename), nil 737 } 738 739 // ListCertificates returns all loaded certificates, or an error if not yet initialized. 740 func (cm *CertificateManager) ListCertificates() ([]*CertInfo, error) { 741 cm.mu.RLock() 742 defer cm.mu.RUnlock() 743 744 if !cm.initialized { 745 return nil, errors.New("certificate manager has not been initialized") 746 } 747 748 ret := make([]*CertInfo, 0, 2+len(cm.clientCerts)) 749 if cm.caCert != nil { 750 ret = append(ret, cm.caCert) 751 } 752 if cm.clientCACert != nil { 753 ret = append(ret, cm.clientCACert) 754 } 755 if cm.uiCACert != nil { 756 ret = append(ret, cm.uiCACert) 757 } 758 if cm.nodeCert != nil { 759 ret = append(ret, cm.nodeCert) 760 } 761 if cm.uiCert != nil { 762 ret = append(ret, cm.uiCert) 763 } 764 if cm.clientCerts != nil { 765 for _, cert := range cm.clientCerts { 766 ret = append(ret, cert) 767 } 768 } 769 770 return ret, nil 771 }