Skip to content
Snippets Groups Projects
Commit 4fa06211 authored by Rafael Guterres Jeffman's avatar Rafael Guterres Jeffman
Browse files

ipasudorule: Add support for batch mode and multiple sudorules

Currently, ipasudorule must add or modify a single sudorule at a time,
incurring in more load in the server if there are many rules to be
processed.

This patch adds suport for adding multiple sudorules in one playbook
task by using the parameter 'sudorules' and defining a list of sudorules
configurations to be ensured.

As multiple sudorules will be processed, the patch also enables batch
mode processing of sudorules, trying to reduce the load on the server.

Test 'tests/sudorule/test_sudorule_client_context.yml' was modified to
include tasks with 'sudorules' to be executed both on the server or on
the client context.

New tests were added to the sudorule test suite:

    tests/sudorule/test_sudorules.yml
    tests/sudorule/test_sudorules_member_case_insensitive.yml
parent da775a21
Branches
Tags
No related merge requests found
...@@ -129,6 +129,49 @@ Example playbook to make sure Sudo Rule is absent: ...@@ -129,6 +129,49 @@ Example playbook to make sure Sudo Rule is absent:
state: absent state: absent
``` ```
Example playbook to ensure multiple Sudo Rule are present using batch mode:
```yaml
---
- name: Playbook to handle sudorules
hosts: ipaserver
become: true
- name: Ensure multiple Sudo Rules are present using batch mode.
ipasudorule:
ipaadmin_password: SomeADMINpassword
sudorules:
- name: testrule1
hostmask:
- 192.168.122.1/24
- name: testrule2
hostcategory: all
```
Example playbook to ensure multiple Sudo Rule members are present using batch mode:
```yaml
---
- name: Playbook to handle sudorules
hosts: ipaserver
become: true
- name: Ensure multiple Sudo Rules are present using batch mode.
ipasudorule:
ipaadmin_password: SomeADMINpassword
action: member
sudorules:
- name: testrule1
user:
- user01
- user02
group:
- group01
- name: testrule2
hostgroup:
- hostgroup01
- hostgroup02
```
Variables Variables
========= =========
...@@ -139,7 +182,9 @@ Variable | Description | Required ...@@ -139,7 +182,9 @@ Variable | Description | Required
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no `ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no `ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no `ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
`name` \| `cn` | The list of sudorule name strings. | yes `name` \| `cn` | The list of sudorule name strings. | no
`sudorules` | The list of sudorule dicts. Each `sudorule` dict entry can contain sudorule variables.<br>There is one required option in the `sudorule` dict:| no
&nbsp; | `name` - The sudorule name string of the entry. | yes
`description` | The sudorule description string. | no `description` | The sudorule description string. | no
`usercategory` \| `usercat` | User category the rule applies to. Choices: ["all", ""] | no `usercategory` \| `usercat` | User category the rule applies to. Choices: ["all", ""] | no
`hostcategory` \| `hostcat` | Host category the rule applies to. Choices: ["all", ""] | no `hostcategory` \| `hostcat` | Host category the rule applies to. Choices: ["all", ""] | no
......
This diff is collapsed.
...@@ -37,3 +37,15 @@ ...@@ -37,3 +37,15 @@
when: groups['ipaclients'] is not defined or not groups['ipaclients'] when: groups['ipaclients'] is not defined or not groups['ipaclients']
vars: vars:
ipa_context: client ipa_context: client
- name: Test sudorule using client context, in client host.
ansible.builtin.import_playbook: test_sudorules.yml
when: groups['ipaclients']
vars:
ipa_test_host: ipaclients
- name: Test sudorule using client context, in server host.
ansible.builtin.import_playbook: test_sudorules.yml
when: groups['ipaclients'] is not defined or not groups['ipaclients']
vars:
ipa_context: client
---
- name: Test sudorule
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: false
gather_facts: true # required for ansible_facts['fqdn']
module_defaults:
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipahostgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudocmdgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudocmd:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudorule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
tasks:
# setup
- name: Ensure ansible facts for DNS are available
ansible.builtin.setup:
gather_subset: dns
- name: Ensure test users are absent
ipauser:
name:
- user01
- user02
state: absent
- name: Ensure test groups are absent
ipagroup:
name:
- group01
- group02
state: absent
- name: Ensure test hostgroup is absent
ipahostgroup:
name: cluster
state: absent
- name: Ensure test users are present
ipauser:
users:
- name: user01
first: user
last: zeroone
- name: user02
first: user
last: zerotwo
- name: Ensure groups are present
ipagroup:
groups:
- name: group01
user: user01
- name: group02
- name: Ensure sudocmdgroup is absent
ipasudocmdgroup:
name: test_sudorule_cmdgroup
state: absent
- name: Ensure hostgroup is present, with a host.
ipahostgroup:
name: cluster
host: "{{ ansible_facts['fqdn'] }}"
- name: Ensure some sudocmds are available
ipasudocmd:
name:
- /sbin/ifconfig
- /usr/bin/vim
- /usr/bin/emacs
state: present
- name: Ensure sudocmdgroup is available
ipasudocmdgroup:
name: test_sudorule_cmdgroup
sudocmd: /usr/bin/vim
state: present
- name: Ensure another sudocmdgroup is available
ipasudocmdgroup:
name: test_sudorule_cmdgroup_2
sudocmd: /usr/bin/emacs
state: present
- name: Ensure sudorules are absent
ipasudorule:
name:
- testrule1
- testrule2
- allusers
- allhosts
- allcommands
state: absent
# tests
- name: Run sudorules tests.
block:
- name: Ensure sudorules are present
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
- name: allhosts
- name: allcommands
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules are present, again
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
- name: allhosts
- name: allcommands
register: result
failed_when: result.changed or result.failed
- name: Ensure testrule1 and testrule2 are absent
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure testrule1 and testrule2 are absent, again
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure allhosts and allcommands sudorules are still present
ipasudorule:
sudorules:
- name: allhosts
- name: allcomands
state: absent
check_mode: true
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules with parameters are present
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- name: testrule2
runasuser_group:
- group01
state: present
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules with parameters are present, again
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- name: testrule2
runasuser_group:
- group01
state: present
register: result
failed_when: result.changed or result.failed
- name: Ensure sudorules with parameters are modified
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user02
- name: testrule2
runasuser_group:
- group02
state: present
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules with parameters are modified again
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user02
- name: testrule2
runasuser_group:
- group02
state: present
register: result
failed_when: result.changed or result.failed
- name: Ensure sudorules members can be modified
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- name: testrule2
runasuser_group:
- group01
action: member
state: present
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules members can modified, again
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- user02
- name: testrule2
runasuser_group:
- group01
- group02
action: member
state: present
register: result
failed_when: result.changed or result.failed
- name: Ensure sudorules members are absent
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- name: testrule2
runasuser_group:
- group02
action: member
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure sudorules members are absent, again
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user01
- name: testrule2
runasuser_group:
- group02
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure testrule1 and testrule2 are present, with proper attributes
ipasudorule:
sudorules:
- name: testrule1
runasuser:
- user02
- name: testrule2
runasuser_group:
- group01
state: present
register: result
failed_when: result.changed or result.failed
- name: Ensure testrule1 and testrule2 are disabled
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: disabled
register: result
failed_when: not result.changed or result.failed
- name: Ensure testrule1 and testrule2 are disabled, again
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: disabled
register: result
failed_when: result.changed or result.failed
- name: Ensure testrule1 and testrule2 are enabled
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: enabled
register: result
failed_when: not result.changed or result.failed
- name: Ensure testrule1 and testrule2 are enabled, again
ipasudorule:
sudorules:
- name: testrule1
- name: testrule2
state: enabled
register: result
failed_when: result.changed or result.failed
- name: Ensure multiple sudorules cannot be enabled with invalid parameters
ipasudorule:
sudorules:
- name: testrule1
runasuser: user01
- name: testrule2
runasuser: user01
state: enabled
register: result
failed_when: not result.failed and "Argument 'runasuser' can not be used with action 'sudorule' and state 'enabled'" not in result.msg
- name: Ensure multiple sudorules cannot be disabled with invalid parameters
ipasudorule:
sudorules:
- name: testrule1
runasuser: user01
- name: testrule2
runasuser: user01
state: disabled
register: result
failed_when: not result.failed and "Argument 'runasuser' can not be used with action 'sudorule' and state 'disabled'" not in result.msg
# cleanup
always:
- name: Cleanup sudorules
ipasudorule:
name:
- testrule1
- testrule2
- allusers
- allhosts
- allcommands
state: absent
- name: Ensure sudocmdgroup is absent
ipasudocmdgroup:
name:
- test_sudorule_cmdgroup
- test_sudorule_cmdgroup_2
state: absent
- name: Ensure sudocmds are absent
ipasudocmd:
name:
- /sbin/ifconfig
- /usr/bin/vim
- /usr/bin/emacs
state: absent
- name: Ensure hostgroup is absent.
ipahostgroup:
name: cluster
state: absent
- name: Ensure groups are absent
ipagroup:
name: group01,group02
state: absent
- name: Ensure user is absent
ipauser:
name: user01,user02
state: absent
---
- name: Test sudorules members should be case insensitive.
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: false
gather_facts: false
module_defaults:
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipahostgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudocmdgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudocmd:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
ipasudorule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
vars:
groups_present:
- eleMENT1
- Element2
- eLeMenT3
- ElemENT4
tasks:
- name: Test sudorule member case insensitive
block:
# SETUP
- name: Ensure domain name
ansible.builtin.set_fact:
ipa_domain: ipa.test
when: ipa_domain is not defined
- name: Ensure test groups are absent.
ipagroup:
name: "{{ groups_present }}"
state: absent
- name: Ensure test hostgroups are absent.
ipahostgroup:
name: "{{ groups_present }}"
state: absent
- name: Ensure test users are absent.
ipauser:
name: "{{ groups_present }}"
state: absent
- name: Ensure test groups exist.
ipagroup:
name: "{{ item }}"
loop: "{{ groups_present }}"
- name: Ensure test hostgroups exist.
ipahostgroup:
name: "{{ item }}"
loop: "{{ groups_present }}"
- name: Ensure test hosts exist.
ipahost:
name: "{{ item }}.{{ ipa_domain }}"
force: yes
loop: "{{ groups_present }}"
- name: Ensure test users exist.
ipauser:
name: "user{{ item }}"
first: "{{ item }}"
last: "{{ item }}"
loop: "{{ groups_present }}"
- name: Ensure sudorule do not exist
ipasudorule:
sudorules:
- name: "{{ item }}"
state: absent
loop: "{{ groups_present }}"
# TESTS
- name: Ensure sudorule exist with runasusers members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasuser: "user{{ item }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or not result.changed
- name: Ensure sudorule exist with lowercase runasusers members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasuser: "user{{ item | lower }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule exist with uppercase runasusers members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasuser: "user{{ item | upper }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule exist with runasgroup members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasgroup: "{{ item }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or not result.changed
- name: Ensure sudorule exist with lowercase runasgroup members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasgroup: "{{ item | lower }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule exist with uppercase runasgroup members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
runasgroup: "{{ item | upper }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule do not exist
ipasudorule:
sudorules:
- name: "{{ item }}"
state: absent
loop: "{{ groups_present }}"
#####
- name: Ensure sudorule exist with members
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
hostgroup: "{{ item }}"
host: "{{ item }}.{{ ipa_domain }}"
group: "{{ item }}"
user: "user{{ item }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or not result.changed
- name: Ensure sudorule exist with members, lowercase
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
hostgroup: "{{ item | lower }}"
host: "{{ item | lower }}.{{ ipa_domain }}"
group: "{{ item | lower }}"
user: "user{{ item | lower }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule exist with members, uppercase
ipasudorule:
sudorules:
- name: "{{ item }}"
cmdcategory: all
hostgroup: "{{ item | upper }}"
host: "{{ item | upper }}.{{ ipa_domain }}"
group: "{{ item | upper }}"
user: "user{{ item | upper }}"
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule member is absent
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item }}"
host: "{{ item }}.{{ ipa_domain }}"
group: "{{ item }}"
user: "user{{ item }}"
action: member
state: absent
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or not result.changed
- name: Ensure sudorule member is absent, lowercase
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item | lower }}"
host: "{{ item | lower }}.{{ ipa_domain }}"
group: "{{ item | lower }}"
user: "user{{ item | lower }}"
action: member
state: absent
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule member is absent, upercase
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item | upper }}"
host: "{{ item | upper }}.{{ ipa_domain }}"
group: "{{ item | upper }}"
user: "user{{ item | upper }}"
action: member
state: absent
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule member is present, upercase
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item | upper }}"
host: "{{ item | upper }}.{{ ipa_domain }}"
group: "{{ item | upper }}"
user: "user{{ item | upper }}"
action: member
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or not result.changed
- name: Ensure sudorule member is present, lowercase
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item | lower }}"
host: "{{ item | lower }}.{{ ipa_domain }}"
group: "{{ item | lower }}"
user: "user{{ item | lower }}"
action: member
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
- name: Ensure sudorule member is present, mixed case
ipasudorule:
sudorules:
- name: "{{ item }}"
hostgroup: "{{ item }}"
host: "{{ item }}.{{ ipa_domain }}"
group: "{{ item }}"
user: "user{{ item }}"
action: member
loop: "{{ groups_present }}"
register: result
failed_when: result.failed or result.changed
# cleanup
always:
- name: Ensure sudorule do not exist
ipasudorule:
name: "{{ item }}"
state: absent
loop: "{{ groups_present }}"
- name: Ensure test groups do not exist.
ipagroup:
name: "{{ item }}"
state: absent
loop: "{{ groups_present }}"
- name: Ensure test hostgroups do not exist.
ipahostgroup:
name: "{{ item }}"
state: absent
loop: "{{ groups_present }}"
- name: Ensure test hosts do not exist.
ipahost:
name: "{{ item }}.{{ ipa_domain }}"
state: absent
loop: "{{ groups_present }}"
- name: Ensure test users do not exist.
ipauser:
name: "user{{ item }}"
state: absent
loop: "{{ groups_present }}"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment