mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 15:06:49 +02:00
copy rolconfig during password rotation (#2183)
* copy rolconfig during password rotation Co-authored-by: idanovinda <idanovinda@gmail.com>
This commit is contained in:
co-authored by
idanovinda
parent
63c9f916a6
commit
4741b3f734
@@ -284,7 +284,7 @@ func (c *Cluster) cleanupRotatedUsers(rotatedUsers []string, db *sql.DB) error {
|
||||
retentionDate := time.Now().AddDate(0, 0, int(retenionDays)*-1)
|
||||
|
||||
for rotatedUser, dateSuffix := range extraUsers {
|
||||
userCreationDate, err := time.Parse("060102", dateSuffix)
|
||||
userCreationDate, err := time.Parse(constants.RotationUserDateFormat, dateSuffix)
|
||||
if err != nil {
|
||||
c.logger.Errorf("could not parse creation date suffix of user %q: %v", rotatedUser, err)
|
||||
continue
|
||||
|
||||
+22
-4
@@ -656,7 +656,6 @@ func (c *Cluster) checkAndSetGlobalPostgreSQLConfiguration(pod *v1.Pod, effectiv
|
||||
}
|
||||
|
||||
func (c *Cluster) syncSecrets() error {
|
||||
|
||||
c.logger.Info("syncing secrets")
|
||||
c.setProcessName("syncing secrets")
|
||||
generatedSecrets := c.generateUserSecrets()
|
||||
@@ -792,6 +791,7 @@ func (c *Cluster) updateSecret(
|
||||
pwdUser.Password = string(secret.Data["password"])
|
||||
// update membership if we deal with a rotation user
|
||||
if secretUsername != pwdUser.Name {
|
||||
pwdUser.Rotated = true
|
||||
pwdUser.MemberOf = []string{secretUsername}
|
||||
}
|
||||
userMap[userKey] = pwdUser
|
||||
@@ -842,7 +842,7 @@ func (c *Cluster) rotatePasswordInSecret(
|
||||
if currentTime.After(nextRotationDate) {
|
||||
// create rotation user if role is not listed for in-place password update
|
||||
if !util.SliceContains(c.Spec.UsersWithInPlaceSecretRotation, secretUsername) {
|
||||
rotationUsername := fmt.Sprintf("%s%s", secretUsername, currentTime.Format("060102"))
|
||||
rotationUsername := fmt.Sprintf("%s%s", secretUsername, currentTime.Format(constants.RotationUserDateFormat))
|
||||
secret.Data["username"] = []byte(rotationUsername)
|
||||
c.logger.Infof("updating username in secret %s and creating rotation user %s in the database", secretName, rotationUsername)
|
||||
// whenever there is a rotation, check if old rotation users can be deleted
|
||||
@@ -924,6 +924,12 @@ func (c *Cluster) syncRoles() (err error) {
|
||||
for _, u := range c.pgUsers {
|
||||
pgRole := u.Name
|
||||
userNames = append(userNames, pgRole)
|
||||
|
||||
// when a rotation happened add group role to query its rolconfig
|
||||
if u.Rotated {
|
||||
userNames = append(userNames, u.MemberOf[0])
|
||||
}
|
||||
|
||||
// add team member role name with rename suffix in case we need to rename it back
|
||||
if u.Origin == spec.RoleOriginTeamsAPI && c.OpConfig.EnableTeamMemberDeprecation {
|
||||
deletedUsers[pgRole+c.OpConfig.RoleDeletionSuffix] = pgRole
|
||||
@@ -950,9 +956,21 @@ func (c *Cluster) syncRoles() (err error) {
|
||||
return fmt.Errorf("error getting users from the database: %v", err)
|
||||
}
|
||||
|
||||
// update pgUsers where a deleted role was found
|
||||
// so that they are skipped in ProduceSyncRequests
|
||||
DBUSERS:
|
||||
for _, dbUser := range dbUsers {
|
||||
// copy rolconfig to rotation users
|
||||
for pgUserName, pgUser := range c.pgUsers {
|
||||
if pgUser.Rotated && pgUser.MemberOf[0] == dbUser.Name {
|
||||
pgUser.Parameters = dbUser.Parameters
|
||||
c.pgUsers[pgUserName] = pgUser
|
||||
// remove group role from dbUsers to not count as deleted role
|
||||
delete(dbUsers, dbUser.Name)
|
||||
continue DBUSERS
|
||||
}
|
||||
}
|
||||
|
||||
// update pgUsers where a deleted role was found
|
||||
// so that they are skipped in ProduceSyncRequests
|
||||
originalUsername, foundDeletedUser := deletedUsers[dbUser.Name]
|
||||
// check if original user does not exist in dbUsers
|
||||
_, originalUserAlreadyExists := dbUsers[originalUsername]
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/zalando/postgres-operator/pkg/spec"
|
||||
"github.com/zalando/postgres-operator/pkg/util"
|
||||
"github.com/zalando/postgres-operator/pkg/util/config"
|
||||
"github.com/zalando/postgres-operator/pkg/util/constants"
|
||||
"github.com/zalando/postgres-operator/pkg/util/k8sutil"
|
||||
"github.com/zalando/postgres-operator/pkg/util/patroni"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
@@ -593,7 +594,7 @@ func TestUpdateSecret(t *testing.T) {
|
||||
t.Errorf("%s: username differs in updated secret: expected %s, got %s", testName, username, secretUsername)
|
||||
}
|
||||
} else {
|
||||
rotatedUsername := username + dayAfterTomorrow.Format("060102")
|
||||
rotatedUsername := username + dayAfterTomorrow.Format(constants.RotationUserDateFormat)
|
||||
if secretUsername != rotatedUsername {
|
||||
t.Errorf("%s: updated secret does not contain correct username: expected %s, got %s", testName, rotatedUsername, secretUsername)
|
||||
}
|
||||
|
||||
@@ -45,14 +45,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
|
||||
@@ -45,14 +45,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
|
||||
@@ -58,6 +58,7 @@ type PgUser struct {
|
||||
AdminRole string `yaml:"admin_role"`
|
||||
IsDbOwner bool `yaml:"is_db_owner"`
|
||||
Deleted bool `yaml:"deleted"`
|
||||
Rotated bool `yaml:"rotated"`
|
||||
}
|
||||
|
||||
func (user *PgUser) Valid() bool {
|
||||
|
||||
@@ -20,4 +20,5 @@ const (
|
||||
WriterRoleNameSuffix = "_writer"
|
||||
UserRoleNameSuffix = "_user"
|
||||
DefaultSearchPath = "\"$user\""
|
||||
RotationUserDateFormat = "060102"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user