mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
sudorule: Add support for 'hostmask' parameter
The hostmask parameter allows matching a sudorule against a network
address, and was missing from ipasudorule module.
Documentation and tests were updated to reflect changes.
Two new example playbooks are available:
playbooks/sudorule/ensure-sudorule-hostmask-member-is-absent.yml
playbooks/sudorule/ensure-sudorule-hostmask-member-is-present.yml
This commit is contained in:
@@ -129,6 +129,7 @@ Variable | Description | Required
|
|||||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||||
`host` | List of host name strings assigned to this sudorule. | no
|
`host` | List of host name strings assigned to this sudorule. | no
|
||||||
`hostgroup` | List of host group name strings assigned to this sudorule. | no
|
`hostgroup` | List of host group name strings assigned to this sudorule. | no
|
||||||
|
`hostmask` | List of host masks of allowed hosts | no
|
||||||
`user` | List of user name strings assigned to this sudorule. | no
|
`user` | List of user name strings assigned to this sudorule. | no
|
||||||
`group` | List of user group name strings assigned to this sudorule. | no
|
`group` | List of user group name strings assigned to this sudorule. | no
|
||||||
`allow_sudocmd` | List of sudocmd name strings assigned to the allow group of this sudorule. | no
|
`allow_sudocmd` | List of sudocmd name strings assigned to the allow group of this sudorule. | no
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
- name: Playbook to manage sudorule
|
||||||
|
hosts: ipaserver
|
||||||
|
become: no
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure hostmask network is absent in sudorule
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule1
|
||||||
|
hostmask: 192.168.122.37/24
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- name: Playbook to manage sudorule
|
||||||
|
hosts: ipaserver
|
||||||
|
become: no
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure hostmask network is present in sudorule
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule1
|
||||||
|
hostmask: 192.168.122.37/24
|
||||||
|
action: member
|
||||||
@@ -143,6 +143,11 @@ options:
|
|||||||
required: false
|
required: false
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
elements: str
|
||||||
|
hostmask:
|
||||||
|
description: Host masks of allowed hosts.
|
||||||
|
required: false
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
action:
|
action:
|
||||||
description: Work on sudorule or member level
|
description: Work on sudorule or member level
|
||||||
type: str
|
type: str
|
||||||
@@ -202,6 +207,15 @@ EXAMPLES = """
|
|||||||
hostcategory: all
|
hostcategory: all
|
||||||
state: enabled
|
state: enabled
|
||||||
|
|
||||||
|
# Ensure sudo rule applies for hosts with hostmasks
|
||||||
|
- ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule1
|
||||||
|
hostmask:
|
||||||
|
- 192.168.122.1/24
|
||||||
|
- 192.168.120.1/24
|
||||||
|
action: member
|
||||||
|
|
||||||
# Ensure Sudo Rule tesrule1 is absent
|
# Ensure Sudo Rule tesrule1 is absent
|
||||||
- ipasudorule:
|
- ipasudorule:
|
||||||
ipaadmin_password: SomeADMINpassword
|
ipaadmin_password: SomeADMINpassword
|
||||||
@@ -214,7 +228,7 @@ RETURN = """
|
|||||||
|
|
||||||
from ansible.module_utils.ansible_freeipa_module import \
|
from ansible.module_utils.ansible_freeipa_module import \
|
||||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
||||||
gen_intersection_list, api_get_domain, ensure_fqdn
|
gen_intersection_list, api_get_domain, ensure_fqdn, netaddr, to_text
|
||||||
|
|
||||||
|
|
||||||
def find_sudorule(module, name):
|
def find_sudorule(module, name):
|
||||||
@@ -275,6 +289,8 @@ def main():
|
|||||||
default=None),
|
default=None),
|
||||||
hostgroup=dict(required=False, type='list', elements="str",
|
hostgroup=dict(required=False, type='list', elements="str",
|
||||||
default=None),
|
default=None),
|
||||||
|
hostmask=dict(required=False, type='list', elements="str",
|
||||||
|
default=None),
|
||||||
user=dict(required=False, type='list', elements="str",
|
user=dict(required=False, type='list', elements="str",
|
||||||
default=None),
|
default=None),
|
||||||
group=dict(required=False, type='list', elements="str",
|
group=dict(required=False, type='list', elements="str",
|
||||||
@@ -334,6 +350,7 @@ def main():
|
|||||||
nomembers = ansible_module.params_get("nomembers") # noqa
|
nomembers = ansible_module.params_get("nomembers") # noqa
|
||||||
host = ansible_module.params_get("host")
|
host = ansible_module.params_get("host")
|
||||||
hostgroup = ansible_module.params_get_lowercase("hostgroup")
|
hostgroup = ansible_module.params_get_lowercase("hostgroup")
|
||||||
|
hostmask = ansible_module.params_get("hostmask")
|
||||||
user = ansible_module.params_get_lowercase("user")
|
user = ansible_module.params_get_lowercase("user")
|
||||||
group = ansible_module.params_get_lowercase("group")
|
group = ansible_module.params_get_lowercase("group")
|
||||||
allow_sudocmd = ansible_module.params_get('allow_sudocmd')
|
allow_sudocmd = ansible_module.params_get('allow_sudocmd')
|
||||||
@@ -351,6 +368,10 @@ def main():
|
|||||||
# state
|
# state
|
||||||
state = ansible_module.params_get("state")
|
state = ansible_module.params_get("state")
|
||||||
|
|
||||||
|
# ensure hostmasks are network cidr
|
||||||
|
if hostmask is not None:
|
||||||
|
hostmask = [to_text(netaddr.IPNetwork(x).cidr) for x in hostmask]
|
||||||
|
|
||||||
# Check parameters
|
# Check parameters
|
||||||
invalid = []
|
invalid = []
|
||||||
|
|
||||||
@@ -382,7 +403,7 @@ def main():
|
|||||||
"cmdcategory", "runasusercategory",
|
"cmdcategory", "runasusercategory",
|
||||||
"runasgroupcategory", "nomembers", "order"]
|
"runasgroupcategory", "nomembers", "order"]
|
||||||
if action == "sudorule":
|
if action == "sudorule":
|
||||||
invalid.extend(["host", "hostgroup", "user", "group",
|
invalid.extend(["host", "hostgroup", "hostmask", "user", "group",
|
||||||
"runasuser", "runasgroup", "allow_sudocmd",
|
"runasuser", "runasgroup", "allow_sudocmd",
|
||||||
"allow_sudocmdgroup", "deny_sudocmd",
|
"allow_sudocmdgroup", "deny_sudocmd",
|
||||||
"deny_sudocmdgroup", "sudooption"])
|
"deny_sudocmdgroup", "sudooption"])
|
||||||
@@ -396,7 +417,7 @@ def main():
|
|||||||
"disabled")
|
"disabled")
|
||||||
invalid = ["description", "usercategory", "hostcategory",
|
invalid = ["description", "usercategory", "hostcategory",
|
||||||
"cmdcategory", "runasusercategory", "runasgroupcategory",
|
"cmdcategory", "runasusercategory", "runasgroupcategory",
|
||||||
"nomembers", "nomembers", "host", "hostgroup",
|
"nomembers", "nomembers", "host", "hostgroup", "hostmask",
|
||||||
"user", "group", "allow_sudocmd", "allow_sudocmdgroup",
|
"user", "group", "allow_sudocmd", "allow_sudocmdgroup",
|
||||||
"deny_sudocmd", "deny_sudocmdgroup", "runasuser",
|
"deny_sudocmd", "deny_sudocmdgroup", "runasuser",
|
||||||
"runasgroup", "order", "sudooption"]
|
"runasgroup", "order", "sudooption"]
|
||||||
@@ -425,6 +446,7 @@ def main():
|
|||||||
user_add, user_del = [], []
|
user_add, user_del = [], []
|
||||||
group_add, group_del = [], []
|
group_add, group_del = [], []
|
||||||
hostgroup_add, hostgroup_del = [], []
|
hostgroup_add, hostgroup_del = [], []
|
||||||
|
hostmask_add, hostmask_del = [], []
|
||||||
allow_cmd_add, allow_cmd_del = [], []
|
allow_cmd_add, allow_cmd_del = [], []
|
||||||
allow_cmdgroup_add, allow_cmdgroup_del = [], []
|
allow_cmdgroup_add, allow_cmdgroup_del = [], []
|
||||||
deny_cmd_add, deny_cmd_del = [], []
|
deny_cmd_add, deny_cmd_del = [], []
|
||||||
@@ -490,6 +512,9 @@ def main():
|
|||||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||||
hostgroup, res_find.get('memberhost_hostgroup', []))
|
hostgroup, res_find.get('memberhost_hostgroup', []))
|
||||||
|
|
||||||
|
hostmask_add, hostmask_del = gen_add_del_lists(
|
||||||
|
hostmask, res_find.get('hostmask', []))
|
||||||
|
|
||||||
user_add, user_del = gen_add_del_lists(
|
user_add, user_del = gen_add_del_lists(
|
||||||
user, res_find.get('memberuser_user', []))
|
user, res_find.get('memberuser_user', []))
|
||||||
|
|
||||||
@@ -556,6 +581,9 @@ def main():
|
|||||||
if hostgroup is not None:
|
if hostgroup is not None:
|
||||||
hostgroup_add = gen_add_list(
|
hostgroup_add = gen_add_list(
|
||||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||||
|
if hostmask is not None:
|
||||||
|
hostmask_add = gen_add_list(
|
||||||
|
hostmask, res_find.get("hostmask"))
|
||||||
if user is not None:
|
if user is not None:
|
||||||
user_add = gen_add_list(
|
user_add = gen_add_list(
|
||||||
user, res_find.get("memberuser_user"))
|
user, res_find.get("memberuser_user"))
|
||||||
@@ -628,6 +656,10 @@ def main():
|
|||||||
hostgroup_del = gen_intersection_list(
|
hostgroup_del = gen_intersection_list(
|
||||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||||
|
|
||||||
|
if hostmask is not None:
|
||||||
|
hostmask_del = gen_intersection_list(
|
||||||
|
hostmask, res_find.get("hostmask"))
|
||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
user_del = gen_intersection_list(
|
user_del = gen_intersection_list(
|
||||||
user, res_find.get("memberuser_user"))
|
user, res_find.get("memberuser_user"))
|
||||||
@@ -719,18 +751,19 @@ def main():
|
|||||||
|
|
||||||
# Manage members.
|
# Manage members.
|
||||||
# Manage hosts and hostgroups
|
# Manage hosts and hostgroups
|
||||||
if host_add or hostgroup_add:
|
if any([host_add, hostgroup_add, hostmask_add]):
|
||||||
commands.append([name, "sudorule_add_host",
|
params = {"host": host_add, "hostgroup": hostgroup_add}
|
||||||
{
|
# An empty Hostmask cannot be used, or IPA API will fail.
|
||||||
"host": host_add,
|
if hostmask_add:
|
||||||
"hostgroup": hostgroup_add,
|
params["hostmask"] = hostmask_add
|
||||||
}])
|
commands.append([name, "sudorule_add_host", params])
|
||||||
if host_del or hostgroup_del:
|
|
||||||
commands.append([name, "sudorule_remove_host",
|
if any([host_del, hostgroup_del, hostmask_del]):
|
||||||
{
|
params = {"host": host_del, "hostgroup": hostgroup_del}
|
||||||
"host": host_del,
|
# An empty Hostmask cannot be used, or IPA API will fail.
|
||||||
"hostgroup": hostgroup_del,
|
if hostmask_del:
|
||||||
}])
|
params["hostmask"] = hostmask_del
|
||||||
|
commands.append([name, "sudorule_remove_host", params])
|
||||||
|
|
||||||
# Manage users and groups
|
# Manage users and groups
|
||||||
if user_add or group_add:
|
if user_add or group_add:
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
name:
|
name:
|
||||||
- test_upstream_issue_664
|
- test_upstream_issue_664
|
||||||
|
- testrule_hostmask
|
||||||
- testrule1
|
- testrule1
|
||||||
- allusers
|
- allusers
|
||||||
- allhosts
|
- allhosts
|
||||||
@@ -1005,6 +1006,116 @@
|
|||||||
register: result
|
register: result
|
||||||
failed_when: not result.changed or result.failed
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule is present with hostmask
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask:
|
||||||
|
- 192.168.122.1/24
|
||||||
|
- 192.168.120.1/24
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule is present with hostmask, again
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask:
|
||||||
|
- 192.168.122.1/24
|
||||||
|
- 192.168.120.1/24
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is absent
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.122.0/24
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is absent, again
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.122.0/24
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule is present with another hostmask
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.122.0/24
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule is present with another hostmask, again
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.122.0/24
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed
|
||||||
|
|
||||||
|
- name: Check sudorule with hostmask is absent
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.120.0/24
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
check_mode: yes
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is present
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.120.0/24
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is present, again
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.120.0/24
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is absent
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.120.0/24
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed or result.failed
|
||||||
|
|
||||||
|
- name: Ensure sudorule hostmask member is absent, again
|
||||||
|
ipasudorule:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||||
|
name: testrule_hostmask
|
||||||
|
hostmask: 192.168.120.0/24
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed or result.failed
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
- name: Ensure sudocmdgroup is absent
|
- name: Ensure sudocmdgroup is absent
|
||||||
ipasudocmdgroup:
|
ipasudocmdgroup:
|
||||||
@@ -1013,6 +1124,7 @@
|
|||||||
name:
|
name:
|
||||||
- test_sudorule
|
- test_sudorule
|
||||||
- test_sudorule2
|
- test_sudorule2
|
||||||
|
- testrule_hostmask
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Ensure sudocmds are absent
|
- name: Ensure sudocmds are absent
|
||||||
|
|||||||
Reference in New Issue
Block a user