mirror of
https://github.com/ansible-collections/community.mysql.git
synced 2025-08-28 08:51:46 -07:00
add option subtract_privs to mysql_role and mysql_user
see https://github.com/ansible-collections/community.mysql/issues/331
This commit is contained in:
parent
641894e6e8
commit
3dc21216cb
3 changed files with 83 additions and 36 deletions
|
@ -169,7 +169,7 @@ def is_hash(password):
|
|||
|
||||
def user_mod(cursor, user, host, host_all, password, encrypted,
|
||||
plugin, plugin_hash_string, plugin_auth_string, new_priv,
|
||||
append_privs, tls_requires, module, role=False, maria_role=False):
|
||||
append_privs, subtract_privs, tls_requires, module, role=False, maria_role=False):
|
||||
changed = False
|
||||
msg = "User unchanged"
|
||||
grant_option = False
|
||||
|
@ -288,47 +288,58 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
|
|||
|
||||
# If the user has privileges on a db.table that doesn't appear at all in
|
||||
# the new specification, then revoke all privileges on it.
|
||||
for db_table, priv in iteritems(curr_priv):
|
||||
# If the user has the GRANT OPTION on a db.table, revoke it first.
|
||||
if "GRANT" in priv:
|
||||
grant_option = True
|
||||
if db_table not in new_priv:
|
||||
if user != "root" and "PROXY" not in priv and not append_privs:
|
||||
msg = "Privileges updated"
|
||||
if module.check_mode:
|
||||
return (True, msg)
|
||||
privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
|
||||
changed = True
|
||||
if not append_privs and not subtract_privs:
|
||||
for db_table, priv in iteritems(curr_priv):
|
||||
# If the user has the GRANT OPTION on a db.table, revoke it first.
|
||||
if "GRANT" in priv:
|
||||
grant_option = True
|
||||
if db_table not in new_priv:
|
||||
if user != "root" and "PROXY" not in priv:
|
||||
msg = "Privileges updated"
|
||||
if module.check_mode:
|
||||
return (True, msg)
|
||||
privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
|
||||
changed = True
|
||||
|
||||
# If the user doesn't currently have any privileges on a db.table, then
|
||||
# we can perform a straight grant operation.
|
||||
for db_table, priv in iteritems(new_priv):
|
||||
if db_table not in curr_priv:
|
||||
msg = "New privileges granted"
|
||||
if module.check_mode:
|
||||
return (True, msg)
|
||||
privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
|
||||
changed = True
|
||||
if not subtract_privs:
|
||||
for db_table, priv in iteritems(new_priv):
|
||||
if db_table not in curr_priv:
|
||||
msg = "New privileges granted"
|
||||
if module.check_mode:
|
||||
return (True, msg)
|
||||
privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
|
||||
changed = True
|
||||
|
||||
# If the db.table specification exists in both the user's current privileges
|
||||
# and in the new privileges, then we need to see if there's a difference.
|
||||
db_table_intersect = set(new_priv.keys()) & set(curr_priv.keys())
|
||||
for db_table in db_table_intersect:
|
||||
|
||||
# If appending privileges, only the set difference between new privileges and current privileges matter.
|
||||
# The symmetric difference isn't relevant for append because existing privileges will not be revoked.
|
||||
grant_privs = []
|
||||
revoke_privs = []
|
||||
if append_privs:
|
||||
priv_diff = set(new_priv[db_table]) - set(curr_priv[db_table])
|
||||
# When appending privileges, only missing privileges need to be granted. Nothing is revoked.
|
||||
grant_privs = list(set(new_priv[db_table]) - set(curr_priv[db_table]))
|
||||
elif subtract_privs:
|
||||
# When subtracting privileges, revoke only the intersection of requested and current privileges.
|
||||
# No privileges are granted.
|
||||
revoke_privs = list(set(new_priv[db_table]) & set(curr_priv[db_table]))
|
||||
else:
|
||||
priv_diff = set(new_priv[db_table]) ^ set(curr_priv[db_table])
|
||||
# When replacing (neither append_privs nor subtract_privs), grant all missing privileges
|
||||
# and revoke existing privileges that were not requested.
|
||||
grant_privs = list(set(new_priv[db_table]) - set(curr_priv[db_table]))
|
||||
revoke_privs = list(set(curr_priv[db_table]) - set(new_priv[db_table]))
|
||||
|
||||
if len(priv_diff) > 0:
|
||||
if len(grant_privs) + len(revoke_privs) > 0:
|
||||
msg = "Privileges updated"
|
||||
if module.check_mode:
|
||||
return (True, msg)
|
||||
if not append_privs:
|
||||
privileges_revoke(cursor, user, host, db_table, curr_priv[db_table], grant_option, maria_role)
|
||||
privileges_grant(cursor, user, host, db_table, new_priv[db_table], tls_requires, maria_role)
|
||||
if len(revoke_privs) > 0:
|
||||
privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option, maria_role)
|
||||
if len(grant_privs) > 0:
|
||||
privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires, maria_role)
|
||||
changed = True
|
||||
|
||||
if role:
|
||||
|
|
|
@ -51,7 +51,14 @@ options:
|
|||
append_privs:
|
||||
description:
|
||||
- Append the privileges defined by the I(priv) option to the existing ones
|
||||
for this role instead of overwriting them.
|
||||
for this role instead of overwriting them. Mutually exclusive with I(subtract_privs).
|
||||
type: bool
|
||||
default: no
|
||||
|
||||
subtract_privs:
|
||||
description:
|
||||
- Revoke the privileges defined by the I(priv) option and keep other existing privileges.
|
||||
Mutually exclusive with I(append_privs).
|
||||
type: bool
|
||||
default: no
|
||||
|
||||
|
@ -233,6 +240,14 @@ EXAMPLES = r'''
|
|||
name: business
|
||||
members:
|
||||
- marketing
|
||||
|
||||
- name: Ensure the role foo does not have the DELETE privilege
|
||||
community.mysql.mysql_role:
|
||||
state: present
|
||||
name: foo
|
||||
subtract_privs: yes
|
||||
priv:
|
||||
'db1.*': DELETE
|
||||
'''
|
||||
|
||||
RETURN = '''#'''
|
||||
|
@ -821,9 +836,9 @@ class Role():
|
|||
return True
|
||||
|
||||
def update(self, users, privs, check_mode=False,
|
||||
append_privs=False, append_members=False,
|
||||
detach_members=False, admin=False,
|
||||
set_default_role_all=True):
|
||||
append_privs=False, subtract_privs=False,
|
||||
append_members=False, detach_members=False,
|
||||
admin=False, set_default_role_all=True):
|
||||
"""Update a role.
|
||||
|
||||
Update a role if needed.
|
||||
|
@ -837,6 +852,8 @@ class Role():
|
|||
check_mode (bool): If True, just checks and does nothing.
|
||||
append_privs (bool): If True, adds new privileges passed through privs
|
||||
not touching current privileges.
|
||||
subtract_privs (bool): If True, revoke the privileges passed through privs
|
||||
not touching other existing privileges.
|
||||
append_members (bool): If True, adds new members passed through users
|
||||
not touching current members.
|
||||
detach_members (bool): If True, removes members passed through users from a role.
|
||||
|
@ -861,7 +878,7 @@ class Role():
|
|||
if privs:
|
||||
changed, msg = user_mod(self.cursor, self.name, self.host,
|
||||
None, None, None, None, None, None,
|
||||
privs, append_privs, None,
|
||||
privs, append_privs, subtract_privs, None,
|
||||
self.module, role=True, maria_role=self.is_mariadb)
|
||||
|
||||
if admin:
|
||||
|
@ -931,6 +948,7 @@ def main():
|
|||
admin=dict(type='str'),
|
||||
priv=dict(type='raw'),
|
||||
append_privs=dict(type='bool', default=False),
|
||||
subtract_privs=dict(type='bool', default=False),
|
||||
members=dict(type='list', elements='str'),
|
||||
append_members=dict(type='bool', default=False),
|
||||
detach_members=dict(type='bool', default=False),
|
||||
|
@ -945,6 +963,7 @@ def main():
|
|||
('admin', 'members'),
|
||||
('admin', 'append_members'),
|
||||
('admin', 'detach_members'),
|
||||
('append_privs', 'subtract_privs'),
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -958,6 +977,7 @@ def main():
|
|||
connect_timeout = module.params['connect_timeout']
|
||||
config_file = module.params['config_file']
|
||||
append_privs = module.params['append_privs']
|
||||
subtract_privs = module.boolean(module.params['subtract_privs'])
|
||||
members = module.params['members']
|
||||
append_members = module.params['append_members']
|
||||
detach_members = module.params['detach_members']
|
||||
|
@ -1047,7 +1067,7 @@ def main():
|
|||
set_default_role_all)
|
||||
|
||||
else:
|
||||
changed = role.update(members, priv, module.check_mode, append_privs,
|
||||
changed = role.update(members, priv, module.check_mode, append_privs, subtract_privs,
|
||||
append_members, detach_members, admin,
|
||||
set_default_role_all)
|
||||
|
||||
|
|
|
@ -63,7 +63,13 @@ options:
|
|||
append_privs:
|
||||
description:
|
||||
- Append the privileges defined by priv to the existing ones for this
|
||||
user instead of overwriting existing ones.
|
||||
user instead of overwriting existing ones. Mutually exclusive with I(subtract_privs).
|
||||
type: bool
|
||||
default: no
|
||||
subtract_privs:
|
||||
description:
|
||||
- Revoke the privileges defined by the I(priv) option and keep other existing privileges.
|
||||
Mutually exclusive with I(append_privs).
|
||||
type: bool
|
||||
default: no
|
||||
tls_requires:
|
||||
|
@ -306,6 +312,13 @@ EXAMPLES = r'''
|
|||
MAX_QUERIES_PER_HOUR: 10
|
||||
MAX_CONNECTIONS_PER_HOUR: 5
|
||||
|
||||
- name: Ensure bob does not have the DELETE privilege
|
||||
community.mysql.mysql_user:
|
||||
name: bob
|
||||
subtract_privs: yes
|
||||
priv:
|
||||
'db1.*': DELETE
|
||||
|
||||
# Example .my.cnf file for setting the root password
|
||||
# [client]
|
||||
# user=root
|
||||
|
@ -352,6 +365,7 @@ def main():
|
|||
priv=dict(type='raw'),
|
||||
tls_requires=dict(type='dict'),
|
||||
append_privs=dict(type='bool', default=False),
|
||||
subtract_privs=dict(type='bool', default=False),
|
||||
check_implicit_admin=dict(type='bool', default=False),
|
||||
update_password=dict(type='str', default='always', choices=['always', 'on_create'], no_log=False),
|
||||
sql_log_bin=dict(type='bool', default=True),
|
||||
|
@ -364,6 +378,7 @@ def main():
|
|||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=(('append_privs', 'subtract_privs'),)
|
||||
)
|
||||
login_user = module.params["login_user"]
|
||||
login_password = module.params["login_password"]
|
||||
|
@ -379,6 +394,7 @@ def main():
|
|||
connect_timeout = module.params["connect_timeout"]
|
||||
config_file = module.params["config_file"]
|
||||
append_privs = module.boolean(module.params["append_privs"])
|
||||
subtract_privs = module.boolean(module.params['subtract_privs'])
|
||||
update_password = module.params['update_password']
|
||||
ssl_cert = module.params["client_cert"]
|
||||
ssl_key = module.params["client_key"]
|
||||
|
@ -435,11 +451,11 @@ def main():
|
|||
if update_password == "always":
|
||||
changed, msg = user_mod(cursor, user, host, host_all, password, encrypted,
|
||||
plugin, plugin_hash_string, plugin_auth_string,
|
||||
priv, append_privs, tls_requires, module)
|
||||
priv, append_privs, subtract_privs, tls_requires, module)
|
||||
else:
|
||||
changed, msg = user_mod(cursor, user, host, host_all, None, encrypted,
|
||||
plugin, plugin_hash_string, plugin_auth_string,
|
||||
priv, append_privs, tls_requires, module)
|
||||
priv, append_privs, subtract_privs, tls_requires, module)
|
||||
|
||||
except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e:
|
||||
module.fail_json(msg=to_native(e))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue