Skip to content

Commit eeb59c5

Browse files
authored
Rename roles that are removed from PostgresTeam CRD (zalando#1457)
* rename db roles that are removed from manifests * extend PostgresTeam e2e test * make suffix configurable and add deprecated field to pgUser struct * deny LOGIN from deprecated roles * update feature documentation
1 parent 7a8dc60 commit eeb59c5

File tree

22 files changed

+262
-49
lines changed

22 files changed

+262
-49
lines changed

charts/postgres-operator/crds/operatorconfigurations.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,9 @@ spec:
443443
enable_postgres_team_crd_superusers:
444444
type: boolean
445445
default: false
446+
enable_team_member_deprecation:
447+
type: boolean
448+
default: false
446449
enable_team_superuser:
447450
type: boolean
448451
default: false
@@ -465,6 +468,9 @@ spec:
465468
type: string
466469
default:
467470
- admin
471+
role_deletion_suffix:
472+
type: string
473+
default: "_deleted"
468474
team_admin_role:
469475
type: string
470476
default: "admin"

charts/postgres-operator/values-crd.yaml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,13 @@ configLogicalBackup:
289289
# automate creation of human users with teams API service
290290
configTeamsApi:
291291
# team_admin_role will have the rights to grant roles coming from PG manifests
292-
# enable_admin_role_for_users: true
293-
292+
enable_admin_role_for_users: true
294293
# operator watches for PostgresTeam CRs to assign additional teams and members to clusters
295294
enable_postgres_team_crd: false
296295
# toogle to create additional superuser teams from PostgresTeam CRs
297-
# enable_postgres_team_crd_superusers: false
298-
296+
enable_postgres_team_crd_superusers: false
297+
# toggle to automatically rename roles of former team members and deny LOGIN
298+
enable_team_member_deprecation: false
299299
# toggle to grant superuser to team members created from the Teams API
300300
enable_team_superuser: false
301301
# toggles usage of the Teams API by the operator
@@ -306,12 +306,13 @@ configTeamsApi:
306306
# operator will add all team member roles to this group and add a pg_hba line
307307
pam_role_name: zalandos
308308
# List of teams which members need the superuser role in each Postgres cluster
309-
# postgres_superuser_teams:
310-
# - postgres_superusers
311-
309+
postgres_superuser_teams:
310+
- postgres_superusers
312311
# List of roles that cannot be overwritten by an application, team or infrastructure role
313312
protected_role_names:
314313
- admin
314+
# Suffix to add if members are removed from TeamsAPI or PostgresTeam CRD
315+
role_deletion_suffix: "_deleted"
315316
# role name to grant to team members created from the Teams API
316317
team_admin_role: admin
317318
# postgres config parameters to apply to each team member role

charts/postgres-operator/values.yaml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -280,36 +280,32 @@ configLogicalBackup:
280280
# automate creation of human users with teams API service
281281
configTeamsApi:
282282
# team_admin_role will have the rights to grant roles coming from PG manifests
283-
# enable_admin_role_for_users: "true"
284-
283+
enable_admin_role_for_users: "true"
285284
# operator watches for PostgresTeam CRs to assign additional teams and members to clusters
286285
enable_postgres_team_crd: "false"
287286
# toogle to create additional superuser teams from PostgresTeam CRs
288-
# enable_postgres_team_crd_superusers: "false"
289-
287+
enable_postgres_team_crd_superusers: "false"
288+
# toggle to automatically rename roles of former team members and deny LOGIN
289+
enable_team_member_deprecation: "false"
290290
# toggle to grant superuser to team members created from the Teams API
291-
# enable_team_superuser: "false"
292-
291+
enable_team_superuser: "false"
293292
# toggles usage of the Teams API by the operator
294293
enable_teams_api: "false"
295294
# should contain a URL to use for authentication (username and token)
296295
# pam_configuration: https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees
297296

298297
# operator will add all team member roles to this group and add a pg_hba line
299-
# pam_role_name: zalandos
300-
298+
pam_role_name: "zalandos"
301299
# List of teams which members need the superuser role in each Postgres cluster
302-
# postgres_superuser_teams: "postgres_superusers"
303-
300+
postgres_superuser_teams: "postgres_superusers"
304301
# List of roles that cannot be overwritten by an application, team or infrastructure role
305-
# protected_role_names: "admin"
306-
302+
protected_role_names: "admin"
303+
# Suffix to add if members are removed from TeamsAPI or PostgresTeam CRD
304+
role_deletion_suffix: "_deleted"
307305
# role name to grant to team members created from the Teams API
308-
# team_admin_role: "admin"
309-
306+
team_admin_role: "admin"
310307
# postgres config parameters to apply to each team member role
311-
# team_api_role_configuration: "log_statement:all"
312-
308+
team_api_role_configuration: "log_statement:all"
313309
# URL of the Teams API service
314310
# teams_api_url: http://fake-teams-api.default.svc.cluster.local
315311

docs/reference/operator_parameters.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,19 @@ key.
704704
cluster to administer Postgres and maintain infrastructure built around it.
705705
The default is empty.
706706

707+
* **role_deletion_suffix**
708+
defines a suffix that - when `enable_team_member_deprecation` is set to
709+
`true` - will be appended to database role names of team members that were
710+
removed from either the team in the Teams API or a `PostgresTeam` custom
711+
resource (additionalMembers). When re-added, the operator will rename roles
712+
with the defined suffix back to the original role name.
713+
The default is `_deleted`.
714+
715+
* **enable_team_member_deprecation**
716+
if `true` database roles of former team members will be renamed by appending
717+
the configured `role_deletion_suffix` and `LOGIN` privilege will be revoked.
718+
The default is `false`.
719+
707720
* **enable_postgres_team_crd**
708721
toggle to make the operator watch for created or updated `PostgresTeam` CRDs
709722
and create roles for specified additional teams and members.

docs/user.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,23 @@ spec:
407407
- "briggs"
408408
```
409409

410+
#### Removed members
411+
412+
The Postgres Operator does not delete database roles when users are removed
413+
from manifests. But, using the `PostgresTeam` custom resource or Teams API it
414+
is very easy to add roles to many clusters. Manually reverting such a change
415+
is cumbersome. Therefore, if members are removed from a `PostgresTeam` or the
416+
Teams API the operator can rename roles appending a configured suffix to the
417+
name (see `role_deletion_suffix` option) and revoke the `LOGIN` privilege.
418+
The suffix makes it easy then for a cleanup script to remove those deprecated
419+
roles completely. Switch `enable_team_member_deprecation` to `true` to enable
420+
this behavior.
421+
422+
When a role is re-added to a `PostgresTeam` manifest (or to the source behind
423+
the Teams API) the operator will check for roles with the configured suffix
424+
and if found, rename the role back to the original name and grant `LOGIN`
425+
again.
426+
410427
## Prepared databases with roles and default privileges
411428

412429
The `users` section in the manifests only allows for creating database roles

e2e/tests/test_e2e.py

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,15 @@ def test_additional_teams_and_members(self):
197197
enable_postgres_team_crd = {
198198
"data": {
199199
"enable_postgres_team_crd": "true",
200-
"resync_period": "15s",
200+
"enable_team_member_deprecation": "true",
201+
"role_deletion_suffix": "_delete_me",
202+
"resync_period": "15s"
201203
},
202204
}
203205
self.k8s.update_config(enable_postgres_team_crd)
204206
self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"},
205207
"Operator does not get in sync")
206-
208+
207209
self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
208210
'acid.zalan.do', 'v1', 'default',
209211
'postgresteams', 'custom-team-membership',
@@ -222,18 +224,60 @@ def test_additional_teams_and_members(self):
222224
}
223225
})
224226

225-
# make sure we let one sync pass and the new user being added
226-
time.sleep(15)
227-
228227
leader = self.k8s.get_cluster_leader_pod()
229228
user_query = """
230-
SELECT usename
231-
FROM pg_catalog.pg_user
232-
WHERE usename IN ('elephant', 'kind');
229+
SELECT rolname
230+
FROM pg_catalog.pg_roles
231+
WHERE rolname IN ('elephant', 'kind');
232+
"""
233+
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
234+
"Not all additional users found in database", 10, 5)
235+
236+
# replace additional member and check if the removed member's role is renamed
237+
self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
238+
'acid.zalan.do', 'v1', 'default',
239+
'postgresteams', 'custom-team-membership',
240+
{
241+
'spec': {
242+
'additionalMembers': {
243+
'e2e': [
244+
'tester'
245+
]
246+
},
247+
}
248+
})
249+
250+
user_query = """
251+
SELECT rolname
252+
FROM pg_catalog.pg_roles
253+
WHERE (rolname = 'tester' AND rolcanlogin)
254+
OR (rolname = 'kind_delete_me' AND NOT rolcanlogin);
255+
"""
256+
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
257+
"Database role of replaced member in PostgresTeam not renamed", 10, 5)
258+
259+
# re-add additional member and check if the role is renamed back
260+
self.k8s.api.custom_objects_api.patch_namespaced_custom_object(
261+
'acid.zalan.do', 'v1', 'default',
262+
'postgresteams', 'custom-team-membership',
263+
{
264+
'spec': {
265+
'additionalMembers': {
266+
'e2e': [
267+
'kind'
268+
]
269+
},
270+
}
271+
})
272+
273+
user_query = """
274+
SELECT rolname
275+
FROM pg_catalog.pg_roles
276+
WHERE (rolname = 'kind' AND rolcanlogin)
277+
OR (rolname = 'tester_delete_me' AND NOT rolcanlogin);
233278
"""
234-
users = self.query_database(leader.metadata.name, "postgres", user_query)
235-
self.eventuallyEqual(lambda: len(users), 2,
236-
"Not all additional users found in database: {}".format(users))
279+
self.eventuallyEqual(lambda: len(self.query_database(leader.metadata.name, "postgres", user_query)), 2,
280+
"Database role of recreated member in PostgresTeam not renamed back to original name", 10, 5)
237281

238282
# revert config change
239283
revert_resync = {
@@ -407,9 +451,9 @@ def test_enable_disable_connection_pooler(self):
407451

408452
leader = k8s.get_cluster_leader_pod()
409453
schemas_query = """
410-
select schema_name
411-
from information_schema.schemata
412-
where schema_name = 'pooler'
454+
SELECT schema_name
455+
FROM information_schema.schemata
456+
WHERE schema_name = 'pooler'
413457
"""
414458

415459
db_list = self.list_databases(leader.metadata.name)
@@ -529,6 +573,7 @@ def verify_role():
529573
"Parameters": None,
530574
"AdminRole": "",
531575
"Origin": 2,
576+
"Deleted": False
532577
})
533578
return True
534579
except:
@@ -1417,7 +1462,7 @@ def list_databases(self, pod_name):
14171462
k8s = self.k8s
14181463
result_set = []
14191464
db_list = []
1420-
db_list_query = "select datname from pg_database"
1465+
db_list_query = "SELECT datname FROM pg_database"
14211466
exec_query = r"psql -tAq -c \"{}\" -d {}"
14221467

14231468
try:

manifests/configmap.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ data:
5151
# enable_shm_volume: "true"
5252
# enable_sidecars: "true"
5353
enable_spilo_wal_path_compat: "true"
54+
enable_team_member_deprecation: "false"
5455
# enable_team_superuser: "false"
5556
enable_teams_api: "false"
5657
# etcd_host: ""
@@ -111,6 +112,7 @@ data:
111112
resource_check_timeout: 10m
112113
resync_period: 30m
113114
ring_log_lines: "100"
115+
role_deletion_suffix: "_deleted"
114116
secret_name_template: "{username}.{cluster}.credentials"
115117
# sidecar_docker_images: ""
116118
# set_memory_request_to_limit: "false"

manifests/operatorconfiguration.crd.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,9 @@ spec:
439439
enable_postgres_team_crd_superusers:
440440
type: boolean
441441
default: false
442+
enable_team_member_deprecation:
443+
type: boolean
444+
default: false
442445
enable_team_superuser:
443446
type: boolean
444447
default: false
@@ -461,6 +464,9 @@ spec:
461464
type: string
462465
default:
463466
- admin
467+
role_deletion_suffix:
468+
type: string
469+
default: "_deleted"
464470
team_admin_role:
465471
type: string
466472
default: "admin"

manifests/postgresql-operator-default-configuration.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ configuration:
141141
# enable_admin_role_for_users: true
142142
# enable_postgres_team_crd: false
143143
# enable_postgres_team_crd_superusers: false
144+
enable_team_member_deprecation: false
144145
enable_team_superuser: false
145146
enable_teams_api: false
146147
# pam_configuration: ""
@@ -149,6 +150,7 @@ configuration:
149150
# - postgres_superusers
150151
protected_role_names:
151152
- admin
153+
role_deletion_suffix: "_deleted"
152154
team_admin_role: admin
153155
team_api_role_configuration:
154156
log_statement: all

pkg/apis/acid.zalan.do/v1/crds.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
13771377
"enable_postgres_team_crd_superusers": {
13781378
Type: "boolean",
13791379
},
1380+
"enable_team_member_deprecation": {
1381+
Type: "boolean",
1382+
},
13801383
"enable_team_superuser": {
13811384
Type: "boolean",
13821385
},
@@ -1405,6 +1408,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
14051408
},
14061409
},
14071410
},
1411+
"role_deletion_suffix": {
1412+
Type: "string",
1413+
},
14081414
"team_admin_role": {
14091415
Type: "string",
14101416
},

0 commit comments

Comments
 (0)