Skip to content

Commit 3d8a411

Browse files
committed
Implement default privileges changes
1 parent 59b18ac commit 3d8a411

File tree

3 files changed

+508
-0
lines changed

3 files changed

+508
-0
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
define postgresql::server::default_privileges (
2+
String $role,
3+
String $db,
4+
String $privilege,
5+
Pattern[
6+
/(?i:^FUNCTIONS$)/,
7+
/(?i:^ROUTINES$)/,
8+
/(?i:^SEQUENCES$)/,
9+
/(?i:^TABLES$)/,
10+
/(?i:^TYPES$)/
11+
] $object_type,
12+
String $schema = 'public',
13+
String $psql_db = $postgresql::server::default_database,
14+
String $psql_user = $postgresql::server::user,
15+
Integer $port = $postgresql::server::port,
16+
Boolean $onlyif_exists = false,
17+
Hash $connect_settings = $postgresql::server::default_connect_settings,
18+
Enum['present',
19+
'absent'
20+
] $ensure = 'present',
21+
String $group = $postgresql::server::group,
22+
String $psql_path = $postgresql::server::psql_path,
23+
) {
24+
25+
# If possible use the version of the remote database, otherwise
26+
# fallback to our local DB version
27+
if $connect_settings != undef and has_key( $connect_settings, 'DBVERSION') {
28+
$version = $connect_settings['DBVERSION']
29+
} else {
30+
$version = $postgresql::server::_version
31+
}
32+
33+
if (versioncmp($version, '9.6') == -1) {
34+
fail 'Default_privileges is only useable with PostgreSQL >= 9.6'
35+
}
36+
37+
case $ensure {
38+
default: {
39+
# default is 'present'
40+
$sql_command = 'ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT %s ON %s TO "%s"'
41+
$unless_is = true
42+
}
43+
'absent': {
44+
$sql_command = 'ALTER DEFAULT PRIVILEGES IN SCHEMA %s REVOKE %s ON %s FROM "%s"'
45+
$unless_is = false
46+
}
47+
}
48+
49+
#
50+
# Port, order of precedence: $port parameter, $connect_settings[PGPORT], $postgresql::server::port
51+
#
52+
if $port != undef {
53+
$port_override = $port
54+
} elsif $connect_settings != undef and has_key( $connect_settings, 'PGPORT') {
55+
$port_override = undef
56+
} else {
57+
$port_override = $postgresql::server::port
58+
}
59+
60+
## Munge the input values
61+
$_object_type = upcase($object_type)
62+
$_privilege = upcase($privilege)
63+
64+
case $_object_type {
65+
# Routines and functions ends up with the same definition
66+
Pattern[
67+
/^ROUTINES$/,
68+
/^FUNCTIONS$/,
69+
]: {
70+
case $_privilege {
71+
Pattern[
72+
/^ALL$/,
73+
/^EXECUTE$/,
74+
]: {
75+
$_check_privilege = 'X'
76+
}
77+
default: { fail('Illegal value for $privilege parameter') }
78+
}
79+
$_check_type = 'f'
80+
}
81+
'SEQUENCES': {
82+
case $_privilege {
83+
/^(ALL)$/: { $_check_privilege = 'rwU' }
84+
/^SELECT$/: { $_check_privilege = 'r'}
85+
/^UPDATE$/: { $_check_privilege = 'w'}
86+
/^USAGE$/: { $_check_privilege = 'U'}
87+
default: { fail('Illegal value for $privilege parameter') }
88+
}
89+
$_check_type = 'S'
90+
}
91+
'TABLES': {
92+
case $_privilege {
93+
/^ALL$/: { $_check_privilege = 'arwdDxt' }
94+
/^DELETE$/: { $_check_privilege = 'd' }
95+
/^INSERT$/: { $_check_privilege = 'a' }
96+
/^REFERENCES$/: { $_check_privilege = 'x' }
97+
/^SELECT$/: { $_check_privilege = 'r' }
98+
/^TRIGGER$/: { $_check_privilege = 'd' }
99+
/^TRUNCATE$/: { $_check_privilege = 'D' }
100+
/^UPDATE$/: { $_check_privilege = 'w' }
101+
default: { fail('Illegal value for $privilege parameter') }
102+
}
103+
$_check_type = 'r'
104+
}
105+
'TYPES': {
106+
case $_privilege {
107+
/^(ALL|USAGE)$/: { $_check_privilege = 'U'}
108+
default: { fail('Illegal value for $privilege parameter') }
109+
}
110+
$_check_type = 'T'
111+
}
112+
default: {
113+
fail("Missing privilege validation for object type ${_object_type}")
114+
}
115+
}
116+
117+
$_unless = $ensure ? {
118+
'absent' => "SELECT 1 WHERE NOT EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s' = ANY (defaclacl) AND nspname = '%s' and defaclobjtype = '%s')",
119+
default => "SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s' = ANY (defaclacl) AND nspname = '%s' and defaclobjtype = '%s')"
120+
}
121+
122+
$unless_cmd = sprintf($_unless, $role, $_check_privilege, $schema, $_check_type)
123+
$grant_cmd = sprintf($sql_command, $schema, $_privilege, $_object_type, $role)
124+
125+
postgresql_psql { "default_privileges:${name}":
126+
command => $grant_cmd,
127+
db => $db,
128+
port => $port_override,
129+
connect_settings => $connect_settings,
130+
psql_user => $psql_user,
131+
psql_group => $group,
132+
psql_path => $psql_path,
133+
unless => $unless_cmd,
134+
environment => "PGOPTIONS=--client-min-messages=error"
135+
}
136+
137+
if($role != undef and defined(Postgresql::Server::Role[$role])) {
138+
Postgresql::Server::Role[$role]->Postgresql_psql["default_privileges:${name}"]
139+
}
140+
141+
if($db != undef and defined(Postgresql::Server::Database[$db])) {
142+
Postgresql::Server::Database[$db]->Postgresql_psql["default_privileges:${name}"]
143+
}
144+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper_acceptance'
4+
5+
describe 'postgresql::server::default_privileges:' do
6+
let(:db) { 'grant_role_test' }
7+
let(:user) { 'psql_grant_role_tester' }
8+
let(:group) { 'test_group' }
9+
let(:password) { 'psql_grant_role_pw' }
10+
11+
# Check that the default privileges were revoked
12+
let(:check_command) do
13+
"SELECT * FROM pg_default_acl a JOIN pg_namespace b ON a.defaclnamespace = b.oid WHERE '#{user}=arwdDxt' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r';"
14+
end
15+
16+
let(:pp_one) do
17+
<<-MANIFEST.unindent
18+
$db = #{db}
19+
$user = #{user}
20+
$group = #{group}
21+
$password = #{password}
22+
23+
class { 'postgresql::server': }
24+
25+
postgresql::server::role { $user:
26+
password_hash => postgresql::postgresql_password($user, $password),
27+
}
28+
29+
postgresql::server::database { $db:
30+
require => Postgresql::Server::Role[$user],
31+
}
32+
33+
# Set default privileges on tables
34+
postgresql::server::default_privileges { "alter default privileges grant all on tables to ${user}":
35+
db => $db,
36+
role => $user,
37+
privilege => 'ALL',
38+
object_type => 'TABLES',
39+
require => Postgresql::Server::Database[$db],
40+
}
41+
MANIFEST
42+
end
43+
let(:pp_two) do
44+
<<-MANIFEST
45+
$db = #{db}
46+
$user = #{user}
47+
$group = #{group}
48+
$password = #{password}
49+
50+
class { 'postgresql::server': }
51+
52+
postgresql::server::role { $user:
53+
password_hash => postgresql::postgresql_password($user, $password),
54+
}
55+
postgresql::server::database { $db:
56+
require => Postgresql::Server::Role[$user],
57+
}
58+
59+
# Removes default privileges on tables
60+
postgresql::server::default_privileges { "alter default privileges revoke all on tables for ${user}":
61+
db => $db,
62+
role => $user,
63+
privilege => 'ALL',
64+
object_type => 'TABLES',
65+
ensure => 'absent',
66+
require => Postgresql::Server::Database[$db],
67+
}
68+
MANIFEST
69+
end
70+
71+
it 'grants default privileges to an user' do
72+
idempotent_apply(pp_one)
73+
74+
psql("--command=\"SET client_min_messages = 'error';#{check_command}\" --db=#{db}") do |r|
75+
expect(r.stdout).to match(%r{\(1 row\)})
76+
expect(r.stderr).to eq('')
77+
end
78+
end
79+
80+
it 'revokes default privileges for an user' do
81+
apply_manifest(pp_one, catch_failures: true)
82+
apply_manifest(pp_two, expect_changes: true)
83+
84+
psql("--command=\"SET client_min_messages = 'error';#{check_command}\" --db=#{db}") do |r|
85+
expect(r.stdout).to match(%r{\(0 rows\)})
86+
expect(r.stderr).to eq('')
87+
end
88+
end
89+
end

0 commit comments

Comments
 (0)