Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d97743e
rename db roles that are removed from manifests
FxKu Apr 14, 2021
f3f389c
check systemUsers not normal pgUsers
FxKu Apr 14, 2021
45a6c46
revert some changes
FxKu Apr 14, 2021
2efea31
add special case for pooler role
FxKu Apr 15, 2021
7164adb
rename only team users using a cache
FxKu Apr 15, 2021
be6a3cf
rename re-addedwq roles
FxKu Apr 16, 2021
f18cc49
extend PostgresTeam e2e test
FxKu Apr 16, 2021
5eac3e8
reflect code review
FxKu Apr 21, 2021
eb20c58
no pgUsers check needed when filling cache
FxKu Apr 21, 2021
1e2dbe4
make suffix configurable and add deprecated field to pgUser struct
FxKu Apr 23, 2021
c4e05d9
add Deprecated field in e2e test
FxKu Apr 23, 2021
635c81e
Merge branch 'master' into rename-removed-roles
FxKu May 11, 2021
e75f5b5
revert change in cluster_test
FxKu May 11, 2021
869502e
deny LOGIN from deprecated roles
FxKu May 12, 2021
c342558
add unit test for StringSliceReplaceElement
FxKu May 12, 2021
4b96ab8
wait just 5s longer for sync
FxKu May 12, 2021
cc27740
retry role query in e2e test and do not wait
FxKu May 12, 2021
044e92a
update feature documentation
FxKu May 14, 2021
8d58ceb
rename suffix and pgUser field
FxKu May 17, 2021
92e6dcf
Merge branch 'master' into rename-removed-roles
FxKu May 17, 2021
b3d30e0
fix e2e test
FxKu May 17, 2021
d326456
report correct number of found additional members
FxKu May 17, 2021
fb38bf7
added more comments and error out if teams api is unavailable
FxKu May 20, 2021
3fa3ab1
disable team member deprecation by default
FxKu May 20, 2021
1ce1e0c
minor fix
FxKu May 20, 2021
37ac851
some aligning in values.yaml files for teamAPI section
FxKu May 20, 2021
3972a33
minor change
FxKu May 20, 2021
1f87100
add exmaples to manifests
FxKu May 20, 2021
32d60f9
fixing config.go
FxKu May 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions charts/postgres-operator/crds/operatorconfigurations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ spec:
enable_postgres_team_crd_superusers:
type: boolean
default: false
enable_team_member_deprecation:
type: boolean
default: false
enable_team_superuser:
type: boolean
default: false
Expand All @@ -465,6 +468,9 @@ spec:
type: string
default:
- admin
role_deletion_suffix:
type: string
default: "_deleted"
team_admin_role:
type: string
default: "admin"
Expand Down
15 changes: 8 additions & 7 deletions charts/postgres-operator/values-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,13 @@ configLogicalBackup:
# automate creation of human users with teams API service
configTeamsApi:
# team_admin_role will have the rights to grant roles coming from PG manifests
# enable_admin_role_for_users: true

enable_admin_role_for_users: true
# operator watches for PostgresTeam CRs to assign additional teams and members to clusters
enable_postgres_team_crd: false
# toogle to create additional superuser teams from PostgresTeam CRs
# enable_postgres_team_crd_superusers: false

enable_postgres_team_crd_superusers: false
# toggle to automatically rename roles of former team members and deny LOGIN
enable_team_member_deprecation: false
# toggle to grant superuser to team members created from the Teams API
enable_team_superuser: false
# toggles usage of the Teams API by the operator
Expand All @@ -306,12 +306,13 @@ configTeamsApi:
# operator will add all team member roles to this group and add a pg_hba line
pam_role_name: zalandos
# List of teams which members need the superuser role in each Postgres cluster
# postgres_superuser_teams:
# - postgres_superusers

postgres_superuser_teams:
- postgres_superusers
# List of roles that cannot be overwritten by an application, team or infrastructure role
protected_role_names:
- admin
# Suffix to add if members are removed from TeamsAPI or PostgresTeam CRD
role_deletion_suffix: "_deleted"
# role name to grant to team members created from the Teams API
team_admin_role: admin
# postgres config parameters to apply to each team member role
Expand Down
28 changes: 12 additions & 16 deletions charts/postgres-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -280,36 +280,32 @@ configLogicalBackup:
# automate creation of human users with teams API service
configTeamsApi:
# team_admin_role will have the rights to grant roles coming from PG manifests
# enable_admin_role_for_users: "true"

enable_admin_role_for_users: "true"
# operator watches for PostgresTeam CRs to assign additional teams and members to clusters
enable_postgres_team_crd: "false"
# toogle to create additional superuser teams from PostgresTeam CRs
# enable_postgres_team_crd_superusers: "false"

enable_postgres_team_crd_superusers: "false"
# toggle to automatically rename roles of former team members and deny LOGIN
enable_team_member_deprecation: "false"
# toggle to grant superuser to team members created from the Teams API
# enable_team_superuser: "false"

enable_team_superuser: "false"
# toggles usage of the Teams API by the operator
enable_teams_api: "false"
# should contain a URL to use for authentication (username and token)
# pam_configuration: https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees

# operator will add all team member roles to this group and add a pg_hba line
# pam_role_name: zalandos

pam_role_name: "zalandos"
# List of teams which members need the superuser role in each Postgres cluster
# postgres_superuser_teams: "postgres_superusers"

postgres_superuser_teams: "postgres_superusers"
# List of roles that cannot be overwritten by an application, team or infrastructure role
# protected_role_names: "admin"

protected_role_names: "admin"
# Suffix to add if members are removed from TeamsAPI or PostgresTeam CRD
role_deletion_suffix: "_deleted"
# role name to grant to team members created from the Teams API
# team_admin_role: "admin"

team_admin_role: "admin"
# postgres config parameters to apply to each team member role
# team_api_role_configuration: "log_statement:all"

team_api_role_configuration: "log_statement:all"
# URL of the Teams API service
# teams_api_url: http://fake-teams-api.default.svc.cluster.local

Expand Down
13 changes: 13 additions & 0 deletions docs/reference/operator_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,19 @@ key.
cluster to administer Postgres and maintain infrastructure built around it.
The default is empty.

* **role_deletion_suffix**
defines a suffix that - when `enable_team_member_deprecation` is set to
`true` - will be appended to database role names of team members that were
removed from either the team in the Teams API or a `PostgresTeam` custom
resource (additionalMembers). When re-added, the operator will rename roles
with the defined suffix back to the original role name.
The default is `_deleted`.

* **enable_team_member_deprecation**
if `true` database roles of former team members will be renamed by appending
the configured `role_deletion_suffix` and `LOGIN` privilege will be revoked.
The default is `false`.

* **enable_postgres_team_crd**
toggle to make the operator watch for created or updated `PostgresTeam` CRDs
and create roles for specified additional teams and members.
Expand Down
17 changes: 17 additions & 0 deletions docs/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,23 @@ spec:
- "briggs"
```

#### Removed members

The Postgres Operator does not delete database roles when users are removed
from manifests. But, using the `PostgresTeam` custom resource or Teams API it
is very easy to add roles to many clusters. Manually reverting such a change
is cumbersome. Therefore, if members are removed from a `PostgresTeam` or the
Teams API the operator can rename roles appending a configured suffix to the
name (see `role_deletion_suffix` option) and revoke the `LOGIN` privilege.
The suffix makes it easy then for a cleanup script to remove those deprecated
roles completely. Switch `enable_team_member_deprecation` to `true` to enable
this behavior.

When a role is re-added to a `PostgresTeam` manifest (or to the source behind
the Teams API) the operator will check for roles with the configured suffix
and if found, rename the role back to the original name and grant `LOGIN`
again.

## Prepared databases with roles and default privileges

The `users` section in the manifests only allows for creating database roles
Expand Down
75 changes: 60 additions & 15 deletions e2e/tests/test_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,15 @@ def test_additional_teams_and_members(self):
enable_postgres_team_crd = {
"data": {
"enable_postgres_team_crd": "true",
"resync_period": "15s",
"enable_team_member_deprecation": "true",
"role_deletion_suffix": "_delete_me",
"resync_period": "15s"
},
}
self.k8s.update_config(enable_postgres_team_crd)
self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"},
"Operator does not get in sync")

self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
'acid.zalan.do', 'v1', 'default',
'postgresteams', 'custom-team-membership',
Expand All @@ -222,18 +224,60 @@ def test_additional_teams_and_members(self):
}
})

# make sure we let one sync pass and the new user being added
time.sleep(15)

leader = self.k8s.get_cluster_leader_pod()
user_query = """
SELECT usename
FROM pg_catalog.pg_user
WHERE usename IN ('elephant', 'kind');
SELECT rolname
FROM pg_catalog.pg_roles
WHERE rolname IN ('elephant', 'kind');
"""
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
"Not all additional users found in database", 10, 5)

# replace additional member and check if the removed member's role is renamed
self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
'acid.zalan.do', 'v1', 'default',
'postgresteams', 'custom-team-membership',
{
'spec': {
'additionalMembers': {
'e2e': [
'tester'
]
},
}
})

user_query = """
SELECT rolname
FROM pg_catalog.pg_roles
WHERE (rolname = 'tester' AND rolcanlogin)
OR (rolname = 'kind_delete_me' AND NOT rolcanlogin);
"""
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
"Database role of replaced member in PostgresTeam not renamed", 10, 5)

# re-add additional member and check if the role is renamed back
self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
'acid.zalan.do', 'v1', 'default',
'postgresteams', 'custom-team-membership',
{
'spec': {
'additionalMembers': {
'e2e': [
'kind'
]
},
}
})

user_query = """
SELECT rolname
FROM pg_catalog.pg_roles
WHERE (rolname = 'kind' AND rolcanlogin)
OR (rolname = 'tester_delete_me' AND NOT rolcanlogin);
"""
users = self.query_database(leader.metadata.name, "postgres", user_query)
self.eventuallyEqual(lambda: len(users), 2,
"Not all additional users found in database: {}".format(users))
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
"Database role of recreated member in PostgresTeam not renamed back to original name", 10, 5)

# revert config change
revert_resync = {
Expand Down Expand Up @@ -407,9 +451,9 @@ def test_enable_disable_connection_pooler(self):

leader = k8s.get_cluster_leader_pod()
schemas_query = """
select schema_name
from information_schema.schemata
where schema_name = 'pooler'
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name = 'pooler'
"""

db_list = self.list_databases(leader.metadata.name)
Expand Down Expand Up @@ -529,6 +573,7 @@ def verify_role():
"Parameters": None,
"AdminRole": "",
"Origin": 2,
"Deleted": False
})
return True
except:
Expand Down Expand Up @@ -1417,7 +1462,7 @@ def list_databases(self, pod_name):
k8s = self.k8s
result_set = []
db_list = []
db_list_query = "select datname from pg_database"
db_list_query = "SELECT datname FROM pg_database"
exec_query = r"psql -tAq -c \"{}\" -d {}"

try:
Expand Down
2 changes: 2 additions & 0 deletions manifests/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ data:
# enable_shm_volume: "true"
# enable_sidecars: "true"
enable_spilo_wal_path_compat: "true"
enable_team_member_deprecation: "false"
# enable_team_superuser: "false"
enable_teams_api: "false"
# etcd_host: ""
Expand Down Expand Up @@ -111,6 +112,7 @@ data:
resource_check_timeout: 10m
resync_period: 30m
ring_log_lines: "100"
role_deletion_suffix: "_deleted"
secret_name_template: "{username}.{cluster}.credentials"
# sidecar_docker_images: ""
# set_memory_request_to_limit: "false"
Expand Down
6 changes: 6 additions & 0 deletions manifests/operatorconfiguration.crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ spec:
enable_postgres_team_crd_superusers:
type: boolean
default: false
enable_team_member_deprecation:
type: boolean
default: false
enable_team_superuser:
type: boolean
default: false
Expand All @@ -461,6 +464,9 @@ spec:
type: string
default:
- admin
role_deletion_suffix:
type: string
default: "_deleted"
team_admin_role:
type: string
default: "admin"
Expand Down
2 changes: 2 additions & 0 deletions manifests/postgresql-operator-default-configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ configuration:
# enable_admin_role_for_users: true
# enable_postgres_team_crd: false
# enable_postgres_team_crd_superusers: false
enable_team_member_deprecation: false
enable_team_superuser: false
enable_teams_api: false
# pam_configuration: ""
Expand All @@ -149,6 +150,7 @@ configuration:
# - postgres_superusers
protected_role_names:
- admin
role_deletion_suffix: "_deleted"
team_admin_role: admin
team_api_role_configuration:
log_statement: all
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/acid.zalan.do/v1/crds.go
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
"enable_postgres_team_crd_superusers": {
Type: "boolean",
},
"enable_team_member_deprecation": {
Type: "boolean",
},
"enable_team_superuser": {
Type: "boolean",
},
Expand Down Expand Up @@ -1405,6 +1408,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
},
},
},
"role_deletion_suffix": {
Type: "string",
},
"team_admin_role": {
Type: "string",
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/acid.zalan.do/v1/operator_configuration_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ type TeamsAPIConfiguration struct {
PostgresSuperuserTeams []string `json:"postgres_superuser_teams,omitempty"`
EnablePostgresTeamCRD bool `json:"enable_postgres_team_crd,omitempty"`
EnablePostgresTeamCRDSuperusers bool `json:"enable_postgres_team_crd_superusers,omitempty"`
EnableTeamMemberDeprecation bool `json:"enable_team_member_deprecation,omitempty"`
RoleDeletionSuffix string `json:"role_deletion_suffix,omitempty"`
}

// LoggingRESTAPIConfiguration defines Logging API conf
Expand Down
18 changes: 16 additions & 2 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type Cluster struct {
eventRecorder record.EventRecorder
patroni patroni.Interface
pgUsers map[string]spec.PgUser
pgUsersCache map[string]spec.PgUser
systemUsers map[string]spec.PgUser
podSubscribers map[spec.NamespacedName]chan PodEvent
podSubscribersMu sync.RWMutex
Expand Down Expand Up @@ -129,7 +130,9 @@ func New(cfg Config, kubeClient k8sutil.KubernetesClient, pgSpec acidv1.Postgres
Secrets: make(map[types.UID]*v1.Secret),
Services: make(map[PostgresRole]*v1.Service),
Endpoints: make(map[PostgresRole]*v1.Endpoints)},
userSyncStrategy: users.DefaultUserSyncStrategy{PasswordEncryption: passwordEncryption},
userSyncStrategy: users.DefaultUserSyncStrategy{
PasswordEncryption: passwordEncryption,
RoleDeletionSuffix: cfg.OpConfig.RoleDeletionSuffix},
deleteOptions: metav1.DeleteOptions{PropagationPolicy: &deletePropagationPolicy},
podEventsQueue: podEventsQueue,
KubeClient: kubeClient,
Expand Down Expand Up @@ -190,6 +193,17 @@ func (c *Cluster) isNewCluster() bool {
func (c *Cluster) initUsers() error {
c.setProcessName("initializing users")

// if team member deprecation is enabled save current state of pgUsers
// to check for deleted roles
c.pgUsersCache = map[string]spec.PgUser{}
if c.OpConfig.EnableTeamMemberDeprecation {
for k, v := range c.pgUsers {
if v.Origin == spec.RoleOriginTeamsAPI {
c.pgUsersCache[k] = v
}
}
}

// clear our the previous state of the cluster users (in case we are
// running a sync).
c.systemUsers = map[string]spec.PgUser{}
Expand Down Expand Up @@ -650,7 +664,7 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error {
needConnectionPooler := needMasterConnectionPoolerWorker(&newSpec.Spec) ||
needReplicaConnectionPoolerWorker(&newSpec.Spec)
if !sameUsers || needConnectionPooler {
c.logger.Debugf("syncing secrets")
c.logger.Debugf("initialize users")
if err := c.initUsers(); err != nil {
c.logger.Errorf("could not init users: %v", err)
updateFailed = true
Expand Down
Loading