Commit c6392c9f authored by Brad Davidson's avatar Brad Davidson Committed by Brad Davidson

Fix issue that caused passwd file and psk to be regenerated when rotating CA certs

parent b1a42e5d
...@@ -75,6 +75,10 @@ func caCertReplace(server *config.Control, buf io.ReadCloser, force bool) error ...@@ -75,6 +75,10 @@ func caCertReplace(server *config.Control, buf io.ReadCloser, force bool) error
return err return err
} }
if err := defaultBootstrap(server, tmpServer); err != nil {
return errors.Wrap(err, "failed to set default bootstrap values")
}
if err := validateBootstrap(server, tmpServer); err != nil { if err := validateBootstrap(server, tmpServer); err != nil {
if !force { if !force {
return errors.Wrap(err, "failed to validate new CA certificates and keys") return errors.Wrap(err, "failed to validate new CA certificates and keys")
...@@ -85,27 +89,16 @@ func caCertReplace(server *config.Control, buf io.ReadCloser, force bool) error ...@@ -85,27 +89,16 @@ func caCertReplace(server *config.Control, buf io.ReadCloser, force bool) error
return cluster.Save(context.TODO(), tmpServer, true) return cluster.Save(context.TODO(), tmpServer, true)
} }
// validateBootstrap checks the new certs and keys to ensure that the cluster would function properly were they to be used. // defaultBootstrap provides default values from the existing bootstrap fields
// - The new leaf CA certificates must be verifiable using the same root and intermediate certs as the current leaf CA certificates. // if the value is not tagged for rotation, or the current value is empty.
// - The new service account signing key bundle must include the currently active signing key. func defaultBootstrap(oldServer, newServer *config.Control) error {
func validateBootstrap(oldServer, newServer *config.Control) error {
errs := []error{} errs := []error{}
// Use reflection to iterate over all of the bootstrap fields, checking files at each of the new paths. // Use reflection to iterate over all of the bootstrap fields, checking files at each of the new paths.
oldMeta := reflect.ValueOf(&oldServer.Runtime.ControlRuntimeBootstrap).Elem() oldMeta := reflect.ValueOf(&oldServer.Runtime.ControlRuntimeBootstrap).Elem()
newMeta := reflect.ValueOf(&newServer.Runtime.ControlRuntimeBootstrap).Elem() newMeta := reflect.ValueOf(&newServer.Runtime.ControlRuntimeBootstrap).Elem()
fields := []reflect.StructField{}
// use the existing file if the new file does not exist or is empty
for _, field := range reflect.VisibleFields(oldMeta.Type()) { for _, field := range reflect.VisibleFields(oldMeta.Type()) {
// Only handle bootstrap fields tagged for rotation
if field.Tag.Get("rotate") != "true" {
continue
}
fields = append(fields, field)
}
// first pass: use the existing file if the new file does not exist or is empty
for _, field := range fields {
newVal := newMeta.FieldByName(field.Name) newVal := newMeta.FieldByName(field.Name)
info, err := os.Stat(newVal.String()) info, err := os.Stat(newVal.String())
if err != nil && !errors.Is(err, fs.ErrNotExist) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
...@@ -113,20 +106,34 @@ func validateBootstrap(oldServer, newServer *config.Control) error { ...@@ -113,20 +106,34 @@ func validateBootstrap(oldServer, newServer *config.Control) error {
continue continue
} }
if info == nil || info.Size() == 0 { if field.Tag.Get("rotate") != "true" || info == nil || info.Size() == 0 {
if newVal.CanSet() { if newVal.CanSet() {
oldVal := oldMeta.FieldByName(field.Name) oldVal := oldMeta.FieldByName(field.Name)
logrus.Infof("certificate: %s not provided; using current value %s", field.Name, oldVal) logrus.Infof("Using current data for %s: %s", field.Name, oldVal)
newVal.Set(oldVal) newVal.Set(oldVal)
} else { } else {
errs = append(errs, fmt.Errorf("cannot use current data for %s; field is not settable", field.Name)) errs = append(errs, fmt.Errorf("cannot use current data for %s; field is not settable", field.Name))
} }
} }
} }
return merr.NewErrors(errs...)
}
// second pass: validate file contents // validateBootstrap checks the new certs and keys to ensure that the cluster would function properly were they to be used.
for _, field := range fields { // - The new leaf CA certificates must be verifiable using the same root and intermediate certs as the current leaf CA certificates.
// - The new service account signing key bundle must include the currently active signing key.
func validateBootstrap(oldServer, newServer *config.Control) error {
errs := []error{}
// Use reflection to iterate over all of the bootstrap fields, checking files at each of the new paths.
oldMeta := reflect.ValueOf(&oldServer.Runtime.ControlRuntimeBootstrap).Elem()
newMeta := reflect.ValueOf(&newServer.Runtime.ControlRuntimeBootstrap).Elem()
for _, field := range reflect.VisibleFields(oldMeta.Type()) {
// Only handle bootstrap fields tagged for rotation
if field.Tag.Get("rotate") != "true" {
continue
}
oldVal := oldMeta.FieldByName(field.Name) oldVal := oldMeta.FieldByName(field.Name)
newVal := newMeta.FieldByName(field.Name) newVal := newMeta.FieldByName(field.Name)
...@@ -150,10 +157,7 @@ func validateBootstrap(oldServer, newServer *config.Control) error { ...@@ -150,10 +157,7 @@ func validateBootstrap(oldServer, newServer *config.Control) error {
} }
} }
if len(errs) > 0 { return merr.NewErrors(errs...)
return merr.NewErrors(errs...)
}
return nil
} }
func validateCA(oldCAPath, newCAPath string) error { func validateCA(oldCAPath, newCAPath string) error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment