diff --git a/cmd/keeper/cmd/keeper.go b/cmd/keeper/cmd/keeper.go index 27c8ab770..70c91604b 100644 --- a/cmd/keeper/cmd/keeper.go +++ b/cmd/keeper/cmd/keeper.go @@ -1058,6 +1058,7 @@ func (p *PostgresKeeper) postgresKeeperSM(pctx context.Context) { // Generate hba auth from clusterData pgm.SetHba(p.generateHBA(cd, db, p.waitSyncStandbysSynced)) + pgm.SetIdent(db.Spec.PgIdent) var pgParameters common.Parameters @@ -1475,6 +1476,7 @@ func (p *PostgresKeeper) postgresKeeperSM(pctx context.Context) { p.waitSyncStandbysSynced = true log.Infow("not allowing connection as normal users since synchronous replication is enabled and instance was down") pgm.SetHba(p.generateHBA(cd, db, true)) + pgm.SetIdent(db.Spec.PgIdent) } if err = pgm.Start(); err != nil { @@ -1657,6 +1659,15 @@ func (p *PostgresKeeper) postgresKeeperSM(pctx context.Context) { // for tests log.Infow("postgres hba entries not changed") } + newIdent := db.Spec.PgIdent + if !reflect.DeepEqual(newIdent, pgm.CurIdent()) { + log.Infow("postgres ident entries changed, reloading postgres instance") + pgm.SetIdent(newIdent) + needsReload = true + } else { + // for tests + log.Infow("postgres ident entries not changed") + } if needsReload { needsReloadGauge.Set(1) // mark as reload needed diff --git a/cmd/sentinel/cmd/sentinel.go b/cmd/sentinel/cmd/sentinel.go index ede28cd2d..8a19e31c3 100644 --- a/cmd/sentinel/cmd/sentinel.go +++ b/cmd/sentinel/cmd/sentinel.go @@ -381,6 +381,7 @@ func (s *Sentinel) setDBSpecFromClusterSpec(cd *cluster.ClusterData) { db.Spec.UsePgrewind = *clusterSpec.UsePgrewind db.Spec.PGParameters = clusterSpec.PGParameters db.Spec.PGHBA = clusterSpec.PGHBA + db.Spec.PgIdent = clusterSpec.PgIdent if db.Spec.FollowConfig != nil && db.Spec.FollowConfig.Type == cluster.FollowTypeExternal { db.Spec.FollowConfig.StandbySettings = clusterSpec.StandbyConfig.StandbySettings db.Spec.FollowConfig.ArchiveRecoverySettings = clusterSpec.StandbyConfig.ArchiveRecoverySettings diff --git a/cmd/stolonctl/cmd/spec.go b/cmd/stolonctl/cmd/spec.go index d26689038..ebf48c2f6 100644 --- a/cmd/stolonctl/cmd/spec.go +++ b/cmd/stolonctl/cmd/spec.go @@ -19,6 +19,7 @@ import ( cmdcommon "github.com/sorintlab/stolon/cmd" "github.com/sorintlab/stolon/internal/cluster" + "github.com/sorintlab/stolon/internal/postgresql" "github.com/spf13/cobra" ) @@ -69,6 +70,7 @@ type ClusterSpecNoDefaults struct { DefaultSUReplAccessMode *cluster.SUReplAccessMode `json:"defaultSUReplAccessMode,omitempty"` PGParameters cluster.PGParameters `json:"pgParameters,omitempty"` PGHBA []string `json:"pgHBA,omitempty"` + PgIdent postgresql.PgIdent `json:"pgIdent"` AutomaticPgRestart *bool `json:"automaticPgRestart,omitempty"` } @@ -100,6 +102,7 @@ type ClusterSpecDefaults struct { DefaultSUReplAccessMode *cluster.SUReplAccessMode `json:"defaultSUReplAccessMode"` PGParameters cluster.PGParameters `json:"pgParameters"` PGHBA []string `json:"pgHBA"` + PgIdent postgresql.PgIdent `json:"pgIdent"` AutomaticPgRestart *bool `json:"automaticPgRestart"` } diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index 1d60388e5..d26f1e322 100644 --- a/internal/cluster/cluster.go +++ b/internal/cluster/cluster.go @@ -286,6 +286,8 @@ type ClusterSpec struct { // Additional pg_hba.conf entries // we don't set omitempty since we want to distinguish between null or empty slice PGHBA []string `json:"pgHBA"` + // pg_ident.conf entries + PgIdent util.PgIdent `json:"pgIdent"` // Enable automatic pg restart when pg parameters that requires restart changes AutomaticPgRestart *bool `json:"automaticPgRestart"` } @@ -625,6 +627,8 @@ type DBSpec struct { // Additional pg_hba.conf entries // We don't set omitempty since we want to distinguish between null or empty slice PGHBA []string `json:"pgHBA"` + // pg_ident.conf entries + PgIdent util.PgIdent `json:"pgIdent"` // DB Role (master or standby) Role common.Role `json:"role,omitempty"` // FollowConfig when Role is "standby" diff --git a/internal/postgresql/postgresql.go b/internal/postgresql/postgresql.go index 00c14bcd7..b76bc0026 100644 --- a/internal/postgresql/postgresql.go +++ b/internal/postgresql/postgresql.go @@ -59,6 +59,13 @@ var ( var log = slog.S() +type PgIdent map[string][]UserMaps + +type UserMaps struct { + SystemUsername string `json:"systemUsername"` + DBUsername string `json:"databaseUsername"` +} + type PGManager interface { GetTimelinesHistory(timeline uint64) ([]*TimelineHistory, error) } @@ -69,6 +76,8 @@ type Manager struct { parameters common.Parameters recoveryOptions *RecoveryOptions hba []string + ident PgIdent + currentIdent PgIdent curParameters common.Parameters curRecoveryOptions *RecoveryOptions curHba []string @@ -178,10 +187,18 @@ func (p *Manager) SetHba(hba []string) { p.hba = hba } +func (p *Manager) SetIdent(ident PgIdent) { + p.ident = ident +} + func (p *Manager) CurHba() []string { return p.curHba } +func (p *Manager) CurIdent() PgIdent { + return p.currentIdent +} + func (p *Manager) UpdateCurParameters() { n, err := copystructure.Copy(p.parameters) if err != nil { @@ -202,6 +219,14 @@ func (p *Manager) UpdateCurHba() { p.curHba = n.([]string) } +func (p *Manager) UpdateCurIdent() { + n, err := copystructure.Copy(p.ident) + if err != nil { + panic(err) + } + p.currentIdent = n.(PgIdent) +} + func (p *Manager) Init(initConfig *InitConfig) error { // ioutil.Tempfile already creates files with 0600 permissions pwfile, err := ioutil.TempFile("", "pwfile") @@ -374,6 +399,7 @@ func (p *Manager) start(args ...string) error { p.UpdateCurParameters() p.UpdateCurRecoveryOptions() p.UpdateCurHba() + p.UpdateCurIdent() return nil } @@ -438,6 +464,7 @@ func (p *Manager) Reload() error { p.UpdateCurParameters() p.UpdateCurRecoveryOptions() p.UpdateCurHba() + p.UpdateCurIdent() return nil } @@ -767,6 +794,9 @@ func (p *Manager) writeConfs(useTmpPostgresConf bool) error { return fmt.Errorf("error writing %s file: %v", postgresRecoverySignal, err) } } + if err := p.writePgIdent(); err != nil { + return fmt.Errorf("error writing pg_ident.conf file: %v", err) + } return nil } @@ -877,6 +907,25 @@ func (p *Manager) writePgHba() error { }) } +func (p *Manager) writePgIdent() error { + return common.WriteFileAtomicFunc(filepath.Join(p.dataDir, "pg_ident.conf"), 0600, + func(f io.Writer) error { + if p.ident != nil && len(p.ident) > 0 { + if _, err := f.Write([]byte("# MAPNAME\tSYSTEM-USERNAME\tPG-USERNAME" + "\n")); err != nil { + return err + } + for key, value := range p.ident { + for _, v := range value { + if _, err := f.Write([]byte(fmt.Sprintf("%s\t%s\t%s", key, v.SystemUsername, v.DBUsername) + "\n")); err != nil { + return err + } + } + } + } + return nil + }) +} + // createPostgresqlAutoConf creates postgresql.auto.conf as a symlink to // /dev/null to block alter systems commands (they'll return an error) func (p *Manager) createPostgresqlAutoConf() error {