set search_path for default roles
This commit is contained in:
		
							parent
							
								
									375963424d
								
							
						
					
					
						commit
						a315c90e71
					
				|  | @ -15,7 +15,7 @@ spec: | |||
|       serviceAccountName: postgres-operator | ||||
|       containers: | ||||
|       - name: postgres-operator | ||||
|         image: registry.opensource.zalan.do/acid/postgres-operator:v1.5.0 | ||||
|         image: registry.opensource.zalan.do/acid/postgres-operator:v1.5.0-19-g37596342-dirty | ||||
|         imagePullPolicy: IfNotPresent | ||||
|         resources: | ||||
|           requests: | ||||
|  |  | |||
|  | @ -955,32 +955,42 @@ func (c *Cluster) initPreparedDatabaseRoles() error { | |||
| 	} | ||||
| 
 | ||||
| 	for preparedDbName, preparedDB := range c.Spec.PreparedDatabases { | ||||
| 		// get list of prepared schemas to set in search_path
 | ||||
| 		preparedSchemas := preparedDB.PreparedSchemas | ||||
| 		if len(preparedDB.PreparedSchemas) == 0 { | ||||
| 			preparedSchemas = map[string]acidv1.PreparedSchema{"data": {DefaultRoles: util.True()}} | ||||
| 		} | ||||
| 
 | ||||
| 		var searchPath strings.Builder | ||||
| 		searchPath.WriteString(constants.DefaultSearchPath) | ||||
| 		for preparedSchemaName := range preparedSchemas { | ||||
| 			searchPath.WriteString(", " + preparedSchemaName) | ||||
| 		} | ||||
| 
 | ||||
| 		// default roles per database
 | ||||
| 		if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName); err != nil { | ||||
| 		if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String()); err != nil { | ||||
| 			return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err) | ||||
| 		} | ||||
| 		if preparedDB.DefaultUsers { | ||||
| 			if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName); err != nil { | ||||
| 			if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String()); err != nil { | ||||
| 				return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// default roles per database schema
 | ||||
| 		preparedSchemas := preparedDB.PreparedSchemas | ||||
| 		if len(preparedDB.PreparedSchemas) == 0 { | ||||
| 			preparedSchemas = map[string]acidv1.PreparedSchema{"data": {DefaultRoles: util.True()}} | ||||
| 		} | ||||
| 		for preparedSchemaName, preparedSchema := range preparedSchemas { | ||||
| 			if preparedSchema.DefaultRoles == nil || *preparedSchema.DefaultRoles { | ||||
| 				if err := c.initDefaultRoles(defaultRoles, | ||||
| 					preparedDbName+constants.OwnerRoleNameSuffix, | ||||
| 					preparedDbName+"_"+preparedSchemaName); err != nil { | ||||
| 					preparedDbName+"_"+preparedSchemaName, | ||||
| 					constants.DefaultSearchPath+", "+preparedSchemaName); err != nil { | ||||
| 					return fmt.Errorf("could not initialize default roles for database schema %s: %v", preparedSchemaName, err) | ||||
| 				} | ||||
| 				if preparedSchema.DefaultUsers { | ||||
| 					if err := c.initDefaultRoles(defaultUsers, | ||||
| 						preparedDbName+constants.OwnerRoleNameSuffix, | ||||
| 						preparedDbName+"_"+preparedSchemaName); err != nil { | ||||
| 						preparedDbName+"_"+preparedSchemaName, | ||||
| 						constants.DefaultSearchPath+", "+preparedSchemaName); err != nil { | ||||
| 						return fmt.Errorf("could not initialize default users for database schema %s: %v", preparedSchemaName, err) | ||||
| 					} | ||||
| 				} | ||||
|  | @ -990,7 +1000,7 @@ func (c *Cluster) initPreparedDatabaseRoles() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix string) error { | ||||
| func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix string, searchPath string) error { | ||||
| 
 | ||||
| 	for defaultRole, inherits := range defaultRoles { | ||||
| 
 | ||||
|  | @ -1014,12 +1024,13 @@ func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix | |||
| 		} | ||||
| 
 | ||||
| 		newRole := spec.PgUser{ | ||||
| 			Origin:    spec.RoleOriginBootstrap, | ||||
| 			Name:      roleName, | ||||
| 			Password:  util.RandomPassword(constants.PasswordLength), | ||||
| 			Flags:     flags, | ||||
| 			MemberOf:  memberOf, | ||||
| 			AdminRole: adminRole, | ||||
| 			Origin:     spec.RoleOriginBootstrap, | ||||
| 			Name:       roleName, | ||||
| 			Password:   util.RandomPassword(constants.PasswordLength), | ||||
| 			Flags:      flags, | ||||
| 			MemberOf:   memberOf, | ||||
| 			Parameters: map[string]string{"search_path": searchPath}, | ||||
| 			AdminRole:  adminRole, | ||||
| 		} | ||||
| 		if currentRole, present := c.pgUsers[roleName]; present { | ||||
| 			c.pgUsers[roleName] = c.resolveNameConflict(¤tRole, &newRole) | ||||
|  |  | |||
|  | @ -2,20 +2,21 @@ package constants | |||
| 
 | ||||
| // Roles specific constants
 | ||||
| const ( | ||||
| 	PasswordLength            = 64 | ||||
| 	SuperuserKeyName          = "superuser" | ||||
| 	PasswordLength              = 64 | ||||
| 	SuperuserKeyName            = "superuser" | ||||
| 	ConnectionPoolerUserKeyName = "pooler" | ||||
| 	ReplicationUserKeyName    = "replication" | ||||
| 	RoleFlagSuperuser         = "SUPERUSER" | ||||
| 	RoleFlagInherit           = "INHERIT" | ||||
| 	RoleFlagLogin             = "LOGIN" | ||||
| 	RoleFlagNoLogin           = "NOLOGIN" | ||||
| 	RoleFlagCreateRole        = "CREATEROLE" | ||||
| 	RoleFlagCreateDB          = "CREATEDB" | ||||
| 	RoleFlagReplication       = "REPLICATION" | ||||
| 	RoleFlagByPassRLS         = "BYPASSRLS" | ||||
| 	OwnerRoleNameSuffix       = "_owner" | ||||
| 	ReaderRoleNameSuffix      = "_reader" | ||||
| 	WriterRoleNameSuffix      = "_writer" | ||||
| 	UserRoleNameSuffix        = "_user" | ||||
| 	ReplicationUserKeyName      = "replication" | ||||
| 	RoleFlagSuperuser           = "SUPERUSER" | ||||
| 	RoleFlagInherit             = "INHERIT" | ||||
| 	RoleFlagLogin               = "LOGIN" | ||||
| 	RoleFlagNoLogin             = "NOLOGIN" | ||||
| 	RoleFlagCreateRole          = "CREATEROLE" | ||||
| 	RoleFlagCreateDB            = "CREATEDB" | ||||
| 	RoleFlagReplication         = "REPLICATION" | ||||
| 	RoleFlagByPassRLS           = "BYPASSRLS" | ||||
| 	OwnerRoleNameSuffix         = "_owner" | ||||
| 	ReaderRoleNameSuffix        = "_reader" | ||||
| 	WriterRoleNameSuffix        = "_writer" | ||||
| 	UserRoleNameSuffix          = "_user" | ||||
| 	DefaultSearchPath           = "\"$user\"" | ||||
| ) | ||||
|  |  | |||
|  | @ -113,14 +113,14 @@ func (strategy DefaultUserSyncStrategy) ExecuteSyncRequests(requests []spec.PgSy | |||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| func (strategy DefaultUserSyncStrategy) alterPgUserSet(user spec.PgUser, db *sql.DB) (err error) { | ||||
| 
 | ||||
| func (strategy DefaultUserSyncStrategy) alterPgUserSet(user spec.PgUser, db *sql.DB) error { | ||||
| 	queries := produceAlterRoleSetStmts(user) | ||||
| 	query := fmt.Sprintf(doBlockStmt, strings.Join(queries, ";")) | ||||
| 	if _, err = db.Exec(query); err != nil { | ||||
| 		err = fmt.Errorf("dB error: %v, query: %s", err, query) | ||||
| 		return | ||||
| 	if _, err := db.Exec(query); err != nil { | ||||
| 		return fmt.Errorf("dB error: %v, query: %s", err, query) | ||||
| 	} | ||||
| 	return | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (strategy DefaultUserSyncStrategy) createPgUser(user spec.PgUser, db *sql.DB) error { | ||||
|  | @ -148,6 +148,12 @@ func (strategy DefaultUserSyncStrategy) createPgUser(user spec.PgUser, db *sql.D | |||
| 		return fmt.Errorf("dB error: %v, query: %s", err, query) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(user.Parameters) > 0 { | ||||
| 		if err := strategy.alterPgUserSet(user, db); err != nil { | ||||
| 			return fmt.Errorf("incomplete setup for user %s: %v", user.Name, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue