do not reset secrets of standby clusters (#3044)

* do not reset secrets of standby clusters
align error message with unit test
* check for other env vars, too
This commit is contained in:
Felix Kunde
2026-02-26 17:27:47 +01:00
committed by GitHub
parent aefe9d8298
commit 2a31c403d0
5 changed files with 67 additions and 34 deletions
+53 -31
View File
@@ -1174,42 +1174,15 @@ func (c *Cluster) updateSecret(
pwdUser := userMap[userKey]
secretName := util.NameFromMeta(secret.ObjectMeta)
// if password rotation is enabled update password and username if rotation interval has been passed
// rotation can be enabled globally or via the manifest (excluding the Postgres superuser)
rotationEnabledInManifest := secretUsername != constants.SuperuserKeyName &&
(slices.Contains(c.Spec.UsersWithSecretRotation, secretUsername) ||
slices.Contains(c.Spec.UsersWithInPlaceSecretRotation, secretUsername))
// globally enabled rotation is only allowed for manifest and bootstrapped roles
allowedRoleTypes := []spec.RoleOrigin{spec.RoleOriginManifest, spec.RoleOriginBootstrap}
rotationAllowed := !pwdUser.IsDbOwner && slices.Contains(allowedRoleTypes, pwdUser.Origin) && c.Spec.StandbyCluster == nil
// users can ignore any kind of rotation
isIgnoringRotation := slices.Contains(c.Spec.UsersIgnoringSecretRotation, secretUsername)
if ((c.OpConfig.EnablePasswordRotation && rotationAllowed) || rotationEnabledInManifest) && !isIgnoringRotation {
updateSecretMsg, err = c.rotatePasswordInSecret(secret, secretUsername, pwdUser.Origin, currentTime, retentionUsers)
// do not perform any rotation of reset for standby clusters
if !isStandbyCluster(&c.Spec) {
updateSecretMsg, err = c.checkForPasswordRotation(secret, secretUsername, pwdUser, retentionUsers, currentTime)
if err != nil {
c.logger.Warnf("password rotation failed for user %s: %v", secretUsername, err)
return nil, fmt.Errorf("error while checking for password rotation: %v", err)
}
if updateSecretMsg != "" {
updateSecret = true
}
} else {
// username might not match if password rotation has been disabled again
usernameFromSecret := string(secret.Data["username"])
if secretUsername != usernameFromSecret {
// handle edge case when manifest user conflicts with a user from prepared databases
if strings.Replace(usernameFromSecret, "-", "_", -1) == strings.Replace(secretUsername, "-", "_", -1) {
return nil, fmt.Errorf("could not update secret because of user name mismatch: expected: %s, got: %s", secretUsername, usernameFromSecret)
}
*retentionUsers = append(*retentionUsers, secretUsername)
secret.Data["username"] = []byte(secretUsername)
secret.Data["password"] = []byte(util.RandomPassword(constants.PasswordLength))
secret.Data["nextRotation"] = []byte{}
updateSecret = true
updateSecretMsg = fmt.Sprintf("secret does not contain the role %s - updating username and resetting password", secretUsername)
}
}
// if this secret belongs to the infrastructure role and the password has changed - replace it in the secret
@@ -1256,6 +1229,55 @@ func (c *Cluster) updateSecret(
return secret, nil
}
func (c *Cluster) checkForPasswordRotation(
secret *v1.Secret,
secretUsername string,
pwdUser spec.PgUser,
retentionUsers *[]string,
currentTime time.Time) (string, error) {
var (
passwordRotationMsg string
err error
)
// if password rotation is enabled update password and username if rotation interval has been passed
// rotation can be enabled globally or via the manifest (excluding the Postgres superuser)
rotationEnabledInManifest := secretUsername != constants.SuperuserKeyName &&
(slices.Contains(c.Spec.UsersWithSecretRotation, secretUsername) ||
slices.Contains(c.Spec.UsersWithInPlaceSecretRotation, secretUsername))
// globally enabled rotation is only allowed for manifest and bootstrapped roles
allowedRoleTypes := []spec.RoleOrigin{spec.RoleOriginManifest, spec.RoleOriginBootstrap}
rotationAllowed := !pwdUser.IsDbOwner && slices.Contains(allowedRoleTypes, pwdUser.Origin)
// users can ignore any kind of rotation
isIgnoringRotation := slices.Contains(c.Spec.UsersIgnoringSecretRotation, secretUsername)
if ((c.OpConfig.EnablePasswordRotation && rotationAllowed) || rotationEnabledInManifest) && !isIgnoringRotation {
passwordRotationMsg, err = c.rotatePasswordInSecret(secret, secretUsername, pwdUser.Origin, currentTime, retentionUsers)
if err != nil {
c.logger.Warnf("password rotation failed for user %s: %v", secretUsername, err)
}
} else {
// username might not match if password rotation has been disabled again
usernameFromSecret := string(secret.Data["username"])
if secretUsername != usernameFromSecret {
// handle edge case when manifest user conflicts with a user from prepared databases
if strings.Replace(usernameFromSecret, "-", "_", -1) == strings.Replace(secretUsername, "-", "_", -1) {
return "", fmt.Errorf("could not update secret because of user name mismatch: expected: %s, got: %s", secretUsername, usernameFromSecret)
}
*retentionUsers = append(*retentionUsers, secretUsername)
secret.Data["username"] = []byte(secretUsername)
secret.Data["password"] = []byte(util.RandomPassword(constants.PasswordLength))
secret.Data["nextRotation"] = []byte{}
passwordRotationMsg = fmt.Sprintf("secret does not contain the role %s - updating username and resetting password", secretUsername)
}
}
return passwordRotationMsg, nil
}
func (c *Cluster) rotatePasswordInSecret(
secret *v1.Secret,
secretUsername string,