Commit 31f74694 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

Signed-off-by: 's avatarBrad Davidson <brad.davidson@rancher.com> (cherry picked from commit c6392c9f) Signed-off-by: 's avatarBrad Davidson <brad.davidson@rancher.com>
parent 64cc911c
...@@ -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