Skip to content

Commit a1f2bd0

Browse files
authored
Prevent superuser from being a connection pool user (zalando#906)
* Protected and system users can't be a connection pool user It's not supported, neither it's a best practice. Also fix potential null pointer access. For protected users it makes sense by intent of protecting this users (e.g. from being overriden or used as something else than supposed). For system users the reason is the same as for superuser, it's about replicastion user and it's under patroni control. This is implemented on both levels, operator config and postgresql manifest. For the latter we just use default name in this case, assuming that operator config is always correct. For the former, since it's a serious misconfiguration, operator panics.
1 parent 7232326 commit a1f2bd0

File tree

5 files changed

+64
-3
lines changed

5 files changed

+64
-3
lines changed

pkg/cluster/cluster.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -877,9 +877,20 @@ func (c *Cluster) initSystemUsers() {
877877
c.Spec.ConnectionPooler = &acidv1.ConnectionPooler{}
878878
}
879879

880-
username := util.Coalesce(
881-
c.Spec.ConnectionPooler.User,
882-
c.OpConfig.ConnectionPooler.User)
880+
// Using superuser as pooler user is not a good idea. First of all it's
881+
// not going to be synced correctly with the current implementation,
882+
// and second it's a bad practice.
883+
username := c.OpConfig.ConnectionPooler.User
884+
885+
isSuperUser := c.Spec.ConnectionPooler.User == c.OpConfig.SuperUsername
886+
isProtectedUser := c.shouldAvoidProtectedOrSystemRole(
887+
c.Spec.ConnectionPooler.User, "connection pool role")
888+
889+
if !isSuperUser && !isProtectedUser {
890+
username = util.Coalesce(
891+
c.Spec.ConnectionPooler.User,
892+
c.OpConfig.ConnectionPooler.User)
893+
}
883894

884895
// connection pooler application should be able to login with this role
885896
connectionPoolerUser := spec.PgUser{

pkg/cluster/cluster_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,4 +721,38 @@ func TestInitSystemUsers(t *testing.T) {
721721
if _, exist := cl.systemUsers[constants.ConnectionPoolerUserKeyName]; !exist {
722722
t.Errorf("%s, connection pooler user is not present", testName)
723723
}
724+
725+
// superuser is not allowed as connection pool user
726+
cl.Spec.ConnectionPooler = &acidv1.ConnectionPooler{
727+
User: "postgres",
728+
}
729+
cl.OpConfig.SuperUsername = "postgres"
730+
cl.OpConfig.ConnectionPooler.User = "pooler"
731+
732+
cl.initSystemUsers()
733+
if _, exist := cl.pgUsers["pooler"]; !exist {
734+
t.Errorf("%s, Superuser is not allowed to be a connection pool user", testName)
735+
}
736+
737+
// neither protected users are
738+
delete(cl.pgUsers, "pooler")
739+
cl.Spec.ConnectionPooler = &acidv1.ConnectionPooler{
740+
User: "admin",
741+
}
742+
cl.OpConfig.ProtectedRoles = []string{"admin"}
743+
744+
cl.initSystemUsers()
745+
if _, exist := cl.pgUsers["pooler"]; !exist {
746+
t.Errorf("%s, Protected user are not allowed to be a connection pool user", testName)
747+
}
748+
749+
delete(cl.pgUsers, "pooler")
750+
cl.Spec.ConnectionPooler = &acidv1.ConnectionPooler{
751+
User: "standby",
752+
}
753+
754+
cl.initSystemUsers()
755+
if _, exist := cl.pgUsers["pooler"]; !exist {
756+
t.Errorf("%s, System users are not allowed to be a connection pool user", testName)
757+
}
724758
}

pkg/cluster/resources.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ func (c *Cluster) createConnectionPooler(lookup InstallFunction) (*ConnectionPoo
105105
var msg string
106106
c.setProcessName("creating connection pooler")
107107

108+
if c.ConnectionPooler == nil {
109+
c.ConnectionPooler = &ConnectionPoolerObjects{}
110+
}
111+
108112
schema := c.Spec.ConnectionPooler.Schema
113+
109114
if schema == "" {
110115
schema = c.OpConfig.ConnectionPooler.Schema
111116
}

pkg/controller/operator_config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
169169
fromCRD.ConnectionPooler.User,
170170
constants.ConnectionPoolerUserName)
171171

172+
if result.ConnectionPooler.User == result.SuperUsername {
173+
msg := "Connection pool user is not allowed to be the same as super user, username: %s"
174+
panic(fmt.Errorf(msg, result.ConnectionPooler.User))
175+
}
176+
172177
result.ConnectionPooler.Image = util.Coalesce(
173178
fromCRD.ConnectionPooler.Image,
174179
"registry.opensource.zalan.do/acid/pgbouncer")

pkg/util/config/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,5 +218,11 @@ func validate(cfg *Config) (err error) {
218218
msg := "number of connection pooler instances should be higher than %d"
219219
err = fmt.Errorf(msg, constants.ConnectionPoolerMinInstances)
220220
}
221+
222+
if cfg.ConnectionPooler.User == cfg.SuperUsername {
223+
msg := "Connection pool user is not allowed to be the same as super user, username: %s"
224+
err = fmt.Errorf(msg, cfg.ConnectionPooler.User)
225+
}
226+
221227
return
222228
}

0 commit comments

Comments
 (0)