Skip to content

Commit

Permalink
server: added init function that uses a recieved bundle to provision …
Browse files Browse the repository at this point in the history
…a node

 * Added InitializeNodeFromBundle to enable a joining/initing node to self generate host certificates
 * Fixed bug where UICA was referenced instead of ClientCA
 * Updated initLifespan to 366d (still need to move this to config)

security: added ClientCAKeyPath helper to align with ClientCACertPath

Release note: None
  • Loading branch information
Aaron Blum authored and itsbilal committed Feb 19, 2021
1 parent 41ee1c2 commit 410940c
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
6 changes: 6 additions & 0 deletions pkg/security/certificate_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,12 @@ func (cl CertsLocator) ClientCACertPath() string {
return filepath.Join(cl.certsDir, "ca-client"+certExtension)
}

// ClientCAKeyPath returns the expected file path for the CA key
// used to sign client certificates.
func (cl CertsLocator) ClientCAKeyPath() string {
return filepath.Join(cl.certsDir, "ca-client"+keyExtension)
}

// UICACertPath returns the expected file path for the CA certificate
// used to verify Admin UI certificates.
func (cl CertsLocator) UICACertPath() string {
Expand Down
96 changes: 93 additions & 3 deletions pkg/server/auto_tls_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func writeKeyFile(keyPath string, keyPEM []byte) error {
func (b *CertificateBundle) InitializeFromConfig(c base.Config) (err error) {
cl := security.MakeCertsLocator(c.SSLCertsDir)
// TODO(aaron-crl): Put this in the config map.
initLifespan, err := time.ParseDuration("60m")
initLifespan, err := time.ParseDuration("366d")

// First check to see if host cert is already present
// if it is, we should fail to initialize.
Expand All @@ -275,9 +275,12 @@ func (b *CertificateBundle) InitializeFromConfig(c base.Config) (err error) {
return
}

// Initialize User auth certificates.
// TODO(aaron-crl): Double check that we want to do this. It seems
// like this is covered by the interface certificates?
err = b.UserAuth.loadOrCreateUserAuthCACertAndKey(
cl.UICACertPath(),
cl.UICAKeyPath(),
cl.ClientCACertPath(),
cl.ClientCAKeyPath(),
initLifespan,
"User Authentication",
)
Expand Down Expand Up @@ -338,6 +341,93 @@ func (b *CertificateBundle) InitializeFromConfig(c base.Config) (err error) {
return
}

// InitializeNodeFromBundle uses the contents of the CertificateBundle and
// details from the config object to write certs to disk and generate any
// missing host-specific certificates and keys
// It is assumed that a node receiving this has not has TLS initialized. If
// a interNodeHost certificate is found, this function will error.
func (b *CertificateBundle) InitializeNodeFromBundle(c base.Config) (err error) {
cl := security.MakeCertsLocator(c.SSLCertsDir)

// First check to see if host cert is already present
// if it is, we should fail to initialize.
if _, err = os.Stat(cl.NodeCertPath()); !os.IsNotExist(err) {
err = errors.New("interNodeHost certificate already present")
return
}

// Write received CA's to disk. If any of them already exist, fail
// and return an error.

// Attempt to write InterNodeHostCA to disk first.
err = b.InterNode.writeCAOrFail(cl.CACertPath(), cl.CAKeyPath())
if err != nil {
err = errors.Wrap(err, "failed to write InterNodeCA to disk")
return
}

// Attempt to write ClientCA to disk.
err = b.InterNode.writeCAOrFail(cl.ClientCACertPath(), cl.ClientCAKeyPath())
if err != nil {
err = errors.Wrap(err, "failed to write ClientCA to disk")
return
}

// Attempt to write SQLServiceCA to disk.
err = b.InterNode.writeCAOrFail(cl.SQLServiceCACertPath(), cl.SQLServiceCAKeyPath())
if err != nil {
err = errors.Wrap(err, "failed to write SQLServiceCA to disk")
return
}

// Attempt to write RPCServiceCA to disk.
err = b.InterNode.writeCAOrFail(cl.RPCServiceCACertPath(), cl.RPCServiceCAKeyPath())
if err != nil {
err = errors.Wrap(err, "failed to write RPCServiceCA to disk")
return
}

// Attempt to write AdminUIServiceCA to disk.
err = b.InterNode.writeCAOrFail(cl.UICACertPath(), cl.UICAKeyPath())
if err != nil {
err = errors.Wrap(err, "failed to write AdminUIServiceCA to disk")
return
}

// Once CAs are written call the same InitFromConfig function to create
// host certificates.
err = b.InitializeFromConfig(c)
if err != nil {
err = errors.Wrap(
err,
"failed to initialize host certs after writing CAs to disk")
return
}

return
}

// writeCAOrFail will attempt to write a service certificate bundle to the
// specified paths on disk. It will ignore any missing certificate fields but
// error if it fails to write a file to disk.
func (sb *ServiceCertificateBundle) writeCAOrFail(certPath string, keyPath string) (err error) {
if sb.CACertificate != nil {
err = writeCertificateFile(certPath, sb.CACertificate)
if err != nil {
return
}
}

if sb.CAKey != nil {
writeKeyFile(keyPath, sb.CAKey)
if err != nil {
return
}
}

return
}

// copyOnlyCAs is a helper function to only populate the CA portion of
// a ServiceCertificateBundle
func (sb *ServiceCertificateBundle) copyOnlyCAs(destBundle *ServiceCertificateBundle) {
Expand Down

0 comments on commit 410940c

Please sign in to comment.